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/.gitattributes b/.gitattributes index 38bba729fc1..d226cebf5d8 100644 --- a/.gitattributes +++ b/.gitattributes @@ -27,4 +27,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..81e73f871ef 100644 --- a/.github/actions/deps/external/action.yml +++ b/.github/actions/deps/external/action.yml @@ -27,7 +27,7 @@ runs: 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 @@ -56,6 +56,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/broadcom/action.yml b/.github/actions/deps/ports/broadcom/action.yml index 9ad0e361bda..fc375aa10f7 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 diff --git a/.github/actions/deps/ports/espressif/action.yml b/.github/actions/deps/ports/espressif/action.yml index 25965eb7ef0..321a0fb2b30 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,7 +27,7 @@ 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 }} diff --git a/.github/actions/deps/ports/nordic/action.yml b/.github/actions/deps/ports/nordic/action.yml index 5f08b17ca7a..96754be9507 100644 --- a/.github/actions/deps/ports/nordic/action.yml +++ b/.github/actions/deps/ports/nordic/action.yml @@ -5,7 +5,7 @@ runs: steps: - name: Get nrfutil 7+ run: | - wget https://developer.nordicsemi.com/.pc-tools/nrfutil/x64-linux/nrfutil + wget https://files.nordicsemi.com/artifactory/swtools/external/nrfutil/executables/x86_64-unknown-linux-gnu/nrfutil chmod +x nrfutil ./nrfutil install nrf5sdk-tools mkdir -p $HOME/.local/bin diff --git a/.github/actions/deps/ports/zephyr-cp/action.yml b/.github/actions/deps/ports/zephyr-cp/action.yml index cfa1177598e..4475132e185 100644 --- a/.github/actions/deps/ports/zephyr-cp/action.yml +++ b/.github/actions/deps/ports/zephyr-cp/action.yml @@ -3,6 +3,19 @@ name: Fetch Zephyr port deps 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 dpkg --add-architecture i386 + sudo apt-get update + sudo apt-get install -y libusb-1.0-0-dev libudev-dev pkg-config mtools + # 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 +26,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..5ec57b594c0 100644 --- a/.github/actions/deps/submodules/action.yml +++ b/.github/actions/deps/submodules/action.yml @@ -48,7 +48,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,7 +56,7 @@ 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') }} diff --git a/.github/actions/mpy_cross/action.yml b/.github/actions/mpy_cross/action.yml index 8839f790915..469b8b0763e 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 @@ -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..c17e1b13f97 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 @@ -124,7 +124,7 @@ jobs: run: make -j4 $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..6fbc5b6a08f 100644 --- a/.github/workflows/build-boards.yml +++ b/.github/workflows/build-boards.yml @@ -29,7 +29,7 @@ jobs: board: ${{ fromJSON(inputs.boards) }} steps: - name: Set up repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: submodules: false show-progress: false @@ -37,7 +37,7 @@ jobs: persist-credentials: false - name: Set up python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: 3.x @@ -87,7 +87,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..9e5c1cdfc4a 100644 --- a/.github/workflows/build-mpy-cross.yml +++ b/.github/workflows/build-mpy-cross.yml @@ -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 @@ -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..bd803a5eb6b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -6,6 +6,9 @@ name: Build CI on: push: + branches: + - main + - '*.x' pull_request: release: types: [published] @@ -28,14 +31,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 @@ -107,21 +110,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 +134,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 + - 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 +159,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 @@ -192,20 +180,20 @@ jobs: pip install -r requirements-doc.txt - name: Build and Validate Stubs run: make check-stubs -j4 - - uses: actions/upload-artifact@v4 + - 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 @@ -261,7 +249,7 @@ jobs: 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 + wget --no-verbose -O gcc-arm.zip https://developer.arm.com/-/media/Files/downloads/gnu/15.2.rel1/binrel/arm-gnu-toolchain-15.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 @@ -275,7 +263,7 @@ jobs: which python; python --version; python -c "import cascadetoml" which python3; python3 --version; python3 -c "import cascadetoml" - name: Set up repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: submodules: false show-progress: false @@ -310,13 +298,13 @@ 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 - - uses: actions/setup-python@v5 + - uses: actions/setup-python@v6 with: python-version: '3.13' - name: Set up Zephyr diff --git a/.github/workflows/bundle_cron.yml b/.github/workflows/bundle_cron.yml new file mode 100644 index 00000000000..eefffaaa5b9 --- /dev/null +++ b/.github/workflows/bundle_cron.yml @@ -0,0 +1,58 @@ +# SPDX-FileCopyrightText: 2019 Michael Schroeder +# +# SPDX-License-Identifier: MIT + +name: Update Bundles + +on: + schedule: + - cron: 0 5 * * * + workflow_dispatch: + +jobs: + check-repo-owner: + # This job is so the entire workflow will end successfully and give some + # output to explain why it hasn't run on a non-Adafruit fork. + runs-on: ubuntu-latest + steps: + - name: repository + env: + OWNER_IS_ADAFRUIT: ${{ startswith(github.repository, 'adafruit/') }} + run: | + echo "This workflow will only run if Adafruit is the repository owner." + echo "Repository owner is Adafruit: $OWNER_IS_ADAFRUIT" + update-bundles: + runs-on: ubuntu-latest + # Only run the build on Adafruit's repository. Forks won't have the secrets. + # It's necessary to do this here, since 'schedule' events cannot (currently) + # be limited (they run on all forks' default branches). + if: startswith(github.repository, 'adafruit/') + steps: + - name: Set up Python 3.12 + uses: actions/setup-python@v6 + with: + python-version: 3.12 + - name: Load contributor cache + uses: actions/cache@v5 + with: + key: "contributor-cache" + path: "contributors.json" + - name: Versions + run: | + python3 --version + - uses: actions/checkout@v6 + with: + repository: 'adafruit/adabot' + submodules: true + - name: Install deps + run: | + pip install -r requirements.txt + - name: Run adabot.circuitpython_bundle + env: + ADABOT_EMAIL: ${{ secrets.ADABOT_EMAIL }} + ADABOT_GITHUB_USER: ${{ secrets.ADABOT_GITHUB_USER }} + ADABOT_GITHUB_ACCESS_TOKEN: ${{ secrets.ADABOT_GITHUB_ACCESS_TOKEN }} + BIGQUERY_PRIVATE_KEY: ${{ secrets.BIGQUERY_PRIVATE_KEY }} + BIGQUERY_CLIENT_EMAIL: ${{ secrets.BIGQUERY_CLIENT_EMAIL }} + run: | + python3 -u -m adabot.circuitpython_bundle 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 new file mode 100644 index 00000000000..135089bfd5e --- /dev/null +++ b/.github/workflows/learn_cron.yml @@ -0,0 +1,41 @@ +# SPDX-FileCopyrightText: 2021 Jeff Epler for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +name: Tag Learning System Guides + +on: + schedule: + - cron: 0 5 * * * + +jobs: + check-repo-owner: + # This job is so the entire workflow will end successfully and give some + # output to explain why it hasn't run on a non-Adafruit fork. + runs-on: ubuntu-latest + if: ${{ (github.repository_owner != 'adafruit') }} + steps: + - run: | + echo "This workflow is only intended to run in the adafruit fork" + + update-learn: + runs-on: ubuntu-latest + # Only run the build if the access token has been configured. This will be + # the case on Adafruit's repository. It's necessary to do this here, since + # 'schedule' events cannot (currently) be limited (they run on all forks' + # default branches). + if: ${{ (github.repository_owner == 'adafruit') }} + steps: + - uses: actions/checkout@v6 + with: + repository: ${{ github.repository_owner }}/Adafruit_Learning_System_Guides + token: ${{ secrets.ADABOT_GITHUB_ACCESS_TOKEN }} + - name: Tag a release + env: + ADABOT_EMAIL: ${{ secrets.ADABOT_EMAIL }} + run: | + git config --global user.name adabot + git config --global user.email "$ADABOT_EMAIL" + TAG_NAME=`date +%Y%m%d` + git tag $TAG_NAME + git push origin $TAG_NAME diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 778270dc08c..21ae984e468 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -17,14 +17,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 +42,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 new file mode 100644 index 00000000000..476ead95d25 --- /dev/null +++ b/.github/workflows/reports_cron.yml @@ -0,0 +1,91 @@ +# SPDX-FileCopyrightText: 2019 Michael Schroeder +# +# SPDX-License-Identifier: MIT + +name: Run Daily Reports + +on: + schedule: + # The actor (github.actor) that runs the cron job may be the user who created the cron job + # initially. It does not appear to be settable via a secret or environment variable. + - cron: 15 5 * * * + workflow_dispatch: + + +jobs: + check-repo-owner: + # This job is so the entire workflow will end successfully and give some + # output to explain why it hasn't run on a non-Adafruit fork. + runs-on: ubuntu-latest + steps: + - name: repository + env: + OWNER_IS_ADAFRUIT: ${{ startswith(github.repository, 'adafruit/') }} + run: | + echo "This workflow will only run if Adafruit is the repository owner." + echo "Repository owner is Adafruit: $OWNER_IS_ADAFRUIT" + run-reports: + runs-on: ubuntu-latest + # Only run the build on Adafruit's repository. Forks won't have the secrets. + # It's necessary to do this here, since 'schedule' events cannot (currently) + # be limited (they run on all forks' default branches). + if: startswith(github.repository, 'adafruit/') + env: + ADABOT_GITHUB_USER: ${{ secrets.ADABOT_GITHUB_USER }} + ADABOT_GITHUB_ACCESS_TOKEN: ${{ secrets.ADABOT_GITHUB_ACCESS_TOKEN }} + RTD_TOKEN: ${{ secrets.RTD_TOKEN }} + BIGQUERY_PRIVATE_KEY: ${{ secrets.BIGQUERY_PRIVATE_KEY }} + BIGQUERY_CLIENT_EMAIL: ${{ secrets.BIGQUERY_CLIENT_EMAIL }} + steps: + - name: Set up Python 3.11 + uses: actions/setup-python@v6 + with: + python-version: 3.11 + - name: Versions + run: | + python3 --version + - uses: actions/checkout@v6 + with: + repository: 'adafruit/adabot' + submodules: true + - name: Install deps + run: | + pip install -r requirements.txt + - name: Make Directory For Report Files + run: mkdir -p bin/adabot + - name: Set Date Variable + id: today + run: | + echo date=$( + date +%Y%m%d + ) >> $GITHUB_OUTPUT + - name: Run adabot.circuitpython_libraries + env: + # LIB_CHECK_CP_FILE is for circuitpython_libraries.py output + LIB_CHECK_CP_FILE: bin/adabot/circuitpython_library_report_${{ steps.today.outputs.date }}.txt + run: | + python3 -u -m adabot.circuitpython_libraries -o $LIB_CHECK_CP_FILE + continue-on-error: true + - name: Run adabot.circuitpython_library_download_stats + env: + # LIB_DL_STATS_FILE is for future Bundle and PyPi download stats script + LIB_DL_STATS_FILE: bin/adabot/library_download_stats_${{ steps.today.outputs.date }}.txt + run: | + python3 -u -m adabot.circuitpython_library_download_stats -o $LIB_DL_STATS_FILE + continue-on-error: true + - name: Run adabot.arduino_libraries + env: + # LIB_CHECK_ARD_FILE is for arduino_libraries.py output + LIB_CHECK_ARD_FILE: bin/adabot/arduino_library_report_${{ steps.today.outputs.date }}.txt + run: | + python3 -u -m adabot.arduino_libraries -o $LIB_CHECK_ARD_FILE + continue-on-error: true + - name: Check For Files + run: | + ls bin/adabot + - name: Upload Reports To AWS S3 + if: ${{ github.event_name != 'workflow_dispatch' }} + env: + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + run: "[ -z \"$AWS_ACCESS_KEY_ID\" ] || aws s3 cp bin/adabot/ s3://adafruit-circuit-python/adabot/bin/reports/ --recursive --no-progress --region us-east-1" diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 80bfc72bd98..83154bbbd2b 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -23,36 +23,36 @@ 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 + - 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 -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' @@ -66,3 +66,39 @@ jobs: # if: matrix.test == 'all' # run: ./run-natmodtests.py extmod/{heapq*,random*,re*}.py # working-directory: tests + + zephyr: + runs-on: ubuntu-24.04 + strategy: + fail-fast: false + 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 + - 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 native sim target + run: make -C ports/zephyr-cp -j2 BOARD=native_native_sim + - name: Build bsim + run: make -j 2 everything + working-directory: ports/zephyr-cp/tools/bsim + - name: Build native_nrf5340bsim + run: make -C ports/zephyr-cp -j2 BOARD=native_nrf5340bsim + - name: Run Zephyr tests + run: make -C ports/zephyr-cp test diff --git a/.gitignore b/.gitignore index f996911d8d7..ca6872387dd 100644 --- a/.gitignore +++ b/.gitignore @@ -55,6 +55,9 @@ __pycache__/ ###################### GNUmakefile user.props +user_pre_mpconfigport.mk +user_post_mpconfigport.mk +user_post_circuitpy_defns.mk # Sphinx output ############### @@ -107,3 +110,10 @@ TAGS # windsurf rules .windsurfrules + +# git-review-web outputs +.review + +# Zephyr trace files +**/channel0_0 +**/*.perfetto-trace diff --git a/.gitmodules b/.gitmodules index b1ec0f9faee..a7b67b8d860 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 @@ -172,7 +172,7 @@ url = https://github.com/adafruit/Adafruit_CircuitPython_SimpleMath [submodule "ports/raspberrypi/sdk"] path = ports/raspberrypi/sdk - url = https://github.com/adafruit/pico-sdk.git + url = https://github.com/raspberrypi/pico-sdk.git branch = force_inline_critical_section_2.1.1 [submodule "data/nvm.toml"] path = data/nvm.toml @@ -415,3 +415,9 @@ [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 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_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 f2fc070a633..175a1b6a302 100644 --- a/Makefile +++ b/Makefile @@ -299,6 +299,9 @@ update-frozen-libraries: one-of-each: samd21 litex mimxrt10xx nordic stm +analog: + $(MAKE) -C ports/analog/ BOARD=apard32690 + samd21: $(MAKE) -C ports/atmel-samd BOARD=trinket_m0 @@ -372,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..e2a8cbbd82f 100644 --- a/conf.py +++ b/conf.py @@ -192,7 +192,12 @@ 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", +] # The reST default role (used for this markup: `text`) to use for all # documents. diff --git a/devices/ble_hci/common-hal/_bleio/Adapter.c b/devices/ble_hci/common-hal/_bleio/Adapter.c index fac7eb9f5fd..aaff47f42a6 100644 --- a/devices/ble_hci/common-hal/_bleio/Adapter.c +++ b/devices/ble_hci/common-hal/_bleio/Adapter.c @@ -29,7 +29,7 @@ #include "shared-bindings/_bleio/ScanEntry.h" #include "shared-bindings/time/__init__.h" -#if CIRCUITPY_OS_GETENV +#if CIRCUITPY_SETTINGS_TOML #include "shared-bindings/os/__init__.h" #endif @@ -259,9 +259,11 @@ 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) { + self->name = NULL; + mp_int_t name_len = 0; - #if CIRCUITPY_OS_GETENV + #if CIRCUITPY_SETTINGS_TOML 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); @@ -950,7 +952,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/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.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.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..f9fdbc50f64 100644 --- a/devices/ble_hci/common-hal/_bleio/__init__.c +++ b/devices/ble_hci/common-hal/_bleio/__init__.c @@ -84,7 +84,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/docs/environment.rst b/docs/environment.rst index b97820b3caf..2c72b4f1004 100644 --- a/docs/environment.rst +++ b/docs/environment.rst @@ -1,69 +1,82 @@ 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 ~~~~~~~~~~~~~~~~~~ -Default BLE name the board advertises as, including for the BLE workflow. +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_HEAP_START_SIZE ~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -83,24 +96,43 @@ Used to avoid "Pystack exhausted" errors when the code can't be reworked to avoi CIRCUITPY_WEB_API_PASSWORD ~~~~~~~~~~~~~~~~~~~~~~~~~~ Password required to make modifications to the board from the Web Workflow. +If the password is not specified, the Web Workflow is not enabled. CIRCUITPY_WEB_API_PORT ~~~~~~~~~~~~~~~~~~~~~~ -TCP port number used for the web HTTP API. Defaults to 80 when omitted. +TCP port number used for the Web Workflow 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. +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 ~~~~~~~~~~~~~~~~~~~ -Wi-Fi SSID to auto-connect to even if user code is not running. +CIRCUITPY_WIFI_PASSWORD +~~~~~~~~~~~~~~~~~~~~~~~ +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. -Additional board specific keys +CIRCUITPY_WIFI_HOSTNAME +~~~~~~~~~~~~~~~~~~~~~~~ +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 +^^^^^^^^^^^^^^^^^^^^ +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``. +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) @@ -181,13 +213,20 @@ Example: Configure the display to 640x480 black and white (1 bit per pixel): `Adafruit Feather RP2350 `_ `Adafruit Metro RP2350 `_ +CIRCUITPY_SAFEMODE_DELAY +~~~~~~~~~~~~~~~~~~~~~~~~ +Wait for the specified amount of time, in seconds (as a float), 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 ~~~~~~~~~~~~~~~~~~~~~~~~ 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. @@ -197,7 +236,7 @@ Specifies a custom font file path to use for the terminalio console instead of t ``/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/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/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..b8aeefd90cf 100644 --- a/docs/library/re.rst +++ b/docs/library/re.rst @@ -154,8 +154,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 +163,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/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/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/workflows.md b/docs/workflows.md index 761504144d8..84d7530e2fe 100644 --- a/docs/workflows.md +++ b/docs/workflows.md @@ -44,6 +44,12 @@ A few boards have SD card automounting. (This is based on the ``DEFAULT_SD`` set ``mpconfigboard.h``.) The 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. + ### CDC serial CircuitPython exposes one CDC USB interface for CircuitPython serial. This is a standard serial USB interface. 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/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/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/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..c4156990bcc 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; diff --git a/extmod/vfs.h b/extmod/vfs.h index 67d5d9239a3..699232e56cd 100644 --- a/extmod/vfs.h +++ b/extmod/vfs.h @@ -52,6 +52,8 @@ #define MP_BLOCKDEV_FLAG_CONCURRENT_WRITE_PROTECTED (0x0020) // Bit set when something has claimed the right to mutate the blockdev. #define MP_BLOCKDEV_FLAG_LOCKED (0x0040) +// Ignore write protections. Used to override other flags temporarily. +#define MP_BLOCKDEV_FLAG_IGNORE_WRITE_PROTECTION (0x0080) // constants for block protocol ioctl #define MP_BLOCKDEV_IOCTL_INIT (1) diff --git a/extmod/vfs_blockdev.c b/extmod/vfs_blockdev.c index f1187b9bbf2..74d1262364e 100644 --- a/extmod/vfs_blockdev.c +++ b/extmod/vfs_blockdev.c @@ -63,7 +63,16 @@ 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 (self->u.ioctl[0] != MP_OBJ_NULL) { @@ -99,7 +108,7 @@ static int mp_vfs_blockdev_call_rw(mp_obj_t *args, size_t block_num, size_t bloc // 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; } } diff --git a/extmod/vfs_fat.c b/extmod/vfs_fat.c index 5011a820af8..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]); } @@ -427,13 +427,10 @@ static MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_statvfs_obj, fat_vfs_statvfs); static mp_obj_t vfs_fat_mount(mp_obj_t self_in, mp_obj_t readonly, mp_obj_t mkfs) { fs_user_mount_t *self = MP_OBJ_TO_PTR(self_in); - // Read-only device indicated by writeblocks[0] == MP_OBJ_NULL. - // User can specify read-only device by: - // 1. readonly=True keyword argument - // 2. nonexistent writeblocks method (then writeblocks[0] == MP_OBJ_NULL already) - if (mp_obj_is_true(readonly)) { - self->blockdev.writeblocks[0] = MP_OBJ_NULL; - } + // CIRCUITPY-CHANGE: Use MP_BLOCKDEV_FLAG_USB_WRITABLE instead of writeblocks[0] =/!= MP_OBJ_NULL + // to specify read-write. + // If readonly to Python, it's writable by USB and vice versa. + filesystem_set_writable_by_usb(self, mp_obj_is_true(readonly)); // check if we need to make the filesystem FRESULT res = (self->blockdev.flags & MP_BLOCKDEV_FLAG_NO_FILESYSTEM) ? FR_NO_FILESYSTEM : FR_OK; diff --git a/extmod/vfs_fat_diskio.c b/extmod/vfs_fat_diskio.c index 6f500104d1e..591da07eb56 100644 --- a/extmod/vfs_fat_diskio.c +++ b/extmod/vfs_fat_diskio.c @@ -43,6 +43,9 @@ #include "lib/oofatfs/diskio.h" #include "extmod/vfs_fat.h" +// CIRCUITPY-CHANGE +#include "supervisor/filesystem.h" + typedef void *bdev_t; static fs_user_mount_t *disk_get_device(void *bdev) { return (fs_user_mount_t *)bdev; @@ -153,7 +156,8 @@ DRESULT disk_ioctl( if (ret != mp_const_none && MP_OBJ_SMALL_INT_VALUE(ret) != 0) { // error initialising stat = STA_NOINIT; - } else if (vfs->blockdev.writeblocks[0] == MP_OBJ_NULL) { + // CIRCUITPY-CHANGE: writability from Python check + } else if (!filesystem_is_writable_by_python(vfs)) { stat = STA_PROTECT; } else { stat = 0; 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..56daa53e068 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 diff --git a/extmod/vfs_posix.c b/extmod/vfs_posix.c index bd9a6d84062..27f833e802f 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,11 +332,13 @@ static mp_obj_t vfs_posix_mkdir(mp_obj_t self_in, mp_obj_t path_in) { static MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_mkdir_obj, vfs_posix_mkdir); static mp_obj_t vfs_posix_remove(mp_obj_t self_in, mp_obj_t path_in) { + vfs_posix_require_writable(self_in); return vfs_posix_fun1_helper(self_in, path_in, unlink); } static MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_remove_obj, vfs_posix_remove); static mp_obj_t vfs_posix_rename(mp_obj_t self_in, mp_obj_t old_path_in, mp_obj_t new_path_in) { + vfs_posix_require_writable(self_in); mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in); const char *old_path = vfs_posix_get_path_str(self, old_path_in); const char *new_path = vfs_posix_get_path_str(self, new_path_in); @@ -339,6 +353,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_reader.c b/extmod/vfs_reader.c index de5c4e03d3c..6c36770295b 100644 --- a/extmod/vfs_reader.c +++ b/extmod/vfs_reader.c @@ -83,7 +83,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/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_Bitmap_Font b/frozen/Adafruit_CircuitPython_Bitmap_Font index 5ca3f55f2e3..fe0cdfd5501 160000 --- a/frozen/Adafruit_CircuitPython_Bitmap_Font +++ b/frozen/Adafruit_CircuitPython_Bitmap_Font @@ -1 +1 @@ -Subproject commit 5ca3f55f2e39302c787ca93f95276e8269024038 +Subproject commit fe0cdfd5501070f5ca47b3e66dfd15e62c54011e 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_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..eae352b0970 160000 --- a/frozen/Adafruit_CircuitPython_Display_Text +++ b/frozen/Adafruit_CircuitPython_Display_Text @@ -1 +1 @@ -Subproject commit 7d1f187aac8e899e791324cc78633bf4f32c984b +Subproject commit eae352b09700e57b78507aace7ff682cb1beff5a diff --git a/frozen/Adafruit_CircuitPython_DotStar b/frozen/Adafruit_CircuitPython_DotStar index 163f2f166ae..d08e231d5f9 160000 --- a/frozen/Adafruit_CircuitPython_DotStar +++ b/frozen/Adafruit_CircuitPython_DotStar @@ -1 +1 @@ -Subproject commit 163f2f166aee11d82303492bb1e5af4937e57b62 +Subproject commit d08e231d5f95566a09f2a0c08cb647703882262d diff --git a/frozen/Adafruit_CircuitPython_ESP32SPI b/frozen/Adafruit_CircuitPython_ESP32SPI index 063b90c8706..b0e2124a175 160000 --- a/frozen/Adafruit_CircuitPython_ESP32SPI +++ b/frozen/Adafruit_CircuitPython_ESP32SPI @@ -1 +1 @@ -Subproject commit 063b90c8706ddef97cc4abf9cb78e0cc09ff3c6c +Subproject commit b0e2124a175f421bb07ac5cc72b81f6209966a3b diff --git a/frozen/Adafruit_CircuitPython_FakeRequests b/frozen/Adafruit_CircuitPython_FakeRequests index aa034280ebf..130a3d7fcfb 160000 --- a/frozen/Adafruit_CircuitPython_FakeRequests +++ b/frozen/Adafruit_CircuitPython_FakeRequests @@ -1 +1 @@ -Subproject commit aa034280ebfed80c245827ff1d49a098ace64b03 +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 b70106b17bb..c1d964fe7bf 160000 --- a/frozen/Adafruit_CircuitPython_HTTPServer +++ b/frozen/Adafruit_CircuitPython_HTTPServer @@ -1 +1 @@ -Subproject commit b70106b17bbfa0070f8573e1e06e384d9d4577de +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..3bc5c15c707 160000 --- a/frozen/Adafruit_CircuitPython_ImageLoad +++ b/frozen/Adafruit_CircuitPython_ImageLoad @@ -1 +1 @@ -Subproject commit 135b0e4478b34e1271e6bd87fa6d8efa0bef64b5 +Subproject commit 3bc5c15c7079e076b49f9929bb956de8812c62f8 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 5d13d0966a7..38a3c7844b4 160000 --- a/frozen/Adafruit_CircuitPython_LED_Animation +++ b/frozen/Adafruit_CircuitPython_LED_Animation @@ -1 +1 @@ -Subproject commit 5d13d0966a775369eca5b137cfef9583dfa8bb42 +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..928d747a826 160000 --- a/frozen/Adafruit_CircuitPython_MPU6050 +++ b/frozen/Adafruit_CircuitPython_MPU6050 @@ -1 +1 @@ -Subproject commit 05a0c3b72279db9fa2431308a77e6ab7ba040c8a +Subproject commit 928d747a826fc8d8c4237ed1b40b53cf723cf1ee diff --git a/frozen/Adafruit_CircuitPython_Motor b/frozen/Adafruit_CircuitPython_Motor index 89facc69a40..20ebf51fe0d 160000 --- a/frozen/Adafruit_CircuitPython_Motor +++ b/frozen/Adafruit_CircuitPython_Motor @@ -1 +1 @@ -Subproject commit 89facc69a405ae83702ce566414adc39d46068f1 +Subproject commit 20ebf51fe0d2bb48b1780c3c9bd74c16c73bc02e 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 3dce5bca3bc..fc4aeea36ae 160000 --- a/frozen/Adafruit_CircuitPython_PortalBase +++ b/frozen/Adafruit_CircuitPython_PortalBase @@ -1 +1 @@ -Subproject commit 3dce5bca3bcd27354becc6d3ecf82244f1e26ffe +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..e168e97a2c9 160000 --- a/frozen/Adafruit_CircuitPython_Register +++ b/frozen/Adafruit_CircuitPython_Register @@ -1 +1 @@ -Subproject commit 96d0a4774f5525b926c131618e436b8e5c218a2f +Subproject commit e168e97a2c9713ec0f82cb6171461873dfffd46d 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 b7d511711c8..292f58b987d 160000 --- a/frozen/Adafruit_CircuitPython_SSD1680 +++ b/frozen/Adafruit_CircuitPython_SSD1680 @@ -1 +1 @@ -Subproject commit b7d511711c8f5557082d9c4307a89ecdec608727 +Subproject commit 292f58b987db50dd622be5b83722893c58c16ab9 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_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 776b932ebf7..9a37fc43eeb 160000 --- a/frozen/Adafruit_CircuitPython_UC8151D +++ b/frozen/Adafruit_CircuitPython_UC8151D @@ -1 +1 @@ -Subproject commit 776b932ebf76937e464ab2656834e7a1c1e3434b +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 6b3484d1ee2..f01275e34ad 160000 --- a/frozen/Adafruit_CircuitPython_Wiznet5k +++ b/frozen/Adafruit_CircuitPython_Wiznet5k @@ -1 +1 @@ -Subproject commit 6b3484d1ee243a7e8bc0513ab84956e1b6e2a520 +Subproject commit f01275e34ad2e5f7ddd9d074e963a8359011a297 diff --git a/frozen/Adafruit_CircuitPython_asyncio b/frozen/Adafruit_CircuitPython_asyncio index 24818f817f5..d0d63f113c7 160000 --- a/frozen/Adafruit_CircuitPython_asyncio +++ b/frozen/Adafruit_CircuitPython_asyncio @@ -1 +1 @@ -Subproject commit 24818f817f5118f59aa696a04776049c179c0f4f +Subproject commit d0d63f113c7da0852bdc5aa303cd738e45d40fbc 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/lfs1.c b/lib/littlefs/lfs1.c index 6a3fd670012..ec18dc47025 100644 --- a/lib/littlefs/lfs1.c +++ b/lib/littlefs/lfs1.c @@ -2141,7 +2141,7 @@ int lfs1_format(lfs1_t *lfs1, const struct lfs1_config *cfg) { .d.elen = sizeof(superblock.d) - sizeof(superblock.d.magic) - 4, .d.nlen = sizeof(superblock.d.magic), .d.version = LFS1_DISK_VERSION, - .d.magic = {"littlefs"}, + .d.magic = {'l', 'i', 't', 't', 'l', 'e', 'f', 's'}, .d.block_size = lfs1->cfg->block_size, .d.block_count = lfs1->cfg->block_count, .d.root = {lfs1->root[0], lfs1->root[1]}, diff --git a/lib/littlefs/lfs2.c b/lib/littlefs/lfs2.c index 613213669c8..8d18b7d1105 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; } @@ -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 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); @@ -1438,32 +1474,46 @@ 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, "/"); + // skip slashes if we're a directory + if (lfs2_tag_type3(tag) == LFS2_TYPE_DIR) { + name += strspn(name, "/"); + } lfs2_size_t namelen = 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; @@ -1475,7 +1525,9 @@ static lfs2_stag_t lfs2_dir_find(lfs2_t *lfs2, lfs2_mdir_t *dir, 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 +1541,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 +1568,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) { @@ -2105,13 +2156,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 +2198,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 +2220,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 +2268,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 +2367,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 +2389,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 +2557,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 +2622,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 +2633,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 +2718,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 +2762,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 +2814,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 +2851,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 +3062,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 +3087,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 +3107,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,22 +3230,22 @@ 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) { +static int lfs2_file_close_(lfs2_t *lfs2, lfs2_file_t *file) { #ifndef LFS2_READONLY - int err = lfs2_file_rawsync(lfs2, file); + int err = lfs2_file_sync_(lfs2, file); #else int err = 0; #endif @@ -3272,7 +3336,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,7 +3428,7 @@ 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) { +static int lfs2_file_sync_(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; @@ -3379,6 +3443,15 @@ static int lfs2_file_rawsync(lfs2_t *lfs2, lfs2_file_t *file) { 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; @@ -3477,7 +3550,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 +3575,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 +3604,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 +3647,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); @@ -3628,25 +3697,19 @@ static lfs2_ssize_t lfs2_file_rawwrite(lfs2_t *lfs2, lfs2_file_t *file, } #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 +3724,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 +3750,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 +3758,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 +3808,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 +3823,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 +3832,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 +3846,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 +3860,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 +3933,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 +3958,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 +3977,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 +3988,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 +4007,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 +4055,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 +4079,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 +4104,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 +4162,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 +4173,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 +4215,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 +4250,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 +4294,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 +4328,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 +4379,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 +4388,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 +4399,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 +4455,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 +4487,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 +4545,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 +4553,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 +4591,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 +4634,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 +4690,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 +4709,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]); @@ -4647,22 +4798,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 +4858,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 +5140,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 +5176,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 +5186,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; + } - if (block_count > lfs2->block_count) { - lfs2->block_count = block_count; + // 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; + } - // fetch the root - lfs2_mdir_t root; - int err = lfs2_dir_fetch(lfs2, &root, lfs2->root); + // 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; + } + } + } + } + + // 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 +5669,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 +5723,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 +5977,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 +5990,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 +6007,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 +6020,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 +6034,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 +6049,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 +6065,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 +6080,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 +6096,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 +6113,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 +6129,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 +6144,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 +6164,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 +6183,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 +6199,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 +6217,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 +6235,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 +6253,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 +6270,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 +6286,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 +6300,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 +6315,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 +6330,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 +6346,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 +6360,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 +6375,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 +6390,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 +6404,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 +6418,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 +6432,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 +6446,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 +6461,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 +6469,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 +6508,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 +6526,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 +6539,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..aee0619e932 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 @@ -205,7 +204,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 +226,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 +248,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 +274,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 +449,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 +732,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 +744,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_config/crt_bundle.c b/lib/mbedtls_config/crt_bundle.c index 9c546a26883..4a8836fb586 100644 --- a/lib/mbedtls_config/crt_bundle.c +++ b/lib/mbedtls_config/crt_bundle.c @@ -74,12 +74,14 @@ static int crt_check_signature(mbedtls_x509_crt *child, const uint8_t *pub_key_b } + #if MBEDTLS_VERSION_MAJOR < 4 // 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; } + #endif 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) { @@ -87,10 +89,17 @@ static int crt_check_signature(mbedtls_x509_crt *child, const uint8_t *pub_key_b goto cleanup; } + #if MBEDTLS_VERSION_MAJOR >= 4 + if ((ret = mbedtls_pk_verify_ext( + 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) { + #else if ((ret = mbedtls_pk_verify_ext( child->MBEDTLS_PRIVATE(sig_pk), child->MBEDTLS_PRIVATE(sig_opts), &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) { + #endif LOGE(TAG, "PK verify failed with error %X", ret); goto cleanup; diff --git a/lib/micropython-lib b/lib/micropython-lib index 5b496e944ec..6ae440a8a14 160000 --- a/lib/micropython-lib +++ b/lib/micropython-lib @@ -1 +1 @@ -Subproject commit 5b496e944ec045177afa1620920a168410b7f60b +Subproject commit 6ae440a8a144233e6e703f6759b7e7a0afaa37a4 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/tinyusb b/lib/tinyusb index 542e5b4550a..c1bf19ed6cf 160000 --- a/lib/tinyusb +++ b/lib/tinyusb @@ -1 +1 @@ -Subproject commit 542e5b4550a01d034b78308d77c408ed89427513 +Subproject commit c1bf19ed6cf1eaa791f221c1bc5ce4b3d069f76d 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 262b5de769c..117b3053610 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -78,6 +78,11 @@ msgid "" "%d address pins, %d rgb pins and %d tiles indicate a height of %d, not %d" msgstr "" +#: py/emitinlinextensa.c +#, c-format +msgid "%d is not a multiple of %d" +msgstr "" + #: shared-bindings/microcontroller/Pin.c msgid "%q and %q contain duplicate pins" msgstr "" @@ -99,6 +104,7 @@ msgid "%q contains duplicate pins" msgstr "" #: ports/atmel-samd/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c msgid "%q failure: %d" msgstr "" @@ -111,6 +117,8 @@ msgid "%q in %q must be of type %q, not %q" 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 @@ -118,7 +126,8 @@ msgstr "" #: 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 +#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/microcontroller/Pin.c +#: shared-module/max3421e/Max3421E.c msgid "%q in use" msgstr "" @@ -130,7 +139,10 @@ msgstr "" msgid "%q indices must be integers, not %s" msgstr "" -#: shared-module/bitbangio/SPI.c +#: 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 msgid "%q init failed" msgstr "" @@ -162,8 +174,8 @@ msgstr "" msgid "%q must be %d" msgstr "" -#: py/argcheck.c shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/displayio/Bitmap.c +#: 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 @@ -174,6 +186,20 @@ msgstr "" msgid "%q must be 1 when %q is True" msgstr "" +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "%q must be 16, 24, or 32" +msgstr "" + +#: 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/audiobusio/PDMIn.c +#: shared-bindings/audioi2sin/I2SIn.c +msgid "%q must be 8, 16, 24, or 32" +msgstr "" + #: py/argcheck.c shared-bindings/gifio/GifWriter.c #: shared-module/gifio/OnDiskGif.c msgid "%q must be <= %d" @@ -233,23 +259,29 @@ msgstr "" msgid "%q must be power of 2" msgstr "" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' attribute" +msgstr "" + +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' method" +msgstr "" + #: shared-bindings/wifi/Monitor.c msgid "%q out of bounds" 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 +#: shared-bindings/bitmaptools/__init__.c shared-bindings/canio/Match.c +#: shared-bindings/time/__init__.c msgid "%q out of range" msgstr "" -#: py/objmodule.c -msgid "%q renamed %q" -msgstr "" - #: py/objrange.c py/objslice.c shared-bindings/random/__init__.c msgid "%q step cannot be zero" msgstr "" @@ -300,7 +332,7 @@ msgstr "" msgid "'%q' argument required" msgstr "" -#: py/proto.c +#: py/proto.c shared-bindings/digitalio/DigitalInOutProtocol.c msgid "'%q' object does not support '%q'" msgstr "" @@ -445,6 +477,7 @@ msgstr "" msgid ", in %q\n" msgstr "" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c #: shared-bindings/busdisplay/BusDisplay.c #: shared-bindings/epaperdisplay/EPaperDisplay.c #: shared-bindings/framebufferio/FramebufferDisplay.c @@ -463,7 +496,7 @@ msgstr "" msgid "AP could not be started" msgstr "" -#: shared-bindings/_bleio/Address.c shared-bindings/ipaddress/IPv4Address.c +#: shared-bindings/ipaddress/IPv4Address.c #, c-format msgid "Address must be %d bytes long" msgstr "" @@ -498,7 +531,8 @@ msgstr "" msgid "All SPI peripherals are in use" msgstr "" -#: ports/espressif/common-hal/busio/UART.c ports/nordic/common-hal/busio/UART.c +#: 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 "" @@ -569,7 +603,7 @@ msgstr "" msgid "Already scanning for wifi networks" msgstr "" -#: shared-module/os/getenv.c +#: supervisor/shared/settings.c #, c-format msgid "An error occurred while retrieving '%s':\n" msgstr "" @@ -596,6 +630,10 @@ msgstr "" msgid "Async SPI transfer in progress on this bus, keep awaiting." msgstr "" +#: shared-bindings/usb_audio/__init__.c +msgid "At least one of microphone and speaker must be enabled" +msgstr "" + #: shared-module/memorymonitor/AllocationAlarm.c #, c-format msgid "Attempt to allocate %d blocks" @@ -607,6 +645,7 @@ msgstr "" #: 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 "" @@ -632,12 +671,14 @@ msgstr "" msgid "Baudrate not supported by peripheral" 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/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 "" @@ -649,20 +690,17 @@ msgstr "" msgid "Boot device must be first (interface #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" msgstr "" +#: 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/_bleio/UUID.c -#, c-format -msgid "Buffer + offset too small %d %d %d" -msgstr "" - #: ports/raspberrypi/bindings/rp2pio/StateMachine.c msgid "Buffer elements must be 4 bytes long or less" msgstr "" @@ -705,10 +743,6 @@ msgstr "" msgid "Bus pin %d is already in use" msgstr "" -#: shared-bindings/_bleio/UUID.c -msgid "Byte buffer must be 16 bytes." -msgstr "" - #: shared-bindings/aesio/aes.c msgid "CBC blocks must be multiples of 16 bytes" msgstr "" @@ -750,9 +784,9 @@ msgstr "" msgid "Can't set CCCD on local Characteristic" 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 +#: 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 "" @@ -760,6 +794,10 @@ msgstr "" msgid "Cannot create a new Adapter; use _bleio.adapter;" msgstr "" +#: shared-module/i2cioexpander/IOExpander.c +msgid "Cannot deinitialize board IOExpander" +msgstr "" + #: shared-bindings/displayio/Bitmap.c #: shared-bindings/memorymonitor/AllocationSize.c #: shared-bindings/pulseio/PulseIn.c @@ -785,7 +823,7 @@ msgstr "" msgid "Cannot pull on input-only pin." msgstr "" -#: shared-bindings/audiobusio/PDMIn.c +#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c msgid "Cannot record to a file" msgstr "" @@ -794,6 +832,7 @@ msgid "Cannot remount path when visible via USB." msgstr "" #: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c msgid "Cannot set value when direction is input." msgstr "" @@ -844,6 +883,10 @@ msgstr "" msgid "Coordinate arrays types have different sizes" 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/rclcpy/Publisher.c msgid "Could not publish to ROS topic" msgstr "" @@ -866,10 +909,12 @@ msgid "Critical ROS failure during soft reboot, reset required: %d" msgstr "" #: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c msgid "DAC Channel Init Error" msgstr "" #: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c msgid "DAC Device Init Error" msgstr "" @@ -900,7 +945,7 @@ msgstr "" msgid "Deep sleep pins must use a rising edge with pulldown" msgstr "" -#: shared-bindings/audiobusio/PDMIn.c +#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c msgid "Destination capacity is smaller than destination_length." msgstr "" @@ -920,6 +965,7 @@ 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 "" @@ -928,6 +974,7 @@ msgid "Done" msgstr "" #: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c msgid "Drive mode not used when direction is input." msgstr "" @@ -939,8 +986,17 @@ msgstr "" msgid "ECB only operates on 16 bytes at a time" msgstr "" +#: py/asmxtensa.c +msgid "ERROR: %q %q not word-aligned" +msgstr "" + +#: py/asmxtensa.c +msgid "ERROR: xtensa %q out of range" +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 "" @@ -987,7 +1043,7 @@ msgid "" "Failed to add service TXT record; non-string or bytes found in txt_records" msgstr "" -#: shared-module/rgbmatrix/RGBMatrix.c +#: ports/analog/common-hal/busio/UART.c shared-module/rgbmatrix/RGBMatrix.c msgid "Failed to allocate %q buffer" msgstr "" @@ -1005,10 +1061,12 @@ 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/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c msgid "Failed to connect: timeout" msgstr "" @@ -1045,6 +1103,10 @@ msgstr "" msgid "Failed to release mutex, err 0x%04x" msgstr "" +#: ports/analog/common-hal/busio/SPI.c +msgid "Failed to set SPI Clock Mode" +msgstr "" + #: ports/zephyr-cp/common-hal/wifi/Radio.c msgid "Failed to set hostname" msgstr "" @@ -1062,7 +1124,6 @@ msgid "File exists" msgstr "" #: shared-bindings/supervisor/__init__.c shared-module/lvfontio/OnDiskFont.c -#: shared-module/os/getenv.c msgid "File not found" msgstr "" @@ -1115,6 +1176,7 @@ msgstr "" msgid "Generic Failure" msgstr "" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c #: shared-bindings/framebufferio/FramebufferDisplay.c #: shared-module/busdisplay/BusDisplay.c #: shared-module/framebufferio/FramebufferDisplay.c @@ -1213,7 +1275,8 @@ msgstr "" msgid "Internal define error" msgstr "" -#: shared-bindings/pwmio/PWMOut.c shared-module/os/getenv.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-bindings/pwmio/PWMOut.c +#: supervisor/shared/settings.c msgid "Internal error" msgstr "" @@ -1247,22 +1310,29 @@ msgstr "" 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/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/pwmio/PWMOut.c -#: shared-bindings/supervisor/__init__.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/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" @@ -1296,6 +1366,10 @@ msgstr "" msgid "Invalid ROS domain ID" msgstr "" +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Invalid advertising data" +msgstr "" + #: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c msgid "Invalid argument" msgstr "" @@ -1304,17 +1378,12 @@ msgstr "" msgid "Invalid bits per value" msgstr "" -#: shared-module/os/getenv.c -#, c-format -msgid "Invalid byte %.*s" -msgstr "" - #: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c #, c-format msgid "Invalid data_pins[%d]" msgstr "" -#: shared-module/msgpack/__init__.c +#: shared-module/msgpack/__init__.c supervisor/shared/settings.c msgid "Invalid format" msgstr "" @@ -1339,12 +1408,13 @@ msgstr "" msgid "Invalid socket for TLS" 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/os/getenv.c +#: supervisor/shared/settings.c msgid "Invalid unicode escape" msgstr "" @@ -1352,10 +1422,6 @@ msgstr "" msgid "Key must be 16, 24, or 32 bytes long" msgstr "" -#: shared-module/os/getenv.c -msgid "Key not found" -msgstr "" - #: shared-module/is31fl3741/FrameBuffer.c msgid "LED mappings must match display size" msgstr "" @@ -1394,6 +1460,18 @@ msgstr "" msgid "Mapping must be a tuple" msgstr "" +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap must have 8 bits per pixel" +msgstr "" + +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap size must match the other bitmaps" +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" @@ -1435,8 +1513,7 @@ msgstr "" msgid "Mount point directory missing" msgstr "" -#: ports/zephyr-cp/bindings/zephyr_serial/UART.c shared-bindings/busio/UART.c -#: shared-bindings/displayio/Group.c +#: shared-bindings/busio/UART.c shared-bindings/displayio/Group.c msgid "Must be a %q subclass." msgstr "" @@ -1483,7 +1560,7 @@ msgstr "" #: 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 +#: shared-bindings/qspibus/QSPIBus.c shared-module/bitbangio/SPI.c msgid "No %q pin" msgstr "" @@ -1494,6 +1571,7 @@ 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 "" @@ -1501,6 +1579,7 @@ msgstr "" #: 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 "" @@ -1615,14 +1694,11 @@ msgid "Not connected" msgstr "" #: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c -#: shared-bindings/audiopwmio/PWMAudioOut.c +#: shared-bindings/audiopwmio/PWMAudioOut.c shared-bindings/mcp4822/MCP4822.c +#: shared-bindings/usb_audio/USBMicrophone.c msgid "Not playing" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Not supported JPEG standard" -msgstr "" - #: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c #: ports/espressif/common-hal/sdioio/SDCard.c #, c-format @@ -1716,6 +1792,7 @@ msgid "Operation or feature not supported" msgstr "" #: ports/espressif/common-hal/espidf/__init__.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c msgid "Operation timed out" msgstr "" @@ -1758,6 +1835,7 @@ msgid "Parameter error" msgstr "" #: ports/espressif/common-hal/audiobusio/__init__.c +#: ports/espressif/common-hal/audioi2sin/I2SIn.c msgid "Peripheral in use" msgstr "" @@ -1855,6 +1933,7 @@ msgid "Publishers can only be created from a parent node" msgstr "" #: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c msgid "Pull not used when direction is output." msgstr "" @@ -1894,6 +1973,7 @@ msgstr "" msgid "ROS topic failed to initialize" 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" @@ -1986,6 +2066,10 @@ msgstr "" msgid "SPI init error" msgstr "" +#: ports/analog/common-hal/busio/SPI.c +msgid "SPI needs MOSI, MISO, and SCK" +msgstr "" + #: ports/raspberrypi/common-hal/busio/SPI.c msgid "SPI peripheral in use" msgstr "" @@ -2031,10 +2115,13 @@ 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/zephyr-cp/common-hal/socketpool/SocketPool.c +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 "" @@ -2071,7 +2158,7 @@ msgstr "" msgid "The length of rgb_pins must be 6, 12, 18, 24, or 30" msgstr "" -#: shared-module/audiocore/__init__.c +#: shared-module/audiocore/__init__.c shared-module/usb_audio/USBMicrophone.c msgid "The sample's %q does not match" msgstr "" @@ -2117,11 +2204,16 @@ msgstr "" msgid "Timeout is too long: Maximum timeout length is %d seconds" msgstr "" +#: ports/analog/common-hal/busio/UART.c +msgid "Timeout must be < 100 seconds" +msgstr "" + #: ports/atmel-samd/common-hal/audiobusio/I2SOut.c msgid "Too many channels in sample" msgstr "" #: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c msgid "Too many channels in sample." msgstr "" @@ -2160,6 +2252,10 @@ msgstr "" msgid "UART init" msgstr "" +#: ports/analog/common-hal/busio/UART.c +msgid "UART needs TX & RX" +msgstr "" + #: ports/raspberrypi/common-hal/busio/UART.c msgid "UART peripheral in use" msgstr "" @@ -2168,6 +2264,14 @@ msgstr "" msgid "UART re-init" 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/stm/common-hal/busio/UART.c msgid "UART write" msgstr "" @@ -2192,10 +2296,6 @@ msgstr "" msgid "USB error" msgstr "" -#: shared-bindings/_bleio/UUID.c -msgid "UUID integer value must be 0-0xffff" -msgstr "" - #: shared-bindings/_bleio/UUID.c msgid "UUID string not 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'" msgstr "" @@ -2212,6 +2312,7 @@ msgstr "" #: 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 "" @@ -2220,6 +2321,7 @@ msgid "Unable to allocate to the heap." msgstr "" #: ports/espressif/common-hal/busio/I2C.c +#: ports/espressif/common-hal/busio/SPI.c msgid "Unable to create lock" msgstr "" @@ -2325,6 +2427,10 @@ msgid "" "declined or ignored." msgstr "" +#: shared-module/jpegio/JpegDecoder.c +msgid "Unsupported JPEG (may be progressive)" +msgstr "" + #: shared-bindings/bitmaptools/__init__.c msgid "Unsupported colorspace" msgstr "" @@ -2347,6 +2453,13 @@ msgstr "" msgid "Update failed" 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/_bleio/Characteristic.c #: ports/nordic/common-hal/_bleio/Characteristic.c #: ports/nordic/common-hal/_bleio/Descriptor.c @@ -2486,6 +2599,10 @@ msgstr "" msgid "a bytes-like object is required" msgstr "" +#: shared-bindings/i2cioexpander/IOExpander.c +msgid "address out of range" +msgstr "" + #: shared-bindings/i2ctarget/I2CTarget.c msgid "addresses is empty" msgstr "" @@ -2552,10 +2669,6 @@ msgstr "" msgid "array/bytes required on right side" msgstr "" -#: py/asmxtensa.c -msgid "asm overflow" -msgstr "" - #: py/compile.c msgid "async for/with outside async function" msgstr "" @@ -2612,10 +2725,6 @@ msgstr "" msgid "binary op %q not implemented" msgstr "" -#: ports/espressif/common-hal/audiobusio/PDMIn.c -msgid "bit_depth must be 8, 16, 24, or 32." -msgstr "" - #: shared-module/bitmapfilter/__init__.c msgid "bitmap size and depth must match" msgstr "" @@ -2769,6 +2878,10 @@ msgstr "" msgid "can't create '%q' instances" msgstr "" +#: py/objtype.c +msgid "can't create instance" +msgstr "" + #: py/compile.c msgid "can't declare nonlocal in outer code" msgstr "" @@ -2867,14 +2980,14 @@ msgstr "" msgid "cannot convert complex type" msgstr "" -#: py/objtype.c -msgid "cannot create instance" -msgstr "" - #: extmod/ulab/code/ndarray.c msgid "cannot delete array elements" msgstr "" +#: py/compile.c +msgid "cannot emit native code for this architecture" +msgstr "" + #: extmod/ulab/code/ndarray.c msgid "cannot reshape array" msgstr "" @@ -3009,6 +3122,10 @@ msgstr "" msgid "destination buffer must be an array of type 'H' for bit_depth = 16" msgstr "" +#: shared-bindings/usb_audio/USBSpeaker.c +msgid "destination must be an array of type 'h'" +msgstr "" + #: py/objdict.c msgid "dict update sequence has wrong length" msgstr "" @@ -3029,7 +3146,7 @@ msgstr "" msgid "div/mod not implemented for uint" msgstr "" -#: extmod/ulab/code/numpy/create.c +#: extmod/ulab/code/numpy/create.c py/objint_longlong.c py/objint_mpz.c msgid "divide by zero" msgstr "" @@ -3128,10 +3245,6 @@ msgstr "" msgid "file write is not available" msgstr "" -#: shared-bindings/storage/__init__.c -msgid "filesystem must provide mount method" -msgstr "" - #: extmod/ulab/code/numpy/vector.c msgid "first argument must be a callable" msgstr "" @@ -3172,10 +3285,6 @@ msgstr "" msgid "float unsupported" msgstr "" -#: shared-bindings/_stage/Text.c -msgid "font must be 2048 bytes long" -msgstr "" - #: extmod/moddeflate.c msgid "format" msgstr "" @@ -3257,10 +3366,6 @@ msgstr "" msgid "generator raised StopIteration" msgstr "" -#: shared-bindings/_stage/Layer.c -msgid "graphic must be 2048 bytes long" -msgstr "" - #: extmod/modhashlib.c msgid "hash is final" msgstr "" @@ -3327,10 +3432,6 @@ msgstr "" msgid "initial values must be iterable" msgstr "" -#: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c -msgid "initial_value length is wrong" -msgstr "" - #: py/compile.c msgid "inline assembler must be a function" msgstr "" @@ -3421,6 +3522,10 @@ msgstr "" msgid "interval must be in range %s-%s" msgstr "" +#: py/emitinlinerv32.c +msgid "invalid RV32 instruction '%q'" +msgstr "" + #: py/compile.c msgid "invalid arch" msgstr "" @@ -3434,6 +3539,11 @@ msgstr "" msgid "invalid cert" msgstr "" +#: shared-bindings/audioi2sin/I2SIn.c +#, c-format +msgid "invalid destination buffer, must be an array of type: %c" +msgstr "" + #: shared-bindings/bitmaptools/__init__.c #, c-format msgid "invalid element size %d for bits_per_pixel %d\n" @@ -3615,6 +3725,10 @@ msgstr "" msgid "mode must be complete, or reduced" msgstr "" +#: py/runtime.c +msgid "module '%q' has no attribute '%q'" +msgstr "" + #: py/builtinimport.c msgid "module not found" msgstr "" @@ -3663,10 +3777,6 @@ msgstr "" msgid "native code in .mpy unsupported" msgstr "" -#: py/asmthumb.c -msgid "native method too big" -msgstr "" - #: py/emitnative.c msgid "native yield" msgstr "" @@ -3688,7 +3798,7 @@ msgstr "" msgid "negative power with no float support" msgstr "" -#: py/objint_mpz.c py/runtime.c +#: py/objint_longlong.c py/objint_mpz.c py/runtime.c msgid "negative shift count" msgstr "" @@ -3765,6 +3875,10 @@ msgstr "" msgid "not supported for input types" msgstr "" +#: shared-bindings/i2cioexpander/IOExpander.c +msgid "num_pins must be 8 or 16" +msgstr "" + #: extmod/ulab/code/numpy/create.c msgid "number of points must be at least 2" msgstr "" @@ -3778,6 +3892,10 @@ msgstr "" msgid "object '%s' isn't a tuple or list" msgstr "" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "object does not support DigitalInOut protocol" +msgstr "" + #: py/obj.c msgid "object doesn't support item assignment" msgstr "" @@ -3969,7 +4087,7 @@ msgstr "" msgid "output array must be contiguous" msgstr "" -#: py/objint_mpz.c +#: py/objint_longlong.c py/objint_mpz.c msgid "overflow converting long int to machine word" msgstr "" @@ -3978,10 +4096,6 @@ msgstr "" 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" -msgstr "" - #: py/emitinlinerv32.c msgid "parameters must be registers in sequence a0 to a3" msgstr "" @@ -4039,6 +4153,10 @@ msgstr "" msgid "real and imaginary parts must be of equal length" msgstr "" +#: extmod/modre.c +msgid "regex too complex" +msgstr "" + #: py/builtinimport.c msgid "relative import" msgstr "" @@ -4048,6 +4166,10 @@ msgstr "" msgid "requested length %d but object has length %d" msgstr "" +#: py/objint_longlong.c py/parsenum.c +msgid "result overflows long long storage" +msgstr "" + #: extmod/ulab/code/ndarray_operators.c msgid "results cannot be cast to specified type" msgstr "" @@ -4312,10 +4434,6 @@ msgstr "" msgid "type takes 1 or 3 arguments" msgstr "" -#: py/objint_longlong.c -msgid "ulonglong too large" -msgstr "" - #: py/parse.c msgid "unexpected indent" msgstr "" @@ -4337,10 +4455,6 @@ msgstr "" msgid "unindent doesn't match any outer indent level" msgstr "" -#: py/emitinlinerv32.c -msgid "unknown RV32 instruction '%q'" -msgstr "" - #: py/objstr.c #, c-format msgid "unknown conversion specifier %c" diff --git a/locale/cs.po b/locale/cs.po index 58785e0a5d7..e4a09a220ee 100644 --- a/locale/cs.po +++ b/locale/cs.po @@ -89,6 +89,11 @@ 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" +#: py/emitinlinextensa.c +#, c-format +msgid "%d is not a multiple of %d" +msgstr "" + #: shared-bindings/microcontroller/Pin.c msgid "%q and %q contain duplicate pins" msgstr "%q a %q obsahují duplicitní piny" @@ -110,6 +115,7 @@ msgid "%q contains duplicate pins" msgstr "%q obsahuje duplicitní piny" #: ports/atmel-samd/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c msgid "%q failure: %d" msgstr "%q: selhání %d" @@ -122,6 +128,8 @@ msgid "%q in %q must be of type %q, not %q" msgstr "%q v %q musí být typu %q, ne %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 @@ -129,7 +137,8 @@ msgstr "%q v %q musí být typu %q, ne %q" #: 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 +#: 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á" @@ -141,7 +150,10 @@ msgstr "Index %q je mimo rozsah" msgid "%q indices must be integers, not %s" msgstr "Indexy %q musí být celá čísla, nikoli %s" -#: shared-module/bitbangio/SPI.c +#: 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 msgid "%q init failed" msgstr "Inicializace %q selhala" @@ -173,8 +185,8 @@ msgstr "Délka %q musí být >= %d" msgid "%q must be %d" msgstr "%q musí být %d" -#: py/argcheck.c shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/displayio/Bitmap.c +#: 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 @@ -185,6 +197,20 @@ msgstr "%q musí být %d-%d" msgid "%q must be 1 when %q is True" msgstr "%q musí být 1, pokud %q je True" +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "%q must be 16, 24, or 32" +msgstr "" + +#: 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/audiobusio/PDMIn.c +#: shared-bindings/audioi2sin/I2SIn.c +msgid "%q must be 8, 16, 24, or 32" +msgstr "" + #: py/argcheck.c shared-bindings/gifio/GifWriter.c #: shared-module/gifio/OnDiskGif.c msgid "%q must be <= %d" @@ -244,23 +270,29 @@ msgstr "%q musí být typu %q, ne %q" msgid "%q must be power of 2" msgstr "%q musí být mocnina 2" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' attribute" +msgstr "" + +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' method" +msgstr "" + #: 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 +#: 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" -#: py/objmodule.c -msgid "%q renamed %q" -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" @@ -311,7 +343,7 @@ msgstr "%s chyba 0x%x" msgid "'%q' argument required" msgstr "Je vyžadován argument '%q'" -#: py/proto.c +#: py/proto.c shared-bindings/digitalio/DigitalInOutProtocol.c msgid "'%q' object does not support '%q'" msgstr "Objekt '%q' nepodporuje '%q'" @@ -456,6 +488,7 @@ msgstr "∗x musí být cíl přiřazení" msgid ", in %q\n" msgstr ", v% q\n" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c #: shared-bindings/busdisplay/BusDisplay.c #: shared-bindings/epaperdisplay/EPaperDisplay.c #: shared-bindings/framebufferio/FramebufferDisplay.c @@ -474,7 +507,7 @@ msgstr "pow() nepodporuje 3 argumenty" msgid "AP could not be started" msgstr "AP nemohl být spuštěn" -#: shared-bindings/_bleio/Address.c shared-bindings/ipaddress/IPv4Address.c +#: shared-bindings/ipaddress/IPv4Address.c #, c-format msgid "Address must be %d bytes long" msgstr "Adresa musí být %d bajtů dlouhá" @@ -509,7 +542,8 @@ msgstr "Všechny RX FIFO jsou používány" msgid "All SPI peripherals are in use" msgstr "Všechny SPI periferie jsou používány" -#: ports/espressif/common-hal/busio/UART.c ports/nordic/common-hal/busio/UART.c +#: 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" @@ -580,7 +614,7 @@ msgstr "Již běží" msgid "Already scanning for wifi networks" msgstr "Již skenuje wifi sítě" -#: shared-module/os/getenv.c +#: 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" @@ -607,6 +641,10 @@ msgstr "Hodnoty pole by měly být jednoduché bajty." msgid "Async SPI transfer in progress on this bus, keep awaiting." msgstr "" +#: shared-bindings/usb_audio/__init__.c +msgid "At least one of microphone and speaker must be enabled" +msgstr "" + #: shared-module/memorymonitor/AllocationAlarm.c #, c-format msgid "Attempt to allocate %d blocks" @@ -618,6 +656,7 @@ msgstr "Konverze audia není implementována" #: 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 "" @@ -645,12 +684,14 @@ msgstr "" msgid "Baudrate not supported by peripheral" msgstr "Baudrate není podporován periférií" +#: 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/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 "" @@ -662,20 +703,17 @@ msgstr "Velikost bitmapy a počet bitů na hodnotu se musí shodovat" msgid "Boot device must be first (interface #0)." msgstr "Bootovací zařízení musí být první (rozhraní #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 a TX jsou vyžadovány pro kontrolu toku" +#: 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ý" -#: 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" - #: 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ě" @@ -718,10 +756,6 @@ msgstr "Buffer příliš malý" msgid "Bus pin %d is already in use" msgstr "Sběrnicový pin %d je již používán" -#: shared-bindings/_bleio/UUID.c -msgid "Byte buffer must be 16 bytes." -msgstr "Buffer musí být dlouhý 16 bajtů." - #: shared-bindings/aesio/aes.c msgid "CBC blocks must be multiples of 16 bytes" msgstr "Bloky CBC musí být násobky 16 bajtů" @@ -766,9 +800,9 @@ msgstr "" msgid "Can't set CCCD on local Characteristic" msgstr "Nelze nastavit CCCD na místní charakteristiku" -#: 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 +#: 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í" @@ -776,6 +810,10 @@ msgstr "Nelze změnit USB zařízení" msgid "Cannot create a new Adapter; use _bleio.adapter;" msgstr "Není možné vytvořit nový adaptér; použití _bleio.adapter;" +#: shared-module/i2cioexpander/IOExpander.c +msgid "Cannot deinitialize board IOExpander" +msgstr "" + #: shared-bindings/displayio/Bitmap.c #: shared-bindings/memorymonitor/AllocationSize.c #: shared-bindings/pulseio/PulseIn.c @@ -801,7 +839,7 @@ msgstr "" msgid "Cannot pull on input-only pin." msgstr "Nelze aktivovat pull rezistor na pinu, který je pouze pro vstup." -#: shared-bindings/audiobusio/PDMIn.c +#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c msgid "Cannot record to a file" msgstr "Nelze nahrávat do souboru" @@ -810,6 +848,7 @@ msgid "Cannot remount path when visible via USB." 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." @@ -861,6 +900,10 @@ msgstr "Pole souřadnic mají různé délky" msgid "Coordinate arrays types have different sizes" 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/rclcpy/Publisher.c msgid "Could not publish to ROS topic" msgstr "" @@ -883,10 +926,12 @@ msgid "Critical ROS failure during soft reboot, reset required: %d" 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" #: 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" @@ -918,7 +963,7 @@ 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/audiobusio/PDMIn.c +#: 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." @@ -938,6 +983,7 @@ msgstr "Displej musí mít 16bitový barevný prostor." #: 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" @@ -946,6 +992,7 @@ msgid "Done" msgstr "Hotovo" #: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c msgid "Drive mode not used when direction is input." msgstr "" @@ -957,8 +1004,17 @@ msgstr "Při zpracování uvedené výjimky nastala další výjimka:" msgid "ECB only operates on 16 bytes at a time" msgstr "ECB operuje najednou pouze 16 bajtů" +#: py/asmxtensa.c +msgid "ERROR: %q %q not word-aligned" +msgstr "" + +#: py/asmxtensa.c +msgid "ERROR: xtensa %q out of range" +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 alokace paměti selhala" @@ -1005,7 +1061,7 @@ msgid "" "Failed to add service TXT record; non-string or bytes found in txt_records" msgstr "" -#: shared-module/rgbmatrix/RGBMatrix.c +#: ports/analog/common-hal/busio/UART.c shared-module/rgbmatrix/RGBMatrix.c msgid "Failed to allocate %q buffer" msgstr "Chyba alokace %q bufferu" @@ -1023,10 +1079,12 @@ msgstr "Nepodařilo se nabufferovat sample" #: 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/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" @@ -1063,6 +1121,10 @@ msgstr "" msgid "Failed to release mutex, err 0x%04x" msgstr "Nepodařilo se uvolnit mutex, err 0x%04x" +#: ports/analog/common-hal/busio/SPI.c +msgid "Failed to set SPI Clock Mode" +msgstr "" + #: ports/zephyr-cp/common-hal/wifi/Radio.c msgid "Failed to set hostname" msgstr "" @@ -1080,7 +1142,6 @@ msgid "File exists" msgstr "soubor existuje" #: shared-bindings/supervisor/__init__.c shared-module/lvfontio/OnDiskFont.c -#: shared-module/os/getenv.c msgid "File not found" msgstr "Soubor nenalezen" @@ -1135,6 +1196,7 @@ msgstr "Inicializace GNSS" msgid "Generic Failure" msgstr "Základní chyba" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c #: shared-bindings/framebufferio/FramebufferDisplay.c #: shared-module/busdisplay/BusDisplay.c #: shared-module/framebufferio/FramebufferDisplay.c @@ -1233,7 +1295,8 @@ msgstr "Interní audio buffer je příliš malý" msgid "Internal define error" msgstr "" -#: shared-bindings/pwmio/PWMOut.c shared-module/os/getenv.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-bindings/pwmio/PWMOut.c +#: supervisor/shared/settings.c msgid "Internal error" msgstr "Interní chyba" @@ -1267,22 +1330,29 @@ msgstr "Chyba přerušení." 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/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/pwmio/PWMOut.c -#: shared-bindings/supervisor/__init__.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 "Špatný %s" +#: 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" @@ -1316,6 +1386,10 @@ msgstr "Chybná MAC adresa" msgid "Invalid ROS domain ID" msgstr "" +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Invalid advertising data" +msgstr "" + #: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c msgid "Invalid argument" msgstr "Neplatný argument" @@ -1324,17 +1398,12 @@ msgstr "Neplatný argument" msgid "Invalid bits per value" msgstr "" -#: shared-module/os/getenv.c -#, c-format -msgid "Invalid byte %.*s" -msgstr "Špatný byte %.*s" - #: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c #, c-format msgid "Invalid data_pins[%d]" msgstr "Chybný data_pin[%d]" -#: shared-module/msgpack/__init__.c +#: shared-module/msgpack/__init__.c supervisor/shared/settings.c msgid "Invalid format" msgstr "Špatný formát" @@ -1359,12 +1428,13 @@ msgstr "Chybná velikost" msgid "Invalid socket for TLS" msgstr "Chybný soket pro TLS" +#: 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/os/getenv.c +#: supervisor/shared/settings.c msgid "Invalid unicode escape" msgstr "Neplatná unicode escape sekvence" @@ -1372,10 +1442,6 @@ msgstr "Neplatná unicode escape sekvence" msgid "Key must be 16, 24, or 32 bytes long" msgstr "Klíč musí být dlouhý 16, 24 nebo 32 bajtů" -#: shared-module/os/getenv.c -msgid "Key not found" -msgstr "Klíč nenalezen" - #: shared-module/is31fl3741/FrameBuffer.c msgid "LED mappings must match display size" msgstr "Mapování LED musí korespondovat s velikostí displeje" @@ -1414,6 +1480,18 @@ msgstr "" msgid "Mapping must be a tuple" msgstr "" +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap must have 8 bits per pixel" +msgstr "" + +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap size must match the other bitmaps" +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" @@ -1455,8 +1533,7 @@ msgstr "Chybí jmp_pin. %q[%u] skáče na pin" msgid "Mount point directory missing" msgstr "" -#: ports/zephyr-cp/bindings/zephyr_serial/UART.c shared-bindings/busio/UART.c -#: shared-bindings/displayio/Group.c +#: shared-bindings/busio/UART.c shared-bindings/displayio/Group.c msgid "Must be a %q subclass." msgstr "Musí být podtřída %q." @@ -1503,7 +1580,7 @@ msgstr "" #: 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 +#: shared-bindings/qspibus/QSPIBus.c shared-module/bitbangio/SPI.c msgid "No %q pin" msgstr "Žádný %q pin" @@ -1514,6 +1591,7 @@ msgstr "Žádné CCCD pro tuto charakteristiku" #: 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" @@ -1521,6 +1599,7 @@ msgstr "Žádný DAC na čipu" #: 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" @@ -1635,14 +1714,11 @@ msgid "Not connected" msgstr "Nepřipojený" #: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c -#: shared-bindings/audiopwmio/PWMAudioOut.c +#: shared-bindings/audiopwmio/PWMAudioOut.c shared-bindings/mcp4822/MCP4822.c +#: shared-bindings/usb_audio/USBMicrophone.c msgid "Not playing" msgstr "Nehraje" -#: shared-module/jpegio/JpegDecoder.c -msgid "Not supported JPEG standard" -msgstr "" - #: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c #: ports/espressif/common-hal/sdioio/SDCard.c #, c-format @@ -1737,6 +1813,7 @@ msgid "Operation or feature not supported" msgstr "Operace nebo funkce není podporována" #: ports/espressif/common-hal/espidf/__init__.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c msgid "Operation timed out" msgstr "Časový limit operace vypršel" @@ -1779,6 +1856,7 @@ msgid "Parameter error" msgstr "" #: ports/espressif/common-hal/audiobusio/__init__.c +#: ports/espressif/common-hal/audioi2sin/I2SIn.c msgid "Peripheral in use" msgstr "Periférie je používána" @@ -1878,6 +1956,7 @@ msgid "Publishers can only be created from a parent node" msgstr "" #: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c msgid "Pull not used when direction is output." msgstr "" @@ -1917,6 +1996,7 @@ msgstr "" msgid "ROS topic failed to initialize" 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" @@ -2009,6 +2089,10 @@ msgstr "Konfigurace SPI selhala" msgid "SPI init error" msgstr "Chyba inicializace SPI" +#: ports/analog/common-hal/busio/SPI.c +msgid "SPI needs MOSI, MISO, and SCK" +msgstr "" + #: ports/raspberrypi/common-hal/busio/SPI.c msgid "SPI peripheral in use" msgstr "SPI periferie je používána" @@ -2054,10 +2138,13 @@ 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 je možné použít pouze s wifi.radio" +#: ports/zephyr-cp/common-hal/socketpool/SocketPool.c +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 "Zdrojové a cílové buffery musí být stejné délky" @@ -2094,7 +2181,7 @@ msgstr "Výše uvedená výjimka byla přímá příčina následující výjimk 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-module/audiocore/__init__.c +#: shared-module/audiocore/__init__.c shared-module/usb_audio/USBMicrophone.c msgid "The sample's %q does not match" msgstr "" @@ -2140,11 +2227,16 @@ msgstr "Čas je v minulosti." 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/analog/common-hal/busio/UART.c +msgid "Timeout must be < 100 seconds" +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/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c msgid "Too many channels in sample." msgstr "" @@ -2184,6 +2276,10 @@ msgstr "De-inicializace UART" msgid "UART init" msgstr "Inicializace UART" +#: ports/analog/common-hal/busio/UART.c +msgid "UART needs TX & RX" +msgstr "" + #: ports/raspberrypi/common-hal/busio/UART.c msgid "UART peripheral in use" msgstr "UART periférie je používána" @@ -2192,6 +2288,14 @@ msgstr "UART periférie je používána" msgid "UART re-init" msgstr "Opětovná inicializace UART" +#: 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/stm/common-hal/busio/UART.c msgid "UART write" msgstr "Zápis na UART" @@ -2216,10 +2320,6 @@ msgstr "USB zařízení používají příliš mnoho názvů rozhraní." 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'" @@ -2236,6 +2336,7 @@ msgstr "Nelze přistupovat k nezarovnanému IO registru" #: 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 "" @@ -2244,6 +2345,7 @@ msgid "Unable to allocate to the heap." msgstr "" #: 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" @@ -2349,6 +2451,10 @@ msgid "" "declined or ignored." msgstr "" +#: shared-module/jpegio/JpegDecoder.c +msgid "Unsupported JPEG (may be progressive)" +msgstr "" + #: shared-bindings/bitmaptools/__init__.c msgid "Unsupported colorspace" msgstr "Nepodporovaný barevný prostor" @@ -2371,6 +2477,13 @@ msgstr "" msgid "Update failed" 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/_bleio/Characteristic.c #: ports/nordic/common-hal/_bleio/Characteristic.c #: ports/nordic/common-hal/_bleio/Descriptor.c @@ -2515,6 +2628,10 @@ msgstr "" msgid "a bytes-like object is required" msgstr "" +#: shared-bindings/i2cioexpander/IOExpander.c +msgid "address out of range" +msgstr "" + #: shared-bindings/i2ctarget/I2CTarget.c msgid "addresses is empty" msgstr "" @@ -2581,10 +2698,6 @@ msgstr "pole je příliš velké" msgid "array/bytes required on right side" msgstr "" -#: py/asmxtensa.c -msgid "asm overflow" -msgstr "přetečení v asm" - #: py/compile.c msgid "async for/with outside async function" msgstr "" @@ -2641,10 +2754,6 @@ msgstr "" msgid "binary op %q not implemented" msgstr "" -#: ports/espressif/common-hal/audiobusio/PDMIn.c -msgid "bit_depth must be 8, 16, 24, or 32." -msgstr "" - #: shared-module/bitmapfilter/__init__.c msgid "bitmap size and depth must match" msgstr "" @@ -2798,6 +2907,10 @@ msgstr "" msgid "can't create '%q' instances" msgstr "" +#: py/objtype.c +msgid "can't create instance" +msgstr "" + #: py/compile.c msgid "can't declare nonlocal in outer code" msgstr "" @@ -2896,14 +3009,14 @@ msgstr "nelze převést complex na dtype" msgid "cannot convert complex type" msgstr "nelze převést typ complex" -#: py/objtype.c -msgid "cannot create instance" -msgstr "" - #: extmod/ulab/code/ndarray.c msgid "cannot delete array elements" msgstr "nelze smazat prvky pole" +#: py/compile.c +msgid "cannot emit native code for this architecture" +msgstr "" + #: extmod/ulab/code/ndarray.c msgid "cannot reshape array" msgstr "nelze změnit rozměry pole" @@ -3038,6 +3151,10 @@ msgstr "" msgid "destination buffer must be an array of type 'H' for bit_depth = 16" msgstr "" +#: shared-bindings/usb_audio/USBSpeaker.c +msgid "destination must be an array of type 'h'" +msgstr "" + #: py/objdict.c msgid "dict update sequence has wrong length" msgstr "" @@ -3058,7 +3175,7 @@ msgstr "dimenze nesouhlasí" msgid "div/mod not implemented for uint" msgstr "div/mod nejsou implementované pro uint" -#: extmod/ulab/code/numpy/create.c +#: extmod/ulab/code/numpy/create.c py/objint_longlong.c py/objint_mpz.c msgid "divide by zero" msgstr "dělení nulou" @@ -3157,10 +3274,6 @@ msgstr "" msgid "file write is not available" msgstr "zápis do souboru není dostupný" -#: shared-bindings/storage/__init__.c -msgid "filesystem must provide mount method" -msgstr "" - #: extmod/ulab/code/numpy/vector.c msgid "first argument must be a callable" msgstr "První argument musí být zavolatelný" @@ -3201,10 +3314,6 @@ msgstr "" msgid "float unsupported" msgstr "float není podporován" -#: shared-bindings/_stage/Text.c -msgid "font must be 2048 bytes long" -msgstr "" - #: extmod/moddeflate.c msgid "format" msgstr "" @@ -3286,10 +3395,6 @@ msgstr "" msgid "generator raised StopIteration" msgstr "generátor způsobil StopIteration" -#: shared-bindings/_stage/Layer.c -msgid "graphic must be 2048 bytes long" -msgstr "" - #: extmod/modhashlib.c msgid "hash is final" msgstr "hash je konečný" @@ -3356,10 +3461,6 @@ msgstr "" 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" msgstr "" @@ -3450,6 +3551,10 @@ msgstr "" msgid "interval must be in range %s-%s" msgstr "" +#: py/emitinlinerv32.c +msgid "invalid RV32 instruction '%q'" +msgstr "" + #: py/compile.c msgid "invalid arch" msgstr "" @@ -3463,6 +3568,11 @@ msgstr "chybné bits_per_pixel %d, musí být 1, 2, 4, 8, 16, 24, or 32" msgid "invalid cert" msgstr "špatný certifikár" +#: shared-bindings/audioi2sin/I2SIn.c +#, c-format +msgid "invalid destination buffer, must be an array of type: %c" +msgstr "" + #: shared-bindings/bitmaptools/__init__.c #, c-format msgid "invalid element size %d for bits_per_pixel %d\n" @@ -3644,6 +3754,10 @@ msgstr "" msgid "mode must be complete, or reduced" msgstr "" +#: py/runtime.c +msgid "module '%q' has no attribute '%q'" +msgstr "" + #: py/builtinimport.c msgid "module not found" msgstr "" @@ -3692,10 +3806,6 @@ msgstr "" msgid "native code in .mpy unsupported" msgstr "" -#: py/asmthumb.c -msgid "native method too big" -msgstr "" - #: py/emitnative.c msgid "native yield" msgstr "" @@ -3717,7 +3827,7 @@ msgstr "záporný faktoriál" msgid "negative power with no float support" msgstr "" -#: py/objint_mpz.c py/runtime.c +#: py/objint_longlong.c py/objint_mpz.c py/runtime.c msgid "negative shift count" msgstr "" @@ -3794,6 +3904,10 @@ msgstr "není implementováno pro komplexní dtype" msgid "not supported for input types" msgstr "není podporováno pro vstupní typy" +#: shared-bindings/i2cioexpander/IOExpander.c +msgid "num_pins must be 8 or 16" +msgstr "" + #: extmod/ulab/code/numpy/create.c msgid "number of points must be at least 2" msgstr "" @@ -3807,6 +3921,10 @@ msgstr "objekt " msgid "object '%s' isn't a tuple or list" msgstr "objekt '%s' není tuple or nebo list" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "object does not support DigitalInOut protocol" +msgstr "" + #: py/obj.c msgid "object doesn't support item assignment" msgstr "" @@ -3998,7 +4116,7 @@ msgstr "" msgid "output array must be contiguous" msgstr "" -#: py/objint_mpz.c +#: py/objint_longlong.c py/objint_mpz.c msgid "overflow converting long int to machine word" msgstr "" @@ -4007,10 +4125,6 @@ msgstr "" 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" -msgstr "" - #: py/emitinlinerv32.c msgid "parameters must be registers in sequence a0 to a3" msgstr "" @@ -4068,6 +4182,10 @@ msgstr "" msgid "real and imaginary parts must be of equal length" msgstr "" +#: extmod/modre.c +msgid "regex too complex" +msgstr "" + #: py/builtinimport.c msgid "relative import" msgstr "" @@ -4077,6 +4195,10 @@ msgstr "" msgid "requested length %d but object has length %d" msgstr "" +#: py/objint_longlong.c py/parsenum.c +msgid "result overflows long long storage" +msgstr "" + #: extmod/ulab/code/ndarray_operators.c msgid "results cannot be cast to specified type" msgstr "" @@ -4341,10 +4463,6 @@ msgstr "" msgid "type takes 1 or 3 arguments" msgstr "" -#: py/objint_longlong.c -msgid "ulonglong too large" -msgstr "" - #: py/parse.c msgid "unexpected indent" msgstr "neočekávané odsazení" @@ -4366,10 +4484,6 @@ msgstr "" msgid "unindent doesn't match any outer indent level" msgstr "" -#: py/emitinlinerv32.c -msgid "unknown RV32 instruction '%q'" -msgstr "" - #: py/objstr.c #, c-format msgid "unknown conversion specifier %c" @@ -4538,6 +4652,29 @@ msgstr "" msgid "zi must be of shape (n_section, 2)" msgstr "" +#~ msgid "asm overflow" +#~ msgstr "přetečení v asm" + +#, c-format +#~ msgid "Buffer + offset too small %d %d %d" +#~ msgstr "Vyrovnávací paměť + offset je příliš malý %d %d %d" + +#~ msgid "Byte buffer must be 16 bytes." +#~ msgstr "Buffer musí být dlouhý 16 bajtů." + +#~ msgid "UUID integer value must be 0-0xffff" +#~ msgstr "UUID integer musí být 0-0xffff" + +#~ msgid "initial_value length is wrong" +#~ msgstr "délka initial_value je chybná" + +#, 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" #~ msgstr "%%c vyžaduje int nebo char" @@ -4830,8 +4967,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 082ae20351e..f4294d794a8 100644 --- a/locale/el.po +++ b/locale/el.po @@ -93,6 +93,11 @@ msgid "" msgstr "" "%d pin διεύθυνσης, %d rgb ping και %d πλακίδια αναδεικνύουν ύψος %d, όχι %d" +#: py/emitinlinextensa.c +#, c-format +msgid "%d is not a multiple of %d" +msgstr "" + #: shared-bindings/microcontroller/Pin.c msgid "%q and %q contain duplicate pins" msgstr "%q και %q περιέχουν διπλότυπα pins" @@ -114,6 +119,7 @@ msgid "%q contains duplicate pins" msgstr "%q περιέχει διπλότυπα pins" #: ports/atmel-samd/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c msgid "%q failure: %d" msgstr "%q αποτυχία: %d" @@ -126,6 +132,8 @@ msgid "%q in %q must be of type %q, not %q" msgstr "%q στο %q πρέπει να είναι τύπου %q, όχι %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 @@ -133,7 +141,8 @@ msgstr "%q στο %q πρέπει να είναι τύπου %q, όχι %q" #: 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 +#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/microcontroller/Pin.c +#: shared-module/max3421e/Max3421E.c msgid "%q in use" msgstr "%q είναι σε χρήση" @@ -145,7 +154,10 @@ msgstr "%q δείκτης εκτός εμβέλειας" msgid "%q indices must be integers, not %s" msgstr "%q δείκτες πρέπει να είναι ακέραιοι, όχι %s" -#: shared-module/bitbangio/SPI.c +#: 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 msgid "%q init failed" msgstr "%q εκκίνηση απέτυχε" @@ -177,8 +189,8 @@ msgstr "%q μήκος πρέπει να είναι >= %d" msgid "%q must be %d" msgstr "%q πρέπει να είναι %d" -#: py/argcheck.c shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/displayio/Bitmap.c +#: 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 @@ -189,6 +201,20 @@ msgstr "%q πρέπει να είναι %d-%d" msgid "%q must be 1 when %q is True" msgstr "%q πρέπει να είναι 1 όταν %q είναι True" +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "%q must be 16, 24, or 32" +msgstr "" + +#: 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/audiobusio/PDMIn.c +#: shared-bindings/audioi2sin/I2SIn.c +msgid "%q must be 8, 16, 24, or 32" +msgstr "" + #: py/argcheck.c shared-bindings/gifio/GifWriter.c #: shared-module/gifio/OnDiskGif.c msgid "%q must be <= %d" @@ -248,23 +274,29 @@ msgstr "%q πρέπει να είναι τύπου %q, όχι %q" msgid "%q must be power of 2" msgstr "%q πρέπει να είναι δύναμη του 2" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' attribute" +msgstr "" + +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' method" +msgstr "" + #: shared-bindings/wifi/Monitor.c msgid "%q out of bounds" msgstr "%q εκτός ορίων" +#: 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 +#: shared-bindings/bitmaptools/__init__.c shared-bindings/canio/Match.c +#: shared-bindings/time/__init__.c msgid "%q out of range" msgstr "%q εκτός εμβέλειας" -#: py/objmodule.c -msgid "%q renamed %q" -msgstr "%q μεταονομάστηκε σε %q" - #: py/objrange.c py/objslice.c shared-bindings/random/__init__.c msgid "%q step cannot be zero" msgstr "%q βήμα δεν μπορεί να είναι μηδέν" @@ -315,7 +347,7 @@ msgstr "%s σφάλμα 0x%x" msgid "'%q' argument required" msgstr "'%q' όρισμα απαιτείται" -#: py/proto.c +#: py/proto.c shared-bindings/digitalio/DigitalInOutProtocol.c msgid "'%q' object does not support '%q'" msgstr "'%q' αντικείμενο δεν υποστηρίζει '%q'" @@ -460,6 +492,7 @@ msgstr "*x πρέπει να είναι στόχος ανάθεσης" msgid ", in %q\n" msgstr ", στο %q\n" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c #: shared-bindings/busdisplay/BusDisplay.c #: shared-bindings/epaperdisplay/EPaperDisplay.c #: shared-bindings/framebufferio/FramebufferDisplay.c @@ -478,7 +511,7 @@ msgstr "pow() με 3 παραμέτρους δεν υποστηρίζεται" msgid "AP could not be started" msgstr "AP δεν μπόρεσε να εκκινηθεί" -#: shared-bindings/_bleio/Address.c shared-bindings/ipaddress/IPv4Address.c +#: shared-bindings/ipaddress/IPv4Address.c #, c-format msgid "Address must be %d bytes long" msgstr "Η διεύθυνση πρέπει να είναι %d bytes μεγάλη" @@ -513,7 +546,8 @@ msgstr "Όλα τα RX FIFOs είναι σε χρήση" msgid "All SPI peripherals are in use" msgstr "Όλα τα SPI περιφεριακά είναι σε χρήση" -#: ports/espressif/common-hal/busio/UART.c ports/nordic/common-hal/busio/UART.c +#: 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 περιφεριακά ειναι σε χρήση" @@ -584,7 +618,7 @@ msgstr "Τρέχει ήδη" msgid "Already scanning for wifi networks" msgstr "Ήδη γίνεται σάρωση για δίκτυα wifi" -#: shared-module/os/getenv.c +#: supervisor/shared/settings.c #, c-format msgid "An error occurred while retrieving '%s':\n" msgstr "Παρουσιάστηκε σφάλμα κατά την ανάκτηση '%s':\n" @@ -611,6 +645,10 @@ msgstr "Η τιμές της παράταξη πρέπει να είναι μο msgid "Async SPI transfer in progress on this bus, keep awaiting." msgstr "" +#: shared-bindings/usb_audio/__init__.c +msgid "At least one of microphone and speaker must be enabled" +msgstr "" + #: shared-module/memorymonitor/AllocationAlarm.c #, c-format msgid "Attempt to allocate %d blocks" @@ -622,6 +660,7 @@ msgstr "Η μετατροπή ήχου δεν υποστηρίζεται" #: 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 "" @@ -649,12 +688,14 @@ msgstr "" msgid "Baudrate not supported by peripheral" msgstr "Baudrate δεν υποστηρίζεται από την περιφεριακή συσκευή" +#: 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" #: 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" @@ -666,20 +707,17 @@ msgstr "Το μέγεθος του bitmap και τα bits ανα τιμή πρ 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" +#: 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-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" @@ -722,10 +760,6 @@ msgstr "Buffer πολύ μικρός" 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" @@ -768,9 +802,9 @@ msgstr "" msgid "Can't set CCCD on local Characteristic" msgstr "Δεν μπορεί να οριστεί CCCD σε τοπικό Characteristic" -#: 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 +#: 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 συσκευές τώρα" @@ -779,6 +813,10 @@ msgid "Cannot create a new Adapter; use _bleio.adapter;" msgstr "" "Δεν μπορεί να δημιουργηθεί νέο Adapter; χρησιμοποιείστε _bleio.adapter;" +#: shared-module/i2cioexpander/IOExpander.c +msgid "Cannot deinitialize board IOExpander" +msgstr "" + #: shared-bindings/displayio/Bitmap.c #: shared-bindings/memorymonitor/AllocationSize.c #: shared-bindings/pulseio/PulseIn.c @@ -806,7 +844,7 @@ msgstr "" msgid "Cannot pull on input-only pin." msgstr "Δεν γίνεται pull σε pin μόνο για εισόδο." -#: shared-bindings/audiobusio/PDMIn.c +#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c msgid "Cannot record to a file" msgstr "Δεν μπορεί να γίνει καταγραφή σε αρχείο" @@ -815,6 +853,7 @@ msgid "Cannot remount path when visible via USB." msgstr "" #: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c msgid "Cannot set value when direction is input." msgstr "Δεν μπορεί να οριστεί τιμή οταν η κατεύθυνση είναι input." @@ -867,6 +906,10 @@ msgstr "" msgid "Coordinate arrays types have different sizes" 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/rclcpy/Publisher.c msgid "Could not publish to ROS topic" msgstr "" @@ -889,10 +932,12 @@ msgid "Critical ROS failure during soft reboot, reset required: %d" msgstr "" #: 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/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c msgid "DAC Device Init Error" msgstr "Σφάλμα εκκίνησης συσκευής DAC" @@ -923,7 +968,7 @@ msgstr "Τα δεδομένα είναι πολύ μεγάλα για πακέτ msgid "Deep sleep pins must use a rising edge with pulldown" msgstr "Τα pins βαθύ ύπνου πρέπει να χρησιμοποιούν rising edge με pulldown" -#: shared-bindings/audiobusio/PDMIn.c +#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c msgid "Destination capacity is smaller than destination_length." msgstr "" "Το μέγεθος προορισμού πρέπει να είναι μικρότερο από το destination_length." @@ -945,6 +990,7 @@ msgstr "Η οθόνη πρέπει να έχει 16 bit χρωματική ευ #: 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 μοιρών" @@ -953,6 +999,7 @@ msgid "Done" msgstr "Ολοκληρώθηκε" #: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c msgid "Drive mode not used when direction is input." msgstr "Ο τρόπος οδήγησης δεν χρησιμοποιείται όταν η κατεύθυνση είναι είσοδος." @@ -965,8 +1012,17 @@ msgstr "" msgid "ECB only operates on 16 bytes at a time" msgstr "ECB δουλεύει μόνο σε 16 bytes κάθε φορά" +#: py/asmxtensa.c +msgid "ERROR: %q %q not word-aligned" +msgstr "" + +#: py/asmxtensa.c +msgid "ERROR: xtensa %q out of range" +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 δέσμευση μνήμης απέτυχε" @@ -1013,7 +1069,7 @@ msgid "" "Failed to add service TXT record; non-string or bytes found in txt_records" msgstr "" -#: shared-module/rgbmatrix/RGBMatrix.c +#: ports/analog/common-hal/busio/UART.c shared-module/rgbmatrix/RGBMatrix.c msgid "Failed to allocate %q buffer" msgstr "" @@ -1031,10 +1087,12 @@ 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/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c msgid "Failed to connect: timeout" msgstr "" @@ -1071,6 +1129,10 @@ msgstr "" msgid "Failed to release mutex, err 0x%04x" msgstr "" +#: ports/analog/common-hal/busio/SPI.c +msgid "Failed to set SPI Clock Mode" +msgstr "" + #: ports/zephyr-cp/common-hal/wifi/Radio.c msgid "Failed to set hostname" msgstr "" @@ -1088,7 +1150,6 @@ msgid "File exists" msgstr "" #: shared-bindings/supervisor/__init__.c shared-module/lvfontio/OnDiskFont.c -#: shared-module/os/getenv.c msgid "File not found" msgstr "" @@ -1141,6 +1202,7 @@ msgstr "" msgid "Generic Failure" msgstr "" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c #: shared-bindings/framebufferio/FramebufferDisplay.c #: shared-module/busdisplay/BusDisplay.c #: shared-module/framebufferio/FramebufferDisplay.c @@ -1239,7 +1301,8 @@ msgstr "" msgid "Internal define error" msgstr "" -#: shared-bindings/pwmio/PWMOut.c shared-module/os/getenv.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-bindings/pwmio/PWMOut.c +#: supervisor/shared/settings.c msgid "Internal error" msgstr "" @@ -1273,22 +1336,29 @@ msgstr "" 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/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/pwmio/PWMOut.c -#: shared-bindings/supervisor/__init__.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/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" @@ -1322,6 +1392,10 @@ msgstr "" msgid "Invalid ROS domain ID" msgstr "" +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Invalid advertising data" +msgstr "" + #: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c msgid "Invalid argument" msgstr "" @@ -1330,17 +1404,12 @@ msgstr "" msgid "Invalid bits per value" msgstr "" -#: shared-module/os/getenv.c -#, c-format -msgid "Invalid byte %.*s" -msgstr "" - #: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c #, c-format msgid "Invalid data_pins[%d]" msgstr "" -#: shared-module/msgpack/__init__.c +#: shared-module/msgpack/__init__.c supervisor/shared/settings.c msgid "Invalid format" msgstr "" @@ -1365,12 +1434,13 @@ msgstr "" msgid "Invalid socket for TLS" 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/os/getenv.c +#: supervisor/shared/settings.c msgid "Invalid unicode escape" msgstr "" @@ -1378,10 +1448,6 @@ msgstr "" msgid "Key must be 16, 24, or 32 bytes long" msgstr "" -#: shared-module/os/getenv.c -msgid "Key not found" -msgstr "" - #: shared-module/is31fl3741/FrameBuffer.c msgid "LED mappings must match display size" msgstr "" @@ -1420,6 +1486,18 @@ msgstr "" msgid "Mapping must be a tuple" msgstr "" +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap must have 8 bits per pixel" +msgstr "" + +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap size must match the other bitmaps" +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" @@ -1461,8 +1539,7 @@ msgstr "" msgid "Mount point directory missing" msgstr "" -#: ports/zephyr-cp/bindings/zephyr_serial/UART.c shared-bindings/busio/UART.c -#: shared-bindings/displayio/Group.c +#: shared-bindings/busio/UART.c shared-bindings/displayio/Group.c msgid "Must be a %q subclass." msgstr "" @@ -1509,7 +1586,7 @@ msgstr "" #: 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 +#: shared-bindings/qspibus/QSPIBus.c shared-module/bitbangio/SPI.c msgid "No %q pin" msgstr "" @@ -1520,6 +1597,7 @@ 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 "" @@ -1527,6 +1605,7 @@ msgstr "" #: 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 "" @@ -1641,14 +1720,11 @@ msgid "Not connected" msgstr "" #: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c -#: shared-bindings/audiopwmio/PWMAudioOut.c +#: shared-bindings/audiopwmio/PWMAudioOut.c shared-bindings/mcp4822/MCP4822.c +#: shared-bindings/usb_audio/USBMicrophone.c msgid "Not playing" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Not supported JPEG standard" -msgstr "" - #: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c #: ports/espressif/common-hal/sdioio/SDCard.c #, c-format @@ -1742,6 +1818,7 @@ msgid "Operation or feature not supported" msgstr "" #: ports/espressif/common-hal/espidf/__init__.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c msgid "Operation timed out" msgstr "" @@ -1784,6 +1861,7 @@ msgid "Parameter error" msgstr "" #: ports/espressif/common-hal/audiobusio/__init__.c +#: ports/espressif/common-hal/audioi2sin/I2SIn.c msgid "Peripheral in use" msgstr "" @@ -1883,6 +1961,7 @@ msgid "Publishers can only be created from a parent node" msgstr "" #: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c msgid "Pull not used when direction is output." msgstr "" @@ -1922,6 +2001,7 @@ msgstr "" msgid "ROS topic failed to initialize" 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" @@ -2014,6 +2094,10 @@ msgstr "" msgid "SPI init error" msgstr "" +#: ports/analog/common-hal/busio/SPI.c +msgid "SPI needs MOSI, MISO, and SCK" +msgstr "" + #: ports/raspberrypi/common-hal/busio/SPI.c msgid "SPI peripheral in use" msgstr "" @@ -2059,10 +2143,13 @@ 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/zephyr-cp/common-hal/socketpool/SocketPool.c +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 "" @@ -2099,7 +2186,7 @@ msgstr "" msgid "The length of rgb_pins must be 6, 12, 18, 24, or 30" msgstr "" -#: shared-module/audiocore/__init__.c +#: shared-module/audiocore/__init__.c shared-module/usb_audio/USBMicrophone.c msgid "The sample's %q does not match" msgstr "" @@ -2145,11 +2232,16 @@ msgstr "" msgid "Timeout is too long: Maximum timeout length is %d seconds" msgstr "" +#: ports/analog/common-hal/busio/UART.c +msgid "Timeout must be < 100 seconds" +msgstr "" + #: ports/atmel-samd/common-hal/audiobusio/I2SOut.c msgid "Too many channels in sample" msgstr "" #: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c msgid "Too many channels in sample." msgstr "" @@ -2188,6 +2280,10 @@ msgstr "" msgid "UART init" msgstr "" +#: ports/analog/common-hal/busio/UART.c +msgid "UART needs TX & RX" +msgstr "" + #: ports/raspberrypi/common-hal/busio/UART.c msgid "UART peripheral in use" msgstr "" @@ -2196,6 +2292,14 @@ msgstr "" msgid "UART re-init" 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/stm/common-hal/busio/UART.c msgid "UART write" msgstr "" @@ -2220,10 +2324,6 @@ msgstr "" msgid "USB error" msgstr "" -#: shared-bindings/_bleio/UUID.c -msgid "UUID integer value must be 0-0xffff" -msgstr "" - #: shared-bindings/_bleio/UUID.c msgid "UUID string not 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'" msgstr "" @@ -2240,6 +2340,7 @@ msgstr "" #: 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 "" @@ -2248,6 +2349,7 @@ msgid "Unable to allocate to the heap." msgstr "" #: ports/espressif/common-hal/busio/I2C.c +#: ports/espressif/common-hal/busio/SPI.c msgid "Unable to create lock" msgstr "" @@ -2353,6 +2455,10 @@ msgid "" "declined or ignored." msgstr "" +#: shared-module/jpegio/JpegDecoder.c +msgid "Unsupported JPEG (may be progressive)" +msgstr "" + #: shared-bindings/bitmaptools/__init__.c msgid "Unsupported colorspace" msgstr "" @@ -2375,6 +2481,13 @@ msgstr "" msgid "Update failed" 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/_bleio/Characteristic.c #: ports/nordic/common-hal/_bleio/Characteristic.c #: ports/nordic/common-hal/_bleio/Descriptor.c @@ -2514,6 +2627,10 @@ msgstr "" msgid "a bytes-like object is required" msgstr "" +#: shared-bindings/i2cioexpander/IOExpander.c +msgid "address out of range" +msgstr "" + #: shared-bindings/i2ctarget/I2CTarget.c msgid "addresses is empty" msgstr "" @@ -2580,10 +2697,6 @@ msgstr "" msgid "array/bytes required on right side" msgstr "" -#: py/asmxtensa.c -msgid "asm overflow" -msgstr "" - #: py/compile.c msgid "async for/with outside async function" msgstr "" @@ -2640,10 +2753,6 @@ msgstr "" msgid "binary op %q not implemented" msgstr "" -#: ports/espressif/common-hal/audiobusio/PDMIn.c -msgid "bit_depth must be 8, 16, 24, or 32." -msgstr "" - #: shared-module/bitmapfilter/__init__.c msgid "bitmap size and depth must match" msgstr "" @@ -2797,6 +2906,10 @@ msgstr "" msgid "can't create '%q' instances" msgstr "" +#: py/objtype.c +msgid "can't create instance" +msgstr "" + #: py/compile.c msgid "can't declare nonlocal in outer code" msgstr "" @@ -2895,14 +3008,14 @@ msgstr "" msgid "cannot convert complex type" msgstr "" -#: py/objtype.c -msgid "cannot create instance" -msgstr "" - #: extmod/ulab/code/ndarray.c msgid "cannot delete array elements" msgstr "" +#: py/compile.c +msgid "cannot emit native code for this architecture" +msgstr "" + #: extmod/ulab/code/ndarray.c msgid "cannot reshape array" msgstr "" @@ -3037,6 +3150,10 @@ msgstr "" msgid "destination buffer must be an array of type 'H' for bit_depth = 16" msgstr "" +#: shared-bindings/usb_audio/USBSpeaker.c +msgid "destination must be an array of type 'h'" +msgstr "" + #: py/objdict.c msgid "dict update sequence has wrong length" msgstr "" @@ -3057,7 +3174,7 @@ msgstr "" msgid "div/mod not implemented for uint" msgstr "" -#: extmod/ulab/code/numpy/create.c +#: extmod/ulab/code/numpy/create.c py/objint_longlong.c py/objint_mpz.c msgid "divide by zero" msgstr "" @@ -3156,10 +3273,6 @@ msgstr "" msgid "file write is not available" msgstr "" -#: shared-bindings/storage/__init__.c -msgid "filesystem must provide mount method" -msgstr "" - #: extmod/ulab/code/numpy/vector.c msgid "first argument must be a callable" msgstr "" @@ -3200,10 +3313,6 @@ msgstr "" msgid "float unsupported" msgstr "" -#: shared-bindings/_stage/Text.c -msgid "font must be 2048 bytes long" -msgstr "" - #: extmod/moddeflate.c msgid "format" msgstr "" @@ -3285,10 +3394,6 @@ msgstr "" msgid "generator raised StopIteration" msgstr "" -#: shared-bindings/_stage/Layer.c -msgid "graphic must be 2048 bytes long" -msgstr "" - #: extmod/modhashlib.c msgid "hash is final" msgstr "" @@ -3355,10 +3460,6 @@ msgstr "" msgid "initial values must be iterable" msgstr "" -#: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c -msgid "initial_value length is wrong" -msgstr "" - #: py/compile.c msgid "inline assembler must be a function" msgstr "" @@ -3449,6 +3550,10 @@ msgstr "" msgid "interval must be in range %s-%s" msgstr "" +#: py/emitinlinerv32.c +msgid "invalid RV32 instruction '%q'" +msgstr "" + #: py/compile.c msgid "invalid arch" msgstr "" @@ -3462,6 +3567,11 @@ msgstr "" msgid "invalid cert" msgstr "" +#: shared-bindings/audioi2sin/I2SIn.c +#, c-format +msgid "invalid destination buffer, must be an array of type: %c" +msgstr "" + #: shared-bindings/bitmaptools/__init__.c #, c-format msgid "invalid element size %d for bits_per_pixel %d\n" @@ -3643,6 +3753,10 @@ msgstr "" msgid "mode must be complete, or reduced" msgstr "" +#: py/runtime.c +msgid "module '%q' has no attribute '%q'" +msgstr "" + #: py/builtinimport.c msgid "module not found" msgstr "" @@ -3691,10 +3805,6 @@ msgstr "" msgid "native code in .mpy unsupported" msgstr "" -#: py/asmthumb.c -msgid "native method too big" -msgstr "" - #: py/emitnative.c msgid "native yield" msgstr "" @@ -3716,7 +3826,7 @@ msgstr "" msgid "negative power with no float support" msgstr "" -#: py/objint_mpz.c py/runtime.c +#: py/objint_longlong.c py/objint_mpz.c py/runtime.c msgid "negative shift count" msgstr "" @@ -3793,6 +3903,10 @@ msgstr "" msgid "not supported for input types" msgstr "" +#: shared-bindings/i2cioexpander/IOExpander.c +msgid "num_pins must be 8 or 16" +msgstr "" + #: extmod/ulab/code/numpy/create.c msgid "number of points must be at least 2" msgstr "" @@ -3806,6 +3920,10 @@ msgstr "" msgid "object '%s' isn't a tuple or list" msgstr "" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "object does not support DigitalInOut protocol" +msgstr "" + #: py/obj.c msgid "object doesn't support item assignment" msgstr "" @@ -3997,7 +4115,7 @@ msgstr "" msgid "output array must be contiguous" msgstr "" -#: py/objint_mpz.c +#: py/objint_longlong.c py/objint_mpz.c msgid "overflow converting long int to machine word" msgstr "" @@ -4006,10 +4124,6 @@ msgstr "" 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" -msgstr "" - #: py/emitinlinerv32.c msgid "parameters must be registers in sequence a0 to a3" msgstr "" @@ -4067,6 +4181,10 @@ msgstr "" msgid "real and imaginary parts must be of equal length" msgstr "" +#: extmod/modre.c +msgid "regex too complex" +msgstr "" + #: py/builtinimport.c msgid "relative import" msgstr "" @@ -4076,6 +4194,10 @@ msgstr "" msgid "requested length %d but object has length %d" msgstr "" +#: py/objint_longlong.c py/parsenum.c +msgid "result overflows long long storage" +msgstr "" + #: extmod/ulab/code/ndarray_operators.c msgid "results cannot be cast to specified type" msgstr "" @@ -4340,10 +4462,6 @@ msgstr "" msgid "type takes 1 or 3 arguments" msgstr "" -#: py/objint_longlong.c -msgid "ulonglong too large" -msgstr "" - #: py/parse.c msgid "unexpected indent" msgstr "" @@ -4365,10 +4483,6 @@ msgstr "" msgid "unindent doesn't match any outer indent level" msgstr "" -#: py/emitinlinerv32.c -msgid "unknown RV32 instruction '%q'" -msgstr "" - #: py/objstr.c #, c-format msgid "unknown conversion specifier %c" @@ -4537,6 +4651,16 @@ msgstr "" msgid "zi must be of shape (n_section, 2)" msgstr "" +#~ 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" 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 fa7377b5b53..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-07-17 04:01+0000\n" -"Last-Translator: Jean Serrano \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" @@ -1803,10 +1801,9 @@ msgid "PWM slice channel A already in use" msgstr "Segmento del PWM canal A ya esta en uso" #: shared-bindings/spitarget/SPITarget.c -#, fuzzy msgid "Packet buffers for an SPI transfer must have the same length." msgstr "" -"Búferes de paquetes para transferencia SPI deben de ser de igual longitud" +"Búferes de paquetes para transferencia SPI deben de ser de igual longitud." #: shared-module/jpegio/JpegDecoder.c msgid "Parameter error" @@ -1913,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." @@ -2171,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/fr.po b/locale/fr.po index 3a53a97e8fa..f871c669f93 100644 --- a/locale/fr.po +++ b/locale/fr.po @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: 0.1\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" +"PO-Revision-Date: 2025-08-03 08:01+0000\n" "Last-Translator: MAE \n" "Language-Team: \n" "Language: fr\n" @@ -49,7 +49,7 @@ msgid "" "Press reset to exit safe mode.\n" msgstr "" "\n" -"Pour quitter le mode sans échec, appuyez sur reset.\n" +"Appuyer sur reset pour sortir du mode sans échec.\n" #: supervisor/shared/safe_mode.c msgid "" @@ -57,7 +57,7 @@ msgid "" "You are in safe mode because:\n" msgstr "" "\n" -"Le mode sans échec est actif , car:\n" +"Le mode sans échec est actif pour cette raison:\n" #: py/obj.c msgid " File \"%q\"" @@ -1879,15 +1879,15 @@ msgstr "Plus tout autres modules présents sur le système de fichiers\n" #: shared-module/vectorio/Polygon.c msgid "Polygon needs at least 3 points" -msgstr "Polygon a besoin d'au moins 3 points" +msgstr "Un polygone a besoin d'au moins 3 points" #: supervisor/shared/safe_mode.c msgid "Power dipped. Make sure you are providing enough power." -msgstr "Chute de puissance.Apportez plus d'énergie." +msgstr "Chute de puissance. Assurez-vous de fournir assez de puissance." #: shared-bindings/_bleio/Adapter.c msgid "Prefix buffer must be on the heap" -msgstr "Le tampon de préfixe doit être sur la pile" +msgstr "Le tampon de préfixe doit être sur le tas" #: main.c msgid "Press any key to enter the REPL. Use CTRL-D to reload.\n" @@ -1919,11 +1919,12 @@ msgstr "Programme trop long" #: shared-bindings/rclcpy/Publisher.c msgid "Publishers can only be created from a parent node" -msgstr "Les Publishers ne peuvent etre crées que du noeud parent" +msgstr "Les Publishers ne peuvent être créés qu'à partir du nœud parent" #: shared-bindings/digitalio/DigitalInOut.c msgid "Pull not used when direction is output." -msgstr "Le tirage 'pull' n'est pas utilisé quand la direction est 'output'." +msgstr "" +"L'attribut \"pull\" n'est pas utilisé quand la direction est \"output\"." #: ports/raspberrypi/common-hal/countio/Counter.c msgid "RISE_AND_FALL not available on this chip" @@ -2024,7 +2025,7 @@ msgstr "Format correct mais non supporté" #: main.c msgid "Running in safe mode! Not running saved code.\n" -msgstr "Mode sans- échec ! Le code sauvegardé n'est pas éxecuté.\n" +msgstr "Mode sans échec ! Le code sauvegardé n'est pas éxecuté.\n" #: shared-module/sdcardio/SDCard.c msgid "SD card CSD format not supported" @@ -3971,7 +3972,7 @@ msgstr "seules les tranches avec 'step=1' (cad None) sont supportées" #: py/vm.c msgid "opcode" -msgstr "opcode" +msgstr "" #: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/bitwise.c #: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/vector.c diff --git a/locale/hi.po b/locale/hi.po index 8e4aa0990ae..21b28028a29 100644 --- a/locale/hi.po +++ b/locale/hi.po @@ -80,6 +80,11 @@ msgid "" "%d address pins, %d rgb pins and %d tiles indicate a height of %d, not %d" msgstr "" +#: py/emitinlinextensa.c +#, c-format +msgid "%d is not a multiple of %d" +msgstr "" + #: shared-bindings/microcontroller/Pin.c msgid "%q and %q contain duplicate pins" msgstr "" @@ -101,6 +106,7 @@ msgid "%q contains duplicate pins" msgstr "" #: ports/atmel-samd/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c msgid "%q failure: %d" msgstr "" @@ -113,6 +119,8 @@ msgid "%q in %q must be of type %q, not %q" 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 @@ -120,7 +128,8 @@ msgstr "" #: 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 +#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/microcontroller/Pin.c +#: shared-module/max3421e/Max3421E.c msgid "%q in use" msgstr "" @@ -132,7 +141,10 @@ msgstr "" msgid "%q indices must be integers, not %s" msgstr "" -#: shared-module/bitbangio/SPI.c +#: 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 msgid "%q init failed" msgstr "" @@ -164,8 +176,8 @@ msgstr "" msgid "%q must be %d" msgstr "" -#: py/argcheck.c shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/displayio/Bitmap.c +#: 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 @@ -176,6 +188,20 @@ msgstr "" msgid "%q must be 1 when %q is True" msgstr "" +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "%q must be 16, 24, or 32" +msgstr "" + +#: 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/audiobusio/PDMIn.c +#: shared-bindings/audioi2sin/I2SIn.c +msgid "%q must be 8, 16, 24, or 32" +msgstr "" + #: py/argcheck.c shared-bindings/gifio/GifWriter.c #: shared-module/gifio/OnDiskGif.c msgid "%q must be <= %d" @@ -235,23 +261,29 @@ msgstr "" msgid "%q must be power of 2" msgstr "" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' attribute" +msgstr "" + +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' method" +msgstr "" + #: shared-bindings/wifi/Monitor.c msgid "%q out of bounds" 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 +#: shared-bindings/bitmaptools/__init__.c shared-bindings/canio/Match.c +#: shared-bindings/time/__init__.c msgid "%q out of range" msgstr "" -#: py/objmodule.c -msgid "%q renamed %q" -msgstr "" - #: py/objrange.c py/objslice.c shared-bindings/random/__init__.c msgid "%q step cannot be zero" msgstr "" @@ -302,7 +334,7 @@ msgstr "" msgid "'%q' argument required" msgstr "" -#: py/proto.c +#: py/proto.c shared-bindings/digitalio/DigitalInOutProtocol.c msgid "'%q' object does not support '%q'" msgstr "" @@ -447,6 +479,7 @@ msgstr "" msgid ", in %q\n" msgstr "" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c #: shared-bindings/busdisplay/BusDisplay.c #: shared-bindings/epaperdisplay/EPaperDisplay.c #: shared-bindings/framebufferio/FramebufferDisplay.c @@ -465,7 +498,7 @@ msgstr "" msgid "AP could not be started" msgstr "" -#: shared-bindings/_bleio/Address.c shared-bindings/ipaddress/IPv4Address.c +#: shared-bindings/ipaddress/IPv4Address.c #, c-format msgid "Address must be %d bytes long" msgstr "" @@ -500,7 +533,8 @@ msgstr "" msgid "All SPI peripherals are in use" msgstr "" -#: ports/espressif/common-hal/busio/UART.c ports/nordic/common-hal/busio/UART.c +#: 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 "" @@ -571,7 +605,7 @@ msgstr "" msgid "Already scanning for wifi networks" msgstr "" -#: shared-module/os/getenv.c +#: supervisor/shared/settings.c #, c-format msgid "An error occurred while retrieving '%s':\n" msgstr "" @@ -598,6 +632,10 @@ msgstr "" msgid "Async SPI transfer in progress on this bus, keep awaiting." msgstr "" +#: shared-bindings/usb_audio/__init__.c +msgid "At least one of microphone and speaker must be enabled" +msgstr "" + #: shared-module/memorymonitor/AllocationAlarm.c #, c-format msgid "Attempt to allocate %d blocks" @@ -609,6 +647,7 @@ msgstr "" #: 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 "" @@ -634,12 +673,14 @@ msgstr "" msgid "Baudrate not supported by peripheral" 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/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 "" @@ -651,20 +692,17 @@ msgstr "" msgid "Boot device must be first (interface #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" msgstr "" +#: 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/_bleio/UUID.c -#, c-format -msgid "Buffer + offset too small %d %d %d" -msgstr "" - #: ports/raspberrypi/bindings/rp2pio/StateMachine.c msgid "Buffer elements must be 4 bytes long or less" msgstr "" @@ -707,10 +745,6 @@ msgstr "" msgid "Bus pin %d is already in use" msgstr "" -#: shared-bindings/_bleio/UUID.c -msgid "Byte buffer must be 16 bytes." -msgstr "" - #: shared-bindings/aesio/aes.c msgid "CBC blocks must be multiples of 16 bytes" msgstr "" @@ -752,9 +786,9 @@ msgstr "" msgid "Can't set CCCD on local Characteristic" 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 +#: 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 "" @@ -762,6 +796,10 @@ msgstr "" msgid "Cannot create a new Adapter; use _bleio.adapter;" msgstr "" +#: shared-module/i2cioexpander/IOExpander.c +msgid "Cannot deinitialize board IOExpander" +msgstr "" + #: shared-bindings/displayio/Bitmap.c #: shared-bindings/memorymonitor/AllocationSize.c #: shared-bindings/pulseio/PulseIn.c @@ -787,7 +825,7 @@ msgstr "" msgid "Cannot pull on input-only pin." msgstr "" -#: shared-bindings/audiobusio/PDMIn.c +#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c msgid "Cannot record to a file" msgstr "" @@ -796,6 +834,7 @@ msgid "Cannot remount path when visible via USB." msgstr "" #: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c msgid "Cannot set value when direction is input." msgstr "" @@ -846,6 +885,10 @@ msgstr "" msgid "Coordinate arrays types have different sizes" 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/rclcpy/Publisher.c msgid "Could not publish to ROS topic" msgstr "" @@ -868,10 +911,12 @@ msgid "Critical ROS failure during soft reboot, reset required: %d" msgstr "" #: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c msgid "DAC Channel Init Error" msgstr "" #: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c msgid "DAC Device Init Error" msgstr "" @@ -902,7 +947,7 @@ msgstr "" msgid "Deep sleep pins must use a rising edge with pulldown" msgstr "" -#: shared-bindings/audiobusio/PDMIn.c +#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c msgid "Destination capacity is smaller than destination_length." msgstr "" @@ -922,6 +967,7 @@ 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 "" @@ -930,6 +976,7 @@ msgid "Done" msgstr "" #: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c msgid "Drive mode not used when direction is input." msgstr "" @@ -941,8 +988,17 @@ msgstr "" msgid "ECB only operates on 16 bytes at a time" msgstr "" +#: py/asmxtensa.c +msgid "ERROR: %q %q not word-aligned" +msgstr "" + +#: py/asmxtensa.c +msgid "ERROR: xtensa %q out of range" +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 "" @@ -989,7 +1045,7 @@ msgid "" "Failed to add service TXT record; non-string or bytes found in txt_records" msgstr "" -#: shared-module/rgbmatrix/RGBMatrix.c +#: ports/analog/common-hal/busio/UART.c shared-module/rgbmatrix/RGBMatrix.c msgid "Failed to allocate %q buffer" msgstr "" @@ -1007,10 +1063,12 @@ 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/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c msgid "Failed to connect: timeout" msgstr "" @@ -1047,6 +1105,10 @@ msgstr "" msgid "Failed to release mutex, err 0x%04x" msgstr "" +#: ports/analog/common-hal/busio/SPI.c +msgid "Failed to set SPI Clock Mode" +msgstr "" + #: ports/zephyr-cp/common-hal/wifi/Radio.c msgid "Failed to set hostname" msgstr "" @@ -1064,7 +1126,6 @@ msgid "File exists" msgstr "" #: shared-bindings/supervisor/__init__.c shared-module/lvfontio/OnDiskFont.c -#: shared-module/os/getenv.c msgid "File not found" msgstr "" @@ -1117,6 +1178,7 @@ msgstr "" msgid "Generic Failure" msgstr "" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c #: shared-bindings/framebufferio/FramebufferDisplay.c #: shared-module/busdisplay/BusDisplay.c #: shared-module/framebufferio/FramebufferDisplay.c @@ -1215,7 +1277,8 @@ msgstr "" msgid "Internal define error" msgstr "" -#: shared-bindings/pwmio/PWMOut.c shared-module/os/getenv.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-bindings/pwmio/PWMOut.c +#: supervisor/shared/settings.c msgid "Internal error" msgstr "" @@ -1249,22 +1312,29 @@ msgstr "" 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/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/pwmio/PWMOut.c -#: shared-bindings/supervisor/__init__.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/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" @@ -1298,6 +1368,10 @@ msgstr "" msgid "Invalid ROS domain ID" msgstr "" +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Invalid advertising data" +msgstr "" + #: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c msgid "Invalid argument" msgstr "" @@ -1306,17 +1380,12 @@ msgstr "" msgid "Invalid bits per value" msgstr "" -#: shared-module/os/getenv.c -#, c-format -msgid "Invalid byte %.*s" -msgstr "" - #: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c #, c-format msgid "Invalid data_pins[%d]" msgstr "" -#: shared-module/msgpack/__init__.c +#: shared-module/msgpack/__init__.c supervisor/shared/settings.c msgid "Invalid format" msgstr "" @@ -1341,12 +1410,13 @@ msgstr "" msgid "Invalid socket for TLS" 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/os/getenv.c +#: supervisor/shared/settings.c msgid "Invalid unicode escape" msgstr "" @@ -1354,10 +1424,6 @@ msgstr "" msgid "Key must be 16, 24, or 32 bytes long" msgstr "" -#: shared-module/os/getenv.c -msgid "Key not found" -msgstr "" - #: shared-module/is31fl3741/FrameBuffer.c msgid "LED mappings must match display size" msgstr "" @@ -1396,6 +1462,18 @@ msgstr "" msgid "Mapping must be a tuple" msgstr "" +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap must have 8 bits per pixel" +msgstr "" + +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap size must match the other bitmaps" +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" @@ -1437,8 +1515,7 @@ msgstr "" msgid "Mount point directory missing" msgstr "" -#: ports/zephyr-cp/bindings/zephyr_serial/UART.c shared-bindings/busio/UART.c -#: shared-bindings/displayio/Group.c +#: shared-bindings/busio/UART.c shared-bindings/displayio/Group.c msgid "Must be a %q subclass." msgstr "" @@ -1485,7 +1562,7 @@ msgstr "" #: 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 +#: shared-bindings/qspibus/QSPIBus.c shared-module/bitbangio/SPI.c msgid "No %q pin" msgstr "" @@ -1496,6 +1573,7 @@ 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 "" @@ -1503,6 +1581,7 @@ msgstr "" #: 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 "" @@ -1617,14 +1696,11 @@ msgid "Not connected" msgstr "" #: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c -#: shared-bindings/audiopwmio/PWMAudioOut.c +#: shared-bindings/audiopwmio/PWMAudioOut.c shared-bindings/mcp4822/MCP4822.c +#: shared-bindings/usb_audio/USBMicrophone.c msgid "Not playing" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Not supported JPEG standard" -msgstr "" - #: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c #: ports/espressif/common-hal/sdioio/SDCard.c #, c-format @@ -1718,6 +1794,7 @@ msgid "Operation or feature not supported" msgstr "" #: ports/espressif/common-hal/espidf/__init__.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c msgid "Operation timed out" msgstr "" @@ -1760,6 +1837,7 @@ msgid "Parameter error" msgstr "" #: ports/espressif/common-hal/audiobusio/__init__.c +#: ports/espressif/common-hal/audioi2sin/I2SIn.c msgid "Peripheral in use" msgstr "" @@ -1857,6 +1935,7 @@ msgid "Publishers can only be created from a parent node" msgstr "" #: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c msgid "Pull not used when direction is output." msgstr "" @@ -1896,6 +1975,7 @@ msgstr "" msgid "ROS topic failed to initialize" 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" @@ -1988,6 +2068,10 @@ msgstr "" msgid "SPI init error" msgstr "" +#: ports/analog/common-hal/busio/SPI.c +msgid "SPI needs MOSI, MISO, and SCK" +msgstr "" + #: ports/raspberrypi/common-hal/busio/SPI.c msgid "SPI peripheral in use" msgstr "" @@ -2033,10 +2117,13 @@ 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/zephyr-cp/common-hal/socketpool/SocketPool.c +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 "" @@ -2073,7 +2160,7 @@ msgstr "" msgid "The length of rgb_pins must be 6, 12, 18, 24, or 30" msgstr "" -#: shared-module/audiocore/__init__.c +#: shared-module/audiocore/__init__.c shared-module/usb_audio/USBMicrophone.c msgid "The sample's %q does not match" msgstr "" @@ -2119,11 +2206,16 @@ msgstr "" msgid "Timeout is too long: Maximum timeout length is %d seconds" msgstr "" +#: ports/analog/common-hal/busio/UART.c +msgid "Timeout must be < 100 seconds" +msgstr "" + #: ports/atmel-samd/common-hal/audiobusio/I2SOut.c msgid "Too many channels in sample" msgstr "" #: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c msgid "Too many channels in sample." msgstr "" @@ -2162,6 +2254,10 @@ msgstr "" msgid "UART init" msgstr "" +#: ports/analog/common-hal/busio/UART.c +msgid "UART needs TX & RX" +msgstr "" + #: ports/raspberrypi/common-hal/busio/UART.c msgid "UART peripheral in use" msgstr "" @@ -2170,6 +2266,14 @@ msgstr "" msgid "UART re-init" 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/stm/common-hal/busio/UART.c msgid "UART write" msgstr "" @@ -2194,10 +2298,6 @@ msgstr "" msgid "USB error" msgstr "" -#: shared-bindings/_bleio/UUID.c -msgid "UUID integer value must be 0-0xffff" -msgstr "" - #: shared-bindings/_bleio/UUID.c msgid "UUID string not 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'" msgstr "" @@ -2214,6 +2314,7 @@ msgstr "" #: 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 "" @@ -2222,6 +2323,7 @@ msgid "Unable to allocate to the heap." msgstr "" #: ports/espressif/common-hal/busio/I2C.c +#: ports/espressif/common-hal/busio/SPI.c msgid "Unable to create lock" msgstr "" @@ -2327,6 +2429,10 @@ msgid "" "declined or ignored." msgstr "" +#: shared-module/jpegio/JpegDecoder.c +msgid "Unsupported JPEG (may be progressive)" +msgstr "" + #: shared-bindings/bitmaptools/__init__.c msgid "Unsupported colorspace" msgstr "" @@ -2349,6 +2455,13 @@ msgstr "" msgid "Update failed" 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/_bleio/Characteristic.c #: ports/nordic/common-hal/_bleio/Characteristic.c #: ports/nordic/common-hal/_bleio/Descriptor.c @@ -2488,6 +2601,10 @@ msgstr "" msgid "a bytes-like object is required" msgstr "" +#: shared-bindings/i2cioexpander/IOExpander.c +msgid "address out of range" +msgstr "" + #: shared-bindings/i2ctarget/I2CTarget.c msgid "addresses is empty" msgstr "" @@ -2554,10 +2671,6 @@ msgstr "" msgid "array/bytes required on right side" msgstr "" -#: py/asmxtensa.c -msgid "asm overflow" -msgstr "" - #: py/compile.c msgid "async for/with outside async function" msgstr "" @@ -2614,10 +2727,6 @@ msgstr "" msgid "binary op %q not implemented" msgstr "" -#: ports/espressif/common-hal/audiobusio/PDMIn.c -msgid "bit_depth must be 8, 16, 24, or 32." -msgstr "" - #: shared-module/bitmapfilter/__init__.c msgid "bitmap size and depth must match" msgstr "" @@ -2771,6 +2880,10 @@ msgstr "" msgid "can't create '%q' instances" msgstr "" +#: py/objtype.c +msgid "can't create instance" +msgstr "" + #: py/compile.c msgid "can't declare nonlocal in outer code" msgstr "" @@ -2869,14 +2982,14 @@ msgstr "" msgid "cannot convert complex type" msgstr "" -#: py/objtype.c -msgid "cannot create instance" -msgstr "" - #: extmod/ulab/code/ndarray.c msgid "cannot delete array elements" msgstr "" +#: py/compile.c +msgid "cannot emit native code for this architecture" +msgstr "" + #: extmod/ulab/code/ndarray.c msgid "cannot reshape array" msgstr "" @@ -3011,6 +3124,10 @@ msgstr "" msgid "destination buffer must be an array of type 'H' for bit_depth = 16" msgstr "" +#: shared-bindings/usb_audio/USBSpeaker.c +msgid "destination must be an array of type 'h'" +msgstr "" + #: py/objdict.c msgid "dict update sequence has wrong length" msgstr "" @@ -3031,7 +3148,7 @@ msgstr "" msgid "div/mod not implemented for uint" msgstr "" -#: extmod/ulab/code/numpy/create.c +#: extmod/ulab/code/numpy/create.c py/objint_longlong.c py/objint_mpz.c msgid "divide by zero" msgstr "" @@ -3130,10 +3247,6 @@ msgstr "" msgid "file write is not available" msgstr "" -#: shared-bindings/storage/__init__.c -msgid "filesystem must provide mount method" -msgstr "" - #: extmod/ulab/code/numpy/vector.c msgid "first argument must be a callable" msgstr "" @@ -3174,10 +3287,6 @@ msgstr "" msgid "float unsupported" msgstr "" -#: shared-bindings/_stage/Text.c -msgid "font must be 2048 bytes long" -msgstr "" - #: extmod/moddeflate.c msgid "format" msgstr "" @@ -3259,10 +3368,6 @@ msgstr "" msgid "generator raised StopIteration" msgstr "" -#: shared-bindings/_stage/Layer.c -msgid "graphic must be 2048 bytes long" -msgstr "" - #: extmod/modhashlib.c msgid "hash is final" msgstr "" @@ -3329,10 +3434,6 @@ msgstr "" msgid "initial values must be iterable" msgstr "" -#: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c -msgid "initial_value length is wrong" -msgstr "" - #: py/compile.c msgid "inline assembler must be a function" msgstr "" @@ -3423,6 +3524,10 @@ msgstr "" msgid "interval must be in range %s-%s" msgstr "" +#: py/emitinlinerv32.c +msgid "invalid RV32 instruction '%q'" +msgstr "" + #: py/compile.c msgid "invalid arch" msgstr "" @@ -3436,6 +3541,11 @@ msgstr "" msgid "invalid cert" msgstr "" +#: shared-bindings/audioi2sin/I2SIn.c +#, c-format +msgid "invalid destination buffer, must be an array of type: %c" +msgstr "" + #: shared-bindings/bitmaptools/__init__.c #, c-format msgid "invalid element size %d for bits_per_pixel %d\n" @@ -3617,6 +3727,10 @@ msgstr "" msgid "mode must be complete, or reduced" msgstr "" +#: py/runtime.c +msgid "module '%q' has no attribute '%q'" +msgstr "" + #: py/builtinimport.c msgid "module not found" msgstr "" @@ -3665,10 +3779,6 @@ msgstr "" msgid "native code in .mpy unsupported" msgstr "" -#: py/asmthumb.c -msgid "native method too big" -msgstr "" - #: py/emitnative.c msgid "native yield" msgstr "" @@ -3690,7 +3800,7 @@ msgstr "" msgid "negative power with no float support" msgstr "" -#: py/objint_mpz.c py/runtime.c +#: py/objint_longlong.c py/objint_mpz.c py/runtime.c msgid "negative shift count" msgstr "" @@ -3767,6 +3877,10 @@ msgstr "" msgid "not supported for input types" msgstr "" +#: shared-bindings/i2cioexpander/IOExpander.c +msgid "num_pins must be 8 or 16" +msgstr "" + #: extmod/ulab/code/numpy/create.c msgid "number of points must be at least 2" msgstr "" @@ -3780,6 +3894,10 @@ msgstr "" msgid "object '%s' isn't a tuple or list" msgstr "" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "object does not support DigitalInOut protocol" +msgstr "" + #: py/obj.c msgid "object doesn't support item assignment" msgstr "" @@ -3971,7 +4089,7 @@ msgstr "" msgid "output array must be contiguous" msgstr "" -#: py/objint_mpz.c +#: py/objint_longlong.c py/objint_mpz.c msgid "overflow converting long int to machine word" msgstr "" @@ -3980,10 +4098,6 @@ msgstr "" 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" -msgstr "" - #: py/emitinlinerv32.c msgid "parameters must be registers in sequence a0 to a3" msgstr "" @@ -4041,6 +4155,10 @@ msgstr "" msgid "real and imaginary parts must be of equal length" msgstr "" +#: extmod/modre.c +msgid "regex too complex" +msgstr "" + #: py/builtinimport.c msgid "relative import" msgstr "" @@ -4050,6 +4168,10 @@ msgstr "" msgid "requested length %d but object has length %d" msgstr "" +#: py/objint_longlong.c py/parsenum.c +msgid "result overflows long long storage" +msgstr "" + #: extmod/ulab/code/ndarray_operators.c msgid "results cannot be cast to specified type" msgstr "" @@ -4314,10 +4436,6 @@ msgstr "" msgid "type takes 1 or 3 arguments" msgstr "" -#: py/objint_longlong.c -msgid "ulonglong too large" -msgstr "" - #: py/parse.c msgid "unexpected indent" msgstr "" @@ -4339,10 +4457,6 @@ msgstr "" msgid "unindent doesn't match any outer indent level" msgstr "" -#: py/emitinlinerv32.c -msgid "unknown RV32 instruction '%q'" -msgstr "" - #: py/objstr.c #, c-format msgid "unknown conversion specifier %c" diff --git a/locale/ko.po b/locale/ko.po index 8bde494eeec..4789c8a566b 100644 --- a/locale/ko.po +++ b/locale/ko.po @@ -91,6 +91,11 @@ msgid "" msgstr "" "%d 주소 핀들, %d rgb 핀들과 %d 타일 들은 높이가 %d임을 나타낸다, %d가 아니라" +#: py/emitinlinextensa.c +#, c-format +msgid "%d is not a multiple of %d" +msgstr "" + #: shared-bindings/microcontroller/Pin.c msgid "%q and %q contain duplicate pins" msgstr "%q 및 %q에 중복된 핀이 포함" @@ -112,6 +117,7 @@ msgid "%q contains duplicate pins" msgstr "%q에 중복된 핀이 포함" #: ports/atmel-samd/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c msgid "%q failure: %d" msgstr "%q 실패: %d" @@ -124,6 +130,8 @@ msgid "%q in %q must be of type %q, not %q" msgstr "%q의 %q는 %q가 아니라 %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 @@ -131,7 +139,8 @@ msgstr "%q의 %q는 %q가 아니라 %q 유형이어야 합니다" #: 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 +#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/microcontroller/Pin.c +#: shared-module/max3421e/Max3421E.c msgid "%q in use" msgstr "%q 사용 중입니다" @@ -143,7 +152,10 @@ msgstr "%q 인덱스 범위를 벗어났습니다" msgid "%q indices must be integers, not %s" msgstr "%q 인덱스는 %s 가 아닌 정수 여야합니다" -#: shared-module/bitbangio/SPI.c +#: 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 msgid "%q init failed" msgstr "%q 초기화 실패" @@ -175,8 +187,8 @@ msgstr "%q 길이는 >= %d이어야 합니다" msgid "%q must be %d" msgstr "%q는 %d이어야 합니다" -#: py/argcheck.c shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/displayio/Bitmap.c +#: 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 @@ -187,6 +199,20 @@ msgstr "%q는 %d-%d이어야 합니다" msgid "%q must be 1 when %q is True" msgstr "%q가 참일 때 %q는 1이어야 합니다" +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "%q must be 16, 24, or 32" +msgstr "" + +#: 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/audiobusio/PDMIn.c +#: shared-bindings/audioi2sin/I2SIn.c +msgid "%q must be 8, 16, 24, or 32" +msgstr "" + #: py/argcheck.c shared-bindings/gifio/GifWriter.c #: shared-module/gifio/OnDiskGif.c #, fuzzy @@ -251,25 +277,31 @@ msgstr "%q는 %q가 아니라 %q 유형이어야 합니다" msgid "%q must be power of 2" msgstr "%q는 2의 거듭제곱이어야 합니다" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' attribute" +msgstr "" + +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' method" +msgstr "" + #: shared-bindings/wifi/Monitor.c #, fuzzy msgid "%q out of bounds" msgstr "%q가 경계를 벗어남" +#: 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 +#: shared-bindings/bitmaptools/__init__.c shared-bindings/canio/Match.c +#: shared-bindings/time/__init__.c #, fuzzy msgid "%q out of range" msgstr "%q가 범위를 벗어남" -#: py/objmodule.c -msgid "%q renamed %q" -msgstr "%q가 %q로 이름이 변경되었습니다" - #: py/objrange.c py/objslice.c shared-bindings/random/__init__.c #, fuzzy msgid "%q step cannot be zero" @@ -324,7 +356,7 @@ msgstr "%s 오류 0x%x" msgid "'%q' argument required" msgstr "'%q' 인수가 필요합니다" -#: py/proto.c +#: py/proto.c shared-bindings/digitalio/DigitalInOutProtocol.c msgid "'%q' object does not support '%q'" msgstr "'%q' 개체가 '%q'를 지원하지 않습니다" @@ -475,6 +507,7 @@ msgstr "*x는 할당 대상이어야 합니다" msgid ", in %q\n" msgstr ", 에서 %q\n" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c #: shared-bindings/busdisplay/BusDisplay.c #: shared-bindings/epaperdisplay/EPaperDisplay.c #: shared-bindings/framebufferio/FramebufferDisplay.c @@ -494,7 +527,7 @@ msgstr "pow() 는 3개의 인수를 지원하지 않습니다" msgid "AP could not be started" msgstr "AP를 시작할 수 없습니다" -#: shared-bindings/_bleio/Address.c shared-bindings/ipaddress/IPv4Address.c +#: shared-bindings/ipaddress/IPv4Address.c #, c-format msgid "Address must be %d bytes long" msgstr "주소 길이는 %d 바이트 여야합니다" @@ -531,7 +564,8 @@ msgstr "모든 RX FIFOs가 사용 중입니다" msgid "All SPI peripherals are in use" msgstr "사용중인 모든 SPI주변 기기" -#: ports/espressif/common-hal/busio/UART.c ports/nordic/common-hal/busio/UART.c +#: 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주변 기기" @@ -608,7 +642,7 @@ msgstr "이미 실행 중입니다" msgid "Already scanning for wifi networks" msgstr "이미 wifi 네트워크를 찾고 있습니다" -#: shared-module/os/getenv.c +#: supervisor/shared/settings.c #, c-format msgid "An error occurred while retrieving '%s':\n" msgstr "%s'을(를) 검색하는 동안 오류가 발생했습니다:\n" @@ -637,6 +671,10 @@ msgstr "배열 값은 1바이트 여야합니다." msgid "Async SPI transfer in progress on this bus, keep awaiting." msgstr "" +#: shared-bindings/usb_audio/__init__.c +msgid "At least one of microphone and speaker must be enabled" +msgstr "" + #: shared-module/memorymonitor/AllocationAlarm.c #, c-format msgid "Attempt to allocate %d blocks" @@ -648,6 +686,7 @@ msgstr "오디오 변환이 구현되지 않음" #: 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 "" @@ -675,12 +714,14 @@ msgstr "" msgid "Baudrate not supported by peripheral" 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/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 핀이어야 합니다" @@ -692,20 +733,17 @@ msgstr "비트맵 크기와 값 당 비트가 일치해야 합니다" 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가 모두 필요합니다" +#: 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/_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 "버퍼 요소는 4바이트 이하여야 합니다" @@ -748,10 +786,6 @@ msgstr "버퍼가 너무 작습니다" msgid "Bus pin %d is already in use" msgstr "Bus 핀 %d은 이미 사용 중입니다" -#: shared-bindings/_bleio/UUID.c -msgid "Byte buffer must be 16 bytes." -msgstr "잘못된 크기의 버퍼. 16 바이트 여야합니다." - #: shared-bindings/aesio/aes.c msgid "CBC blocks must be multiples of 16 bytes" msgstr "CBC 블록은 16 바이트의 배수여야 합니다" @@ -794,9 +828,9 @@ msgstr "" msgid "Can't set CCCD on local Characteristic" msgstr "로컬 특성에 CCCD를 설정할 수 없습니다" -#: 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 +#: 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 디바이스를 변경할 수 없습니다" @@ -804,6 +838,10 @@ msgstr "현재 USB 디바이스를 변경할 수 없습니다" msgid "Cannot create a new Adapter; use _bleio.adapter;" msgstr "_bleio.adapter를 사용해서; 새로운 Adapter를 만들 수 없습니다;" +#: shared-module/i2cioexpander/IOExpander.c +msgid "Cannot deinitialize board IOExpander" +msgstr "" + #: shared-bindings/displayio/Bitmap.c #: shared-bindings/memorymonitor/AllocationSize.c #: shared-bindings/pulseio/PulseIn.c @@ -829,7 +867,7 @@ msgstr "확장되고 연결 가능한 광고에 대한 검색 응답을 가질 msgid "Cannot pull on input-only pin." msgstr "입력 전용 핀을 끌어올 수 없습니다." -#: shared-bindings/audiobusio/PDMIn.c +#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c msgid "Cannot record to a file" msgstr "파일에 녹음 할 수 없습니다" @@ -838,6 +876,7 @@ msgid "Cannot remount path when visible via USB." msgstr "" #: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c msgid "Cannot set value when direction is input." msgstr "방향이 입력되면 값을 설정할 수 없습니다." @@ -890,6 +929,10 @@ msgstr "좌표 배열의 길이가 다릅니다" msgid "Coordinate arrays types have different sizes" 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/rclcpy/Publisher.c msgid "Could not publish to ROS topic" msgstr "" @@ -912,10 +955,12 @@ msgid "Critical ROS failure during soft reboot, reset required: %d" msgstr "" #: 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/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c msgid "DAC Device Init Error" msgstr "DAC 장치 초기화 오류" @@ -947,7 +992,7 @@ msgstr "광고 (브로드 캐스트) 패킷에 대한 데이터가 너무 큽니 msgid "Deep sleep pins must use a rising edge with pulldown" msgstr "딥 슬립 핀은 풀다운이 있는 상승 에지를 사용해야 합니다" -#: shared-bindings/audiobusio/PDMIn.c +#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c msgid "Destination capacity is smaller than destination_length." msgstr "대상 용량이 destination_length보다 작습니다." @@ -967,6 +1012,7 @@ msgstr "디스플레이는 16 비트 색 공간을 가져야 합니다." #: 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도씩 증가해야 합니다" @@ -975,6 +1021,7 @@ msgid "Done" msgstr "완료" #: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c msgid "Drive mode not used when direction is input." msgstr "방향을 입력할 때 드라이브 모드는 사용되지 않습니다." @@ -986,8 +1033,17 @@ msgstr "위 예외를 처리하는 동안, 또 다른 예외가 발생하였습 msgid "ECB only operates on 16 bytes at a time" msgstr "ECB는 한 번에 16 바이트에서만 작동합니다" +#: py/asmxtensa.c +msgid "ERROR: %q %q not word-aligned" +msgstr "" + +#: py/asmxtensa.c +msgid "ERROR: xtensa %q out of range" +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 메모리 할당에 실패하였습니다" @@ -1037,7 +1093,7 @@ msgstr "" "서비스 TXT 레코드를 추가하는 것에 실패했습니다; txt_records에서 비문자열 또" "는 바이트가 발견되었습니다" -#: shared-module/rgbmatrix/RGBMatrix.c +#: ports/analog/common-hal/busio/UART.c shared-module/rgbmatrix/RGBMatrix.c msgid "Failed to allocate %q buffer" msgstr "%q 버퍼 할당에 실패했습니다" @@ -1055,10 +1111,12 @@ 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/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c msgid "Failed to connect: timeout" msgstr "연결에 실패했습니다: 시간 초과" @@ -1095,6 +1153,10 @@ msgstr "" msgid "Failed to release mutex, err 0x%04x" msgstr "뮤텍스 해제에 실패했습니다, 오류 0x%04x" +#: ports/analog/common-hal/busio/SPI.c +msgid "Failed to set SPI Clock Mode" +msgstr "" + #: ports/zephyr-cp/common-hal/wifi/Radio.c msgid "Failed to set hostname" msgstr "" @@ -1113,7 +1175,6 @@ msgid "File exists" msgstr "파일이 있습니다" #: shared-bindings/supervisor/__init__.c shared-module/lvfontio/OnDiskFont.c -#: shared-module/os/getenv.c msgid "File not found" msgstr "파일을 찾을 수 없습니다" @@ -1168,6 +1229,7 @@ msgstr "GNSS 초기화" msgid "Generic Failure" msgstr "일반 오류" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c #: shared-bindings/framebufferio/FramebufferDisplay.c #: shared-module/busdisplay/BusDisplay.c #: shared-module/framebufferio/FramebufferDisplay.c @@ -1266,7 +1328,8 @@ msgstr "내부 오디오 버퍼가 너무 작습니다" msgid "Internal define error" msgstr "내부 정의 오류" -#: shared-bindings/pwmio/PWMOut.c shared-module/os/getenv.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-bindings/pwmio/PWMOut.c +#: supervisor/shared/settings.c msgid "Internal error" msgstr "내부 오류" @@ -1300,22 +1363,29 @@ msgstr "인터럽트 오류." 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/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/pwmio/PWMOut.c -#: shared-bindings/supervisor/__init__.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/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" @@ -1349,6 +1419,10 @@ msgstr "잘못된 MAC 주소" msgid "Invalid ROS domain ID" msgstr "" +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Invalid advertising data" +msgstr "" + #: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c msgid "Invalid argument" msgstr "잘못된 인수" @@ -1357,17 +1431,12 @@ msgstr "잘못된 인수" msgid "Invalid bits per value" msgstr "값 당 잘못된 비트" -#: shared-module/os/getenv.c -#, c-format -msgid "Invalid byte %.*s" -msgstr "잘못된 바이트 %.*s" - #: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c #, c-format msgid "Invalid data_pins[%d]" msgstr "잘못된 data_pins[%d]" -#: shared-module/msgpack/__init__.c +#: shared-module/msgpack/__init__.c supervisor/shared/settings.c msgid "Invalid format" msgstr "잘못된 형식" @@ -1392,12 +1461,13 @@ msgstr "잘못된 크기" msgid "Invalid socket for TLS" msgstr "TLS에 대한 잘못된 소켓" +#: 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/os/getenv.c +#: supervisor/shared/settings.c msgid "Invalid unicode escape" msgstr "잘못된 유니코드 이스케이프" @@ -1405,10 +1475,6 @@ msgstr "잘못된 유니코드 이스케이프" msgid "Key must be 16, 24, or 32 bytes long" msgstr "키는 16, 24, 또는 32 바이트 길이여야 합니다" -#: shared-module/os/getenv.c -msgid "Key not found" -msgstr "키를 찾을 수 없습니다" - #: shared-module/is31fl3741/FrameBuffer.c msgid "LED mappings must match display size" msgstr "LED 매핑은 디스플레이 크기와 일치해야 합니다" @@ -1447,6 +1513,18 @@ msgstr "" msgid "Mapping must be a tuple" msgstr "매핑은 투플이어야 합니다" +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap must have 8 bits per pixel" +msgstr "" + +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap size must match the other bitmaps" +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" @@ -1491,8 +1569,7 @@ msgstr "jmp_pin이 누락되었습니다. %q[%u] 핀으로 점프합니다" msgid "Mount point directory missing" msgstr "" -#: ports/zephyr-cp/bindings/zephyr_serial/UART.c shared-bindings/busio/UART.c -#: shared-bindings/displayio/Group.c +#: shared-bindings/busio/UART.c shared-bindings/displayio/Group.c msgid "Must be a %q subclass." msgstr "%q의 하위클래스여야 합니다." @@ -1540,7 +1617,7 @@ msgstr "빠른 메모리 부족" #: 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 +#: shared-bindings/qspibus/QSPIBus.c shared-module/bitbangio/SPI.c msgid "No %q pin" msgstr "%q 핀이 없습니다" @@ -1551,6 +1628,7 @@ msgstr "이 특성에 대한 CCCD가 없습니다" #: 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가 없습니다" @@ -1558,6 +1636,7 @@ msgstr "칩에 DAC가 없습니다" #: 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 채널을 찾을 수 없습니다" @@ -1675,15 +1754,11 @@ msgid "Not connected" msgstr "연결되지 않았습니다" #: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c -#: shared-bindings/audiopwmio/PWMAudioOut.c +#: shared-bindings/audiopwmio/PWMAudioOut.c shared-bindings/mcp4822/MCP4822.c +#: shared-bindings/usb_audio/USBMicrophone.c msgid "Not playing" msgstr "재생되지 않았습니다" -#: shared-module/jpegio/JpegDecoder.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 @@ -1782,6 +1857,7 @@ msgid "Operation or feature not supported" msgstr "작업 또는 기능이 지원되지 않습니다" #: ports/espressif/common-hal/espidf/__init__.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c #, fuzzy msgid "Operation timed out" msgstr "작업 시간 초과되었습니다" @@ -1830,6 +1906,7 @@ msgid "Parameter error" msgstr "파라미터 오류" #: ports/espressif/common-hal/audiobusio/__init__.c +#: ports/espressif/common-hal/audioi2sin/I2SIn.c #, fuzzy msgid "Peripheral in use" msgstr "주변 기기가 사용 중입니다" @@ -1930,6 +2007,7 @@ msgid "Publishers can only be created from a parent node" msgstr "" #: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c #, fuzzy msgid "Pull not used when direction is output." msgstr "방향이 출력 될 때 풀은 사용되지 않습니다" @@ -1970,6 +2048,7 @@ msgstr "" msgid "ROS topic failed to initialize" 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" @@ -2062,6 +2141,10 @@ msgstr "" msgid "SPI init error" msgstr "" +#: ports/analog/common-hal/busio/SPI.c +msgid "SPI needs MOSI, MISO, and SCK" +msgstr "" + #: ports/raspberrypi/common-hal/busio/SPI.c msgid "SPI peripheral in use" msgstr "" @@ -2107,10 +2190,13 @@ 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/zephyr-cp/common-hal/socketpool/SocketPool.c +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 "" @@ -2147,7 +2233,7 @@ msgstr "" msgid "The length of rgb_pins must be 6, 12, 18, 24, or 30" msgstr "" -#: shared-module/audiocore/__init__.c +#: shared-module/audiocore/__init__.c shared-module/usb_audio/USBMicrophone.c msgid "The sample's %q does not match" msgstr "" @@ -2193,11 +2279,16 @@ msgstr "" msgid "Timeout is too long: Maximum timeout length is %d seconds" msgstr "" +#: ports/analog/common-hal/busio/UART.c +msgid "Timeout must be < 100 seconds" +msgstr "" + #: ports/atmel-samd/common-hal/audiobusio/I2SOut.c msgid "Too many channels in sample" msgstr "" #: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c msgid "Too many channels in sample." msgstr "" @@ -2236,6 +2327,10 @@ msgstr "" msgid "UART init" msgstr "" +#: ports/analog/common-hal/busio/UART.c +msgid "UART needs TX & RX" +msgstr "" + #: ports/raspberrypi/common-hal/busio/UART.c msgid "UART peripheral in use" msgstr "" @@ -2244,6 +2339,14 @@ msgstr "" msgid "UART re-init" 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/stm/common-hal/busio/UART.c msgid "UART write" msgstr "" @@ -2268,10 +2371,6 @@ msgstr "" msgid "USB error" msgstr "" -#: shared-bindings/_bleio/UUID.c -msgid "UUID integer value must be 0-0xffff" -msgstr "" - #: shared-bindings/_bleio/UUID.c msgid "UUID string not 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'" msgstr "UUID문자열이 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'형식이 아닙니다" @@ -2289,6 +2388,7 @@ msgstr "" #: 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 "" @@ -2297,6 +2397,7 @@ msgid "Unable to allocate to the heap." msgstr "" #: ports/espressif/common-hal/busio/I2C.c +#: ports/espressif/common-hal/busio/SPI.c msgid "Unable to create lock" msgstr "" @@ -2402,6 +2503,10 @@ msgid "" "declined or ignored." msgstr "" +#: shared-module/jpegio/JpegDecoder.c +msgid "Unsupported JPEG (may be progressive)" +msgstr "" + #: shared-bindings/bitmaptools/__init__.c msgid "Unsupported colorspace" msgstr "" @@ -2424,6 +2529,13 @@ msgstr "" msgid "Update failed" 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/_bleio/Characteristic.c #: ports/nordic/common-hal/_bleio/Characteristic.c #: ports/nordic/common-hal/_bleio/Descriptor.c @@ -2563,6 +2675,10 @@ msgstr "" msgid "a bytes-like object is required" msgstr "" +#: shared-bindings/i2cioexpander/IOExpander.c +msgid "address out of range" +msgstr "" + #: shared-bindings/i2ctarget/I2CTarget.c msgid "addresses is empty" msgstr "" @@ -2629,10 +2745,6 @@ msgstr "" msgid "array/bytes required on right side" msgstr "" -#: py/asmxtensa.c -msgid "asm overflow" -msgstr "" - #: py/compile.c msgid "async for/with outside async function" msgstr "" @@ -2689,10 +2801,6 @@ msgstr "" msgid "binary op %q not implemented" msgstr "" -#: ports/espressif/common-hal/audiobusio/PDMIn.c -msgid "bit_depth must be 8, 16, 24, or 32." -msgstr "" - #: shared-module/bitmapfilter/__init__.c msgid "bitmap size and depth must match" msgstr "" @@ -2846,6 +2954,10 @@ msgstr "" msgid "can't create '%q' instances" msgstr "" +#: py/objtype.c +msgid "can't create instance" +msgstr "" + #: py/compile.c msgid "can't declare nonlocal in outer code" msgstr "" @@ -2944,14 +3056,14 @@ msgstr "" msgid "cannot convert complex type" msgstr "" -#: py/objtype.c -msgid "cannot create instance" -msgstr "" - #: extmod/ulab/code/ndarray.c msgid "cannot delete array elements" msgstr "" +#: py/compile.c +msgid "cannot emit native code for this architecture" +msgstr "" + #: extmod/ulab/code/ndarray.c msgid "cannot reshape array" msgstr "" @@ -3086,6 +3198,10 @@ msgstr "" msgid "destination buffer must be an array of type 'H' for bit_depth = 16" msgstr "" +#: shared-bindings/usb_audio/USBSpeaker.c +msgid "destination must be an array of type 'h'" +msgstr "" + #: py/objdict.c msgid "dict update sequence has wrong length" msgstr "" @@ -3106,7 +3222,7 @@ msgstr "" msgid "div/mod not implemented for uint" msgstr "" -#: extmod/ulab/code/numpy/create.c +#: extmod/ulab/code/numpy/create.c py/objint_longlong.c py/objint_mpz.c msgid "divide by zero" msgstr "" @@ -3205,10 +3321,6 @@ msgstr "" msgid "file write is not available" msgstr "" -#: shared-bindings/storage/__init__.c -msgid "filesystem must provide mount method" -msgstr "" - #: extmod/ulab/code/numpy/vector.c msgid "first argument must be a callable" msgstr "" @@ -3249,10 +3361,6 @@ msgstr "float이 너무 큽니다" msgid "float unsupported" msgstr "" -#: shared-bindings/_stage/Text.c -msgid "font must be 2048 bytes long" -msgstr "" - #: extmod/moddeflate.c msgid "format" msgstr "" @@ -3334,10 +3442,6 @@ msgstr "" msgid "generator raised StopIteration" msgstr "" -#: shared-bindings/_stage/Layer.c -msgid "graphic must be 2048 bytes long" -msgstr "" - #: extmod/modhashlib.c msgid "hash is final" msgstr "" @@ -3404,10 +3508,6 @@ msgstr "" msgid "initial values must be iterable" msgstr "" -#: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c -msgid "initial_value length is wrong" -msgstr "" - #: py/compile.c msgid "inline assembler must be a function" msgstr "" @@ -3498,6 +3598,10 @@ msgstr "" msgid "interval must be in range %s-%s" msgstr "" +#: py/emitinlinerv32.c +msgid "invalid RV32 instruction '%q'" +msgstr "" + #: py/compile.c msgid "invalid arch" msgstr "" @@ -3511,6 +3615,11 @@ msgstr "" msgid "invalid cert" msgstr "cert가 유효하지 않습니다" +#: shared-bindings/audioi2sin/I2SIn.c +#, c-format +msgid "invalid destination buffer, must be an array of type: %c" +msgstr "" + #: shared-bindings/bitmaptools/__init__.c #, c-format msgid "invalid element size %d for bits_per_pixel %d\n" @@ -3692,6 +3801,10 @@ msgstr "" msgid "mode must be complete, or reduced" msgstr "" +#: py/runtime.c +msgid "module '%q' has no attribute '%q'" +msgstr "" + #: py/builtinimport.c msgid "module not found" msgstr "" @@ -3740,10 +3853,6 @@ msgstr "" msgid "native code in .mpy unsupported" msgstr "" -#: py/asmthumb.c -msgid "native method too big" -msgstr "" - #: py/emitnative.c msgid "native yield" msgstr "" @@ -3765,7 +3874,7 @@ msgstr "" msgid "negative power with no float support" msgstr "" -#: py/objint_mpz.c py/runtime.c +#: py/objint_longlong.c py/objint_mpz.c py/runtime.c msgid "negative shift count" msgstr "" @@ -3842,6 +3951,10 @@ msgstr "" msgid "not supported for input types" msgstr "" +#: shared-bindings/i2cioexpander/IOExpander.c +msgid "num_pins must be 8 or 16" +msgstr "" + #: extmod/ulab/code/numpy/create.c msgid "number of points must be at least 2" msgstr "" @@ -3855,6 +3968,10 @@ msgstr "" msgid "object '%s' isn't a tuple or list" msgstr "" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "object does not support DigitalInOut protocol" +msgstr "" + #: py/obj.c msgid "object doesn't support item assignment" msgstr "" @@ -4046,7 +4163,7 @@ msgstr "" msgid "output array must be contiguous" msgstr "" -#: py/objint_mpz.c +#: py/objint_longlong.c py/objint_mpz.c msgid "overflow converting long int to machine word" msgstr "" @@ -4055,10 +4172,6 @@ msgstr "" 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" -msgstr "" - #: py/emitinlinerv32.c msgid "parameters must be registers in sequence a0 to a3" msgstr "" @@ -4116,6 +4229,10 @@ msgstr "" msgid "real and imaginary parts must be of equal length" msgstr "" +#: extmod/modre.c +msgid "regex too complex" +msgstr "" + #: py/builtinimport.c msgid "relative import" msgstr "" @@ -4125,6 +4242,10 @@ msgstr "" msgid "requested length %d but object has length %d" msgstr "" +#: py/objint_longlong.c py/parsenum.c +msgid "result overflows long long storage" +msgstr "" + #: extmod/ulab/code/ndarray_operators.c msgid "results cannot be cast to specified type" msgstr "" @@ -4389,10 +4510,6 @@ msgstr "" msgid "type takes 1 or 3 arguments" msgstr "" -#: py/objint_longlong.c -msgid "ulonglong too large" -msgstr "" - #: py/parse.c msgid "unexpected indent" msgstr "" @@ -4414,10 +4531,6 @@ msgstr "" msgid "unindent doesn't match any outer indent level" msgstr "" -#: py/emitinlinerv32.c -msgid "unknown RV32 instruction '%q'" -msgstr "" - #: py/objstr.c #, c-format msgid "unknown conversion specifier %c" @@ -4586,6 +4699,27 @@ msgstr "" msgid "zi must be of shape (n_section, 2)" msgstr "" +#~ 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 "잘못된 크기의 버퍼. 16 바이트 여야합니다." + +#, c-format +#~ msgid "Invalid byte %.*s" +#~ msgstr "잘못된 바이트 %.*s" + +#~ msgid "Key not found" +#~ msgstr "키를 찾을 수 없습니다" + +#, fuzzy +#~ msgid "Not supported JPEG standard" +#~ msgstr "지원되지 않는 JPEG 표준" + #, fuzzy #~ msgid "%q moved from %q to %q" #~ msgstr "%q가 %q에서 %q로 이동했습니다" diff --git a/locale/pl.po b/locale/pl.po index 9b20c513e7a..2e55f983e00 100644 --- a/locale/pl.po +++ b/locale/pl.po @@ -7,8 +7,8 @@ msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-01-04 12:55-0600\n" -"PO-Revision-Date: 2025-07-23 09:07+0000\n" -"Last-Translator: MuskoM \n" +"PO-Revision-Date: 2025-08-06 18:01+0000\n" +"Last-Translator: MAE \n" "Language-Team: pl\n" "Language: pl\n" "MIME-Version: 1.0\n" @@ -90,8 +90,8 @@ msgstr "%%c wymaga int lub char" msgid "" "%d address pins, %d rgb pins and %d tiles indicate a height of %d, not %d" msgstr "" -"%d pinów adresowalnych, %d pinów rgb oraz %d płytek wskazują na wysokość " -"%d, nie %d" +"%d pinów adresowalnych, %d pinów rgb oraz %d płytek wskazują na wysokość %d, " +"nie %d" #: shared-bindings/microcontroller/Pin.c msgid "%q and %q contain duplicate pins" @@ -204,7 +204,7 @@ msgstr "" #: py/argcheck.c msgid "%q must be >= %d" -msgstr "" +msgstr "%q musi być >= %d" #: shared-bindings/analogbufio/BufferedIn.c msgid "%q must be a bytearray or array of type 'H' or 'B'" diff --git a/locale/ru.po b/locale/ru.po index d3d94152304..a88c6cbbea3 100644 --- a/locale/ru.po +++ b/locale/ru.po @@ -93,6 +93,11 @@ msgstr "" "Адресные контакты %d, контакты rgb %d и плитки %d обозначают высоту %d, а не " "%d" +#: py/emitinlinextensa.c +#, c-format +msgid "%d is not a multiple of %d" +msgstr "" + #: shared-bindings/microcontroller/Pin.c msgid "%q and %q contain duplicate pins" msgstr "%q и %q содержат пины дупликаты" @@ -114,6 +119,7 @@ msgid "%q contains duplicate pins" msgstr "%q содержит пины дупликаты" #: ports/atmel-samd/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c msgid "%q failure: %d" msgstr "%q сбой: %d" @@ -126,6 +132,8 @@ msgid "%q in %q must be of type %q, not %q" msgstr "%q в %q должно быть типа %q, а не %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 @@ -133,7 +141,8 @@ msgstr "%q в %q должно быть типа %q, а не %q" #: 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 +#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/microcontroller/Pin.c +#: shared-module/max3421e/Max3421E.c msgid "%q in use" msgstr "%q используется" @@ -145,7 +154,10 @@ msgstr "Индекс %q вне диапазона" msgid "%q indices must be integers, not %s" msgstr "Индексы %q должны быть целыми числами, а не %s" -#: shared-module/bitbangio/SPI.c +#: 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 msgid "%q init failed" msgstr "Инициализация %q не удалась" @@ -177,8 +189,8 @@ msgstr "Длинна %q должна быть >= %d" msgid "%q must be %d" msgstr "%q должно быть %d" -#: py/argcheck.c shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/displayio/Bitmap.c +#: 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 @@ -189,6 +201,20 @@ msgstr "%q должно быть %d-%d" msgid "%q must be 1 when %q is True" msgstr "%q должен быть равен 1, если %q имеет значение True" +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "%q must be 16, 24, or 32" +msgstr "" + +#: 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/audiobusio/PDMIn.c +#: shared-bindings/audioi2sin/I2SIn.c +msgid "%q must be 8, 16, 24, or 32" +msgstr "" + #: py/argcheck.c shared-bindings/gifio/GifWriter.c #: shared-module/gifio/OnDiskGif.c msgid "%q must be <= %d" @@ -248,23 +274,29 @@ msgstr "%q должно быть типа %q, а не %q" msgid "%q must be power of 2" msgstr "%q должен быть во 2-й степени" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' attribute" +msgstr "" + +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' method" +msgstr "" + #: shared-bindings/wifi/Monitor.c msgid "%q out of bounds" msgstr "%q за пределом" +#: 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 +#: shared-bindings/bitmaptools/__init__.c shared-bindings/canio/Match.c +#: shared-bindings/time/__init__.c msgid "%q out of range" msgstr "%q вне диапазона" -#: py/objmodule.c -msgid "%q renamed %q" -msgstr "%q переименован %q" - #: py/objrange.c py/objslice.c shared-bindings/random/__init__.c msgid "%q step cannot be zero" msgstr "Шаг %q не может быть нулём" @@ -315,7 +347,7 @@ msgstr "%s ошибка 0x%x" msgid "'%q' argument required" msgstr "Требуется аргумент '%q'" -#: py/proto.c +#: py/proto.c shared-bindings/digitalio/DigitalInOutProtocol.c msgid "'%q' object does not support '%q'" msgstr "Объект '%q' не поддерживает '%q'" @@ -460,6 +492,7 @@ msgstr "*x должно быть целью назначения" msgid ", in %q\n" msgstr ", в %q\n" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c #: shared-bindings/busdisplay/BusDisplay.c #: shared-bindings/epaperdisplay/EPaperDisplay.c #: shared-bindings/framebufferio/FramebufferDisplay.c @@ -478,7 +511,7 @@ msgstr "Pow() с 3 аргументами не поддерживается" msgid "AP could not be started" msgstr "AP не может быть запущен" -#: shared-bindings/_bleio/Address.c shared-bindings/ipaddress/IPv4Address.c +#: shared-bindings/ipaddress/IPv4Address.c #, c-format msgid "Address must be %d bytes long" msgstr "Адрес должен быть длиной %d байт" @@ -513,7 +546,8 @@ msgstr "Все RX FIFO уже используются" msgid "All SPI peripherals are in use" msgstr "Все периферийные устройства SPI уже используются" -#: ports/espressif/common-hal/busio/UART.c ports/nordic/common-hal/busio/UART.c +#: 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 уже используются" @@ -584,7 +618,7 @@ msgstr "Уже запущен" msgid "Already scanning for wifi networks" msgstr "Поиск сетей wifi уже происходит" -#: shared-module/os/getenv.c +#: supervisor/shared/settings.c #, c-format msgid "An error occurred while retrieving '%s':\n" msgstr "Произошла ошибка при получении '%s':\n" @@ -611,6 +645,10 @@ msgstr "Значения массива должны быть однобайто msgid "Async SPI transfer in progress on this bus, keep awaiting." msgstr "" +#: shared-bindings/usb_audio/__init__.c +msgid "At least one of microphone and speaker must be enabled" +msgstr "" + #: shared-module/memorymonitor/AllocationAlarm.c #, c-format msgid "Attempt to allocate %d blocks" @@ -622,6 +660,7 @@ msgstr "Преобразование звука не реализовано" #: 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 "" @@ -649,12 +688,14 @@ msgstr "" msgid "Baudrate not supported by peripheral" 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/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 пинами" @@ -667,20 +708,17 @@ msgstr "" 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" +#: 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/_bleio/UUID.c -#, c-format -msgid "Buffer + offset too small %d %d %d" -msgstr "Буфер + сдвиг слишком малы %d %d %d" - #: ports/raspberrypi/bindings/rp2pio/StateMachine.c msgid "Buffer elements must be 4 bytes long or less" msgstr "Элементы буфера должны иметь длину не более 4 байт" @@ -723,10 +761,6 @@ msgstr "Слишком маленький буфер" msgid "Bus pin %d is already in use" msgstr "Вывод шины %d уже используется" -#: shared-bindings/_bleio/UUID.c -msgid "Byte buffer must be 16 bytes." -msgstr "Буфер байтов должен быть размером 16 байтам." - #: shared-bindings/aesio/aes.c msgid "CBC blocks must be multiples of 16 bytes" msgstr "Блоки CBC должны быть кратны 16 байтам" @@ -771,9 +805,9 @@ msgstr "" msgid "Can't set CCCD on local Characteristic" msgstr "Невозможно установить CCCD для локальной характеристики" -#: 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 +#: 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 устройство сейчас" @@ -781,6 +815,10 @@ msgstr "Невозможно изменить USB устройство сейч msgid "Cannot create a new Adapter; use _bleio.adapter;" msgstr "Невозможно создать новый Adapter; используйте _bleio.adapter;" +#: shared-module/i2cioexpander/IOExpander.c +msgid "Cannot deinitialize board IOExpander" +msgstr "" + #: shared-bindings/displayio/Bitmap.c #: shared-bindings/memorymonitor/AllocationSize.c #: shared-bindings/pulseio/PulseIn.c @@ -808,7 +846,7 @@ msgstr "" msgid "Cannot pull on input-only pin." msgstr "Невозможно вытащить контакт только для ввода." -#: shared-bindings/audiobusio/PDMIn.c +#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c msgid "Cannot record to a file" msgstr "Невозможно записать в файл" @@ -817,6 +855,7 @@ msgid "Cannot remount path when visible via USB." msgstr "" #: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c msgid "Cannot set value when direction is input." msgstr "Невозможно установить значение при вводе направления." @@ -870,6 +909,10 @@ msgstr "Координатные массивы имеют разные длин msgid "Coordinate arrays types have different sizes" 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/rclcpy/Publisher.c msgid "Could not publish to ROS topic" msgstr "" @@ -892,10 +935,12 @@ msgid "Critical ROS failure during soft reboot, reset required: %d" msgstr "" #: 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/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c msgid "DAC Device Init Error" msgstr "Ошибка инициализации устройства DAC" @@ -928,7 +973,7 @@ msgstr "" "Выводы глубокого сна должны использовать сигнал по возрастанию с подтяжкой к " "земле" -#: shared-bindings/audiobusio/PDMIn.c +#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c msgid "Destination capacity is smaller than destination_length." msgstr "Емкость места назначения меньше длины места назначения." @@ -948,6 +993,7 @@ msgstr "Дисплей должен иметь 16 битное цветовое #: 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 градусов" @@ -956,6 +1002,7 @@ msgid "Done" msgstr "Выполнено" #: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c msgid "Drive mode not used when direction is input." msgstr "Режим движения не используется при вводе направления." @@ -968,8 +1015,17 @@ msgstr "" msgid "ECB only operates on 16 bytes at a time" msgstr "ECB работает только с 16 байтами за раз" +#: py/asmxtensa.c +msgid "ERROR: %q %q not word-aligned" +msgstr "" + +#: py/asmxtensa.c +msgid "ERROR: xtensa %q out of range" +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" @@ -1018,7 +1074,7 @@ msgstr "" "Не удалось добавить служебную TXT-запись; в txt_records обнаружена нестрока " "или байт" -#: shared-module/rgbmatrix/RGBMatrix.c +#: ports/analog/common-hal/busio/UART.c shared-module/rgbmatrix/RGBMatrix.c msgid "Failed to allocate %q buffer" msgstr "Не удалось выделить буфер %q" @@ -1036,10 +1092,12 @@ 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/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c msgid "Failed to connect: timeout" msgstr "Не удалось подключиться: таймаут" @@ -1076,6 +1134,10 @@ msgstr "" msgid "Failed to release mutex, err 0x%04x" msgstr "Не удалось освободить mutex, ошибка 0x%04x" +#: ports/analog/common-hal/busio/SPI.c +msgid "Failed to set SPI Clock Mode" +msgstr "" + #: ports/zephyr-cp/common-hal/wifi/Radio.c msgid "Failed to set hostname" msgstr "" @@ -1093,7 +1155,6 @@ msgid "File exists" msgstr "Файл существует" #: shared-bindings/supervisor/__init__.c shared-module/lvfontio/OnDiskFont.c -#: shared-module/os/getenv.c msgid "File not found" msgstr "Файл не найден" @@ -1152,6 +1213,7 @@ msgstr "Инициализация GNSS" msgid "Generic Failure" msgstr "Общий сбой" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c #: shared-bindings/framebufferio/FramebufferDisplay.c #: shared-module/busdisplay/BusDisplay.c #: shared-module/framebufferio/FramebufferDisplay.c @@ -1254,7 +1316,8 @@ msgstr "Внутренний звуковой буфер слишком мал" msgid "Internal define error" msgstr "Внутренняя ошибка определения" -#: shared-bindings/pwmio/PWMOut.c shared-module/os/getenv.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-bindings/pwmio/PWMOut.c +#: supervisor/shared/settings.c msgid "Internal error" msgstr "Внутренняя ошибка" @@ -1288,22 +1351,29 @@ msgstr "Прерванная ошибка." 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/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/pwmio/PWMOut.c -#: shared-bindings/supervisor/__init__.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/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" @@ -1337,6 +1407,10 @@ msgstr "Неверный MAC-адрес" msgid "Invalid ROS domain ID" msgstr "" +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Invalid advertising data" +msgstr "" + #: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c msgid "Invalid argument" msgstr "Недопустимый аргумент" @@ -1345,17 +1419,12 @@ msgstr "Недопустимый аргумент" msgid "Invalid bits per value" msgstr "Недопустимое бит-на-значение" -#: shared-module/os/getenv.c -#, c-format -msgid "Invalid byte %.*s" -msgstr "Неверный байт %.*s" - #: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c #, c-format msgid "Invalid data_pins[%d]" msgstr "Неверный data_pins[%d]" -#: shared-module/msgpack/__init__.c +#: shared-module/msgpack/__init__.c supervisor/shared/settings.c msgid "Invalid format" msgstr "Недопустимый формат" @@ -1380,12 +1449,13 @@ msgstr "Неверный размер" msgid "Invalid socket for TLS" msgstr "Неверный сокет для TLS" +#: 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/os/getenv.c +#: supervisor/shared/settings.c msgid "Invalid unicode escape" msgstr "Недопустимое экранирование Юникода" @@ -1393,10 +1463,6 @@ msgstr "Недопустимое экранирование Юникода" msgid "Key must be 16, 24, or 32 bytes long" msgstr "Ключ должен быть длинной 16, 24 или 32 байта" -#: shared-module/os/getenv.c -msgid "Key not found" -msgstr "Ключ не найден" - #: shared-module/is31fl3741/FrameBuffer.c msgid "LED mappings must match display size" msgstr "Светодиодные сопоставления должны соответствовать размеру дисплея" @@ -1435,6 +1501,18 @@ msgstr "" msgid "Mapping must be a tuple" msgstr "Сопоставление должно быть кортежом" +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap must have 8 bits per pixel" +msgstr "" + +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap size must match the other bitmaps" +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" @@ -1476,8 +1554,7 @@ msgstr "Не хватает jmp_pin.%q [%u] прыгает на пин" msgid "Mount point directory missing" msgstr "Отсутствует каталог точки монтирования" -#: ports/zephyr-cp/bindings/zephyr_serial/UART.c shared-bindings/busio/UART.c -#: shared-bindings/displayio/Group.c +#: shared-bindings/busio/UART.c shared-bindings/displayio/Group.c msgid "Must be a %q subclass." msgstr "Должен быть субклассом %q." @@ -1526,7 +1603,7 @@ msgstr "Изображение памяти" #: 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 +#: shared-bindings/qspibus/QSPIBus.c shared-module/bitbangio/SPI.c msgid "No %q pin" msgstr "Нет пина %q" @@ -1537,6 +1614,7 @@ msgstr "Для этой характеристики нет CCCD" #: 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 отсутствует на чипе" @@ -1544,6 +1622,7 @@ msgstr "DAC отсутствует на чипе" #: 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 не найден" @@ -1658,14 +1737,11 @@ msgid "Not connected" msgstr "Не подключено" #: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c -#: shared-bindings/audiopwmio/PWMAudioOut.c +#: shared-bindings/audiopwmio/PWMAudioOut.c shared-bindings/mcp4822/MCP4822.c +#: shared-bindings/usb_audio/USBMicrophone.c msgid "Not playing" msgstr "Не воспроизводится (Not playing)" -#: shared-module/jpegio/JpegDecoder.c -msgid "Not supported JPEG standard" -msgstr "Не поддерживается Стандарт JPEG" - #: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c #: ports/espressif/common-hal/sdioio/SDCard.c #, c-format @@ -1763,6 +1839,7 @@ msgid "Operation or feature not supported" msgstr "Операция или функция, не поддерживаемые" #: ports/espressif/common-hal/espidf/__init__.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c msgid "Operation timed out" msgstr "Истекло время ожидания операции" @@ -1805,6 +1882,7 @@ msgid "Parameter error" msgstr "Ошибка параметра" #: ports/espressif/common-hal/audiobusio/__init__.c +#: ports/espressif/common-hal/audioi2sin/I2SIn.c msgid "Peripheral in use" msgstr "Периферийные устройства в использовании" @@ -1908,6 +1986,7 @@ msgid "Publishers can only be created from a parent node" msgstr "" #: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c msgid "Pull not used when direction is output." msgstr "Тяга не используется, когда выводится направление." @@ -1947,6 +2026,7 @@ msgstr "" msgid "ROS topic failed to initialize" 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" @@ -2039,6 +2119,10 @@ msgstr "Сбой конфигурации SPI" msgid "SPI init error" msgstr "Ошибка инициализации SPI" +#: ports/analog/common-hal/busio/SPI.c +msgid "SPI needs MOSI, MISO, and SCK" +msgstr "" + #: ports/raspberrypi/common-hal/busio/SPI.c msgid "SPI peripheral in use" msgstr "Используемое периферийное устройство SPI" @@ -2084,10 +2168,13 @@ 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" +#: ports/zephyr-cp/common-hal/socketpool/SocketPool.c +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 "Исходный и конечный буферы должны иметь одинаковую длину" @@ -2127,7 +2214,7 @@ msgstr "" msgid "The length of rgb_pins must be 6, 12, 18, 24, or 30" msgstr "Длина rgb_pins должна быть 6, 12, 18, 24 или 30" -#: shared-module/audiocore/__init__.c +#: shared-module/audiocore/__init__.c shared-module/usb_audio/USBMicrophone.c msgid "The sample's %q does not match" msgstr "%q образца не совпадает" @@ -2175,11 +2262,16 @@ msgstr "Время в прошлом." msgid "Timeout is too long: Maximum timeout length is %d seconds" msgstr "Таймаут слишком длинный: максимальная длина таймаута %d секунд" +#: ports/analog/common-hal/busio/UART.c +msgid "Timeout must be < 100 seconds" +msgstr "" + #: ports/atmel-samd/common-hal/audiobusio/I2SOut.c msgid "Too many channels in sample" msgstr "Слишком много каналов в выборке" #: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c msgid "Too many channels in sample." msgstr "Слишком много каналов в выборке." @@ -2218,6 +2310,10 @@ msgstr "Деинициализация UART" msgid "UART init" msgstr "Инициализация UART" +#: ports/analog/common-hal/busio/UART.c +msgid "UART needs TX & RX" +msgstr "" + #: ports/raspberrypi/common-hal/busio/UART.c msgid "UART peripheral in use" msgstr "Используемое периферийное устройство UART" @@ -2226,6 +2322,14 @@ msgstr "Используемое периферийное устройство U msgid "UART re-init" msgstr "Повторная инициализация UART" +#: 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/stm/common-hal/busio/UART.c msgid "UART write" msgstr "Запись UART" @@ -2250,10 +2354,6 @@ msgstr "USB-устройства указывают слишком много и msgid "USB error" msgstr "Ошибка USB" -#: shared-bindings/_bleio/UUID.c -msgid "UUID integer value must be 0-0xffff" -msgstr "Целое значение UUID должно быть равно 0-0xffff" - #: shared-bindings/_bleio/UUID.c msgid "UUID string not 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'" msgstr "UUID строка не 'xxxxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxxxxxxxxxx \"" @@ -2270,6 +2370,7 @@ msgstr "Невозможно получить доступ к невыровне #: 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 "Не удается выделить буферы для подписанного преобразования" @@ -2278,6 +2379,7 @@ msgid "Unable to allocate to the heap." msgstr "Невозможно выделить место в куче." #: ports/espressif/common-hal/busio/I2C.c +#: ports/espressif/common-hal/busio/SPI.c msgid "Unable to create lock" msgstr "Не удается создать блокировку" @@ -2386,6 +2488,10 @@ msgstr "" "Неуказанная проблема. Возможно, запрос на сопряжение на другом устройстве " "был отклонен или проигнорирован." +#: shared-module/jpegio/JpegDecoder.c +msgid "Unsupported JPEG (may be progressive)" +msgstr "" + #: shared-bindings/bitmaptools/__init__.c msgid "Unsupported colorspace" msgstr "Неподдерживаемое цветовое пространство" @@ -2408,6 +2514,13 @@ msgstr "Неподдерживаемый тип сокета" msgid "Update failed" 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/_bleio/Characteristic.c #: ports/nordic/common-hal/_bleio/Characteristic.c #: ports/nordic/common-hal/_bleio/Descriptor.c @@ -2554,6 +2667,10 @@ msgstr "__new__ arg должен быть пользовательского т msgid "a bytes-like object is required" msgstr "Требуется байтоподобный объект" +#: shared-bindings/i2cioexpander/IOExpander.c +msgid "address out of range" +msgstr "" + #: shared-bindings/i2ctarget/I2CTarget.c msgid "addresses is empty" msgstr "адреса пусты" @@ -2620,10 +2737,6 @@ msgstr "массив слишком велик" msgid "array/bytes required on right side" msgstr "массив/байты, необходимые справа" -#: py/asmxtensa.c -msgid "asm overflow" -msgstr "Переполнение ASM" - #: py/compile.c msgid "async for/with outside async function" msgstr "async для/вместе с внешней async-функцией" @@ -2684,10 +2797,6 @@ msgstr "Неверный шрифт" 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." - #: shared-module/bitmapfilter/__init__.c msgid "bitmap size and depth must match" msgstr "Размер и глубина растрового изображения должны совпадать" @@ -2842,6 +2951,10 @@ msgstr "не может превратиться в полосу неявно" msgid "can't create '%q' instances" msgstr "" +#: py/objtype.c +msgid "can't create instance" +msgstr "" + #: py/compile.c msgid "can't declare nonlocal in outer code" msgstr "не может объявить нелокальный во внешнем коде" @@ -2944,14 +3057,14 @@ msgstr "не может превратить комплекс в dtype" msgid "cannot convert complex type" msgstr "Не удается преобразовать сложный тип" -#: py/objtype.c -msgid "cannot create instance" -msgstr "Не удается создать экземпляр" - #: extmod/ulab/code/ndarray.c msgid "cannot delete array elements" msgstr "Не удается удалить элементы массива" +#: py/compile.c +msgid "cannot emit native code for this architecture" +msgstr "" + #: extmod/ulab/code/ndarray.c msgid "cannot reshape array" msgstr "Не удается изменить форму массива" @@ -3092,6 +3205,10 @@ msgid "destination buffer must be an array of type 'H' for bit_depth = 16" msgstr "" "буфер назначения должен быть массивом типа «H» для битовой_глубины = 16" +#: shared-bindings/usb_audio/USBSpeaker.c +msgid "destination must be an array of type 'h'" +msgstr "" + #: py/objdict.c msgid "dict update sequence has wrong length" msgstr "последовательность обновления дикта имеет неправильную длину" @@ -3112,7 +3229,7 @@ msgstr "Размеры не совпадают" msgid "div/mod not implemented for uint" msgstr "div/mod не реализован для uint" -#: extmod/ulab/code/numpy/create.c +#: extmod/ulab/code/numpy/create.c py/objint_longlong.c py/objint_mpz.c msgid "divide by zero" msgstr "Делим на ноль" @@ -3211,10 +3328,6 @@ msgstr "Файл должен быть файлом, открытым в бай msgid "file write is not available" msgstr "Запись файлов недоступна" -#: shared-bindings/storage/__init__.c -msgid "filesystem must provide mount method" -msgstr "Файловая система должна предусматривать метод монтирования" - #: extmod/ulab/code/numpy/vector.c msgid "first argument must be a callable" msgstr "Первый аргумент должен быть вызываемым" @@ -3255,10 +3368,6 @@ msgstr "Поплавок слишком большой" msgid "float unsupported" msgstr "Плавающий без поддержки" -#: shared-bindings/_stage/Text.c -msgid "font must be 2048 bytes long" -msgstr "Длина шрифта должна составлять 2048 байт" - #: extmod/moddeflate.c msgid "format" msgstr "формат" @@ -3340,10 +3449,6 @@ msgstr "генератор проигнорировал Выход" msgid "generator raised StopIteration" msgstr "генератор поднят Остановить итерацию" -#: shared-bindings/_stage/Layer.c -msgid "graphic must be 2048 bytes long" -msgstr "Длина рисунка должна составлять 2048 байт" - #: extmod/modhashlib.c msgid "hash is final" msgstr "хэш является окончательным" @@ -3410,10 +3515,6 @@ msgstr "индексы должны быть целыми числами, сре msgid "initial values must be iterable" msgstr "Начальные значения должны быть итерируемыми" -#: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c -msgid "initial_value length is wrong" -msgstr "длина первоначального_значения ошибочна" - #: py/compile.c msgid "inline assembler must be a function" msgstr "Встроенный ассемблер должен быть функцией" @@ -3504,6 +3605,10 @@ msgstr "interp определен для 1D-итераций одинаково msgid "interval must be in range %s-%s" msgstr "Интервал должен находиться в диапазоне %s-%s" +#: py/emitinlinerv32.c +msgid "invalid RV32 instruction '%q'" +msgstr "" + #: py/compile.c msgid "invalid arch" msgstr "недействительная арка" @@ -3517,6 +3622,11 @@ msgstr "неверный бит_на_пиксель %d, должно быть 1, msgid "invalid cert" msgstr "Неверный сертификат" +#: shared-bindings/audioi2sin/I2SIn.c +#, c-format +msgid "invalid destination buffer, must be an array of type: %c" +msgstr "" + #: shared-bindings/bitmaptools/__init__.c #, c-format msgid "invalid element size %d for bits_per_pixel %d\n" @@ -3704,6 +3814,10 @@ msgstr "mktime нужен кортеж длины 8 или 9" msgid "mode must be complete, or reduced" msgstr "Режим должен быть завершенным или уменьшенным" +#: py/runtime.c +msgid "module '%q' has no attribute '%q'" +msgstr "" + #: py/builtinimport.c msgid "module not found" msgstr "модуль не найден" @@ -3752,10 +3866,6 @@ msgstr "слишком длинное имя" msgid "native code in .mpy unsupported" msgstr "Нативный код в .mpy не поддерживается" -#: py/asmthumb.c -msgid "native method too big" -msgstr "родной метод слишком большой" - #: py/emitnative.c msgid "native yield" msgstr "родной урожай" @@ -3777,7 +3887,7 @@ msgstr "отрицательный факториал" msgid "negative power with no float support" msgstr "Отрицательная мощность без поплавковой опоры" -#: py/objint_mpz.c py/runtime.c +#: py/objint_longlong.c py/objint_mpz.c py/runtime.c msgid "negative shift count" msgstr "Количество отрицательных сдвигов" @@ -3856,6 +3966,10 @@ msgstr "не реализовано для сложного типа d" msgid "not supported for input types" msgstr "Не поддерживается для типов ввода" +#: shared-bindings/i2cioexpander/IOExpander.c +msgid "num_pins must be 8 or 16" +msgstr "" + #: extmod/ulab/code/numpy/create.c msgid "number of points must be at least 2" msgstr "Количество баллов должно быть не менее 2" @@ -3869,6 +3983,10 @@ msgstr "объект " msgid "object '%s' isn't a tuple or list" msgstr "Объект \"%s\" не является кортежом или списком" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "object does not support DigitalInOut protocol" +msgstr "" + #: py/obj.c msgid "object doesn't support item assignment" msgstr "Объект не поддерживает назначение элементов" @@ -4060,7 +4178,7 @@ msgstr "Выходной массив имеет неправильный тип msgid "output array must be contiguous" msgstr "выходной массив должен быть непрерывным" -#: py/objint_mpz.c +#: py/objint_longlong.c py/objint_mpz.c msgid "overflow converting long int to machine word" msgstr "переполнение преобразование длинного целого в машинное слово" @@ -4069,10 +4187,6 @@ msgstr "переполнение преобразование длинного msgid "pack expected %d items for packing (got %d)" msgstr "Упаковка ожидаемых %d товаров для упаковки (получил %d)" -#: shared-bindings/_stage/Layer.c shared-bindings/_stage/Text.c -msgid "palette must be 32 bytes long" -msgstr "Длина палитры должна составлять 32 байта" - #: py/emitinlinerv32.c msgid "parameters must be registers in sequence a0 to a3" msgstr "" @@ -4130,6 +4244,10 @@ msgstr "Маски вытягивания конфликтуют с маскам msgid "real and imaginary parts must be of equal length" msgstr "реальные и воображаемые части должны быть одинаковой длины" +#: extmod/modre.c +msgid "regex too complex" +msgstr "" + #: py/builtinimport.c msgid "relative import" msgstr "Относительный импорт" @@ -4139,6 +4257,10 @@ msgstr "Относительный импорт" msgid "requested length %d but object has length %d" msgstr "запрашиваемая длина %d, но объект имеет длину %d" +#: py/objint_longlong.c py/parsenum.c +msgid "result overflows long long storage" +msgstr "" + #: extmod/ulab/code/ndarray_operators.c msgid "results cannot be cast to specified type" msgstr "Результаты не могут быть приведены к указанному типу" @@ -4405,10 +4527,6 @@ msgstr "тип объекта '%q' не имеет атрибута '%q \"" msgid "type takes 1 or 3 arguments" msgstr "тип занимает 1 или 3 аргумента" -#: py/objint_longlong.c -msgid "ulonglong too large" -msgstr "голова длинная слишком большая" - #: py/parse.c msgid "unexpected indent" msgstr "Неожиданный отступ" @@ -4430,10 +4548,6 @@ msgstr "Экранирование имен в Юникоде" msgid "unindent doesn't match any outer indent level" msgstr "Отступ не совпадает ни с одним уровнем внешнего отступа" -#: py/emitinlinerv32.c -msgid "unknown RV32 instruction '%q'" -msgstr "" - #: py/objstr.c #, c-format msgid "unknown conversion specifier %c" @@ -4604,9 +4718,62 @@ msgstr "zi должно быть типа float" msgid "zi must be of shape (n_section, 2)" msgstr "zi должен иметь форму (n_section, 2)" +#~ msgid "bit_depth must be 8, 16, 24, or 32." +#~ msgstr "Глубина_бита должна быть равна 8, 16, 24 или 32." + +#~ msgid "%q renamed %q" +#~ msgstr "%q переименован %q" + +#~ msgid "asm overflow" +#~ msgstr "Переполнение ASM" + +#~ msgid "cannot create instance" +#~ msgstr "Не удается создать экземпляр" + +#~ msgid "native method too big" +#~ msgstr "родной метод слишком большой" + +#~ msgid "ulonglong too large" +#~ msgstr "голова длинная слишком большая" + +#~ msgid "font must be 2048 bytes long" +#~ msgstr "Длина шрифта должна составлять 2048 байт" + +#~ msgid "graphic must be 2048 bytes long" +#~ msgstr "Длина рисунка должна составлять 2048 байт" + +#~ msgid "palette must be 32 bytes long" +#~ msgstr "Длина палитры должна составлять 32 байта" + +#, c-format +#~ msgid "Buffer + offset too small %d %d %d" +#~ msgstr "Буфер + сдвиг слишком малы %d %d %d" + +#~ msgid "Byte buffer must be 16 bytes." +#~ msgstr "Буфер байтов должен быть размером 16 байтам." + +#~ msgid "UUID integer value must be 0-0xffff" +#~ msgstr "Целое значение UUID должно быть равно 0-0xffff" + +#~ msgid "initial_value length is wrong" +#~ msgstr "длина первоначального_значения ошибочна" + +#, c-format +#~ msgid "Invalid byte %.*s" +#~ msgstr "Неверный байт %.*s" + +#~ msgid "Key not found" +#~ msgstr "Ключ не найден" + +#~ msgid "Not supported JPEG standard" +#~ msgstr "Не поддерживается Стандарт JPEG" + #~ msgid "%q moved from %q to %q" #~ msgstr "%q переместился из %q в %q" +#~ msgid "filesystem must provide mount method" +#~ msgstr "Файловая система должна предусматривать метод монтирования" + #~ msgid "start/end indices" #~ msgstr "Начальные/конечные индексы" @@ -5106,8 +5273,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 10a288553a6..2ff8c837768 100644 --- a/locale/tr.po +++ b/locale/tr.po @@ -91,6 +91,11 @@ msgstr "" "%d adres pinleri, %d RGB pinleri ve %d döşemeleri %d'nin yüksekliği " "gösterir, %d'nin değil" +#: py/emitinlinextensa.c +#, c-format +msgid "%d is not a multiple of %d" +msgstr "" + #: shared-bindings/microcontroller/Pin.c msgid "%q and %q contain duplicate pins" msgstr "%q ve %q yinelenen pinler içeriyor" @@ -112,6 +117,7 @@ msgid "%q contains duplicate pins" msgstr "%q yinelenen pinler içeriyor" #: ports/atmel-samd/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c msgid "%q failure: %d" msgstr "%q hata: %d" @@ -124,6 +130,8 @@ msgid "%q in %q must be of type %q, not %q" 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 @@ -131,7 +139,8 @@ msgstr "" #: 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 +#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/microcontroller/Pin.c +#: shared-module/max3421e/Max3421E.c msgid "%q in use" msgstr "%q kullanımda" @@ -143,7 +152,10 @@ msgstr "%q indeksi aralık dışında" msgid "%q indices must be integers, not %s" msgstr "%q indeksleri integer olmalı, %s değil" -#: shared-module/bitbangio/SPI.c +#: 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 msgid "%q init failed" msgstr "%q init başarısız oldu" @@ -175,8 +187,8 @@ msgstr "%q boyutu >= %d olmalıdır" msgid "%q must be %d" msgstr "%q, %d olmalıdır" -#: py/argcheck.c shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/displayio/Bitmap.c +#: 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 @@ -187,6 +199,20 @@ msgstr "%q, %d-%d olmalıdır" msgid "%q must be 1 when %q is True" msgstr "%q 1 olmalı, %q True olduğu zaman" +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "%q must be 16, 24, or 32" +msgstr "" + +#: 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/audiobusio/PDMIn.c +#: shared-bindings/audioi2sin/I2SIn.c +msgid "%q must be 8, 16, 24, or 32" +msgstr "" + #: py/argcheck.c shared-bindings/gifio/GifWriter.c #: shared-module/gifio/OnDiskGif.c msgid "%q must be <= %d" @@ -246,23 +272,29 @@ msgstr "" msgid "%q must be power of 2" msgstr "%q, 2'nin kuvveti olmalıdır" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' attribute" +msgstr "" + +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' method" +msgstr "" + #: shared-bindings/wifi/Monitor.c msgid "%q out of bounds" msgstr "%q sınırların dışında" +#: 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 +#: 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" -#: py/objmodule.c -msgid "%q renamed %q" -msgstr "" - #: py/objrange.c py/objslice.c shared-bindings/random/__init__.c msgid "%q step cannot be zero" msgstr "%q sıfır olamaz" @@ -313,7 +345,7 @@ msgstr "%s hatası 0x%x" msgid "'%q' argument required" msgstr "'%q' argümanı gerekli" -#: py/proto.c +#: py/proto.c shared-bindings/digitalio/DigitalInOutProtocol.c msgid "'%q' object does not support '%q'" msgstr "'%q' nesnesi '%q' öğesini desteklemiyor" @@ -458,6 +490,7 @@ msgstr "*x atama hedefi olmalıdır" msgid ", in %q\n" msgstr ", içinde %q\n" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c #: shared-bindings/busdisplay/BusDisplay.c #: shared-bindings/epaperdisplay/EPaperDisplay.c #: shared-bindings/framebufferio/FramebufferDisplay.c @@ -476,7 +509,7 @@ msgstr "3-argümanlı pow() desteklenmemektedir" msgid "AP could not be started" msgstr "" -#: shared-bindings/_bleio/Address.c shared-bindings/ipaddress/IPv4Address.c +#: shared-bindings/ipaddress/IPv4Address.c #, c-format msgid "Address must be %d bytes long" msgstr "Adres %d byte uzunluğunda olmalıdır" @@ -511,7 +544,8 @@ msgstr "Tüm RX FIFO'ları kullanımda" msgid "All SPI peripherals are in use" msgstr "Tüm SPI çevre birimleri kullanımda" -#: ports/espressif/common-hal/busio/UART.c ports/nordic/common-hal/busio/UART.c +#: 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" @@ -582,7 +616,7 @@ msgstr "Halihazırda çalışıyor" msgid "Already scanning for wifi networks" msgstr "Halihazırda wifi ağları için tarama yapılıyor" -#: shared-module/os/getenv.c +#: supervisor/shared/settings.c #, c-format msgid "An error occurred while retrieving '%s':\n" msgstr "" @@ -609,6 +643,10 @@ msgstr "Dizi değerleri tekil bytelar olmalıdır." msgid "Async SPI transfer in progress on this bus, keep awaiting." msgstr "" +#: shared-bindings/usb_audio/__init__.c +msgid "At least one of microphone and speaker must be enabled" +msgstr "" + #: shared-module/memorymonitor/AllocationAlarm.c #, c-format msgid "Attempt to allocate %d blocks" @@ -620,6 +658,7 @@ msgstr "Ses dönüşümü implemente edilmedi" #: 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 "" @@ -647,12 +686,14 @@ msgstr "" msgid "Baudrate not supported by peripheral" msgstr "Baudhızı, çevre birimi tarafından desteklenmiyor" +#: 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" #: 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 "" @@ -664,20 +705,17 @@ msgstr "Bitmap boyutu ve bit başına değer uyuşmalı" msgid "Boot device must be first (interface #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" msgstr "Hem RX hem de TX akış kontrolü için gerekli" +#: 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" -#: shared-bindings/_bleio/UUID.c -#, c-format -msgid "Buffer + offset too small %d %d %d" -msgstr "Buffer + offset çok küçük %d %d %d" - #: ports/raspberrypi/bindings/rp2pio/StateMachine.c msgid "Buffer elements must be 4 bytes long or less" msgstr "Buffer elementleri 4 bit olmak zorunda" @@ -720,10 +758,6 @@ msgstr "" msgid "Bus pin %d is already in use" msgstr "Veriyolu pini %d kullanımda" -#: shared-bindings/_bleio/UUID.c -msgid "Byte buffer must be 16 bytes." -msgstr "Bit buffer'ı 16bit olmalı." - #: shared-bindings/aesio/aes.c msgid "CBC blocks must be multiples of 16 bytes" msgstr "CBC blokları 16 baytın katları şeklinde olmalı" @@ -765,9 +799,9 @@ msgstr "" msgid "Can't set CCCD on local Characteristic" 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 +#: 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" @@ -775,6 +809,10 @@ msgstr "USB aygıtları şu an değiştirilemez" msgid "Cannot create a new Adapter; use _bleio.adapter;" msgstr "yeni Adaptör oluşturulamadı; _bleio.adapter kullanın;" +#: shared-module/i2cioexpander/IOExpander.c +msgid "Cannot deinitialize board IOExpander" +msgstr "" + #: shared-bindings/displayio/Bitmap.c #: shared-bindings/memorymonitor/AllocationSize.c #: shared-bindings/pulseio/PulseIn.c @@ -801,7 +839,7 @@ msgstr "Genişletilmiş, bağlanabilir reklamlar için tarama yanıtları yapıl msgid "Cannot pull on input-only pin." msgstr "" -#: shared-bindings/audiobusio/PDMIn.c +#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c msgid "Cannot record to a file" msgstr "Dosyaya kayıt yapılamıyor" @@ -810,6 +848,7 @@ msgid "Cannot remount path when visible via USB." msgstr "" #: 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." @@ -860,6 +899,10 @@ msgstr "" msgid "Coordinate arrays types have different sizes" 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/rclcpy/Publisher.c msgid "Could not publish to ROS topic" msgstr "" @@ -882,10 +925,12 @@ msgid "Critical ROS failure during soft reboot, reset required: %d" msgstr "" #: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c msgid "DAC Channel Init Error" msgstr "" #: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c msgid "DAC Device Init Error" msgstr "" @@ -916,7 +961,7 @@ msgstr "" msgid "Deep sleep pins must use a rising edge with pulldown" msgstr "" -#: shared-bindings/audiobusio/PDMIn.c +#: 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." @@ -936,6 +981,7 @@ msgstr "Ekran 16 bitlik bir renk uzayına sahip olmalıdır." #: 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" @@ -944,6 +990,7 @@ msgid "Done" msgstr "Tamamlandı" #: 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." @@ -955,8 +1002,17 @@ msgstr "Yukarıdaki hatanın işlenmesi sırasında başka bir hata oluştu:" msgid "ECB only operates on 16 bytes at a time" msgstr "ECB aynı anda yalnızca 16 baytla çalışır" +#: py/asmxtensa.c +msgid "ERROR: %q %q not word-aligned" +msgstr "" + +#: py/asmxtensa.c +msgid "ERROR: xtensa %q out of range" +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 "" @@ -1003,7 +1059,7 @@ msgid "" "Failed to add service TXT record; non-string or bytes found in txt_records" msgstr "" -#: shared-module/rgbmatrix/RGBMatrix.c +#: ports/analog/common-hal/busio/UART.c shared-module/rgbmatrix/RGBMatrix.c msgid "Failed to allocate %q buffer" msgstr "" @@ -1021,10 +1077,12 @@ 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 "Bağlantı kurulamadı: internal error" #: 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" @@ -1061,6 +1119,10 @@ msgstr "" 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/zephyr-cp/common-hal/wifi/Radio.c msgid "Failed to set hostname" msgstr "" @@ -1078,7 +1140,6 @@ msgid "File exists" msgstr "Dosya var" #: shared-bindings/supervisor/__init__.c shared-module/lvfontio/OnDiskFont.c -#: shared-module/os/getenv.c msgid "File not found" msgstr "" @@ -1135,6 +1196,7 @@ msgstr "GNSS init" msgid "Generic Failure" msgstr "" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c #: shared-bindings/framebufferio/FramebufferDisplay.c #: shared-module/busdisplay/BusDisplay.c #: shared-module/framebufferio/FramebufferDisplay.c @@ -1233,7 +1295,8 @@ msgstr "Dahili ses arabelleği çok küçük" msgid "Internal define error" msgstr "Dahili tanımlama hatası" -#: shared-bindings/pwmio/PWMOut.c shared-module/os/getenv.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-bindings/pwmio/PWMOut.c +#: supervisor/shared/settings.c msgid "Internal error" msgstr "Dahili hata" @@ -1267,22 +1330,29 @@ msgstr "" 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/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/pwmio/PWMOut.c -#: shared-bindings/supervisor/__init__.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 "Geçersiz %q" +#: 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" @@ -1316,6 +1386,10 @@ msgstr "Geçersiz MAC adresi" msgid "Invalid ROS domain ID" msgstr "" +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Invalid advertising data" +msgstr "" + #: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c msgid "Invalid argument" msgstr "Geçersiz argüman" @@ -1325,17 +1399,12 @@ msgstr "Geçersiz argüman" msgid "Invalid bits per value" msgstr "Geçersiz bit başına değer" -#: shared-module/os/getenv.c -#, c-format -msgid "Invalid byte %.*s" -msgstr "" - #: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c #, c-format msgid "Invalid data_pins[%d]" msgstr "Geçersiz veri_pini [%d]" -#: shared-module/msgpack/__init__.c +#: shared-module/msgpack/__init__.c supervisor/shared/settings.c msgid "Invalid format" msgstr "" @@ -1360,12 +1429,13 @@ msgstr "Geçersiz boyut" msgid "Invalid socket for TLS" msgstr "TLS için geçersiz soket" +#: 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/os/getenv.c +#: supervisor/shared/settings.c msgid "Invalid unicode escape" msgstr "" @@ -1373,10 +1443,6 @@ msgstr "" msgid "Key must be 16, 24, or 32 bytes long" msgstr "Anahtar 16, 24 veya 32 bayt uzunluğunda olmalıdır" -#: shared-module/os/getenv.c -msgid "Key not found" -msgstr "" - #: shared-module/is31fl3741/FrameBuffer.c msgid "LED mappings must match display size" msgstr "LED eşlemeleri ekran boyutuyla eşleşmelidir" @@ -1415,6 +1481,18 @@ msgstr "" msgid "Mapping must be a tuple" msgstr "Map tuple olmalıdır" +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap must have 8 bits per pixel" +msgstr "" + +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap size must match the other bitmaps" +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" @@ -1456,8 +1534,7 @@ msgstr "" msgid "Mount point directory missing" msgstr "" -#: ports/zephyr-cp/bindings/zephyr_serial/UART.c shared-bindings/busio/UART.c -#: shared-bindings/displayio/Group.c +#: shared-bindings/busio/UART.c shared-bindings/displayio/Group.c msgid "Must be a %q subclass." msgstr "" @@ -1504,7 +1581,7 @@ msgstr "" #: 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 +#: shared-bindings/qspibus/QSPIBus.c shared-module/bitbangio/SPI.c msgid "No %q pin" msgstr "%q pini yok" @@ -1515,6 +1592,7 @@ 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 "" @@ -1522,6 +1600,7 @@ msgstr "" #: 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 "" @@ -1636,14 +1715,11 @@ msgid "Not connected" msgstr "" #: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c -#: shared-bindings/audiopwmio/PWMAudioOut.c +#: shared-bindings/audiopwmio/PWMAudioOut.c shared-bindings/mcp4822/MCP4822.c +#: shared-bindings/usb_audio/USBMicrophone.c msgid "Not playing" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Not supported JPEG standard" -msgstr "" - #: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c #: ports/espressif/common-hal/sdioio/SDCard.c #, c-format @@ -1737,6 +1813,7 @@ msgid "Operation or feature not supported" msgstr "" #: ports/espressif/common-hal/espidf/__init__.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c msgid "Operation timed out" msgstr "" @@ -1779,6 +1856,7 @@ msgid "Parameter error" msgstr "" #: ports/espressif/common-hal/audiobusio/__init__.c +#: ports/espressif/common-hal/audioi2sin/I2SIn.c msgid "Peripheral in use" msgstr "" @@ -1879,6 +1957,7 @@ msgid "Publishers can only be created from a parent node" msgstr "" #: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c msgid "Pull not used when direction is output." msgstr "" @@ -1918,6 +1997,7 @@ msgstr "" msgid "ROS topic failed to initialize" 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" @@ -2010,6 +2090,10 @@ msgstr "" msgid "SPI init error" msgstr "" +#: ports/analog/common-hal/busio/SPI.c +msgid "SPI needs MOSI, MISO, and SCK" +msgstr "" + #: ports/raspberrypi/common-hal/busio/SPI.c msgid "SPI peripheral in use" msgstr "" @@ -2055,10 +2139,13 @@ 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/zephyr-cp/common-hal/socketpool/SocketPool.c +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 "" @@ -2095,7 +2182,7 @@ msgstr "" msgid "The length of rgb_pins must be 6, 12, 18, 24, or 30" msgstr "" -#: shared-module/audiocore/__init__.c +#: shared-module/audiocore/__init__.c shared-module/usb_audio/USBMicrophone.c msgid "The sample's %q does not match" msgstr "" @@ -2141,11 +2228,16 @@ msgstr "" msgid "Timeout is too long: Maximum timeout length is %d seconds" msgstr "" +#: ports/analog/common-hal/busio/UART.c +msgid "Timeout must be < 100 seconds" +msgstr "" + #: ports/atmel-samd/common-hal/audiobusio/I2SOut.c msgid "Too many channels in sample" msgstr "" #: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c msgid "Too many channels in sample." msgstr "" @@ -2184,6 +2276,10 @@ msgstr "" msgid "UART init" msgstr "" +#: ports/analog/common-hal/busio/UART.c +msgid "UART needs TX & RX" +msgstr "" + #: ports/raspberrypi/common-hal/busio/UART.c msgid "UART peripheral in use" msgstr "" @@ -2192,6 +2288,14 @@ msgstr "" msgid "UART re-init" 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/stm/common-hal/busio/UART.c msgid "UART write" msgstr "" @@ -2216,10 +2320,6 @@ msgstr "" msgid "USB error" msgstr "" -#: shared-bindings/_bleio/UUID.c -msgid "UUID integer value must be 0-0xffff" -msgstr "" - #: shared-bindings/_bleio/UUID.c msgid "UUID string not 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'" msgstr "" @@ -2236,6 +2336,7 @@ msgstr "" #: 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 "" @@ -2244,6 +2345,7 @@ msgid "Unable to allocate to the heap." msgstr "" #: ports/espressif/common-hal/busio/I2C.c +#: ports/espressif/common-hal/busio/SPI.c msgid "Unable to create lock" msgstr "" @@ -2349,6 +2451,10 @@ msgid "" "declined or ignored." msgstr "" +#: shared-module/jpegio/JpegDecoder.c +msgid "Unsupported JPEG (may be progressive)" +msgstr "" + #: shared-bindings/bitmaptools/__init__.c msgid "Unsupported colorspace" msgstr "" @@ -2371,6 +2477,13 @@ msgstr "" msgid "Update failed" 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/_bleio/Characteristic.c #: ports/nordic/common-hal/_bleio/Characteristic.c #: ports/nordic/common-hal/_bleio/Descriptor.c @@ -2510,6 +2623,10 @@ msgstr "" msgid "a bytes-like object is required" msgstr "" +#: shared-bindings/i2cioexpander/IOExpander.c +msgid "address out of range" +msgstr "" + #: shared-bindings/i2ctarget/I2CTarget.c msgid "addresses is empty" msgstr "" @@ -2576,10 +2693,6 @@ msgstr "" msgid "array/bytes required on right side" msgstr "" -#: py/asmxtensa.c -msgid "asm overflow" -msgstr "" - #: py/compile.c msgid "async for/with outside async function" msgstr "" @@ -2636,10 +2749,6 @@ msgstr "" msgid "binary op %q not implemented" msgstr "" -#: ports/espressif/common-hal/audiobusio/PDMIn.c -msgid "bit_depth must be 8, 16, 24, or 32." -msgstr "" - #: shared-module/bitmapfilter/__init__.c msgid "bitmap size and depth must match" msgstr "" @@ -2793,6 +2902,10 @@ msgstr "" msgid "can't create '%q' instances" msgstr "" +#: py/objtype.c +msgid "can't create instance" +msgstr "" + #: py/compile.c msgid "can't declare nonlocal in outer code" msgstr "" @@ -2891,14 +3004,14 @@ msgstr "" msgid "cannot convert complex type" msgstr "" -#: py/objtype.c -msgid "cannot create instance" -msgstr "" - #: extmod/ulab/code/ndarray.c msgid "cannot delete array elements" msgstr "" +#: py/compile.c +msgid "cannot emit native code for this architecture" +msgstr "" + #: extmod/ulab/code/ndarray.c msgid "cannot reshape array" msgstr "" @@ -3033,6 +3146,10 @@ msgstr "" msgid "destination buffer must be an array of type 'H' for bit_depth = 16" msgstr "" +#: shared-bindings/usb_audio/USBSpeaker.c +msgid "destination must be an array of type 'h'" +msgstr "" + #: py/objdict.c msgid "dict update sequence has wrong length" msgstr "" @@ -3053,7 +3170,7 @@ msgstr "" msgid "div/mod not implemented for uint" msgstr "" -#: extmod/ulab/code/numpy/create.c +#: extmod/ulab/code/numpy/create.c py/objint_longlong.c py/objint_mpz.c msgid "divide by zero" msgstr "" @@ -3152,10 +3269,6 @@ msgstr "" msgid "file write is not available" msgstr "" -#: shared-bindings/storage/__init__.c -msgid "filesystem must provide mount method" -msgstr "" - #: extmod/ulab/code/numpy/vector.c msgid "first argument must be a callable" msgstr "" @@ -3196,10 +3309,6 @@ msgstr "" msgid "float unsupported" msgstr "" -#: shared-bindings/_stage/Text.c -msgid "font must be 2048 bytes long" -msgstr "" - #: extmod/moddeflate.c msgid "format" msgstr "" @@ -3281,10 +3390,6 @@ msgstr "" msgid "generator raised StopIteration" msgstr "" -#: shared-bindings/_stage/Layer.c -msgid "graphic must be 2048 bytes long" -msgstr "" - #: extmod/modhashlib.c msgid "hash is final" msgstr "" @@ -3351,10 +3456,6 @@ msgstr "" msgid "initial values must be iterable" msgstr "" -#: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c -msgid "initial_value length is wrong" -msgstr "" - #: py/compile.c msgid "inline assembler must be a function" msgstr "" @@ -3445,6 +3546,10 @@ msgstr "" msgid "interval must be in range %s-%s" msgstr "" +#: py/emitinlinerv32.c +msgid "invalid RV32 instruction '%q'" +msgstr "" + #: py/compile.c msgid "invalid arch" msgstr "" @@ -3458,6 +3563,11 @@ msgstr "" msgid "invalid cert" msgstr "" +#: shared-bindings/audioi2sin/I2SIn.c +#, c-format +msgid "invalid destination buffer, must be an array of type: %c" +msgstr "" + #: shared-bindings/bitmaptools/__init__.c #, c-format msgid "invalid element size %d for bits_per_pixel %d\n" @@ -3639,6 +3749,10 @@ msgstr "" msgid "mode must be complete, or reduced" msgstr "" +#: py/runtime.c +msgid "module '%q' has no attribute '%q'" +msgstr "" + #: py/builtinimport.c msgid "module not found" msgstr "" @@ -3687,10 +3801,6 @@ msgstr "" msgid "native code in .mpy unsupported" msgstr "" -#: py/asmthumb.c -msgid "native method too big" -msgstr "" - #: py/emitnative.c msgid "native yield" msgstr "" @@ -3712,7 +3822,7 @@ msgstr "" msgid "negative power with no float support" msgstr "" -#: py/objint_mpz.c py/runtime.c +#: py/objint_longlong.c py/objint_mpz.c py/runtime.c msgid "negative shift count" msgstr "" @@ -3789,6 +3899,10 @@ msgstr "" msgid "not supported for input types" msgstr "" +#: shared-bindings/i2cioexpander/IOExpander.c +msgid "num_pins must be 8 or 16" +msgstr "" + #: extmod/ulab/code/numpy/create.c msgid "number of points must be at least 2" msgstr "" @@ -3802,6 +3916,10 @@ msgstr "" msgid "object '%s' isn't a tuple or list" msgstr "" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "object does not support DigitalInOut protocol" +msgstr "" + #: py/obj.c msgid "object doesn't support item assignment" msgstr "" @@ -3993,7 +4111,7 @@ msgstr "" msgid "output array must be contiguous" msgstr "" -#: py/objint_mpz.c +#: py/objint_longlong.c py/objint_mpz.c msgid "overflow converting long int to machine word" msgstr "" @@ -4002,10 +4120,6 @@ msgstr "" 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" -msgstr "" - #: py/emitinlinerv32.c msgid "parameters must be registers in sequence a0 to a3" msgstr "" @@ -4063,6 +4177,10 @@ msgstr "" msgid "real and imaginary parts must be of equal length" msgstr "" +#: extmod/modre.c +msgid "regex too complex" +msgstr "" + #: py/builtinimport.c msgid "relative import" msgstr "" @@ -4072,6 +4190,10 @@ msgstr "" msgid "requested length %d but object has length %d" msgstr "" +#: py/objint_longlong.c py/parsenum.c +msgid "result overflows long long storage" +msgstr "" + #: extmod/ulab/code/ndarray_operators.c msgid "results cannot be cast to specified type" msgstr "" @@ -4336,10 +4458,6 @@ msgstr "" msgid "type takes 1 or 3 arguments" msgstr "" -#: py/objint_longlong.c -msgid "ulonglong too large" -msgstr "" - #: py/parse.c msgid "unexpected indent" msgstr "" @@ -4361,10 +4479,6 @@ msgstr "" msgid "unindent doesn't match any outer indent level" msgstr "" -#: py/emitinlinerv32.c -msgid "unknown RV32 instruction '%q'" -msgstr "" - #: py/objstr.c #, c-format msgid "unknown conversion specifier %c" @@ -4533,6 +4647,13 @@ msgstr "" msgid "zi must be of shape (n_section, 2)" msgstr "" +#, 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" @@ -4772,8 +4893,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 1f387b7ca3c..063044e44f2 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" @@ -112,8 +113,8 @@ 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) { @@ -124,23 +125,24 @@ static void reset_devices(void) { 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,20 +209,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 - mp_vfs_mount_t *vfs = MP_STATE_VM(vfs_mount_table); // Unmount all heap allocated vfs mounts. - while (gc_nbytes(vfs) > 0) { - vfs = vfs->next; - } - MP_STATE_VM(vfs_mount_table) = vfs; - // The last vfs is CIRCUITPY and the root directory. - while (vfs->next != NULL) { - vfs = vfs->next; + mp_vfs_mount_t *vfs = MP_STATE_VM(vfs_mount_table); + 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; + } } MP_STATE_VM(vfs_cur) = vfs; #endif @@ -401,8 +416,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(); } @@ -421,17 +441,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; @@ -505,6 +514,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; @@ -630,20 +640,13 @@ 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")); printed_press_any_key = true; } if (!serial_connected()) { - serial_connected_at_start = false; printed_press_any_key = false; } @@ -855,6 +858,14 @@ static void __attribute__ ((noinline)) run_boot_py(safe_mode_t safe_mode) { boot_output = &boot_text; #endif + // Get the base filesystem. + fs_user_mount_t *vfs = filesystem_circuitpy(); + FATFS *fs = &vfs->fatfs; + + // Allow boot.py access to CIRCUITPY, and allow writes to boot_out.txt. + // We can't use the regular flags for this, because they might get modified inside boot.py. + filesystem_set_ignore_write_protection(vfs, true); + // Write version info mp_printf(&mp_plat_print, "%s\nBoard ID:%s\n", MICROPY_FULL_VERSION_INFO, CIRCUITPY_BOARD_ID); #if CIRCUITPY_MICROCONTROLLER && COMMON_HAL_MCU_PROCESSOR_UID_LENGTH > 0 @@ -873,10 +884,6 @@ static void __attribute__ ((noinline)) run_boot_py(safe_mode_t safe_mode) { #ifdef CIRCUITPY_BOOT_OUTPUT_FILE - // Get the base filesystem. - fs_user_mount_t *vfs = filesystem_circuitpy(); - FATFS *fs = &vfs->fatfs; - boot_output = NULL; #if CIRCUITPY_STATUS_BAR supervisor_status_bar_resume(); @@ -898,9 +905,6 @@ static void __attribute__ ((noinline)) run_boot_py(safe_mode_t safe_mode) { // in case power is momentary or will fail shortly due to, say a low, battery. mp_hal_delay_ms(1000); - // USB isn't up, so we can write the file. - // operating at the oofatfs (f_open) layer means the usb concurrent write permission - // is not even checked! f_open(fs, &boot_output_file, CIRCUITPY_BOOT_OUTPUT_FILE, FA_WRITE | FA_CREATE_ALWAYS); UINT chars_written; f_write(&boot_output_file, boot_text.buf, boot_text.len, &chars_written); @@ -908,6 +912,9 @@ static void __attribute__ ((noinline)) run_boot_py(safe_mode_t safe_mode) { filesystem_flush(); } #endif + + // Back to regular filesystem protections. + filesystem_set_ignore_write_protection(vfs, false); } cleanup_after_vm(_exec_result.exception); @@ -995,8 +1002,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(); @@ -1011,18 +1022,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 @@ -1039,6 +1044,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. @@ -1120,7 +1132,7 @@ int __attribute__((used)) main(void) { } else { skip_repl = false; } - } else if (exit_code != 0) { + } else if (exit_code != PYEXEC_NORMAL_EXIT) { break; } @@ -1136,13 +1148,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. @@ -1179,22 +1185,22 @@ void gc_collect(void) { gc_collect_end(); } -// Ports may provide an implementation of this function if it is needed -MP_WEAK void port_gc_collect(void) { -} - 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..add07c3d49b 100644 --- a/mpy-cross/main.c +++ b/mpy-cross/main.c @@ -34,13 +34,19 @@ #include "py/persistentcode.h" #include "py/runtime.h" #include "py/gc.h" -#include "py/stackctrl.h" +#include "py/parsenum.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; @@ -82,13 +88,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 +144,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 string)\n" + " supported flags for rv32imc: zba\n" "\n" "Implementation specific options:\n", argv[0] ); @@ -212,9 +228,39 @@ 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 its small int representation allows to fit in there. +static bool parse_integer(const char *value, mp_uint_t *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 = 10; + if (value_length > 2 && value[0] == '0') { + if ((value[1] | 0x20) == 'b') { + base = 2; + } else if ((value[1] | 0x20) == 'x') { + base = 16; + } else { + return false; + } + } + + bool valid = false; + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_obj_t parsed = mp_parse_num_integer(value, value_length, base, NULL); + if (mp_obj_is_small_int(parsed)) { + *integer = MP_OBJ_SMALL_INT_VALUE(parsed); + valid = true; + } + nlr_pop(); + } + return valid; +} + +MP_NOINLINE int main_(int argc, char **argv) { pre_process_options(argc, argv); char *heap = malloc(heap_size); @@ -237,11 +283,13 @@ 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; 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++) { @@ -318,6 +366,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 +382,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 +392,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 +408,38 @@ 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; + mp_uint_t raw_flags = 0; + if (parse_integer(arch_flags, &raw_flags)) { + if ((raw_flags & ~((mp_uint_t)RV32_EXT_ALL)) == 0) { + rv32_options.allowed_extensions = raw_flags; + processed = true; + } + } else if (strncmp(arch_flags, "zba", sizeof("zba") - 1) == 0) { + rv32_options.allowed_extensions |= RV32_EXT_ZBA; + 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); @@ -371,7 +459,7 @@ MP_NOINLINE int main_(int argc, char **argv) { } 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..36bcbc11394 100644 --- a/mpy-cross/mpconfigport.h +++ b/mpy-cross/mpconfigport.h @@ -59,6 +59,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) @@ -90,11 +91,12 @@ #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 +104,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 +128,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 08b245c5897..6b86bd70396 100644 --- a/ports/analog/Makefile +++ b/ports/analog/Makefile @@ -2,15 +2,17 @@ # # SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries # SPDX-FileCopyrightText: Copyright (c) 2024 Brandon Hurst, Analog Devices, Inc. +# SPDX-FileCopyrightText: Copyright (c) 2025 Peggy Zhu, Analog Devices, Inc. # # SPDX-License-Identifier: MIT +BOARD ?= apard32690 +CROSS_COMPILE = arm-none-eabi- + # Includes mpconfigboard.mk & mpconfigport.mk, # along with numerous other shared environment makefiles. include ../../py/circuitpy_mkenv.mk -CROSS_COMPILE = arm-none-eabi- - # MCU_SERIES e.g. "max32" # MCU_VARIANT e.g. "max32690" # defined in mpconfigboard.mk @@ -19,6 +21,7 @@ MCU_SERIES_UPPER := $(shell echo $(MCU_SERIES) | tr '[:lower:]' '[:upper:]') MCU_VARIANT_LOWER := $(shell echo $(MCU_VARIANT) | tr '[:upper:]' '[:lower:]') MCU_VARIANT_UPPER := $(shell echo $(MCU_VARIANT) | tr '[:lower:]' '[:upper:]') + # ******************************************************************************* #### MSDK INCLUDES #### # Necessary for msdk makefiles @@ -58,6 +61,7 @@ DIE_TYPE=me18 endif PERIPH_SRC = $(ADI_PERIPH)/Source +PERIPH_INC = $(ADI_PERIPH)/Include/$(MCU_VARIANT_UPPER) INC += -I. INC += -I../.. @@ -74,7 +78,7 @@ INC += \ -I$(TOP)/lib/cmsis/inc \ -I$(CMSIS_ROOT)/Include \ -I$(CMSIS_ROOT)/Device/Maxim/$(MCU_VARIANT_UPPER)/Include \ - -I$(ADI_PERIPH)/Include/$(MCU_VARIANT_UPPER) \ + -I$(PERIPH_INC) \ -I$(PERIPH_SRC)/SYS \ -I$(PERIPH_SRC)/CTB \ -I$(PERIPH_SRC)/DMA \ @@ -83,7 +87,10 @@ INC += \ -I$(PERIPH_SRC)/ICC \ -I$(PERIPH_SRC)/TMR \ -I$(PERIPH_SRC)/RTC \ - -I$(PERIPH_SRC)/UART + -I$(PERIPH_SRC)/UART \ + -I$(PERIPH_SRC)/TRNG \ + -I$(PERIPH_SRC)/I2C \ + -I$(PERIPH_SRC)/SPI INC += -I$(CMSIS_ROOT)/Device/Maxim/$(MCU_VARIANT_UPPER)/Source/GCC @@ -116,13 +123,22 @@ SRC_MAX32 += \ $(PERIPH_SRC)/TMR/tmr_$(DIE_TYPE).c \ $(PERIPH_SRC)/UART/uart_common.c \ $(PERIPH_SRC)/UART/uart_$(DIE_TYPE).c \ - $(PERIPH_SRC)/UART/uart_revb.c + $(PERIPH_SRC)/UART/uart_revb.c \ + $(PERIPH_SRC)/TRNG/trng_revb.c \ + $(PERIPH_SRC)/TRNG/trng_$(DIE_TYPE).c \ + $(PERIPH_SRC)/I2C/i2c_$(DIE_TYPE).c \ + $(PERIPH_SRC)/I2C/i2c_reva.c \ + $(PERIPH_SRC)/SPI/spi_$(DIE_TYPE).c \ + $(PERIPH_SRC)/SPI/spi_reva1.c SRC_C += $(SRC_MAX32) \ boards/$(BOARD)/board.c \ boards/$(BOARD)/pins.c \ peripherals/$(MCU_VARIANT_LOWER)/pins.c \ - peripherals/$(MCU_VARIANT_LOWER)/gpios.c + peripherals/$(MCU_VARIANT_LOWER)/gpios.c \ + peripherals/$(MCU_VARIANT_LOWER)/max32_uart.c \ + peripherals/$(MCU_VARIANT_LOWER)/max32_i2c.c \ + peripherals/$(MCU_VARIANT_LOWER)/max32_spi.c # ******************************************************************************* ### Compiler & Linker Flags ### @@ -138,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) \ @@ -236,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 @@ -263,11 +280,16 @@ flash-msdk: -f interface/cmsis-dap.cfg -f target/$(MCU_VARIANT_LOWER).cfg \ -c "program $(BUILD)/firmware.elf verify; init; reset; exit" +flash-openocd-jlink: + $(OPENOCD) -s $(OPENOCD_SCRIPTS) \ + -f interface/jlink.cfg -f target/$(MCU_VARIANT_LOWER).cfg \ + -c "program $(BUILD)/firmware.elf verify; init; reset; exit" + # flash target using JLink JLINK_DEVICE = $(MCU_VARIANT_LOWER) JLINKEXE ?= JLink.exe -JLINKEXE += -if SWD -device ${JLINK_DEVICE} -speed 10000 +JLINKEXE += -if SWD -device ${JLINK_DEVICE} -speed 4000 COMMAND_FILE := tools/flash_max32.jlink flash-jlink: $(BUILD)/firmware.bin diff --git a/ports/analog/background.c b/ports/analog/background.c index ffad007ffa5..ad840c6dcda 100644 --- a/ports/analog/background.c +++ b/ports/analog/background.c @@ -19,19 +19,13 @@ extern const mxc_gpio_cfg_t led_pin[]; extern const int num_leds; /** NOTE: ALL "ticks" refer to a 1/1024 s period */ -static int status_led_ticks = 0; +static int status_ticks = 0; // This function is where port-specific background // tasks should be performed // Execute port specific actions during background tick. Only if ticks are enabled. void port_background_tick(void) { - status_led_ticks++; - - // Set an LED approx. 1/s - if (status_led_ticks > 1024) { - MXC_GPIO_OutToggle(led_pin[2].port, led_pin[2].mask); - status_led_ticks = 0; - } + status_ticks++; } // Execute port specific actions during background tasks. This is before the 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 new file mode 100644 index 00000000000..7ebe721b3f4 --- /dev/null +++ b/ports/analog/common-hal/busio/I2C.c @@ -0,0 +1,256 @@ +/* + * This file is part of Adafruit for EFR32 project + * + * The MIT License (MIT) + * + * Copyright 2023 Silicon Laboratories Inc. www.silabs.com + * + * 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 "shared-bindings/busio/I2C.h" +#include "py/mperrno.h" +#include "py/runtime.h" +#include "shared-bindings/microcontroller/__init__.h" +#include "shared-bindings/microcontroller/Pin.h" + +#include "max32_port.h" + +#define I2C_PRIORITY 1 + +// Set each bit to indicate an active I2c +static uint8_t i2c_active = 0; +static volatile int i2c_err; + +// I2C struct for configuring GPIO pins +extern const mxc_gpio_cfg_t i2c_maps[NUM_I2C]; + +// Construct I2C protocol, this function init i2c peripheral +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) { + // Check for NULL Pointers && valid I2C settings + assert(self); + + /* NOTE: The validate_obj_is_free_pin() calls in shared-bindings/busio/I2C.c + will ensure that scl and sda are both pins and cannot be null + ref: https://github.com/adafruit/circuitpython/pull/10413 + */ + + // Assign I2C ID based on pins + int i2c_id = pinsToI2c(sda, scl); + if (i2c_id == -1) { + return; + } else { + self->i2c_id = i2c_id; + self->i2c_regs = MXC_I2C_GET_I2C(i2c_id); + } + + // Check for valid I2C controller + assert((self->i2c_id >= 0) && (self->i2c_id < NUM_I2C)); + assert(!(i2c_active & (1 << self->i2c_id))); + + // Attach I2C pins + self->sda = sda; + self->scl = scl; + common_hal_mcu_pin_claim(self->sda); + common_hal_mcu_pin_claim(self->scl); + + // Clear all flags + MXC_I2C_ClearFlags(self->i2c_regs, 0xFFFFFF, 0xFFFFFF); + + // Init as master, no slave address + MXC_I2C_Shutdown(self->i2c_regs); + MXC_I2C_Init(self->i2c_regs, 1, 0); + + // Set frequency arg (CircuitPython shared-bindings validate) + MXC_I2C_SetFrequency(self->i2c_regs, frequency); + + // Indicate to this module that the I2C is active + i2c_active |= (1 << self->i2c_id); + + // Set the timeout to a default value + if (timeout > 100) { + self->timeout = 1; + } else { + self->timeout = timeout; + } + + return; +} + +// Never reset I2C obj when reload +void common_hal_busio_i2c_never_reset(busio_i2c_obj_t *self) { + common_hal_never_reset_pin(self->sda); + common_hal_never_reset_pin(self->scl); +} + +// Check I2C status, deinited or not +bool common_hal_busio_i2c_deinited(busio_i2c_obj_t *self) { + return self->sda == NULL; +} + +// Deinit i2c obj, reset I2C pin +void common_hal_busio_i2c_deinit(busio_i2c_obj_t *self) { + MXC_I2C_Shutdown(self->i2c_regs); + + common_hal_reset_pin(self->sda); + common_hal_reset_pin(self->scl); + + self->sda = NULL; + self->scl = NULL; +} + +// Probe device in I2C bus +bool common_hal_busio_i2c_probe(busio_i2c_obj_t *self, uint8_t addr) { + uint32_t int_fl0; + bool ret = 0; + + // If not in Master mode, error out (can happen in some error conditions) + if (!(self->i2c_regs->ctrl & MXC_F_I2C_CTRL_MST_MODE)) { + return false; + } + + // Clear FIFOs & all interrupt flags + MXC_I2C_ClearRXFIFO(self->i2c_regs); + MXC_I2C_ClearTXFIFO(self->i2c_regs); + MXC_I2C_ClearFlags(self->i2c_regs, 0xFFFFFF, 0xFFFFFF); + + // Pre-load target address into transmit FIFO + addr = (addr << 1); + self->i2c_regs->fifo = addr; + + // Set start bit & wait for it to clear + MXC_I2C_Start(self->i2c_regs); + + // wait for ACK/NACK + while (!(self->i2c_regs->intfl0 & MXC_F_I2C_INTFL0_ADDR_ACK) && + !(self->i2c_regs->intfl0 & MXC_F_I2C_INTFL0_ADDR_NACK_ERR)) { + } + + // Save interrupt flags for ACK/NACK checking + int_fl0 = self->i2c_regs->intfl0; + + // Set / Wait for stop + MXC_I2C_Stop(self->i2c_regs); + + // Wait for controller not busy, then clear flags + while (self->i2c_regs->status & MXC_F_I2C_STATUS_BUSY) { + ; + } + MXC_I2C_ClearFlags(self->i2c_regs, 0xFFFFFF, 0xFFFFFF); + + if (int_fl0 & MXC_F_I2C_INTFL0_ADDR_ACK) { + ret = true; + } else { + ret = false; + } + return ret; +} + +// Lock I2C bus +bool common_hal_busio_i2c_try_lock(busio_i2c_obj_t *self) { + + if (self->i2c_regs->status & MXC_F_I2C_STATUS_BUSY) { + return false; + } else { + self->has_lock = true; + return true; + } +} + +// Check I2C lock status +bool common_hal_busio_i2c_has_lock(busio_i2c_obj_t *self) { + return self->has_lock; +} + +// Unlock I2C bus +void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self) { + self->has_lock = false; +} + +// Write data to the device selected by address +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; + mxc_i2c_req_t wr_req = { + .addr = addr, + .i2c = self->i2c_regs, + .tx_buf = (uint8_t *)data, + .tx_len = len, + .rx_buf = NULL, + .rx_len = 0, + .callback = NULL + }; + ret = MXC_I2C_MasterTransaction(&wr_req); + if (ret) { + return -MP_EIO; + } + + return 0; +} + +// Read into buffer from the device selected by address +mp_negative_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, + uint16_t addr, + uint8_t *data, size_t len) { + + int ret; + mxc_i2c_req_t rd_req = { + .addr = addr, + .i2c = self->i2c_regs, + .tx_buf = NULL, + .tx_len = 0, + .rx_buf = data, + .rx_len = len, + .callback = NULL + }; + ret = MXC_I2C_MasterTransaction(&rd_req); + if (ret) { + // Return I/O error + return -MP_EIO; + } + + return 0; +} + +// Write the bytes from out_data to the device selected by address +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) { + + int ret; + mxc_i2c_req_t wr_rd_req = { + .addr = addr, + .i2c = self->i2c_regs, + .tx_buf = out_data, + .tx_len = out_len, + .rx_buf = in_data, + .rx_len = in_len, + .callback = NULL + }; + ret = MXC_I2C_MasterTransaction(&wr_rd_req); + if (ret) { + return -MP_EIO; + } + + return 0; +} diff --git a/ports/analog/common-hal/busio/I2C.h b/ports/analog/common-hal/busio/I2C.h new file mode 100644 index 00000000000..55c230ee2f9 --- /dev/null +++ b/ports/analog/common-hal/busio/I2C.h @@ -0,0 +1,28 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Brandon Hurst, Analog Devices, Inc. +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "common-hal/microcontroller/Pin.h" +#include "py/obj.h" + +// HAL-specific +#include "i2c.h" +#include "gpio.h" + +// Define a struct for what BUSIO.I2C should carry +typedef struct { + mp_obj_base_t base; + + int i2c_id; + mxc_i2c_regs_t *i2c_regs; + const mcu_pin_obj_t *scl; + const mcu_pin_obj_t *sda; + const int frequency; + + uint32_t timeout; + bool has_lock; +} busio_i2c_obj_t; diff --git a/ports/analog/common-hal/busio/SPI.c b/ports/analog/common-hal/busio/SPI.c new file mode 100644 index 00000000000..de3856b23b3 --- /dev/null +++ b/ports/analog/common-hal/busio/SPI.c @@ -0,0 +1,321 @@ +/* + * This file is part of Adafruit for EFR32 project + * + * The MIT License (MIT) + * + * Copyright 2023 Silicon Laboratories Inc. www.silabs.com + * + * 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 "shared-bindings/busio/SPI.h" +#include "py/mperrno.h" +#include "py/runtime.h" +#include "shared-bindings/microcontroller/__init__.h" +#include "supervisor/board.h" +#include "shared-bindings/microcontroller/Pin.h" + +#include "max32_port.h" +#include "spi_reva1.h" + +// Note that any bugs introduced in this file can cause crashes +// at startupfor chips using external SPI flash. + +#define SPI_PRIORITY 1 + +typedef enum { + SPI_FREE = 0, + SPI_BUSY, +} spi_status_t; + +// Set each bit to indicate an active SPI +static uint8_t spi_active = 0; +static spi_status_t spi_status[NUM_SPI]; +static volatile int spi_err; + +// Construct SPI protocol, this function init SPI peripheral +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) { + int err = 0; + + // 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) { + return; + } else { + self->spi_id = spi_id; + self->spi_regs = MXC_SPI_GET_SPI(spi_id); + } + + // Other pins default to true + mxc_spi_pins_t spi_pins = { + .clock = TRUE, + .mosi = TRUE, + .miso = TRUE, + .ss0 = FALSE, + .ss1 = FALSE, + .ss2 = FALSE, + .vddioh = true, + .drvstr = MXC_GPIO_DRVSTR_0 + }; + + assert((self->spi_id >= 0) && (self->spi_id < NUM_SPI)); + + // Init SPI controller + if ((mosi != NULL) && (miso != NULL) && (sck != NULL)) { + // spi, mastermode, quadModeUsed, numSubs, ssPolarity, frequency + err = MXC_SPI_Init(self->spi_regs, MXC_SPI_TYPE_CONTROLLER, MXC_SPI_INTERFACE_STANDARD, + 1, 0x01, 1000000, spi_pins); + MXC_GPIO_SetVSSEL(MXC_GPIO_GET_GPIO(sck->port), MXC_GPIO_VSSEL_VDDIOH, (sck->mask | miso->mask | mosi->mask | MXC_GPIO_PIN_0)); + if (err) { + // NOTE: Reuse existing messages from locales/circuitpython.pot to save space + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("%q init failed"), MP_QSTR_SPI); + } + } else { + mp_raise_NotImplementedError(MP_ERROR_TEXT("SPI needs MOSI, MISO, and SCK")); + } + + // Attach SPI pins + self->mosi = mosi; + self->miso = miso; + self->sck = sck; + common_hal_mcu_pin_claim(self->mosi); + common_hal_mcu_pin_claim(self->miso); + common_hal_mcu_pin_claim(self->sck); + + // Indicate to this module that the SPI is active + spi_active |= (1 << self->spi_id); + + return; +} + +// Never reset SPI when reload +void common_hal_busio_spi_never_reset(busio_spi_obj_t *self) { + common_hal_never_reset_pin(self->mosi); + common_hal_never_reset_pin(self->miso); + common_hal_never_reset_pin(self->sck); + common_hal_never_reset_pin(self->nss); +} + +// Check SPI status, deinited or not +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) { + + MXC_SPI_Shutdown(self->spi_regs); + common_hal_reset_pin(self->mosi); + common_hal_reset_pin(self->miso); + common_hal_reset_pin(self->sck); + common_hal_reset_pin(self->nss); + + self->mosi = NULL; + self->miso = NULL; + self->nss = NULL; + + common_hal_busio_spi_mark_deinit(self); +} + +// Configures the SPI bus. The SPI object must be locked. +bool common_hal_busio_spi_configure(busio_spi_obj_t *self, + uint32_t baudrate, + uint8_t polarity, + uint8_t phase, + uint8_t bits) { + + mxc_spi_clkmode_t clk_mode; + int ret; + + self->baudrate = baudrate; + self->polarity = polarity; + self->phase = phase; + self->bits = bits; + + switch ((polarity << 1) | (phase)) { + case 0b00: + clk_mode = MXC_SPI_CLKMODE_0; + break; + case 0b01: + clk_mode = MXC_SPI_CLKMODE_1; + break; + case 0b10: + clk_mode = MXC_SPI_CLKMODE_2; + break; + case 0b11: + clk_mode = MXC_SPI_CLKMODE_3; + break; + default: + // should not be reachable; validated in shared-bindings/busio/SPI.c + return false; + } + + ret = MXC_SPI_SetFrequency(self->spi_regs, baudrate); + if (ret) { + mp_raise_ValueError_varg(MP_ERROR_TEXT("%q out of range"), MP_QSTR_baudrate); + return false; + } + 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); + return false; + } else if (ret == E_BAD_STATE) { + mp_raise_RuntimeError(MP_ERROR_TEXT("Invalid state")); + } + ret = MXC_SPI_SetMode(self->spi_regs, clk_mode); + if (ret) { + mp_raise_ValueError(MP_ERROR_TEXT("Failed to set SPI Clock Mode")); + return false; + } + return true; +} + +// Lock SPI bus +bool common_hal_busio_spi_try_lock(busio_spi_obj_t *self) { + if (spi_status[self->spi_id] != SPI_BUSY) { + self->has_lock = true; + return true; + } else { + return false; + } +} + +// Check SPI lock status +bool common_hal_busio_spi_has_lock(busio_spi_obj_t *self) { + return self->has_lock; +} + +// Unlock SPI bus +void common_hal_busio_spi_unlock(busio_spi_obj_t *self) { + self->has_lock = false; +} + +// Write the data contained in buffer +bool common_hal_busio_spi_write(busio_spi_obj_t *self, + const uint8_t *data, + size_t len) { + int ret = 0; + + mxc_spi_req_t wr_req = { + .spi = self->spi_regs, + .ssIdx = 0, + .txCnt = 0, + .rxCnt = 0, + .txData = (uint8_t *)data, + .txLen = len, + .rxData = NULL, + .rxLen = 0, + .ssDeassert = 1, + .completeCB = NULL, + .txDummyValue = 0xFF, + }; + ret = MXC_SPI_MasterTransaction(&wr_req); + if (ret) { + return false; + } else { + return true; + } +} + +// Read data into buffer +bool common_hal_busio_spi_read(busio_spi_obj_t *self, + uint8_t *data, size_t len, + uint8_t write_value) { + + int ret = 0; + + mxc_spi_req_t rd_req = { + .spi = self->spi_regs, + .ssIdx = 0, + .txCnt = 0, + .rxCnt = 0, + .txData = NULL, + .txLen = len, + .rxData = data, + .rxLen = len, + .ssDeassert = 1, + .completeCB = NULL, + .txDummyValue = write_value, + }; + ret = MXC_SPI_MasterTransaction(&rd_req); + if (ret) { + return false; + } else { + return true; + } +} + +// Write out the data in data_out +// while simultaneously reading data into data_in +bool common_hal_busio_spi_transfer(busio_spi_obj_t *self, + const uint8_t *data_out, + uint8_t *data_in, + size_t len) { + + int ret = 0; + + mxc_spi_req_t rd_req = { + .spi = self->spi_regs, + .ssIdx = 0, + .txCnt = 0, + .rxCnt = 0, + .txData = (uint8_t *)data_out, + .txLen = len, + .rxData = data_in, + .rxLen = len, + .ssDeassert = 1, + .completeCB = NULL, + .txDummyValue = 0xFF, + }; + ret = MXC_SPI_MasterTransaction(&rd_req); + if (ret) { + return false; + } else { + return true; + } +} + +// Get SPI baudrate +uint32_t common_hal_busio_spi_get_frequency(busio_spi_obj_t *self) { + return self->baudrate; +} + +// Get SPI phase +uint8_t common_hal_busio_spi_get_phase(busio_spi_obj_t *self) { + return self->phase; +} + +// Get SPI polarity +uint8_t common_hal_busio_spi_get_polarity(busio_spi_obj_t *self) { + return self->polarity; +} diff --git a/ports/analog/common-hal/busio/SPI.h b/ports/analog/common-hal/busio/SPI.h new file mode 100644 index 00000000000..d10601876fb --- /dev/null +++ b/ports/analog/common-hal/busio/SPI.h @@ -0,0 +1,41 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Brandon Hurst, Analog Devices, Inc. +// +// SPDX-License-Identifier: MIT + +#ifndef MICROPY_INCLUDED_MAX32_COMMON_HAL_BUSIO_SPI_H +#define MICROPY_INCLUDED_MAX32_COMMON_HAL_BUSIO_SPI_H + +#include "common-hal/microcontroller/Pin.h" +#include "py/obj.h" + +// HAL-specific +#include "spi.h" + +// Define a struct for what BUSIO.SPI should carry +typedef struct { + mp_obj_base_t base; + + // Spi regs & pins + int spi_id; + mxc_spi_regs_t *spi_regs; + const mcu_pin_obj_t *sck; + const mcu_pin_obj_t *mosi; + const mcu_pin_obj_t *miso; + const mcu_pin_obj_t *nss; + + // Configuration + uint32_t baudrate; + uint16_t prescaler; + uint8_t polarity; + uint8_t phase; + uint8_t bits; + + // Synch data + bool has_lock; +} busio_spi_obj_t; + +void spi_reset(void); + +#endif // MICROPY_INCLUDED_MAX32_COMMON_HAL_BUSIO_SPI_H diff --git a/ports/analog/common-hal/busio/UART.c b/ports/analog/common-hal/busio/UART.c new file mode 100644 index 00000000000..be7851f52a2 --- /dev/null +++ b/ports/analog/common-hal/busio/UART.c @@ -0,0 +1,460 @@ +/* + * This file is part of Adafruit for EFR32 project + * + * The MIT License (MIT) + * + * Copyright 2023 Silicon Laboratories Inc. www.silabs.com + * + * 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. + */ + +#if CIRCUITPY_BUSIO_UART + +#include "mpconfigport.h" +#include "supervisor/shared/tick.h" + +#include "shared-bindings/microcontroller/__init__.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/busio/UART.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared/readline/readline.h" +#include "shared/runtime/interrupt_char.h" + +#include "py/gc.h" +#include "py/ringbuf.h" +#include "py/mperrno.h" +#include "py/mpprint.h" +#include "py/runtime.h" + +#include "max32_port.h" +#include "UART.h" +#include "nvic_table.h" + +// UART IRQ Priority +#define UART_PRIORITY 1 + +typedef enum { + UART_9600 = 9600, + UART_14400 = 14400, + UART_19200 = 19200, + UART_38400 = 38400, + UART_57600 = 57600, + UART_115200 = 115200, + UART_230400 = 230400, + UART_460800 = 460800, + UART_921600 = 921600, +} uart_valid_baudrates; + +typedef enum { + UART_FREE = 0, + UART_BUSY, + UART_NEVER_RESET, +} uart_status_t; + +static uint32_t timeout_ms = 0; + +// Set each bit to indicate an active UART +// will be checked by ISR Handler for which ones to call +static uint8_t uarts_active = 0; +static uart_status_t uart_status[NUM_UARTS]; +static volatile int uart_err; +static uint8_t uart_never_reset_mask = 0; +static busio_uart_obj_t *context; + +static bool isValidBaudrate(uint32_t baudrate) { + switch (baudrate) { + case UART_9600: + return true; + break; + case UART_14400: + return true; + break; + case UART_19200: + return true; + break; + case UART_38400: + return true; + break; + case UART_57600: + return true; + break; + case UART_115200: + return true; + break; + case UART_230400: + return true; + break; + case UART_460800: + return true; + break; + case UART_921600: + return true; + break; + default: + return false; + break; + } +} + +static mxc_uart_parity_t convertParity(busio_uart_parity_t busio_parity) { + switch (busio_parity) { + case BUSIO_UART_PARITY_NONE: + return MXC_UART_PARITY_DISABLE; + case BUSIO_UART_PARITY_EVEN: + return MXC_UART_PARITY_EVEN_0; + case BUSIO_UART_PARITY_ODD: + return MXC_UART_PARITY_ODD_0; + default: + // not reachable due to validation in shared-bindings/busio/SPI.c + return MXC_UART_PARITY_DISABLE; + } +} + +void uart_isr(void) { + for (int i = 0; i < NUM_UARTS; i++) { + if (uarts_active & (1 << i)) { + MXC_UART_AsyncHandler(MXC_UART_GET_UART(i)); + } + } +} + +// Callback gets called when AsyncRequest is COMPLETE +// (e.g. txLen == txCnt) +static volatile void uartCallback(mxc_uart_req_t *req, int error) { + uart_status[MXC_UART_GET_IDX(req->uart)] = UART_FREE; + uart_err = error; + + MXC_SYS_Crit_Enter(); + ringbuf_put_n(context->ringbuf, req->rxData, req->rxLen); + MXC_SYS_Crit_Exit(); +} + +// Construct an underlying UART object. +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) { + int err, temp; + + // Check for NULL Pointers && valid UART settings + assert(self); + + // Assign UART ID based on pins + temp = pinsToUart(tx, rx); + if (temp == -1) { + // Error will be indicated by pinsToUart(tx, rx) function + return; + } else { + self->uart_id = temp; + self->uart_regs = MXC_UART_GET_UART(temp); + } + assert((self->uart_id >= 0) && (self->uart_id < NUM_UARTS)); + + // Check for size of ringbuffer, desire powers of 2 + // At least use 1 byte if no size is given + assert((receiver_buffer_size & (receiver_buffer_size - 1)) == 0); + if (receiver_buffer_size == 0) { + receiver_buffer_size += 1; + } + + // Indicate RS485 not implemented + if ((rs485_dir != NULL) || (rs485_invert)) { + mp_raise_NotImplementedError(MP_ERROR_TEXT("RS485")); + } + + if ((rx != NULL) && (tx != NULL)) { + err = MXC_UART_Init(self->uart_regs, baudrate, MXC_UART_IBRO_CLK); + if (err != E_NO_ERROR) { + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("%q init failed"), MP_QSTR_UART); + } + + // attach & configure pins + self->tx_pin = tx; + self->rx_pin = rx; + common_hal_mcu_pin_claim(self->tx_pin); + common_hal_mcu_pin_claim(self->rx_pin); + } else { + mp_raise_NotImplementedError(MP_ERROR_TEXT("UART needs TX & RX")); + } + + if ((cts) && (rts)) { + MXC_UART_SetFlowCtrl(self->uart_regs, MXC_UART_FLOW_EN, 8); + self->cts_pin = cts; + self->rts_pin = rts; + common_hal_mcu_pin_claim(self->cts_pin); + common_hal_mcu_pin_claim(self->rts_pin); + } else if (cts || rts) { + mp_raise_ValueError(MP_ERROR_TEXT("Both RX and TX required for flow control")); + } + + // Set stop bits & data size + assert((stop == 1) || (stop == 2)); + mp_arg_validate_int(bits, 8, MP_QSTR_bits); + MXC_UART_SetDataSize(self->uart_regs, bits); + MXC_UART_SetStopBits(self->uart_regs, stop); + + // Set parity + MXC_UART_SetParity(self->uart_regs, convertParity(parity)); + + // attach UART parameters + self->stop_bits = stop; // must be 1 or 2 + self->bits = bits; + self->parity = parity; + self->baudrate = baudrate; + self->error = E_NO_ERROR; + + // Indicate to this module that the UART is active + uarts_active |= (1 << self->uart_id); + + // Set the timeout to a default value + if (((timeout < 0.0) || (timeout > 100.0))) { + self->timeout = 1.0; + } else { + self->timeout = timeout; + } + + // Initialize ringbuffer + if (receiver_buffer == NULL) { + self->ringbuf = m_malloc_without_collect(receiver_buffer_size); + if (!ringbuf_alloc(self->ringbuf, receiver_buffer_size)) { + m_malloc_fail(receiver_buffer_size); + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("Failed to allocate %q buffer"), + MP_QSTR_UART); + } + } else { + if (!(ringbuf_init(self->ringbuf, receiver_buffer, receiver_buffer_size))) { + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("Failed to allocate %q buffer"), + MP_QSTR_UART); + } + } + + context = self; + + // Setup UART interrupt + NVIC_ClearPendingIRQ(MXC_UART_GET_IRQ(self->uart_id)); + NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); + NVIC_SetPriority(MXC_UART_GET_IRQ(self->uart_id), UART_PRIORITY); + NVIC_SetVector(MXC_UART_GET_IRQ(self->uart_id), (uint32_t)uart_isr); + + NVIC_EnableIRQ(MXC_UART_GET_IRQ(self->uart_id)); + + return; +} + +void common_hal_busio_uart_deinit(busio_uart_obj_t *self) { + assert(self); + + if (!common_hal_busio_uart_deinited(self)) { + // First disable the ISR to avoid pre-emption + NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); + + // Shutdown the UART Controller + MXC_UART_Shutdown(self->uart_regs); + self->error = E_UNINITIALIZED; + + assert(self->rx_pin && self->tx_pin); + reset_pin_number(self->rx_pin->port, self->rx_pin->mask); + reset_pin_number(self->tx_pin->port, self->tx_pin->mask); + + if (self->cts_pin && self->rts_pin) { + reset_pin_number(self->cts_pin->port, self->cts_pin->mask); + reset_pin_number(self->rts_pin->port, self->rts_pin->mask); + } + + self->tx_pin = NULL; + self->rx_pin = NULL; + self->cts_pin = NULL; + self->rts_pin = NULL; + + ringbuf_deinit(self->ringbuf); + + // Indicate to this module that the UART is not active + uarts_active &= ~(1 << self->uart_id); + } +} + +bool common_hal_busio_uart_deinited(busio_uart_obj_t *self) { + if (uarts_active & (1 << self->uart_id)) { + return false; + } else { + return true; + }; +} + +// Read characters. len is in characters. +size_t common_hal_busio_uart_read(busio_uart_obj_t *self, + uint8_t *data, size_t len, int *errcode) { + int err; + uint32_t start_time = 0; + static size_t bytes_remaining; + + // Setup globals & status tracking + uart_err = E_NO_ERROR; + uarts_active |= (1 << self->uart_id); + uart_status[self->uart_id] = UART_BUSY; + bytes_remaining = len; + + mxc_uart_req_t uart_rd_req; + uart_rd_req.rxCnt = 0; + uart_rd_req.txCnt = 0; + uart_rd_req.rxData = data; + uart_rd_req.txData = NULL; + uart_rd_req.rxLen = bytes_remaining; + uart_rd_req.txLen = 0; + uart_rd_req.uart = self->uart_regs; + uart_rd_req.callback = (void *)uartCallback; + + // Initiate the read transaction + start_time = supervisor_ticks_ms64(); + err = MXC_UART_TransactionAsync(&uart_rd_req); + if (err != E_NO_ERROR) { + *errcode = err; + MXC_UART_AbortAsync(self->uart_regs); + NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("UART read error")); + } + + // Wait for transaction completion or timeout + while ((uart_status[self->uart_id] != UART_FREE) && + (supervisor_ticks_ms64() - start_time < (self->timeout * 1000))) { + } + + // If the timeout gets hit, abort and error out + if (uart_status[self->uart_id] != UART_FREE) { + MXC_UART_AbortAsync(self->uart_regs); + NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); + mp_raise_RuntimeError(MP_ERROR_TEXT("UART transaction timeout")); + } + // Check for errors from the callback + else if (uart_err != E_NO_ERROR) { + mp_raise_RuntimeError(MP_ERROR_TEXT("UART read error")); + MXC_UART_AbortAsync(self->uart_regs); + } + + // Copy the data from the ringbuf (or return error) + MXC_SYS_Crit_Enter(); + err = ringbuf_get_n(context->ringbuf, data, len); + MXC_SYS_Crit_Exit(); + + return err; +} + +// Write characters. len is in characters NOT bytes! +// This function blocks until the timeout finishes +size_t common_hal_busio_uart_write(busio_uart_obj_t *self, + const uint8_t *data, size_t len, int *errcode) { + int err; + static size_t bytes_remaining; + + // Setup globals & status tracking + uart_err = E_NO_ERROR; + uarts_active |= (1 << self->uart_id); + uart_status[self->uart_id] = UART_BUSY; + bytes_remaining = len; + + mxc_uart_req_t uart_wr_req = {}; + + // Setup transaction + uart_wr_req.rxCnt = 0; + uart_wr_req.txCnt = 0; + uart_wr_req.rxData = NULL; + uart_wr_req.txData = data; + uart_wr_req.txLen = bytes_remaining; + uart_wr_req.rxLen = 0; + uart_wr_req.uart = self->uart_regs; + uart_wr_req.callback = (void *)uartCallback; + + // Start the transaction + err = MXC_UART_TransactionAsync(&uart_wr_req); + if (err != E_NO_ERROR) { + *errcode = err; + MXC_UART_AbortAsync(self->uart_regs); + NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); + mp_raise_ValueError(MP_ERROR_TEXT("All UART peripherals are in use")); + } + + // Wait for transaction completion + while (uart_status[self->uart_id] != UART_FREE) { + // Call the handler and abort if errors + uart_err = MXC_UART_AsyncHandler(self->uart_regs); + if (uart_err != E_NO_ERROR) { + MXC_UART_AbortAsync(self->uart_regs); + } + } + // Check for errors from the callback + if (uart_err != E_NO_ERROR) { + MXC_UART_AbortAsync(self->uart_regs); + } + + return len; +} + +uint32_t common_hal_busio_uart_get_baudrate(busio_uart_obj_t *self) { + return self->baudrate; +} + +// Validate baudrate +void common_hal_busio_uart_set_baudrate(busio_uart_obj_t *self, uint32_t baudrate) { + if (isValidBaudrate(baudrate)) { + self->baudrate = baudrate; + } else { + mp_raise_ValueError_varg(MP_ERROR_TEXT("Invalid %q"), MP_QSTR_baudrate); + } +} + +mp_float_t common_hal_busio_uart_get_timeout(busio_uart_obj_t *self) { + return self->timeout; +} + +void common_hal_busio_uart_set_timeout(busio_uart_obj_t *self, mp_float_t timeout) { + if (timeout > 100.0) { + mp_raise_ValueError(MP_ERROR_TEXT("Timeout must be < 100 seconds")); + } + + timeout_ms = 1000 * (uint32_t)timeout; + self->timeout = (uint32_t)timeout; + + return; +} + +uint32_t common_hal_busio_uart_rx_characters_available(busio_uart_obj_t *self) { + return ringbuf_num_filled(self->ringbuf); +} + +void common_hal_busio_uart_clear_rx_buffer(busio_uart_obj_t *self) { + MXC_UART_ClearRXFIFO(self->uart_regs); + ringbuf_clear(self->ringbuf); +} + +bool common_hal_busio_uart_ready_to_tx(busio_uart_obj_t *self) { + return !(MXC_UART_GetStatus(self->uart_regs) & (MXC_F_UART_STATUS_TX_BUSY)); +} + +void common_hal_busio_uart_never_reset(busio_uart_obj_t *self) { + common_hal_never_reset_pin(self->tx_pin); + common_hal_never_reset_pin(self->rx_pin); + common_hal_never_reset_pin(self->cts_pin); + common_hal_never_reset_pin(self->rts_pin); + uart_never_reset_mask |= (1 << (self->uart_id)); +} + +#endif // CIRCUITPY_BUSIO_UART diff --git a/ports/analog/common-hal/busio/UART.h b/ports/analog/common-hal/busio/UART.h new file mode 100644 index 00000000000..296c738772e --- /dev/null +++ b/ports/analog/common-hal/busio/UART.h @@ -0,0 +1,39 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Brandon Hurst, Analog Devices, Inc. +// +// SPDX-License-Identifier: MIT + +#ifndef MICROPY_INCLUDED_MAX32_COMMON_HAL_BUSIO_UART_H +#define MICROPY_INCLUDED_MAX32_COMMON_HAL_BUSIO_UART_H + +#include "common-hal/microcontroller/Pin.h" +#include "py/obj.h" +#include "py/ringbuf.h" + +#include "max32_port.h" + +// Define a struct for what BUSIO.UART should contain +typedef struct { + mp_obj_base_t base; + int error; + float timeout; + + int uart_id; + int uart_map; + mxc_uart_regs_t *uart_regs; + ringbuf_t *ringbuf; + bool parity; + uint8_t bits; + uint8_t stop_bits; + uint32_t baudrate; + + const mcu_pin_obj_t *rx_pin; + const mcu_pin_obj_t *tx_pin; + const mcu_pin_obj_t *rts_pin; + const mcu_pin_obj_t *cts_pin; +} busio_uart_obj_t; + +void uart_reset(void); + +#endif // MICROPY_INCLUDED_MAX32_COMMON_HAL_BUSIO_UART_H diff --git a/ports/analog/common-hal/busio/__init__.c b/ports/analog/common-hal/busio/__init__.c new file mode 100644 index 00000000000..ff05be051bb --- /dev/null +++ b/ports/analog/common-hal/busio/__init__.c @@ -0,0 +1,5 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Brandon Hurst, Analog Devices, Inc. +// +// SPDX-License-Identifier: MIT diff --git a/ports/analog/common-hal/digitalio/DigitalInOut.c b/ports/analog/common-hal/digitalio/DigitalInOut.c index 7d4048d77e7..93e2242fbb6 100644 --- a/ports/analog/common-hal/digitalio/DigitalInOut.c +++ b/ports/analog/common-hal/digitalio/DigitalInOut.c @@ -107,7 +107,7 @@ digitalio_direction_t common_hal_digitalio_digitalinout_get_direction( if (self->pin->port < 4) { // Check that I/O mode is enabled and we don't have in AND out on at the same time - MP_STATIC_ASSERT(!((port->en0 & mask) && (port->inen & mask) && (port->outen & mask))); + MP_STATIC_ASSERT_NONCONSTEXPR(!((port->en0 & mask) && (port->inen & mask) && (port->outen & mask))); if ((port->en0 & mask) && (port->outen & mask)) { return DIRECTION_OUTPUT; diff --git a/ports/analog/common-hal/microcontroller/Pin.c b/ports/analog/common-hal/microcontroller/Pin.c index 4545aa039c2..83e2f3b9c3a 100644 --- a/ports/analog/common-hal/microcontroller/Pin.c +++ b/ports/analog/common-hal/microcontroller/Pin.c @@ -37,7 +37,7 @@ void reset_all_pins(void) { } void reset_pin_number(uint8_t pin_port, uint8_t pin_pad) { - if (pin_port == INVALID_PIN || pin_port > NUM_GPIO_PORTS) { + if ((pin_port == INVALID_PIN) || (pin_port > NUM_GPIO_PORTS)) { return; } diff --git a/ports/analog/common-hal/os/__init__.c b/ports/analog/common-hal/os/__init__.c index 7b607cf6b3c..508b40798e2 100644 --- a/ports/analog/common-hal/os/__init__.c +++ b/ports/analog/common-hal/os/__init__.c @@ -2,6 +2,7 @@ // // SPDX-FileCopyrightText: Copyright (c) 2017 Scott Shawcroft for Adafruit Industries // SPDX-FileCopyrightText: Copyright (c) 2019 Lucian Copeland for Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2025 Peggy Zhu, Analog Devices, Inc. // // SPDX-License-Identifier: MIT @@ -15,9 +16,14 @@ // #include "peripherals/periph.h" +// true random number generator, TRNG +#include "trng.h" + bool common_hal_os_urandom(uint8_t *buffer, uint32_t length) { #if (HAS_TRNG) - // todo (low prior): implement + // get a random number of "length" number of bytes + MXC_TRNG_Random(buffer, length); + return true; #else #endif return false; diff --git a/ports/analog/common-hal/rtc/RTC.c b/ports/analog/common-hal/rtc/RTC.c new file mode 100644 index 00000000000..c9d2258c1ec --- /dev/null +++ b/ports/analog/common-hal/rtc/RTC.c @@ -0,0 +1,42 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2019 Nick Moore for Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2019 Artur Pacholec +// SPDX-FileCopyrightText: Copyright (c) 2025 Peggy Zhu, Analog Devices, Inc. +// +// SPDX-License-Identifier: MIT + +#include + +#include "py/obj.h" +#include "py/runtime.h" +#include "shared/timeutils/timeutils.h" +#include "supervisor/port.h" + +// This is the time in seconds since 2000 that the RTC was started. +// TODO: Change the offset to ticks so that it can be a subsecond adjustment. +static uint32_t rtc_offset = 0; + +void common_hal_rtc_get_time(timeutils_struct_time_t *tm) { + uint64_t ticks_s = port_get_raw_ticks(NULL) / 1024; + timeutils_seconds_since_2000_to_struct_time(rtc_offset + ticks_s, tm); +} + +void common_hal_rtc_set_time(timeutils_struct_time_t *tm) { + uint64_t ticks_s = port_get_raw_ticks(NULL) / 1024; + uint32_t epoch_s = timeutils_seconds_since_2000( + tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec + ); + rtc_offset = epoch_s - ticks_s; +} + +// the calibration function will be implemented in near future +// the RTC oscillator on my MAX32690-APARD is only off by 0.001 second +// the inaccuracy is still tolerable +int common_hal_rtc_get_calibration(void) { + return 0; +} + +void common_hal_rtc_set_calibration(int calibration) { + mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_calibration); +} diff --git a/ports/analog/common-hal/rtc/RTC.h b/ports/analog/common-hal/rtc/RTC.h new file mode 100644 index 00000000000..590bc93ab52 --- /dev/null +++ b/ports/analog/common-hal/rtc/RTC.h @@ -0,0 +1,11 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2018 Noralf Trønnes +// SPDX-FileCopyrightText: Copyright (c) 2019 Artur Pacholec +// SPDX-FileCopyrightText: Copyright (c) 2025 Peggy Zhu, Analog Devices, Inc. +// +// SPDX-License-Identifier: MIT + +#pragma once + +extern void rtc_reset(void); diff --git a/ports/zephyr-cp/common-hal/zephyr_serial/__init__.c b/ports/analog/common-hal/rtc/__init__.c similarity index 70% rename from ports/zephyr-cp/common-hal/zephyr_serial/__init__.c rename to ports/analog/common-hal/rtc/__init__.c index 2784446ba15..ddf788bb0b5 100644 --- a/ports/zephyr-cp/common-hal/zephyr_serial/__init__.c +++ b/ports/analog/common-hal/rtc/__init__.c @@ -1,7 +1,6 @@ // This file is part of the CircuitPython project: https://circuitpython.org // // SPDX-FileCopyrightText: Copyright (c) 2024 Adafruit Industries LLC +// SPDX-FileCopyrightText: Copyright (c) 2025 Peggy Zhu, Analog Devices, Inc. // // SPDX-License-Identifier: MIT - -// No zephyr_serial module functions. diff --git a/ports/analog/max32_port.h b/ports/analog/max32_port.h index 5d92fcfe6d3..89830e96b0a 100644 --- a/ports/analog/max32_port.h +++ b/ports/analog/max32_port.h @@ -22,29 +22,34 @@ #include "system_max32690.h" #include "max32690.h" +// UART Ports & pins +#include "peripherals/max32690/max32_uart.h" +#include "peripherals/max32690/max32_i2c.h" +#include "peripherals/max32690/max32_spi.h" + /** START: GPIO4 Handling specific to MAX32690 */ -#define GPIO4_PIN_MASK 0x00000003 -#define GPIO4_RESET_MASK 0xFFFFFF77 -#define GPIO4_OUTEN_MASK(mask) \ + #define GPIO4_PIN_MASK 0x00000003 + #define GPIO4_RESET_MASK 0xFFFFFF77 + #define GPIO4_OUTEN_MASK(mask) \ (((mask & (1 << 0)) << MXC_F_MCR_GPIO4_CTRL_P40_OE_POS) | \ ((mask & (1 << 1)) << (MXC_F_MCR_GPIO4_CTRL_P41_OE_POS - 1))) -#define GPIO4_PULLDIS_MASK(mask) \ + #define GPIO4_PULLDIS_MASK(mask) \ (((mask & (1 << 0)) << MXC_F_MCR_GPIO4_CTRL_P40_PE_POS) | \ ((mask & (1 << 1)) << (MXC_F_MCR_GPIO4_CTRL_P41_PE_POS - 1))) -#define GPIO4_DATAOUT_MASK(mask) \ + #define GPIO4_DATAOUT_MASK(mask) \ (((mask & (1 << 0)) << MXC_F_MCR_GPIO4_CTRL_P40_DO_POS) | \ ((mask & (1 << 1)) << (MXC_F_MCR_GPIO4_CTRL_P41_DO_POS - 1))) -#define GPIO4_DATAOUT_GET_MASK(mask) \ + #define GPIO4_DATAOUT_GET_MASK(mask) \ ((((MXC_MCR->gpio4_ctrl & MXC_F_MCR_GPIO4_CTRL_P40_DO) >> MXC_F_MCR_GPIO4_CTRL_P40_DO_POS) | \ ((MXC_MCR->gpio4_ctrl & MXC_F_MCR_GPIO4_CTRL_P41_DO) >> \ (MXC_F_MCR_GPIO4_CTRL_P41_DO_POS - 1))) & \ mask) -#define GPIO4_DATAIN_MASK(mask) \ + #define GPIO4_DATAIN_MASK(mask) \ ((((MXC_MCR->gpio4_ctrl & MXC_F_MCR_GPIO4_CTRL_P40_IN) >> MXC_F_MCR_GPIO4_CTRL_P40_IN_POS) | \ ((MXC_MCR->gpio4_ctrl & MXC_F_MCR_GPIO4_CTRL_P41_IN) >> \ (MXC_F_MCR_GPIO4_CTRL_P41_IN_POS - 1))) & \ mask) -#define GPIO4_AFEN_MASK(mask) \ + #define GPIO4_AFEN_MASK(mask) \ (((mask & (1 << 0)) << MXC_F_MCR_OUTEN_PDOWN_OUT_EN_POS) | \ ((mask & (1 << 1)) >> (MXC_F_MCR_OUTEN_SQWOUT_EN_POS + 1))) /** END: GPIO4 Handling specific to MAX32690 */ 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 1729a284a3f..f1cd0bb2901 100644 --- a/ports/analog/mpconfigport.mk +++ b/ports/analog/mpconfigport.mk @@ -2,6 +2,7 @@ # # SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries # SPDX-FileCopyrightText: Copyright (c) 2024 Brandon Hurst, Analog Devices, Inc. +# SPDX-FileCopyrightText: Copyright (c) 2025 Peggy Zhu, Analog Devices, Inc. # # SPDX-License-Identifier: MIT @@ -21,9 +22,8 @@ INTERNAL_FLASH_FILESYSTEM = 1 #################################################################################### # These modules are implemented in ports//common-hal: -# Plan to implement -CIRCUITPY_BUSIO ?= 0 -CIRCUITPY_RTC ?= 0 +CIRCUITPY_BUSIO ?= 1 +CIRCUITPY_RTC ?= 1 # Other modules (may or may not implement): CIRCUITPY_ANALOGIO ?= 0 @@ -51,7 +51,7 @@ CIRCUITPY_BITBANGIO ?= 1 # Requires Microcontroller CIRCUITPY_TOUCHIO ?= 1 # Requires OS -CIRCUITPY_RANDOM ?= 0 +CIRCUITPY_RANDOM ?= 1 # Requires busio.UART CIRCUITPY_CONSOLE_UART ?= 0 # Does nothing without I2C diff --git a/ports/analog/peripherals/max32690/gpios.h b/ports/analog/peripherals/max32690/gpios.h index 4677bf8f33d..fe912277282 100644 --- a/ports/analog/peripherals/max32690/gpios.h +++ b/ports/analog/peripherals/max32690/gpios.h @@ -4,6 +4,8 @@ // // SPDX-License-Identifier: MIT +#pragma once + #include "py/obj.h" #include "py/mphal.h" diff --git a/ports/analog/peripherals/max32690/max32_i2c.c b/ports/analog/peripherals/max32690/max32_i2c.c new file mode 100644 index 00000000000..4b9ec8b4db2 --- /dev/null +++ b/ports/analog/peripherals/max32690/max32_i2c.c @@ -0,0 +1,75 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Brandon Hurst, Analog Devices, Inc. +// +// SPDX-License-Identifier: MIT + +#include "peripherals/pins.h" + +#include "common-hal/busio/I2C.h" +#include "max32_i2c.h" +#include "max32690.h" + +#include "py/runtime.h" +#include "py/mperrno.h" + + +/* Note: The MAX32690 assigns the same alternate function to multiple sets + * of pins. The drivers will enable both sets so that either can be used. + * Users should ensure the unused set is left unconnected. + * + * See MAX32690 Rev A2 Errata #16: + * https://www.analog.com/media/en/technical-documentation/data-sheets/max32690_a2_errata_rev2.pdf + * + * Additionally, note that the TQFN package does not expose some of the duplicate pins. For this package, + * enabling the un-routed GPIOs has been shown to cause initialization issues with the I2C block. + * To work around this, "MAX32690GTK_PACKAGE_TQFN" can be defined by the build system. The recommend place + * to do it is in the "board.mk" file of the BSP. This will prevent the inaccessible pins from being configured. + */ + +const mxc_gpio_cfg_t i2c_maps[NUM_I2C] = { + // I2C0 + { MXC_GPIO2, (MXC_GPIO_PIN_7 | MXC_GPIO_PIN_8), MXC_GPIO_FUNC_ALT1, + MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, + // I2C1 + { MXC_GPIO0, (MXC_GPIO_PIN_11 | MXC_GPIO_PIN_12), MXC_GPIO_FUNC_ALT1, + MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, + // I2C2 + { MXC_GPIO1, (MXC_GPIO_PIN_7 | MXC_GPIO_PIN_8), MXC_GPIO_FUNC_ALT3, + MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIOH, MXC_GPIO_DRVSTR_0 }, +}; +#ifndef MAX32690GTK_PACKAGE_TQFN +const mxc_gpio_cfg_t i2c_maps_extra[NUM_I2C] = { + // I2C0A + { MXC_GPIO0, (MXC_GPIO_PIN_30 | MXC_GPIO_PIN_31), MXC_GPIO_FUNC_ALT1, + MXC_GPIO_PAD_PULL_UP, MXC_GPIO_VSSEL_VDDIOH, MXC_GPIO_DRVSTR_0 }, + // I2C1A + { MXC_GPIO2, (MXC_GPIO_PIN_17 | MXC_GPIO_PIN_18), MXC_GPIO_FUNC_ALT1, + MXC_GPIO_PAD_PULL_UP, MXC_GPIO_VSSEL_VDDIOH, MXC_GPIO_DRVSTR_0 }, + // I2C2C + { MXC_GPIO0, (MXC_GPIO_PIN_13 | MXC_GPIO_PIN_14), MXC_GPIO_FUNC_ALT3, + MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, +}; +#endif + +int pinsToI2c(const mcu_pin_obj_t *sda, const mcu_pin_obj_t *scl) { + for (int i = 0; i < NUM_I2C; i++) { + if ((i2c_maps[i].port == (MXC_GPIO_GET_GPIO(sda->port))) + && (i2c_maps[i].mask == ((sda->mask) | (scl->mask)))) { + return i; + } + } + + // Additional for loop to cover alternate potential I2C maps + #ifndef MAX32690GTK_PACKAGE_TQFN + for (int i = 0; i < NUM_I2C; i++) { + if ((i2c_maps_extra[i].port == (MXC_GPIO_GET_GPIO(sda->port))) + && (i2c_maps_extra[i].mask == ((sda->mask) | (scl->mask)))) { + return i; + } + } + #endif + + mp_raise_ValueError_varg(MP_ERROR_TEXT("Invalid %q"), MP_QSTR_pins); + return -1; +} diff --git a/ports/analog/peripherals/max32690/max32_i2c.h b/ports/analog/peripherals/max32690/max32_i2c.h new file mode 100644 index 00000000000..b64cfd308dc --- /dev/null +++ b/ports/analog/peripherals/max32690/max32_i2c.h @@ -0,0 +1,16 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Brandon Hurst, Analog Devices, Inc. +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "i2c_regs.h" +#include "mxc_sys.h" +#include "i2c.h" +#include "peripherals/pins.h" + +#define NUM_I2C 3 + +int pinsToI2c(const mcu_pin_obj_t *sda, const mcu_pin_obj_t *scl); diff --git a/ports/analog/peripherals/max32690/max32_spi.c b/ports/analog/peripherals/max32690/max32_spi.c new file mode 100644 index 00000000000..c78fd64dbd7 --- /dev/null +++ b/ports/analog/peripherals/max32690/max32_spi.c @@ -0,0 +1,44 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Brandon Hurst, Analog Devices, Inc. +// +// SPDX-License-Identifier: MIT + +#include "peripherals/pins.h" + +#include "common-hal/busio/SPI.h" +#include "max32_spi.h" +#include "max32690.h" + +#include "py/runtime.h" +#include "py/mperrno.h" + +const mxc_gpio_cfg_t spi_maps[NUM_SPI] = { + // SPI0 + { MXC_GPIO2, (MXC_GPIO_PIN_27 | MXC_GPIO_PIN_28 | MXC_GPIO_PIN_29), + MXC_GPIO_FUNC_ALT2, MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, + // SPI1 + { MXC_GPIO1, (MXC_GPIO_PIN_26 | MXC_GPIO_PIN_28 | MXC_GPIO_PIN_29), + MXC_GPIO_FUNC_ALT1, MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, + // SPI2 + { MXC_GPIO2, (MXC_GPIO_PIN_2 | MXC_GPIO_PIN_3 | MXC_GPIO_PIN_4), + MXC_GPIO_FUNC_ALT1, MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, + // SPI3 + { MXC_GPIO0, (MXC_GPIO_PIN_16 | MXC_GPIO_PIN_20 | MXC_GPIO_PIN_21), + MXC_GPIO_FUNC_ALT1, MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, + // SPI4 + { MXC_GPIO1, (MXC_GPIO_PIN_1 | MXC_GPIO_PIN_2 | MXC_GPIO_PIN_3), + MXC_GPIO_FUNC_ALT1, MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, +}; + +int pinsToSpi(const mcu_pin_obj_t *mosi, const mcu_pin_obj_t *miso, + const mcu_pin_obj_t *sck) { + for (int i = 0; i < NUM_SPI; i++) { + if ((spi_maps[i].port == (MXC_GPIO_GET_GPIO(mosi->port))) + && (spi_maps[i].mask == ((mosi->mask) | (miso->mask) | (sck->mask)))) { + return i; + } + } + mp_raise_ValueError_varg(MP_ERROR_TEXT("Invalid %q"), MP_QSTR_pins); + return -1; +} diff --git a/ports/analog/peripherals/max32690/max32_spi.h b/ports/analog/peripherals/max32690/max32_spi.h new file mode 100644 index 00000000000..76bb48a59a7 --- /dev/null +++ b/ports/analog/peripherals/max32690/max32_spi.h @@ -0,0 +1,17 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Brandon Hurst, Analog Devices, Inc. +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "spi_regs.h" +#include "mxc_sys.h" +#include "spi.h" +#include "peripherals/pins.h" + +#define NUM_SPI 5 + +int pinsToSpi(const mcu_pin_obj_t *mosi, const mcu_pin_obj_t *miso, + const mcu_pin_obj_t *sck); diff --git a/ports/analog/peripherals/max32690/max32_uart.c b/ports/analog/peripherals/max32690/max32_uart.c new file mode 100644 index 00000000000..7d377087974 --- /dev/null +++ b/ports/analog/peripherals/max32690/max32_uart.c @@ -0,0 +1,36 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Brandon Hurst, Analog Devices, Inc. +// +// SPDX-License-Identifier: MIT + +#include "peripherals/pins.h" + +#include "common-hal/busio/UART.h" +#include "max32_uart.h" +#include "max32690.h" + +#include "py/runtime.h" +#include "py/mperrno.h" + +const mxc_gpio_cfg_t uart_maps[NUM_UARTS] = { + { MXC_GPIO2, (MXC_GPIO_PIN_11 | MXC_GPIO_PIN_12), MXC_GPIO_FUNC_ALT1, + MXC_GPIO_PAD_WEAK_PULL_UP, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, + { MXC_GPIO2, (MXC_GPIO_PIN_14 | MXC_GPIO_PIN_16), MXC_GPIO_FUNC_ALT1, + MXC_GPIO_PAD_WEAK_PULL_UP, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, + { MXC_GPIO1, (MXC_GPIO_PIN_9 | MXC_GPIO_PIN_10), MXC_GPIO_FUNC_ALT1, + MXC_GPIO_PAD_WEAK_PULL_UP, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, + { MXC_GPIO3, (MXC_GPIO_PIN_0 | MXC_GPIO_PIN_1), MXC_GPIO_FUNC_ALT2, + MXC_GPIO_PAD_WEAK_PULL_UP, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 } +}; + +int pinsToUart(const mcu_pin_obj_t *rx, const mcu_pin_obj_t *tx) { + for (int i = 0; i < NUM_UARTS; i++) { + if ((uart_maps[i].port == (MXC_GPIO_GET_GPIO(tx->port))) + && (uart_maps[i].mask == ((tx->mask) | (rx->mask)))) { + return i; + } + } + mp_raise_ValueError_varg(MP_ERROR_TEXT("Invalid %q"), MP_QSTR_pins); + return -1; +} diff --git a/ports/analog/peripherals/max32690/max32_uart.h b/ports/analog/peripherals/max32690/max32_uart.h new file mode 100644 index 00000000000..f03b500a3c5 --- /dev/null +++ b/ports/analog/peripherals/max32690/max32_uart.h @@ -0,0 +1,16 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Brandon Hurst, Analog Devices, Inc. +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "uart_regs.h" +#include "mxc_sys.h" +#include "uart.h" +#include "peripherals/pins.h" + +#define NUM_UARTS 4 + +int pinsToUart(const mcu_pin_obj_t *rx, const mcu_pin_obj_t *tx); diff --git a/ports/analog/supervisor/port.c b/ports/analog/supervisor/port.c index ad003c12ed9..e95deaba2a8 100644 --- a/ports/analog/supervisor/port.c +++ b/ports/analog/supervisor/port.c @@ -39,11 +39,15 @@ // Sys includes #include "max32_port.h" +#include "nvic_table.h" // Timers #include "mxc_delay.h" #include "rtc.h" +// true random number generator, TRNG +#include "trng.h" + // msec to RTC subsec ticks (4 kHz) /* Converts a time in milleseconds to equivalent RSSA register value */ #define MSEC_TO_SS_ALARM(x) (0 - ((x * 4096) / 1000)) @@ -63,18 +67,27 @@ 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; void SysTick_Handler(void) { system_ticks++; + + MXC_DelayHandler(); } safe_mode_t port_init(void) { int err = E_NO_ERROR; + // Set Vector Table to RAM & configure ARM core to use RAM-based ISRs + // This allows definition of ISRs with custom names + // + // Useful for mapping ISRs with names not related to a specific IRQn. + // Source: https://arm-software.github.io/CMSIS_5/Core/html/using_VTOR_pg.html + NVIC_SetRAM(); + // 1ms tick timer SysTick_Config(SystemCoreClock / 1000); NVIC_EnableIRQ(SysTick_IRQn); @@ -112,9 +125,18 @@ safe_mode_t port_init(void) { } ; + // enable TRNG (true random number generator) + #if CIRCUITPY_RANDOM + MXC_TRNG_Init(); + #endif + return SAFE_MODE_NONE; } +void TRNG_IRQHandler(void) { + MXC_TRNG_Handler(); +} + void RTC_IRQHandler(void) { // Read flags to clear int flags = MXC_RTC_GetFlags(); @@ -144,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/analog/tools/debug-dap.gdb b/ports/analog/tools/debug-dap.gdb new file mode 100644 index 00000000000..d0aa7e2b13f --- /dev/null +++ b/ports/analog/tools/debug-dap.gdb @@ -0,0 +1,3 @@ +target remote :3333 +break main +continue diff --git a/ports/analog/tools/debug-dap.sh b/ports/analog/tools/debug-dap.sh new file mode 100644 index 00000000000..df2964fcb12 --- /dev/null +++ b/ports/analog/tools/debug-dap.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +# Primer on taking cmd line args in Linux shell scripts +# $0 is the script itself +# $1 $2 $3 are arg1, arg2, arg3, etc + +# Export OCD Path +### USER ACTION: Replace with your path to OpenOCD ### +OCD_PATH="~/MaximSDK/Tools/OpenOCD" + +# Call openocd to setup the debug server, storing the PID for OpenOCD +sh -c "openocd -s $OCD_PATH/scripts -f interface/cmsis-dap.cfg -f target/$1.cfg -c \"init; reset halt\" " & + +# Allow enough time for OCD server to set up +# + wait for the sleep to finish +sleep 3 & +wait $! + +# spawn the gdb process and store the gdb_pid +gdb-multiarch build-apard32690/firmware.elf -x "tools/debug-dap.gdb" + +# when gdb exits, kill all openocd processes +killall openocd diff --git a/ports/analog/tools/flash_max32.jlink b/ports/analog/tools/flash_max32.jlink index 4c9cbacb96f..0453f4cb077 100644 --- a/ports/analog/tools/flash_max32.jlink +++ b/ports/analog/tools/flash_max32.jlink @@ -1,6 +1,7 @@ -si 1 +selectinterface swd erase -loadbin build-APARD/firmware.bin 0x10000000 -r -g +loadbin build-apard32690/firmware.bin 0x10000000 +reset +halt +go exit diff --git a/ports/atmel-samd/Makefile b/ports/atmel-samd/Makefile index 9582eff212d..0aaf6e3d849 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 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/audio_dma.c b/ports/atmel-samd/audio_dma.c index e25b74d9a28..e3980401506 100644 --- a/ports/atmel-samd/audio_dma.c +++ b/ports/atmel-samd/audio_dma.c @@ -39,14 +39,14 @@ uint8_t find_sync_event_channel_raise(void) { } void audio_dma_disable_channel(uint8_t channel) { - if (channel >= AUDIO_DMA_CHANNEL_COUNT) { + if (channel == NO_DMA_CHANNEL) { return; } dma_disable_channel(channel); } void audio_dma_enable_channel(uint8_t channel) { - if (channel >= AUDIO_DMA_CHANNEL_COUNT) { + if (channel == NO_DMA_CHANNEL) { return; } dma_enable_channel(channel); @@ -171,8 +171,8 @@ audio_dma_result audio_dma_setup_playback(audio_dma_t *dma, bool output_signed, uint32_t output_register_address, uint8_t dma_trigger_source) { - uint8_t dma_channel = dma_allocate_channel(true); - if (dma_channel >= AUDIO_DMA_CHANNEL_COUNT) { + uint8_t dma_channel = dma_allocate_audio_channel(); + if (dma_channel == NO_DMA_CHANNEL) { return AUDIO_DMA_DMA_BUSY; } @@ -298,14 +298,14 @@ audio_dma_result audio_dma_setup_playback(audio_dma_t *dma, void audio_dma_stop(audio_dma_t *dma) { uint8_t channel = dma->dma_channel; - if (channel < AUDIO_DMA_CHANNEL_COUNT) { + if (channel != NO_DMA_CHANNEL) { audio_dma_disable_channel(channel); disable_event_channel(dma->event_channel); MP_STATE_PORT(playing_audio)[channel] = NULL; audio_dma_state[channel] = NULL; dma_free_channel(dma->dma_channel); } - dma->dma_channel = AUDIO_DMA_CHANNEL_COUNT; + dma->dma_channel = NO_DMA_CHANNEL; dma->playing_in_progress = false; } @@ -318,7 +318,7 @@ void audio_dma_resume(audio_dma_t *dma) { } bool audio_dma_get_paused(audio_dma_t *dma) { - if (dma->dma_channel >= AUDIO_DMA_CHANNEL_COUNT) { + if (dma->dma_channel == NO_DMA_CHANNEL) { return false; } uint32_t status = dma_transfer_status(dma->dma_channel); @@ -327,7 +327,7 @@ bool audio_dma_get_paused(audio_dma_t *dma) { } void audio_dma_init(audio_dma_t *dma) { - dma->dma_channel = AUDIO_DMA_CHANNEL_COUNT; + dma->dma_channel = NO_DMA_CHANNEL; } void audio_dma_reset(void) { @@ -341,7 +341,7 @@ void audio_dma_reset(void) { } bool audio_dma_get_playing(audio_dma_t *dma) { - if (dma->dma_channel >= AUDIO_DMA_CHANNEL_COUNT) { + if (dma->dma_channel == NO_DMA_CHANNEL) { return false; } return dma->playing_in_progress; 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/bradanlanestudio_coin_m0/mpconfigboard.mk b/ports/atmel-samd/boards/bradanlanestudio_coin_m0/mpconfigboard.mk index 33165c8cfc5..9a2cdcd668e 100644 --- a/ports/atmel-samd/boards/bradanlanestudio_coin_m0/mpconfigboard.mk +++ b/ports/atmel-samd/boards/bradanlanestudio_coin_m0/mpconfigboard.mk @@ -18,7 +18,7 @@ CHIP_FAMILY = samd21 SPI_FLASH_FILESYSTEM = 1 EXTERNAL_FLASH_DEVICES = "W25Q32JVxQ" -LONGINT_IMPL = NONE +LONGINT_IMPL = MPZ # the M0 Coin has limited functionality and many modules can be eliminated @@ -26,7 +26,7 @@ LONGINT_IMPL = NONE # Disable modules that are unusable on this special-purpose board. -CIRCUITPY_FULL_BUILD = 0 +CIRCUITPY_FULL_BUILD = 1 CIRCUITPY_AUDIOIO = 1 CIRCUITPY_DISPLAYIO = 0 @@ -38,7 +38,8 @@ CIRCUITPY_ROTARYIO = 0 CIRCUITPY_RTC = 0 CIRCUITPY_USB_HID = 1 CIRCUITPY_USB_MIDI = 0 - +CIRCUITPY_NEOPIXEL_WRITE = 1 +CIRCUITPY_PIXELBUF = 1 # Include these Python libraries in firmware. FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_HID diff --git a/ports/atmel-samd/boards/circuitbrains_basic_m0/mpconfigboard.mk b/ports/atmel-samd/boards/circuitbrains_basic_m0/mpconfigboard.mk index 7c301e3ea96..121becc472d 100755 --- a/ports/atmel-samd/boards/circuitbrains_basic_m0/mpconfigboard.mk +++ b/ports/atmel-samd/boards/circuitbrains_basic_m0/mpconfigboard.mk @@ -11,4 +11,5 @@ EXTERNAL_FLASH_DEVICES = "W25Q32JVxQ" LONGINT_IMPL = MPZ CIRCUITPY_CODEOP = 0 -CIRCUITPY_JPEGIO = 0 +CIRCUITPY_ERRNO = 0 +CIRCUITPY_RAINBOWIO = 0 diff --git a/ports/atmel-samd/boards/feather_m0_express/mpconfigboard.mk b/ports/atmel-samd/boards/feather_m0_express/mpconfigboard.mk index 00418114841..1152fb4acc4 100644 --- a/ports/atmel-samd/boards/feather_m0_express/mpconfigboard.mk +++ b/ports/atmel-samd/boards/feather_m0_express/mpconfigboard.mk @@ -10,4 +10,6 @@ SPI_FLASH_FILESYSTEM = 1 EXTERNAL_FLASH_DEVICES = "S25FL216K, GD25Q16C, W25Q16JVxQ" LONGINT_IMPL = MPZ +CIRCUITPY_CODEOP = 0 +CIRCUITPY_ERRNO = 0 CIRCUITPY_RAINBOWIO = 0 diff --git a/ports/atmel-samd/boards/feather_m0_supersized/mpconfigboard.h b/ports/atmel-samd/boards/feather_m0_supersized/mpconfigboard.h index be48cb81055..8fdf20f186b 100644 --- a/ports/atmel-samd/boards/feather_m0_supersized/mpconfigboard.h +++ b/ports/atmel-samd/boards/feather_m0_supersized/mpconfigboard.h @@ -20,6 +20,8 @@ #define SPI_FLASH_SCK_PIN &pin_PA09 #define SPI_FLASH_CS_PIN &pin_PA13 +#define BOARD_HAS_CRYSTAL 1 + #define DEFAULT_I2C_BUS_SCL (&pin_PA23) #define DEFAULT_I2C_BUS_SDA (&pin_PA22) diff --git a/ports/atmel-samd/boards/feather_m0_supersized/mpconfigboard.mk b/ports/atmel-samd/boards/feather_m0_supersized/mpconfigboard.mk index 573a69bee32..dd58e8d1ce5 100644 --- a/ports/atmel-samd/boards/feather_m0_supersized/mpconfigboard.mk +++ b/ports/atmel-samd/boards/feather_m0_supersized/mpconfigboard.mk @@ -11,3 +11,5 @@ EXTERNAL_FLASH_DEVICES = "S25FL064L" LONGINT_IMPL = MPZ CIRCUITPY_CODEOP = 0 +CIRCUITPY_ERRNO = 0 +CIRCUITPY_RAINBOWIO = 0 diff --git a/ports/atmel-samd/boards/feather_m4_can/mpconfigboard.mk b/ports/atmel-samd/boards/feather_m4_can/mpconfigboard.mk index a7c18acba3c..ee414b6e214 100644 --- a/ports/atmel-samd/boards/feather_m4_can/mpconfigboard.mk +++ b/ports/atmel-samd/boards/feather_m4_can/mpconfigboard.mk @@ -17,6 +17,7 @@ CIRCUITPY_FLOPPYIO = 0 CIRCUITPY_GIFIO = 0 CIRCUITPY_I2CTARGET = 0 CIRCUITPY_JPEGIO = 0 +CIRCUITPY_PS2IO = 0 CIRCUITPY_SYNTHIO = 0 CIRCUITPY_LTO_PARTITION = one diff --git a/ports/atmel-samd/boards/feather_m4_express/mpconfigboard.mk b/ports/atmel-samd/boards/feather_m4_express/mpconfigboard.mk index 4958581056e..f780ea4aa3d 100644 --- a/ports/atmel-samd/boards/feather_m4_express/mpconfigboard.mk +++ b/ports/atmel-samd/boards/feather_m4_express/mpconfigboard.mk @@ -14,6 +14,7 @@ CIRCUITPY__EVE = 1 CIRCUITPY_CODEOP = 0 CIRCUITPY_FLOPPYIO = 0 CIRCUITPY_JPEGIO = 0 +CIRCUITPY_MSGPACK = 0 CIRCUITPY_SYNTHIO = 0 CIRCUITPY_VECTORIO = 0 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 3dbef7c576a..76c60b44646 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_MSGPACK = 0 CIRCUITPY_PARALLELDISPLAYBUS = 0 CIRCUITPY_RGBMATRIX = 0 CIRCUITPY_SHARPDISPLAY = 0 diff --git a/ports/atmel-samd/boards/itsybitsy_m4_express/mpconfigboard.mk b/ports/atmel-samd/boards/itsybitsy_m4_express/mpconfigboard.mk index 27bf8c165da..be22cb94fae 100644 --- a/ports/atmel-samd/boards/itsybitsy_m4_express/mpconfigboard.mk +++ b/ports/atmel-samd/boards/itsybitsy_m4_express/mpconfigboard.mk @@ -10,11 +10,13 @@ QSPI_FLASH_FILESYSTEM = 1 EXTERNAL_FLASH_DEVICES = "GD25Q16C,W25Q16JVxQ" LONGINT_IMPL = MPZ +CIRCUITPY__EVE = 1 CIRCUITPY_CODEOP = 0 CIRCUITPY_FLOPPYIO = 0 -CIRCUITPY_GIFIO = 0 CIRCUITPY_JPEGIO = 0 -CIRCUITPY_TILEPALETTEMAPPER = 0 +CIRCUITPY_MSGPACK = 0 +CIRCUITPY_SYNTHIO = 0 +CIRCUITPY_VECTORIO = 0 CIRCUITPY_BITBANG_APA102 = 1 diff --git a/ports/atmel-samd/boards/metro_m0_express/mpconfigboard.mk b/ports/atmel-samd/boards/metro_m0_express/mpconfigboard.mk index d758d6878fb..d4801359cf8 100644 --- a/ports/atmel-samd/boards/metro_m0_express/mpconfigboard.mk +++ b/ports/atmel-samd/boards/metro_m0_express/mpconfigboard.mk @@ -11,4 +11,5 @@ EXTERNAL_FLASH_DEVICES = "S25FL216K, GD25Q16C, W25Q16JVxQ" LONGINT_IMPL = MPZ CIRCUITPY_CODEOP = 0 +CIRCUITPY_ERRNO = 0 CIRCUITPY_RAINBOWIO = 0 diff --git a/ports/atmel-samd/boards/metro_m4_airlift_lite/mpconfigboard.mk b/ports/atmel-samd/boards/metro_m4_airlift_lite/mpconfigboard.mk index 69cd5b0e286..cb7e690c6c0 100644 --- a/ports/atmel-samd/boards/metro_m4_airlift_lite/mpconfigboard.mk +++ b/ports/atmel-samd/boards/metro_m4_airlift_lite/mpconfigboard.mk @@ -11,9 +11,13 @@ EXTERNAL_FLASH_DEVICES = "S25FL116K, S25FL216K, GD25Q16C, W25Q16JVxQ" LONGINT_IMPL = MPZ CIRCUITPY__EVE = 0 +CIRCUITPY_CODEOP = 0 CIRCUITPY_FLOPPYIO = 0 CIRCUITPY_JPEGIO = 0 +CIRCUITPY_MSGPACK = 0 CIRCUITPY_SYNTHIO = 0 +CIRCUITPY_VECTORIO = 0 + # We don't have room for the fonts for terminalio for certain languages, # so turn off terminalio, and if it's off and displayio is on, diff --git a/ports/atmel-samd/boards/metro_m4_express/mpconfigboard.mk b/ports/atmel-samd/boards/metro_m4_express/mpconfigboard.mk index 55a307ed4e3..d5aef01a037 100644 --- a/ports/atmel-samd/boards/metro_m4_express/mpconfigboard.mk +++ b/ports/atmel-samd/boards/metro_m4_express/mpconfigboard.mk @@ -14,6 +14,7 @@ CIRCUITPY__EVE = 1 CIRCUITPY_CODEOP = 0 CIRCUITPY_FLOPPYIO = 0 CIRCUITPY_JPEGIO = 0 +CIRCUITPY_MSGPACK = 0 CIRCUITPY_SYNTHIO = 0 CIRCUITPY_VECTORIO = 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/mini_sam_m4/mpconfigboard.mk b/ports/atmel-samd/boards/mini_sam_m4/mpconfigboard.mk index 73c56fb5fba..8fae53c0101 100644 --- a/ports/atmel-samd/boards/mini_sam_m4/mpconfigboard.mk +++ b/ports/atmel-samd/boards/mini_sam_m4/mpconfigboard.mk @@ -10,9 +10,13 @@ QSPI_FLASH_FILESYSTEM = 1 EXTERNAL_FLASH_DEVICES = "W25Q16JVxM, W25Q16JVxQ" LONGINT_IMPL = MPZ +CIRCUITPY__EVE = 1 +CIRCUITPY_CODEOP = 0 CIRCUITPY_FLOPPYIO = 0 CIRCUITPY_JPEGIO = 0 +CIRCUITPY_MSGPACK = 0 CIRCUITPY_SYNTHIO = 0 +CIRCUITPY_VECTORIO = 0 CIRCUITPY_BITBANG_APA102 = 1 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 3ad2e162ecf..ebabfb84e9b 100644 --- a/ports/atmel-samd/boards/openbook_m4/board.c +++ b/ports/atmel-samd/boards/openbook_m4/board.c @@ -44,50 +44,33 @@ 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 epaperdisplay_epaperdisplay_obj_t *display = &allocate_display()->epaper_display; display->base.type = &epaperdisplay_epaperdisplay_type; - common_hal_epaperdisplay_epaperdisplay_construct(display, - bus, - start_sequence, - sizeof(start_sequence), - 0, // start up time - stop_sequence, - sizeof(stop_sequence), - 300, // width - 400, // height - 300, // RAM width - 400, // RAM height - 0, // colstart - 0, // rowstart - 270, // rotation - NO_COMMAND, // set_column_window_command - NO_COMMAND, // set_row_window_command - NO_COMMAND, // set_current_column_command - NO_COMMAND, // set_current_row_command - 0x13, // write_black_ram_command - false, // black_bits_inverted - NO_COMMAND, // write_color_ram_command (can add this for grayscale eventually) - false, // color_bits_inverted - 0x000000, // highlight_color - refresh_sequence, // refresh_display_sequence - sizeof(refresh_sequence), - 40, // refresh_time - &pin_PA01, // busy_pin - false, // busy_state - 5, // seconds_per_frame - false, // chip_select (don't always toggle chip select) - false, // grayscale - false, // acep - false, // spectra6 - false, // two_byte_sequence_length - false); // address_little_endian + 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 = 300; + args.height = 400; + args.ram_width = 300; + args.ram_height = 400; + args.rotation = 270; + args.write_black_ram_command = 0x13; + args.refresh_sequence = refresh_sequence; + args.refresh_sequence_len = sizeof(refresh_sequence); + args.refresh_time = 40.0; + args.busy_pin = &pin_PA01; + args.seconds_per_frame = 5.0; + common_hal_epaperdisplay_epaperdisplay_construct(display, &args); } // Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. 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/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/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/seeeduino_wio_terminal/mpconfigboard.mk b/ports/atmel-samd/boards/seeeduino_wio_terminal/mpconfigboard.mk index dd8afd51f6e..4ade6a14831 100644 --- a/ports/atmel-samd/boards/seeeduino_wio_terminal/mpconfigboard.mk +++ b/ports/atmel-samd/boards/seeeduino_wio_terminal/mpconfigboard.mk @@ -9,6 +9,14 @@ CHIP_FAMILY = samd51 QSPI_FLASH_FILESYSTEM = 1 EXTERNAL_FLASH_DEVICES = "W25Q32JVxQ" LONGINT_IMPL = MPZ + +CIRCUITPY__EVE = 1 +CIRCUITPY_CODEOP = 0 CIRCUITPY_FLOPPYIO = 0 -CIRCUITPY_FRAMEBUFFERIO = 0 +CIRCUITPY_JPEGIO = 0 +CIRCUITPY_MSGPACK = 0 +CIRCUITPY_PARALLELDISPLAYBUS = 0 +CIRCUITPY_RGBMATRIX = 0 +CIRCUITPY_SHARPDISPLAY = 0 CIRCUITPY_SYNTHIO = 0 +CIRCUITPY_VECTORIO = 0 diff --git a/ports/atmel-samd/boards/snekboard/mpconfigboard.mk b/ports/atmel-samd/boards/snekboard/mpconfigboard.mk index d19e606319b..441853c554d 100644 --- a/ports/atmel-samd/boards/snekboard/mpconfigboard.mk +++ b/ports/atmel-samd/boards/snekboard/mpconfigboard.mk @@ -9,3 +9,6 @@ CHIP_FAMILY = samd21 SPI_FLASH_FILESYSTEM = 1 EXTERNAL_FLASH_DEVICES = "W25Q16JVxQ" LONGINT_IMPL = MPZ + +CIRCUITPY_CODEOP = 0 +CIRCUITPY_RAINBOWIO = 0 diff --git a/ports/atmel-samd/boards/sparkfun_redboard_turbo/mpconfigboard.mk b/ports/atmel-samd/boards/sparkfun_redboard_turbo/mpconfigboard.mk index 64049e8d598..b34dfb3d2e6 100755 --- a/ports/atmel-samd/boards/sparkfun_redboard_turbo/mpconfigboard.mk +++ b/ports/atmel-samd/boards/sparkfun_redboard_turbo/mpconfigboard.mk @@ -11,4 +11,5 @@ EXTERNAL_FLASH_DEVICES = "W25Q32FV" LONGINT_IMPL = MPZ CIRCUITPY_CODEOP = 0 +CIRCUITPY_ERRNO = 0 CIRCUITPY_RAINBOWIO = 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..38ef58bea76 100644 --- a/ports/atmel-samd/common-hal/alarm/__init__.c +++ b/ports/atmel-samd/common-hal/alarm/__init__.c @@ -133,7 +133,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(); 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/PDMIn.c b/ports/atmel-samd/common-hal/audiobusio/PDMIn.c index a1a67d04082..f409563f5ed 100644 --- a/ports/atmel-samd/common-hal/audiobusio/PDMIn.c +++ b/ports/atmel-samd/common-hal/audiobusio/PDMIn.c @@ -364,7 +364,7 @@ static uint16_t filter_sample(uint32_t pdm_samples[4]) { // output_buffer_length is the number of slots, not the number of bytes. uint32_t common_hal_audiobusio_pdmin_record_to_buffer(audiobusio_pdmin_obj_t *self, uint16_t *output_buffer, uint32_t output_buffer_length) { - uint8_t dma_channel = dma_allocate_channel(true); + uint8_t dma_channel = dma_allocate_audio_channel(); pdmin_event_channel = find_sync_event_channel_raise(); pdmin_dma_block_done = false; diff --git a/ports/atmel-samd/common-hal/busio/I2C.c b/ports/atmel-samd/common-hal/busio/I2C.c index e13b5410ae3..d9da050dabe 100644 --- a/ports/atmel-samd/common-hal/busio/I2C.c +++ b/ports/atmel-samd/common-hal/busio/I2C.c @@ -135,6 +135,7 @@ void common_hal_busio_i2c_deinit(busio_i2c_obj_t *self) { if (common_hal_busio_i2c_deinited(self)) { return; } + allow_reset_sercom(self->i2c_desc.device.hw); i2c_m_sync_disable(&self->i2c_desc); i2c_m_sync_deinit(&self->i2c_desc); @@ -175,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; @@ -196,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; @@ -227,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 5d7633be7f8..19fd81e425d 100644 --- a/ports/atmel-samd/common-hal/busio/SPI.c +++ b/ports/atmel-samd/common-hal/busio/SPI.c @@ -21,7 +21,17 @@ #include "samd/dma.h" #include "samd/sercom.h" -void setup_pin(const mcu_pin_obj_t *pin, uint32_t pinmux); + +static void setup_pin(const mcu_pin_obj_t *pin, uint32_t pinmux, const enum gpio_direction direction) { + gpio_set_pin_direction(pin->number, direction); + gpio_set_pin_pull_mode(pin->number, GPIO_PULL_OFF); + gpio_set_pin_function(pin->number, pinmux); + if (direction == GPIO_DIRECTION_OUT) { + // Use strong drive strength for SPI outputs. + hri_port_set_PINCFG_DRVSTR_bit(PORT, (enum gpio_port)GPIO_PORT(pin->number), GPIO_PIN(pin->number)); + } + claim_pin(pin); +} void common_hal_busio_spi_construct(busio_spi_obj_t *self, const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi, @@ -43,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) @@ -128,6 +138,7 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, // Pads must be set after spi_m_sync_init(), which uses default values from // the prototypical SERCOM. + // Set to SPI host mode and choose pads. hri_sercomspi_write_CTRLA_MODE_bf(sercom, 3); hri_sercomspi_write_CTRLA_DOPO_bf(sercom, dopo); hri_sercomspi_write_CTRLA_DIPO_bf(sercom, miso_pad); @@ -141,20 +152,20 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, mp_raise_OSError(MP_EIO); } - setup_pin(clock, clock_pinmux); + setup_pin(clock, clock_pinmux, GPIO_DIRECTION_OUT); self->clock_pin = clock->number; if (mosi_none) { self->MOSI_pin = NO_PIN; } else { - setup_pin(mosi, mosi_pinmux); + setup_pin(mosi, mosi_pinmux, GPIO_DIRECTION_OUT); self->MOSI_pin = mosi->number; } if (miso_none) { self->MISO_pin = NO_PIN; } else { - setup_pin(miso, miso_pinmux); + setup_pin(miso, miso_pinmux, GPIO_DIRECTION_IN); self->MISO_pin = miso->number; } @@ -173,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; @@ -184,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, @@ -317,11 +334,3 @@ uint8_t common_hal_busio_spi_get_polarity(busio_spi_obj_t *self) { void *hw = self->spi_desc.dev.prvt; return hri_sercomspi_get_CTRLA_CPOL_bit(hw); } - -void setup_pin(const mcu_pin_obj_t *pin, uint32_t pinmux) { - gpio_set_pin_direction(pin->number, GPIO_DIRECTION_OUT); - gpio_set_pin_pull_mode(pin->number, GPIO_PULL_OFF); - gpio_set_pin_function(pin->number, pinmux); - claim_pin(pin); - hri_port_set_PINCFG_DRVSTR_bit(PORT, (enum gpio_port)GPIO_PORT(pin->number), GPIO_PIN(pin->number)); -} diff --git a/ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c b/ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c index a6d8fef0f39..56eb82678ec 100644 --- a/ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c +++ b/ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c @@ -135,7 +135,8 @@ void common_hal_imagecapture_parallelimagecapture_singleshot_capture(imagecaptur mp_buffer_info_t bufinfo; mp_get_buffer_raise(buffer, &bufinfo, MP_BUFFER_RW); - uint8_t dma_channel = dma_allocate_channel(true); + // Allocate a permanent channel (not really audio). + uint8_t dma_channel = dma_allocate_audio_channel(); uint32_t *dest = bufinfo.buf; size_t count = bufinfo.len / 4; // PCC receives 4 bytes (2 pixels) at a time diff --git a/ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c b/ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c index c6cd4605784..a8c87d82ed2 100644 --- a/ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c +++ b/ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c @@ -17,6 +17,10 @@ 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); + if (!pin_a->has_extint) { raise_ValueError_invalid_pin_name(MP_QSTR_pin_a); } @@ -83,10 +87,13 @@ void common_hal_rotaryio_incrementalencoder_deinit(rotaryio_incrementalencoder_o turn_off_eic_channel(self->eic_channel_b); reset_pin_number(self->pin_a); - self->pin_a = NO_PIN; - reset_pin_number(self->pin_b); - self->pin_b = NO_PIN; + + common_hal_rotaryio_incrementalencoder_mark_deinit(self); +} + +void common_hal_rotaryio_incrementalencoder_mark_deinit(rotaryio_incrementalencoder_obj_t *self) { + self->pin_a = NO_PIN; } void incrementalencoder_interrupt_handler(uint8_t channel) { 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/common-hal/spitarget/SPITarget.c b/ports/atmel-samd/common-hal/spitarget/SPITarget.c index b9062911cc3..e5011b141fc 100644 --- a/ports/atmel-samd/common-hal/spitarget/SPITarget.c +++ b/ports/atmel-samd/common-hal/spitarget/SPITarget.c @@ -192,7 +192,7 @@ void common_hal_spitarget_spi_target_transfer_start(spitarget_spi_target_obj_t * self->miso_packet = miso_packet; Sercom *sercom = self->spi_desc.dev.prvt; - self->running_dma = shared_dma_transfer_start(sercom, miso_packet, &sercom->SPI.DATA.reg, &sercom->SPI.DATA.reg, mosi_packet, len, 0); + shared_dma_transfer_start(&self->running_dma, sercom, miso_packet, &sercom->SPI.DATA.reg, &sercom->SPI.DATA.reg, mosi_packet, len, 0); // There is an issue where if an unexpected SPI transfer is received before the user calls "end" for the in-progress, expected // transfer, the SERCOM has an error and gets confused. This can be detected from INTFLAG.ERROR. I think the code in @@ -200,7 +200,7 @@ void common_hal_spitarget_spi_target_transfer_start(spitarget_spi_target_obj_t * // s->SPI.DATA.reg) is supposed to fix this, but experimentation seems to show that it does not in fact fix anything. Anyways, if // the ERROR bit is set, let's just reset the peripheral and then setup the transfer again -- that seems to work. if (hri_sercomspi_get_INTFLAG_ERROR_bit(sercom)) { - shared_dma_transfer_close(self->running_dma); + shared_dma_transfer_close(&self->running_dma); // disable the sercom spi_m_sync_disable(&self->spi_desc); @@ -223,19 +223,19 @@ void common_hal_spitarget_spi_target_transfer_start(spitarget_spi_target_obj_t * spi_m_sync_enable(&self->spi_desc); hri_sercomspi_wait_for_sync(sercom, SERCOM_SPI_SYNCBUSY_MASK); - self->running_dma = shared_dma_transfer_start(sercom, miso_packet, &sercom->SPI.DATA.reg, &sercom->SPI.DATA.reg, mosi_packet, len, 0); + shared_dma_transfer_start(&self->running_dma, sercom, miso_packet, &sercom->SPI.DATA.reg, &sercom->SPI.DATA.reg, mosi_packet, len, 0); } } bool common_hal_spitarget_spi_target_transfer_is_finished(spitarget_spi_target_obj_t *self) { - return self->running_dma.failure == 1 || shared_dma_transfer_finished(self->running_dma); + return self->running_dma.failure == 1 || shared_dma_transfer_finished(&self->running_dma); } int common_hal_spitarget_spi_target_transfer_close(spitarget_spi_target_obj_t *self) { if (self->running_dma.failure == 1) { return 0; } - int res = shared_dma_transfer_close(self->running_dma); + int res = shared_dma_transfer_close(&self->running_dma); self->running_dma.failure = 1; self->mosi_packet = NULL; diff --git a/ports/atmel-samd/common-hal/spitarget/SPITarget.h b/ports/atmel-samd/common-hal/spitarget/SPITarget.h index 50f2bcb3309..9fff23c1743 100644 --- a/ports/atmel-samd/common-hal/spitarget/SPITarget.h +++ b/ports/atmel-samd/common-hal/spitarget/SPITarget.h @@ -18,7 +18,7 @@ typedef struct { uint8_t *mosi_packet; const uint8_t *miso_packet; - dma_descr_t running_dma; + dma_transfer_t running_dma; } spitarget_spi_target_obj_t; #endif // MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_BUSIO_SPI_TARGET_H diff --git a/ports/atmel-samd/mpconfigport.mk b/ports/atmel-samd/mpconfigport.mk index 861ef374646..b0947ea6f25 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 diff --git a/ports/atmel-samd/peripherals b/ports/atmel-samd/peripherals index d3210221bbd..da0a1d7dccb 160000 --- a/ports/atmel-samd/peripherals +++ b/ports/atmel-samd/peripherals @@ -1 +1 @@ -Subproject commit d3210221bbd018ae9d0183ea4640c42cf4bce672 +Subproject commit da0a1d7dccb34b7fa07738e7a8ce25118c88d1a3 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/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..6c49e0f2750 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,6 +65,10 @@ 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; 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/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 3bcb2528687..ec606a76547 100644 --- a/ports/cxd56/mpconfigport.h +++ b/ports/cxd56/mpconfigport.h @@ -8,6 +8,9 @@ #define MICROPY_PY_SYS_PLATFORM "CXD56" +// SD card socket on board is configured for sdioio, which is not supported for automatic USB presentation. +#define CIRCUITPY_SDCARD_USB (0) + // 64kiB stack #define CIRCUITPY_DEFAULT_STACK_SIZE (0x10000) @@ -20,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..ca70127565f 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,201 @@ 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),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 @@ -350,6 +567,8 @@ else ifeq ($(IDF_TARGET),esp32c3) CFLAGS += -DCFG_TUSB_MCU=OPT_MCU_ESP32C3 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 +639,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 +654,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 +769,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 +776,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,17 +843,19 @@ 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 + +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);$(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) \ @@ -662,7 +892,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 +903,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 @@ -682,6 +913,7 @@ ifneq ($(CIRCUITPY_BLEIO_NATIVE),0) BLE_IMPL_esp32c2 := libble BLE_IMPL_esp32c3 := esp32c3 BLE_IMPL_esp32c6 := libble + BLE_IMPL_esp32c61 := libble BLE_IMPL_esp32h2 := libble BLE_IMPL = $(BLE_IMPL_$(IDF_TARGET)) @@ -700,8 +932,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 +951,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 @@ -769,6 +1008,8 @@ else ifeq ($(IDF_TARGET),esp32c3) BOOTLOADER_OFFSET = 0x0 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 +1023,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 +1048,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 +1070,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 +1089,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 63174fd1670..fe5542aafe4 100644 --- a/ports/espressif/README.rst +++ b/ports/espressif/README.rst @@ -222,4 +222,3 @@ And follow the Espressif GDB tutorial `instructions for connecting `_ +//| +//| **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.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_reverse_tft/mpconfigboard.h b/ports/espressif/boards/adafruit_feather_esp32s2_reverse_tft/mpconfigboard.h index 42b51434edf..f2ec187abde 100644 --- a/ports/espressif/boards/adafruit_feather_esp32s2_reverse_tft/mpconfigboard.h +++ b/ports/espressif/boards/adafruit_feather_esp32s2_reverse_tft/mpconfigboard.h @@ -23,7 +23,7 @@ #define DEFAULT_SPI_BUS_MOSI (&pin_GPIO35) #define DEFAULT_SPI_BUS_MISO (&pin_GPIO37) -#define DEFAULT_UART_BUS_RX (&pin_GPIO34) -#define DEFAULT_UART_BUS_TX (&pin_GPIO35) +#define DEFAULT_UART_BUS_RX (&pin_GPIO38) +#define DEFAULT_UART_BUS_TX (&pin_GPIO39) #define DOUBLE_TAP_PIN (&pin_GPIO34) diff --git a/ports/espressif/boards/adafruit_feather_esp32s2_reverse_tft/mpconfigboard.mk b/ports/espressif/boards/adafruit_feather_esp32s2_reverse_tft/mpconfigboard.mk index 06a1bf706d3..a0be8c7a5ca 100644 --- a/ports/espressif/boards/adafruit_feather_esp32s2_reverse_tft/mpconfigboard.mk +++ b/ports/espressif/boards/adafruit_feather_esp32s2_reverse_tft/mpconfigboard.mk @@ -13,3 +13,6 @@ CIRCUITPY_ESP_FLASH_SIZE = 4MB CIRCUITPY_ESP_PSRAM_SIZE = 2MB CIRCUITPY_ESP_PSRAM_MODE = qio CIRCUITPY_ESP_PSRAM_FREQ = 80m + +# Already have a display. +CIRCUITPY_PARALLELDISPLAYBUS = 0 diff --git a/ports/espressif/boards/adafruit_feather_esp32s2_reverse_tft/sdkconfig b/ports/espressif/boards/adafruit_feather_esp32s2_reverse_tft/sdkconfig index e69de29bb2d..e9628662160 100644 --- a/ports/espressif/boards/adafruit_feather_esp32s2_reverse_tft/sdkconfig +++ b/ports/espressif/boards/adafruit_feather_esp32s2_reverse_tft/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/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_reverse_tft/mpconfigboard.h b/ports/espressif/boards/adafruit_feather_esp32s3_reverse_tft/mpconfigboard.h index c11780faf41..5053a1b2b58 100644 --- a/ports/espressif/boards/adafruit_feather_esp32s3_reverse_tft/mpconfigboard.h +++ b/ports/espressif/boards/adafruit_feather_esp32s3_reverse_tft/mpconfigboard.h @@ -23,7 +23,7 @@ #define DEFAULT_SPI_BUS_MOSI (&pin_GPIO35) #define DEFAULT_SPI_BUS_MISO (&pin_GPIO37) -#define DEFAULT_UART_BUS_RX (&pin_GPIO34) -#define DEFAULT_UART_BUS_TX (&pin_GPIO35) +#define DEFAULT_UART_BUS_RX (&pin_GPIO38) +#define DEFAULT_UART_BUS_TX (&pin_GPIO39) #define DOUBLE_TAP_PIN (&pin_GPIO34) 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 6d4fcbf135e..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,74 +298,61 @@ void board_init(void) { epaperdisplay_epaperdisplay_obj_t *display = &allocate_display()->epaper_display; display->base.type = &epaperdisplay_epaperdisplay_type; - if (is_ssd1680) { - common_hal_epaperdisplay_epaperdisplay_construct( - display, - bus, - ssd1680_display_start_sequence, sizeof(ssd1680_display_start_sequence), - 0, // start up time - ssd1680_display_stop_sequence, sizeof(ssd1680_display_stop_sequence), - 296, // width - 128, // height - 250, // ram_width - 296, // ram_height - 0, // colstart - 0, // rowstart - 270, // rotation - 0x44, // set_column_window_command - 0x45, // set_row_window_command - 0x4e, // set_current_column_command - 0x4f, // set_current_row_command - 0x24, // write_black_ram_command - false, // black_bits_inverted - 0x26, // write_color_ram_command - false, // color_bits_inverted - 0x000000, // highlight_color - ssd1680_display_refresh_sequence, sizeof(ssd1680_display_refresh_sequence), - 1.0, // refresh_time - &pin_GPIO5, // busy_pin - true, // busy_state - 5.0, // seconds_per_frame - false, // always_toggle_chip_select - true, // grayscale - false, // acep - false, // spectra6 - true, // two_byte_sequence_length - true); // address_little_endian + 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 { - common_hal_epaperdisplay_epaperdisplay_construct( - display, - bus, - il0373_display_start_sequence, sizeof(il0373_display_start_sequence), - 0, // start up time - il0373_display_stop_sequence, sizeof(il0373_display_stop_sequence), - 296, // width - 128, // height - 160, // ram_width - 296, // ram_height - 0, // colstart - 0, // rowstart - 270, // rotation - NO_COMMAND, // set_column_window_command - NO_COMMAND, // set_row_window_command - NO_COMMAND, // set_current_column_command - NO_COMMAND, // set_current_row_command - 0x10, // write_black_ram_command - false, // black_bits_inverted - 0x13, // write_color_ram_command - false, // color_bits_inverted - 0x000000, // highlight_color - il0373_display_refresh_sequence, sizeof(il0373_display_refresh_sequence), - 1.0, // refresh_time - &pin_GPIO5, // busy_pin - false, // busy_state - 5.0, // seconds_per_frame - false, // always_toggle_chip_select - true, // grayscale - false, // acep - false, // spectra6 - false, // two_byte_sequence_length - false); // address_little_endian + epaperdisplay_construct_args_t args = EPAPERDISPLAY_CONSTRUCT_ARGS_DEFAULTS; + args.bus = bus; + 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; + args.height = 128; + 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.refresh_sequence = ssd1680_display_refresh_sequence; + args.refresh_sequence_len = sizeof(ssd1680_display_refresh_sequence); + args.refresh_time = 1.0; + args.busy_pin = &pin_GPIO5; + args.busy_state = true; + args.seconds_per_frame = 5.0; + args.grayscale = true; + args.two_byte_sequence_length = true; + args.address_little_endian = 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_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 515b6da5c07..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,4 +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/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 88150dd401b..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,49 +56,37 @@ 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 -// Set up the DisplayIO epaper object + // Set up the DisplayIO epaper object epaperdisplay_epaperdisplay_obj_t *display = &allocate_display()->epaper_display; display->base.type = &epaperdisplay_epaperdisplay_type; - common_hal_epaperdisplay_epaperdisplay_construct( - display, - bus, - display_start_sequence, sizeof(display_start_sequence), - 1, // start up time - display_stop_sequence, sizeof(display_stop_sequence), - 400, // width - 300, // height - 400, // ram_width - 300, // ram_height - 0, // colstart - 0, // rowstart - 0, // rotation - NO_COMMAND, // set_column_window_command - NO_COMMAND, // set_row_window_command - NO_COMMAND, // set_current_column_command - NO_COMMAND, // set_current_row_command - 0x24, // write_black_ram_command - false, // black_bits_inverted - 0x26, // write_color_ram_command - false, // color_bits_inverted - 0x000000, // highlight_color - refresh_sequence, sizeof(refresh_sequence), // refresh_display_command - 1.0, // refresh_time - &pin_GPIO48, // busy_pin - true, // busy_state - 2.0, // seconds_per_frame - false, // always_toggle_chip_select - false, // grayscale - false, // acep - false, // spectra6 - false, // two_byte_sequence_length - false); // address_little_endian + + epaperdisplay_construct_args_t args = EPAPERDISPLAY_CONSTRUCT_ARGS_DEFAULTS; + args.bus = bus; + args.start_sequence = display_start_sequence; + args.start_sequence_len = sizeof(display_start_sequence); + args.start_up_time = 1.0; + args.stop_sequence = display_stop_sequence; + args.stop_sequence_len = sizeof(display_stop_sequence); + args.width = 400; + args.height = 300; + args.ram_width = 400; + args.ram_height = 300; + args.write_black_ram_command = 0x24; + args.write_color_ram_command = 0x26; + args.refresh_sequence = refresh_sequence; + args.refresh_sequence_len = sizeof(refresh_sequence); + args.refresh_time = 1.0; + args.busy_pin = &pin_GPIO48; + args.busy_state = true; + args.seconds_per_frame = 2.0; + common_hal_epaperdisplay_epaperdisplay_construct(display, &args); } void board_deinit(void) { diff --git a/ports/espressif/boards/espressif_esp32c3_lyra_v2/board.c b/ports/espressif/boards/espressif_esp32c3_lyra_v2/board.c new file mode 100644 index 00000000000..b3b20cfe2d3 --- /dev/null +++ b/ports/espressif/boards/espressif_esp32c3_lyra_v2/board.c @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 microDev +// +// 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_esp32c3_lyra_v2/mpconfigboard.h b/ports/espressif/boards/espressif_esp32c3_lyra_v2/mpconfigboard.h new file mode 100644 index 00000000000..d38d4f4d09f --- /dev/null +++ b/ports/espressif/boards/espressif_esp32c3_lyra_v2/mpconfigboard.h @@ -0,0 +1,23 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 microDev +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Board setup +#define MICROPY_HW_BOARD_NAME "ESP32-C3-Lyra-V2" +#define MICROPY_HW_MCU_NAME "ESP32-C3N4" + +// Status LED +#define MICROPY_HW_NEOPIXEL (&pin_GPIO10) +#define MICROPY_HW_NEOPIXEL_COUNT (1) + +// Default bus pins +#define DEFAULT_UART_BUS_RX (&pin_GPIO20) +#define DEFAULT_UART_BUS_TX (&pin_GPIO21) + +// Serial over UART +#define CIRCUITPY_CONSOLE_UART_RX DEFAULT_UART_BUS_RX +#define CIRCUITPY_CONSOLE_UART_TX DEFAULT_UART_BUS_TX diff --git a/ports/espressif/boards/espressif_esp32c3_lyra_v2/mpconfigboard.mk b/ports/espressif/boards/espressif_esp32c3_lyra_v2/mpconfigboard.mk new file mode 100644 index 00000000000..4b23a76ba6a --- /dev/null +++ b/ports/espressif/boards/espressif_esp32c3_lyra_v2/mpconfigboard.mk @@ -0,0 +1,10 @@ +CIRCUITPY_CREATOR_ID = 0x000C303A +CIRCUITPY_CREATION_ID = 0x00C3A000 + +IDF_TARGET = esp32c3 + +CIRCUITPY_ESP_FLASH_MODE = qio +CIRCUITPY_ESP_FLASH_FREQ = 80m +CIRCUITPY_ESP_FLASH_SIZE = 4MB + +CIRCUITPY_ESP_USB_SERIAL_JTAG = 0 diff --git a/ports/espressif/boards/espressif_esp32c3_lyra_v2/pins.c b/ports/espressif/boards/espressif_esp32c3_lyra_v2/pins.c new file mode 100644 index 00000000000..5f7c3d084dd --- /dev/null +++ b/ports/espressif/boards/espressif_esp32c3_lyra_v2/pins.c @@ -0,0 +1,41 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 microDev +// +// 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_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_BUTTON), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), 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/tests/feature_check/io_module.py.exp b/ports/espressif/boards/espressif_esp32c3_lyra_v2/sdkconfig similarity index 100% rename from tests/feature_check/io_module.py.exp rename to ports/espressif/boards/espressif_esp32c3_lyra_v2/sdkconfig 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_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 e392f65a764..5a102c7119b 100644 --- a/ports/espressif/boards/heltec_vision_master_e290/board.c +++ b/ports/espressif/boards/heltec_vision_master_e290/board.c @@ -54,49 +54,44 @@ 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 -// Set up the DisplayIO epaper object + // Set up the DisplayIO epaper object epaperdisplay_epaperdisplay_obj_t *display = &allocate_display()->epaper_display; display->base.type = &epaperdisplay_epaperdisplay_type; - common_hal_epaperdisplay_epaperdisplay_construct( - display, - bus, - display_start_sequence, sizeof(display_start_sequence), - 0, // start up time - display_stop_sequence, sizeof(display_stop_sequence), - 296, // width - 128, // height - 250, // ram_width - 296, // ram_height - 8, // colstart - 0, // rowstart - 90, // rotation - 0x44, // set_column_window_command - 0x45, // set_row_window_command - 0x4E, // set_current_column_command - 0x4F, // set_current_row_command - 0x24, // write_black_ram_command - false, // black_bits_inverted - 0x26, // write_color_ram_command - false, // color_bits_inverted - 0xFF0000, // highlight_color - refresh_sequence, sizeof(refresh_sequence), // refresh_display_command - 1.0, // refresh_time - &pin_GPIO6, // busy_pin - true, // busy_state - 2.0, // seconds_per_frame - false, // always_toggle_chip_select - false, // grayscale - false, // acep - false, // spectra6 - false, // two_byte_sequence_length - true); // address_little_endian + + epaperdisplay_construct_args_t args = EPAPERDISPLAY_CONSTRUCT_ARGS_DEFAULTS; + args.bus = bus; + args.start_sequence = display_start_sequence; + args.start_sequence_len = sizeof(display_start_sequence); + args.stop_sequence = display_stop_sequence; + args.stop_sequence_len = sizeof(display_stop_sequence); + args.width = 296; + args.height = 128; + args.ram_width = 250; + args.ram_height = 296; + args.colstart = 8; + args.rotation = 90; + 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.highlight_color = 0xFF0000; + args.refresh_sequence = refresh_sequence; + args.refresh_sequence_len = sizeof(refresh_sequence); + args.refresh_time = 1.0; + args.busy_pin = &pin_GPIO6; + args.busy_state = true; + args.seconds_per_frame = 2.0; + args.address_little_endian = true; + common_hal_epaperdisplay_epaperdisplay_construct(display, &args); } void board_deinit(void) { diff --git a/ports/espressif/boards/heltec_wireless_paper/board.c b/ports/espressif/boards/heltec_wireless_paper/board.c index 28fb6ae41b9..38f6472e085 100644 --- a/ports/espressif/boards/heltec_wireless_paper/board.c +++ b/ports/espressif/boards/heltec_wireless_paper/board.c @@ -94,49 +94,36 @@ 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 -// Set up the DisplayIO epaper object + // Set up the DisplayIO epaper object epaperdisplay_epaperdisplay_obj_t *display = &allocate_display()->epaper_display; display->base.type = &epaperdisplay_epaperdisplay_type; - common_hal_epaperdisplay_epaperdisplay_construct( - display, - bus, - display_start_sequence, sizeof(display_start_sequence), - 0, // start up time - display_stop_sequence, sizeof(display_stop_sequence), - 250, // width - 122, // height - 128, // ram_width - 296, // ram_height - 0, // colstart - 0, // rowstart - 270, // rotation - NO_COMMAND, // set_column_window_command - NO_COMMAND, // set_row_window_command - NO_COMMAND, // set_current_column_command - NO_COMMAND, // set_current_row_command - 0x13, // write_black_ram_command - false, // black_bits_inverted - 0x10, // write_color_ram_command - false, // color_bits_inverted - 0x000000, // highlight_color - refresh_sequence, sizeof(refresh_sequence), // refresh_display_command - 1.0, // refresh_time - &pin_GPIO7, // busy_pin - false, // busy_state - 2.0, // seconds_per_frame - false, // always_toggle_chip_select - false, // grayscale - false, // acep - false, // spectra6 - false, // two_byte_sequence_length - false); // address_little_endian + + epaperdisplay_construct_args_t args = EPAPERDISPLAY_CONSTRUCT_ARGS_DEFAULTS; + args.bus = bus; + args.start_sequence = display_start_sequence; + args.start_sequence_len = sizeof(display_start_sequence); + args.stop_sequence = display_stop_sequence; + args.stop_sequence_len = sizeof(display_stop_sequence); + args.width = 250; + args.height = 122; + args.ram_width = 128; + args.ram_height = 296; + args.rotation = 270; + args.write_black_ram_command = 0x13; + args.write_color_ram_command = 0x10; + args.refresh_sequence = refresh_sequence; + args.refresh_sequence_len = sizeof(refresh_sequence); + args.refresh_time = 1.0; + args.busy_pin = &pin_GPIO7; + args.seconds_per_frame = 2.0; + common_hal_epaperdisplay_epaperdisplay_construct(display, &args); } void board_deinit(void) { 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/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..ede75a5842e 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 diff --git a/ports/espressif/boards/lilygo_tdongle_s3/mpconfigboard.h b/ports/espressif/boards/lilygo_tdongle_s3/mpconfigboard.h index fe5525ef056..0edea0bf63b 100644 --- a/ports/espressif/boards/lilygo_tdongle_s3/mpconfigboard.h +++ b/ports/espressif/boards/lilygo_tdongle_s3/mpconfigboard.h @@ -11,5 +11,8 @@ #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) 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_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_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/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/mpconfigboard.mk b/ports/espressif/boards/m5stack_cardputer/mpconfigboard.mk index cd18ccf8a5a..bc30ae3afd5 100644 --- a/ports/espressif/boards/m5stack_cardputer/mpconfigboard.mk +++ b/ports/espressif/boards/m5stack_cardputer/mpconfigboard.mk @@ -13,4 +13,4 @@ CIRCUITPY_ESP_FLASH_SIZE = 8MB CIRCUITPY_ESPCAMERA = 0 CIRCUITPY_MAX3421E = 0 -SRC_C += boards/$(BOARD)/cardputer_keyboard.c +SRC_C += module/cardputer_keyboard.c 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/cardputer_keyboard.c b/ports/espressif/boards/m5stack_cardputer_ros/cardputer_keyboard.c deleted file mode 100644 index 73880f66e19..00000000000 --- a/ports/espressif/boards/m5stack_cardputer_ros/cardputer_keyboard.c +++ /dev/null @@ -1,238 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2016 Scott Shawcroft -// -// SPDX-License-Identifier: MIT - -#include "py/obj.h" -#include "py/objstr.h" -#include "py/runtime.h" - -#include "supervisor/shared/serial.h" -#include "shared-bindings/keypad/EventQueue.h" -#include "shared-bindings/keypad_demux/DemuxKeyMatrix.h" -#include "shared-bindings/microcontroller/Pin.h" -#include "shared-module/keypad/EventQueue.h" -#include "shared-module/keypad_demux/DemuxKeyMatrix.h" -#include "supervisor/shared/reload.h" - -#include "keymap.h" - -//| """M5Stack Cardputer keyboard integration. -//| """ -//| -//| """The KEYBOARD object is an instance of DemuxKeyMatrix, configured with correct pins. -//| The pins cannot be used for any other purposes (even though exposed in the board module). -//| By default all keyboard events are consumed and routed to the standard input - there is -//| not much use of the KEYBOARD object in this configuration - just read the input via sys.stdin. -//| -//| If you need to manually process individual key up / key down events via KEYBOARD.events, -//| call `detach_serial()`. -//| """" -//| KEYBOARD: keypad_demux.DemuxKeymatrix -//| -keypad_demux_demuxkeymatrix_obj_t cardputer_keyboard_obj; -bool cardputer_keyboard_serial_attached = false; - -void cardputer_keyboard_init(void); -void keyboard_seq(const char *seq); -void update_keyboard(keypad_eventqueue_obj_t *queue); - -//| def detach_serial() -> None: -//| """Stops consuming keyboard events and routing them to sys.stdin.""" -//| ... -//| -static mp_obj_t detach_serial(void) { - cardputer_keyboard_serial_attached = false; - common_hal_keypad_eventqueue_set_event_handler(cardputer_keyboard_obj.events, NULL); - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_0(detach_serial_obj, detach_serial); - -//| def attach_serial() -> None: -//| """Starts consuming keyboard events and routing them to sys.stdin.""" -//| ... -//| -static mp_obj_t attach_serial(void) { - common_hal_keypad_eventqueue_set_event_handler(cardputer_keyboard_obj.events, update_keyboard); - cardputer_keyboard_serial_attached = true; - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_0(attach_serial_obj, attach_serial); - -//| def key_to_char(key: int, shifted: bool) -> str | None: -//| """Converts a key index to the respective key (with or without shift modifier). -//| Returns None for functional & modifier keys or whenever not 0 <= key < 56. -//| """ -//| ... -//| -static mp_obj_t key_to_char(mp_obj_t key_obj, mp_obj_t shifted_obj) { - mp_int_t key = mp_obj_get_int(key_obj); - if (key < 0 || key > (mp_int_t)(sizeof keymap / sizeof *keymap) || keymap[key] == 0) { - return mp_const_none; - } else if (shifted_obj == mp_const_true) { - return mp_obj_new_str(&keymap_shifted[key], 1); - } else { - return mp_obj_new_str(&keymap[key], 1); - } -} -static MP_DEFINE_CONST_FUN_OBJ_2(key_to_char_obj, key_to_char); - -// Ring buffer of characters consumed from keyboard events (when serial attached) -ringbuf_t keyqueue; -char keybuf[32]; - -keypad_event_obj_t event; -char keystate[56]; - -// Keyboard pins -const mcu_pin_obj_t *row_addr_pins[] = { - &pin_GPIO8, - &pin_GPIO9, - &pin_GPIO11, -}; - -const mcu_pin_obj_t *column_pins[] = { - &pin_GPIO13, - &pin_GPIO15, - &pin_GPIO3, - &pin_GPIO4, - &pin_GPIO5, - &pin_GPIO6, - &pin_GPIO7 -}; - -void cardputer_keyboard_init(void) { - cardputer_keyboard_obj.base.type = &keypad_demux_demuxkeymatrix_type; - common_hal_keypad_demux_demuxkeymatrix_construct( - &cardputer_keyboard_obj, // self - 3, // num_row_addr_pins - row_addr_pins, // row_addr_pins - 7, // num_column_pins - column_pins, // column_pins - true, // columns_to_anodes - false, // transpose - 0.01f, // interval - 20, // max_events - 2 // debounce_threshold - ); - demuxkeymatrix_never_reset(&cardputer_keyboard_obj); - - ringbuf_init(&keyqueue, (uint8_t *)keybuf, sizeof(keybuf)); - attach_serial(); -} - -// Overrides the weakly linked function from supervisor/shared/serial.c -void board_serial_init(void) { - cardputer_keyboard_init(); -} - -// Overrides the weakly linked function from supervisor/shared/serial.c -bool board_serial_connected(void) { - return cardputer_keyboard_serial_attached; -} - -// Overrides the weakly linked function from supervisor/shared/serial.c -uint32_t board_serial_bytes_available(void) { - if (cardputer_keyboard_serial_attached) { - return ringbuf_num_filled(&keyqueue); - } else { - return 0; - } -} - -// Overrides the weakly linked function from supervisor/shared/serial.c -char board_serial_read(void) { - if (cardputer_keyboard_serial_attached) { - return ringbuf_get(&keyqueue); - } else { - return 0; - } -} - -void keyboard_seq(const char *seq) { - while (*seq) { - ringbuf_put(&keyqueue, *seq++); - } -} - -void update_keyboard(keypad_eventqueue_obj_t *queue) { - uint8_t ascii = 0; - - if (common_hal_keypad_eventqueue_get_length(queue) == 0) { - return; - } - - while (common_hal_keypad_eventqueue_get_into(queue, &event)) { - if (event.pressed) { - keystate[event.key_number] = 1; - - if (keystate[KEY_CTRL]) { - if (keystate[KEY_ALT] && keystate[KEY_BACKSPACE]) { - reload_initiate(RUN_REASON_REPL_RELOAD); - } - ascii = keymap[event.key_number]; - if (ascii >= 'a' && ascii <= 'z') { - ascii -= 'a' - 1; - } - - if (ascii == mp_interrupt_char) { - mp_sched_keyboard_interrupt(); - } - } else if (keystate[KEY_SHIFT]) { - ascii = keymap_shifted[event.key_number]; - } else if (keystate[KEY_FN] && event.key_number != KEY_FN) { - switch (event.key_number | FN_MOD) - { - case KEY_DOWN: - keyboard_seq("\e[B"); - break; - case KEY_UP: - keyboard_seq("\e[A"); - break; - case KEY_DELETE: - keyboard_seq("\e[3~"); - break; - case KEY_LEFT: - keyboard_seq("\e[D"); - break; - case KEY_RIGHT: - keyboard_seq("\e[C"); - break; - case KEY_ESC: - ringbuf_put(&keyqueue, '\e'); - break; - } - } else { - ascii = keymap[event.key_number]; - } - - if (ascii > 0) { - if (keystate[KEY_ALT]) { - ringbuf_put(&keyqueue, '\e'); - } else if (keystate[KEY_OPT]) { - ringbuf_put(&keyqueue, '\x10'); - } - ringbuf_put(&keyqueue, ascii); - } - } else { - keystate[event.key_number] = 0; - } - } -} - -static const mp_rom_map_elem_t cardputer_keyboard_module_globals_table[] = { - {MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_cardputer_keyboard)}, - {MP_ROM_QSTR(MP_QSTR_KEYBOARD), MP_ROM_PTR(&cardputer_keyboard_obj)}, - {MP_ROM_QSTR(MP_QSTR_attach_serial), MP_ROM_PTR(&attach_serial_obj)}, - {MP_ROM_QSTR(MP_QSTR_detach_serial), MP_ROM_PTR(&detach_serial_obj)}, - {MP_ROM_QSTR(MP_QSTR_key_to_char), MP_ROM_PTR(&key_to_char_obj)}, -}; -MP_DEFINE_CONST_DICT(cardputer_keyboard_module_globals, cardputer_keyboard_module_globals_table); - -const mp_obj_module_t cardputer_keyboard_module = { - .base = {&mp_type_module}, - .globals = (mp_obj_dict_t *)&cardputer_keyboard_module_globals, -}; - -MP_REGISTER_MODULE(MP_QSTR_cardputer_keyboard, cardputer_keyboard_module); diff --git a/ports/espressif/boards/m5stack_cardputer_ros/keymap.h b/ports/espressif/boards/m5stack_cardputer_ros/keymap.h deleted file mode 100644 index 0256fafaa0f..00000000000 --- a/ports/espressif/boards/m5stack_cardputer_ros/keymap.h +++ /dev/null @@ -1,214 +0,0 @@ -// 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 - -#pragma once - -#define SHIFT_MOD 0x40 -#define FN_MOD 0x80 - -#define KEY_OPT 0 -#define KEY_Z 1 -#define KEY_C 2 -#define KEY_B 3 -#define KEY_M 4 -#define KEY_DOT 5 -#define KEY_SPACE 6 -#define KEY_SHIFT 7 -#define KEY_S 8 -#define KEY_F 9 -#define KEY_H 10 -#define KEY_K 11 -#define KEY_SEMICOLON 12 -#define KEY_ENTER 13 -#define KEY_Q 14 -#define KEY_E 15 -#define KEY_T 16 -#define KEY_U 17 -#define KEY_O 18 -#define KEY_LEFT_BRACKET 19 -#define KEY_BACKSLASH 20 -#define KEY_1 21 -#define KEY_3 22 -#define KEY_5 23 -#define KEY_7 24 -#define KEY_9 25 -#define KEY_UNDERSCORE 26 -#define KEY_BACKSPACE 27 -#define KEY_CTRL 28 -#define KEY_ALT 29 -#define KEY_X 30 -#define KEY_V 31 -#define KEY_N 32 -#define KEY_COMMA 33 -#define KEY_SLASH 34 -#define KEY_FN 35 -#define KEY_A 36 -#define KEY_D 37 -#define KEY_G 38 -#define KEY_J 39 -#define KEY_L 40 -#define KEY_APOSTROPHE 41 -#define KEY_TAB 42 -#define KEY_W 43 -#define KEY_R 44 -#define KEY_Y 45 -#define KEY_I 46 -#define KEY_P 47 -#define KEY_RIGHT_BRACKET 48 -#define KEY_GRAVE 49 -#define KEY_2 50 -#define KEY_4 51 -#define KEY_6 52 -#define KEY_8 53 -#define KEY_0 54 -#define KEY_EQUALS 55 - -#define KEY_GREATER (5 | SHIFT_MOD) -#define KEY_COLON (12 | SHIFT_MOD) -#define KEY_LEFT_CURLY_BRACKET (19 | SHIFT_MOD) -#define KEY_PIPE (20 | SHIFT_MOD) -#define KEY_EXCLAMATION (21 | SHIFT_MOD) -#define KEY_HASH (22 | SHIFT_MOD) -#define KEY_PERCENT (23 | SHIFT_MOD) -#define KEY_AMPERSAND (24 | SHIFT_MOD) -#define KEY_OPEN_PARENTHESIS (25 | SHIFT_MOD) -#define KEY_MINUS (26 | SHIFT_MOD) -#define KEY_LESS (33 | SHIFT_MOD) -#define KEY_QUESTION (34 | SHIFT_MOD) -#define KEY_DOUBLE_QUOTE (41 | SHIFT_MOD) -#define KEY_RIGHT_CURLY_BRACKET (48 | SHIFT_MOD) -#define KEY_TILDE (49 | SHIFT_MOD) -#define KEY_AT (50 | SHIFT_MOD) -#define KEY_DOLLAR (51 | SHIFT_MOD) -#define KEY_CARET (52 | SHIFT_MOD) -#define KEY_ASTERISK (53 | SHIFT_MOD) -#define KEY_CLOSE_PARENTHESIS (54 | SHIFT_MOD) -#define KEY_PLUS (55 | SHIFT_MOD) - -#define KEY_DOWN (5 | FN_MOD) -#define KEY_UP (12 | FN_MOD) -#define KEY_DELETE (27 | FN_MOD) -#define KEY_LEFT (33 | FN_MOD) -#define KEY_RIGHT (34 | FN_MOD) -#define KEY_ESC (49 | FN_MOD) - -const char keymap[56] = { - 0, // KEY_OPT - 'z', // KEY_Z - 'c', // KEY_C - 'b', // KEY_B - 'm', // KEY_M - '.', // KEY_DOT - ' ', // KEY_SPACE - 0, // KEY_SHIFT - 's', // KEY_S - 'f', // KEY_F - 'h', // KEY_H - 'k', // KEY_K - ';', // KEY_SEMICOLON - '\r',// KEY_ENTER - 'q', // KEY_Q - 'e', // KEY_E - 't', // KEY_T - 'u', // KEY_U - 'o', // KEY_O - '[', // KEY_LEFT_BRACKET - '\\',// KEY_BACKSLASH - '1', // KEY_1 - '3', // KEY_3 - '5', // KEY_5 - '7', // KEY_7 - '9', // KEY_9 - '_', // KEY_UNDERSCORE - '\b',// KEY_BACKSPACE - 0, // KEY_CTRL - 0, // KEY_ALT - 'x', // KEY_X - 'v', // KEY_V - 'n', // KEY_N - ',', // KEY_COMMA - '/', // KEY_SLASH - 0, // KEY_FN - 'a', // KEY_A - 'd', // KEY_D - 'g', // KEY_G - 'j', // KEY_J - 'l', // KEY_L - '\'',// KEY_APOSTROPHE - '\t',// KEY_TAB - 'w', // KEY_W - 'r', // KEY_R - 'y', // KEY_Y - 'i', // KEY_I - 'p', // KEY_P - ']', // KEY_RIGHT_BRACKET - '`', // KEY_GRAVE - '2', // KEY_2 - '4', // KEY_4 - '6', // KEY_6 - '8', // KEY_8 - '0', // KEY_0 - '=' // KEY_EQUALS -}; - -const char keymap_shifted[56] = { - 0, // KEY_OPT - 'Z', // KEY_Z - 'C', // KEY_C - 'B', // KEY_B - 'M', // KEY_M - '>', // KEY_DOT -> '>' - ' ', // KEY_SPACE - 0, // KEY_SHIFT - 'S', // KEY_S - 'F', // KEY_F - 'H', // KEY_H - 'K', // KEY_K - ':', // KEY_SEMICOLON -> ':' - '\r',// KEY_ENTER - 'Q', // KEY_Q - 'E', // KEY_E - 'T', // KEY_T - 'U', // KEY_U - 'O', // KEY_O - '{', // KEY_LEFT_BRACKET -> '{' - '|', // KEY_BACKSLASH -> '|' - '!', // KEY_1 -> '!' - '#', // KEY_3 -> '#' - '%', // KEY_5 -> '%' - '&', // KEY_7 -> '&' - '(', // KEY_9 -> '(' - '-', // KEY_UNDERSCORE -> '-' - '\b',// KEY_BACKSPACE - 0, // KEY_CTRL - 0, // KEY_ALT - 'X', // KEY_X - 'V', // KEY_V - 'N', // KEY_N - '<', // KEY_COMMA -> '<' - '?', // KEY_SLASH -> '?' - 0, // KEY_FN - 'A', // KEY_A - 'D', // KEY_D - 'G', // KEY_G - 'J', // KEY_J - 'L', // KEY_L - '"', // KEY_APOSTROPHE -> '"' - '\t',// KEY_TAB - 'W', // KEY_W - 'R', // KEY_R - 'Y', // KEY_Y - 'I', // KEY_I - 'P', // KEY_P - '}', // KEY_RIGHT_BRACKET -> '}' - '~', // KEY_GRAVE -> '~' - '@', // KEY_2 -> '@' - '$', // KEY_4 -> '$' - '^', // KEY_6 -> '^' - '*', // KEY_8 -> '*' - ')', // KEY_0 -> ')' - '+' // KEY_EQUALS -> '+' -}; diff --git a/ports/espressif/boards/m5stack_cardputer_ros/mpconfigboard.mk b/ports/espressif/boards/m5stack_cardputer_ros/mpconfigboard.mk index 573f947f0a8..98d2ad502dd 100644 --- a/ports/espressif/boards/m5stack_cardputer_ros/mpconfigboard.mk +++ b/ports/espressif/boards/m5stack_cardputer_ros/mpconfigboard.mk @@ -9,10 +9,10 @@ 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 CIRCUITPY_MAX3421E = 0 -SRC_C += boards/$(BOARD)/cardputer_keyboard.c +SRC_C += module/cardputer_keyboard.c 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..629472da526 100644 --- a/ports/espressif/boards/m5stack_cores3/board.c +++ b/ports/espressif/boards/m5stack_cores3/board.c @@ -45,9 +45,9 @@ static bool display_init(void) { 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/pins.c b/ports/espressif/boards/m5stack_cores3/pins.c index 2ebb225277d..8b40d9e8484 100644 --- a/ports/espressif/boards/m5stack_cores3/pins.c +++ b/ports/espressif/boards/m5stack_cores3/pins.c @@ -28,42 +28,59 @@ 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 & PORT B) + // 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) }, + { 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_D12), 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_D5), 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_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_D7), MP_ROM_PTR(&pin_GPIO7) }, { MP_ROM_QSTR(MP_QSTR_A7), MP_ROM_PTR(&pin_GPIO7) }, - // Port B - { 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_PORTB_OUT), MP_ROM_PTR(&pin_GPIO9) }, - { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_GPIO9) }, - // 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_IS2_DATA), MP_ROM_PTR(&pin_GPIO13) }, - { MP_ROM_QSTR(MP_QSTR_IS2_MASTER_CLOCK), MP_ROM_PTR(&pin_GPIO0) }, + { 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) }, // Camera { MP_ROM_QSTR(MP_QSTR_CAMERA_DATA), MP_ROM_PTR(&camera_data_tuple) }, 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..623fe29f98f --- /dev/null +++ b/ports/espressif/boards/m5stack_cores3_se/board.c @@ -0,0 +1,224 @@ +// 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) { + 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_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..070ccf9195e --- /dev/null +++ b/ports/espressif/boards/m5stack_cores3_se/mpconfigboard.h @@ -0,0 +1,25 @@ +// 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_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_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..f0e20926bfa --- /dev/null +++ b/ports/espressif/boards/m5stack_cores3_se/pins.c @@ -0,0 +1,87 @@ +// 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) + { 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) }, + + { 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_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_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_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 new file mode 100644 index 00000000000..37fafa994dc --- /dev/null +++ b/ports/espressif/boards/m5stack_dinmeter/board.c @@ -0,0 +1,107 @@ +// 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" +#include "supervisor/board.h" +#include "supervisor/shared/serial.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 "py/runtime.h" +#include "py/ringbuf.h" +#include "shared/runtime/interrupt_char.h" + + +uint8_t display_init_sequence[] = { + 0x01, 0x80, 0x96, // SWRESET and Delay 150ms + 0x11, 0x80, 0xff, // SLPOUT and Delay + 0xb1, 0x03, 0x01, 0x2C, 0x2D, // _FRMCTR1 + 0xb2, 0x03, 0x01, 0x2C, 0x2D, // _FRMCTR2 + 0xb3, 0x06, 0x01, 0x2C, 0x2D, 0x01, 0x2C, 0x2D, // _FRMCTR3 + 0xb4, 0x01, 0x07, // _INVCTR line inversion + 0xc0, 0x03, 0xa2, 0x02, 0x84, // _PWCTR1 GVDD = 4.7V, 1.0uA + 0xc1, 0x01, 0xc5, // _PWCTR2 VGH=14.7V, VGL=-7.35V + 0xc2, 0x02, 0x0a, 0x00, // _PWCTR3 Opamp current small, Boost frequency + 0xc3, 0x02, 0x8a, 0x2a, + 0xc4, 0x02, 0x8a, 0xee, + 0xc5, 0x01, 0x0e, // _VMCTR1 VCOMH = 4V, VOML = -1.1V + 0x36, 0x01, 0xc8, // MADCTL Rotate display + 0x21, 0x00, // _INVON + 0x3a, 0x01, 0x05, // COLMOD - 16bit color + 0xe0, 0x10, 0x02, 0x1c, 0x07, 0x12, 0x37, 0x32, 0x29, 0x2d, 0x29, 0x25, 0x2B, 0x39, 0x00, 0x01, 0x03, 0x10, // _GMCTRP1 Gamma + 0xe1, 0x10, 0x03, 0x1d, 0x07, 0x06, 0x2E, 0x2C, 0x29, 0x2D, 0x2E, 0x2E, 0x37, 0x3F, 0x00, 0x00, 0x02, 0x10, // _GMCTRN1 + 0x13, 0x80, 0x0a, // _NORON + 0x29, 0x80, 0x64 // _DISPON +}; + + +// Overrides the weakly linked function from supervisor/shared/board.c +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; + + // see here for inspiration: https://github.com/m5stack/M5GFX/blob/33d7d3135e816a86a008fae8ab3757938cee95d2/src/M5GFX.cpp#L1350 + common_hal_fourwire_fourwire_construct( + bus, + spi, + 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 + ); + 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) + 135, // height (after rotation) + 40, // column start + 52, // 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_GPIO9, // backlight pin + NO_BRIGHTNESS_COMMAND, + 1.0f, // brightness + false, // single_byte_bounds + false, // data_as_commands + true, // auto_refresh + 80, // native_frames_per_second + true, // backlight_on_high + false, // SH1107_addressing + 50000 // backlight pwm frequency + ); +} + + +bool espressif_board_reset_pin_number(gpio_num_t pin_number) { + // Hold pin must be set high to avoid a power off when battery powered + if (pin_number == 46) { + // Turn on hold output + config_pin_as_output_with_level(pin_number, true); + return true; + } + return false; +} + +// TODO: Should we turn off the display when asleep, in board_deinit() ? diff --git a/ports/espressif/boards/m5stack_dinmeter/mpconfigboard.h b/ports/espressif/boards/m5stack_dinmeter/mpconfigboard.h new file mode 100644 index 00000000000..2d69e61ea95 --- /dev/null +++ b/ports/espressif/boards/m5stack_dinmeter/mpconfigboard.h @@ -0,0 +1,22 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 CDarius +// SPDX-FileCopyrightText: Copyright (c) 2025 juergenpabel +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Micropython setup + +#define MICROPY_HW_BOARD_NAME "M5Stack DinMeter" +#define MICROPY_HW_MCU_NAME "ESP32S3" + +#define CIRCUITPY_BOARD_I2C (2) +#define CIRCUITPY_BOARD_I2C_PIN {{.scl = &pin_GPIO12, .sda = &pin_GPIO11}, \ + {.scl = &pin_GPIO15, .sda = &pin_GPIO13}} + +#define CIRCUITPY_BOARD_SPI (1) +#define CIRCUITPY_BOARD_SPI_PIN {{.clock = &pin_GPIO6, .mosi = &pin_GPIO5}} + +#define CIRCUITPY_I2C_ALLOW_INTERNAL_PULL_UP (1) diff --git a/ports/espressif/boards/m5stack_dinmeter/mpconfigboard.mk b/ports/espressif/boards/m5stack_dinmeter/mpconfigboard.mk new file mode 100644 index 00000000000..81a23af1fe4 --- /dev/null +++ b/ports/espressif/boards/m5stack_dinmeter/mpconfigboard.mk @@ -0,0 +1,15 @@ +USB_VID = 0x303A +USB_PID = 0x830B + +USB_PRODUCT = "DinMeter" +USB_MANUFACTURER = "M5Stack" + +IDF_TARGET = esp32s3 + +CIRCUITPY_ESP_FLASH_MODE = qio +CIRCUITPY_ESP_FLASH_FREQ = 80m +CIRCUITPY_ESP_FLASH_SIZE = 8MB + +# Very few pins. +CIRCUITPY_ESPCAMERA = 0 +CIRCUITPY_PARALLELDISPLAYBUS = 0 diff --git a/ports/espressif/boards/m5stack_dinmeter/pins.c b/ports/espressif/boards/m5stack_dinmeter/pins.c new file mode 100644 index 00000000000..f75e05e848b --- /dev/null +++ b/ports/espressif/boards/m5stack_dinmeter/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-FileCopyrightText: Copyright (c) 2025 Juergen Pabel +// +// 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 + + // Port A + { MP_ROM_QSTR(MP_QSTR_PORTA_SCL), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_D15), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_PORTA_SDA), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_GPIO13) }, + + // Port B + { MP_ROM_QSTR(MP_QSTR_PORTB_IN), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_PORTB_OUT), 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) }, + + // Encoder + { MP_ROM_QSTR(MP_QSTR_ENC_A), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_ENC_B), MP_ROM_PTR(&pin_GPIO40) }, + + // Button + { 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) }, + + // Misc + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_SPEAKER), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_KNOB_BUTTON), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_POWER_HOLD), MP_ROM_PTR(&pin_GPIO46) }, + + // Display + { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_TFT_CS), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_TFT_DC), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_TFT_RESET), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_TFT_BACKLIGHT), MP_ROM_PTR(&pin_GPIO9) }, + + { 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_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_dinmeter/sdkconfig b/ports/espressif/boards/m5stack_dinmeter/sdkconfig new file mode 100644 index 00000000000..e9628662160 --- /dev/null +++ b/ports/espressif/boards/m5stack_dinmeter/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_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/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_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/ports/espressif/boards/pcbcupid_glyph_s3/sdkconfig b/ports/espressif/boards/pcbcupid_glyph_s3/sdkconfig new file mode 100644 index 00000000000..e69de29bb2d diff --git a/ports/espressif/boards/prokyber_ai_on_the_edge_cam/board.c b/ports/espressif/boards/prokyber_ai_on_the_edge_cam/board.c new file mode 100644 index 00000000000..a3a9eec0471 --- /dev/null +++ b/ports/espressif/boards/prokyber_ai_on_the_edge_cam/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/prokyber_ai_on_the_edge_cam/mpconfigboard.h b/ports/espressif/boards/prokyber_ai_on_the_edge_cam/mpconfigboard.h new file mode 100644 index 00000000000..2114fecf373 --- /dev/null +++ b/ports/espressif/boards/prokyber_ai_on_the_edge_cam/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 "Prokyber Ai-On-The-Edge-Cam" +#define MICROPY_HW_MCU_NAME "ESP32S3" + +#define MICROPY_HW_NEOPIXEL (&pin_GPIO12) + +#define MICROPY_HW_LED_STATUS (&pin_GPIO48) + +#define DEFAULT_UART_BUS_RX (&pin_GPIO44) +#define DEFAULT_UART_BUS_TX (&pin_GPIO43) + +#define CIRCUITPY_BOARD_I2C (1) +#define CIRCUITPY_BOARD_I2C_PIN {{.scl = &pin_GPIO5, .sda = &pin_GPIO4}} diff --git a/ports/espressif/boards/prokyber_ai_on_the_edge_cam/mpconfigboard.mk b/ports/espressif/boards/prokyber_ai_on_the_edge_cam/mpconfigboard.mk new file mode 100644 index 00000000000..82419bb8074 --- /dev/null +++ b/ports/espressif/boards/prokyber_ai_on_the_edge_cam/mpconfigboard.mk @@ -0,0 +1,14 @@ +USB_VID = 0x1209 +USB_PID = 0xDABB +USB_PRODUCT = "AI-ON-THE-EDGE-CAM" +USB_MANUFACTURER = "Prokyber" + +IDF_TARGET = esp32s3 + +CIRCUITPY_ESP_FLASH_MODE = qio +CIRCUITPY_ESP_FLASH_FREQ = 80m +CIRCUITPY_ESP_FLASH_SIZE = 16MB + +CIRCUITPY_ESP_PSRAM_MODE = opi +CIRCUITPY_ESP_PSRAM_FREQ = 80m +CIRCUITPY_ESP_PSRAM_SIZE = 8MB diff --git a/ports/espressif/boards/prokyber_ai_on_the_edge_cam/pins.c b/ports/espressif/boards/prokyber_ai_on_the_edge_cam/pins.c new file mode 100644 index 00000000000..68dc40781a4 --- /dev/null +++ b/ports/espressif/boards/prokyber_ai_on_the_edge_cam/pins.c @@ -0,0 +1,106 @@ +// 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 "py/objtuple.h" +#include "shared-bindings/board/__init__.h" + +static const mp_rom_obj_tuple_t camera_data_tuple = { + {&mp_type_tuple}, + 8, + { + MP_ROM_PTR(&pin_GPIO11), + MP_ROM_PTR(&pin_GPIO9), + MP_ROM_PTR(&pin_GPIO8), + MP_ROM_PTR(&pin_GPIO10), + MP_ROM_PTR(&pin_GPIO47), + MP_ROM_PTR(&pin_GPIO18), + MP_ROM_PTR(&pin_GPIO17), + MP_ROM_PTR(&pin_GPIO16), + } +}; + +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_IO2), MP_ROM_PTR(&pin_GPIO2) }, + + { MP_ROM_QSTR(MP_QSTR_IO46), MP_ROM_PTR(&pin_GPIO46) }, + { MP_ROM_QSTR(MP_QSTR_PER_EN), MP_ROM_PTR(&pin_GPIO46) }, + + // SD + { MP_ROM_QSTR(MP_QSTR_SD_CS), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_IO3), MP_ROM_PTR(&pin_GPIO3) }, + + { MP_ROM_QSTR(MP_QSTR_SD_MISO), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_IO41), MP_ROM_PTR(&pin_GPIO41) }, + + { MP_ROM_QSTR(MP_QSTR_SD_MOSI), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_IO42), MP_ROM_PTR(&pin_GPIO42) }, + + { MP_ROM_QSTR(MP_QSTR_SD_CLK), MP_ROM_PTR(&pin_GPIO40) }, + { MP_ROM_QSTR(MP_QSTR_IO40), MP_ROM_PTR(&pin_GPIO40) }, + + // Ethernet + { MP_ROM_QSTR(MP_QSTR_ETH_RST), MP_ROM_PTR(&pin_GPIO45) }, + { MP_ROM_QSTR(MP_QSTR_IO45), MP_ROM_PTR(&pin_GPIO45) }, + + { MP_ROM_QSTR(MP_QSTR_ETH_INT), MP_ROM_PTR(&pin_GPIO38) }, + { MP_ROM_QSTR(MP_QSTR_IO38), MP_ROM_PTR(&pin_GPIO38) }, + + { MP_ROM_QSTR(MP_QSTR_ETH_MOSI), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_IO1), MP_ROM_PTR(&pin_GPIO1) }, + + { MP_ROM_QSTR(MP_QSTR_ETH_MISO), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_IO14), MP_ROM_PTR(&pin_GPIO14) }, + + { MP_ROM_QSTR(MP_QSTR_ETH_CLK), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_IO21), MP_ROM_PTR(&pin_GPIO21) }, + + { MP_ROM_QSTR(MP_QSTR_ETH_CS), MP_ROM_PTR(&pin_GPIO39) }, + { MP_ROM_QSTR(MP_QSTR_IO39), MP_ROM_PTR(&pin_GPIO39) }, + + // LEDs + { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_IO12), MP_ROM_PTR(&pin_GPIO12) }, + + { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO48) }, + { MP_ROM_QSTR(MP_QSTR_IO48), MP_ROM_PTR(&pin_GPIO48) }, + + // UART + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_IO43), MP_ROM_PTR(&pin_GPIO43) }, + + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO44) }, + { MP_ROM_QSTR(MP_QSTR_IO44), MP_ROM_PTR(&pin_GPIO44) }, + + // I2C + { 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_CAMERA_DATA), MP_ROM_PTR(&camera_data_tuple) }, + + { MP_ROM_QSTR(MP_QSTR_CAMERA_VSYNC), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_CAMERA_HREF), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_CAMERA_DATA9), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_CAMERA_XCLK), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_CAMERA_DATA8), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_CAMERA_DATA7), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_CAMERA_PCLK), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_CAMERA_DATA6), MP_ROM_PTR(&pin_GPIO47) }, + { MP_ROM_QSTR(MP_QSTR_CAMERA_DATA2), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_CAMERA_DATA5), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_CAMERA_DATA3), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_CAMERA_DATA4), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_CAMERA_SIOD), MP_ROM_PTR(&pin_GPIO4) }, // SDA + { MP_ROM_QSTR(MP_QSTR_CAMERA_SIOC), MP_ROM_PTR(&pin_GPIO5) }, // SCL + + { 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_UART), MP_ROM_PTR(&board_uart_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/espressif/boards/prokyber_ai_on_the_edge_cam/sdkconfig b/ports/espressif/boards/prokyber_ai_on_the_edge_cam/sdkconfig new file mode 100644 index 00000000000..ac1c5357176 --- /dev/null +++ b/ports/espressif/boards/prokyber_ai_on_the_edge_cam/sdkconfig @@ -0,0 +1,14 @@ +# +# Espressif IoT Development Framework Configuration +# +# +# Component config +# +# +# LWIP +# +# end of LWIP +CONFIG_OV2640_SUPPORT=y +# end of Component config + +# end of Espressif IoT Development Framework Configuration 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_mcu_esp32s2/mpconfigboard.mk b/ports/espressif/boards/sensebox_mcu_esp32s2/mpconfigboard.mk index 9d3fbecabde..6b97c870cc0 100644 --- a/ports/espressif/boards/sensebox_mcu_esp32s2/mpconfigboard.mk +++ b/ports/espressif/boards/sensebox_mcu_esp32s2/mpconfigboard.mk @@ -1,7 +1,7 @@ USB_VID = 0x303A USB_PID = 0x81B9 USB_PRODUCT = "senseBox MCU-S2 ESP32S2" -USB_MANUFACTURER = "Espressif" +USB_MANUFACTURER = "senseBox" IDF_TARGET = esp32s2 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_mcu_eye_esp32s3/mpconfigboard.h b/ports/espressif/boards/sensebox_mcu_eye_esp32s3/mpconfigboard.h new file mode 100644 index 00000000000..300154fe344 --- /dev/null +++ b/ports/espressif/boards/sensebox_mcu_eye_esp32s3/mpconfigboard.h @@ -0,0 +1,18 @@ +// 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 + +// Micropython setup + +#define MICROPY_HW_BOARD_NAME "senseBox MCU Eye ESP32S3" +#define MICROPY_HW_MCU_NAME "ESP32S3" + +#define MICROPY_HW_NEOPIXEL (&pin_GPIO45) + +#define DEFAULT_I2C_BUS_SCL (&pin_GPIO1) +#define DEFAULT_I2C_BUS_SDA (&pin_GPIO2) + +#define DEFAULT_UART_BUS_RX (&pin_GPIO44) +#define DEFAULT_UART_BUS_TX (&pin_GPIO43) diff --git a/ports/espressif/boards/sensebox_mcu_eye_esp32s3/mpconfigboard.mk b/ports/espressif/boards/sensebox_mcu_eye_esp32s3/mpconfigboard.mk new file mode 100644 index 00000000000..be3c65746c8 --- /dev/null +++ b/ports/espressif/boards/sensebox_mcu_eye_esp32s3/mpconfigboard.mk @@ -0,0 +1,21 @@ +USB_VID = 0x303A +USB_PID = 0x82D2 + +USB_PRODUCT = "senseBox-eye ESP32S3" +USB_MANUFACTURER = "senseBox" + +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_ESPCAMERA = 1 +CIRCUITPY_AUDIOBUSIO = 1 + +# Include these Python libraries in firmware. +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_NeoPixel diff --git a/ports/espressif/boards/sensebox_mcu_eye_esp32s3/pins.c b/ports/espressif/boards/sensebox_mcu_eye_esp32s3/pins.c new file mode 100644 index 00000000000..71b984f7ff5 --- /dev/null +++ b/ports/espressif/boards/sensebox_mcu_eye_esp32s3/pins.c @@ -0,0 +1,82 @@ +// 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 "py/objtuple.h" +#include "shared-bindings/board/__init__.h" +#include "shared-module/displayio/__init__.h" + +CIRCUITPY_BOARD_BUS_SINGLETON(sscb_i2c, i2c, 2) + +static const mp_rom_obj_tuple_t camera_data_tuple = { + // The order matters. + // They must be ordered from low to high (CAM_D0, CAM_D1...CAM_D7). + + // Do not include any of the control pins in here. + {&mp_type_tuple}, + 8, + { + MP_ROM_PTR(&pin_GPIO11), + MP_ROM_PTR(&pin_GPIO9), + MP_ROM_PTR(&pin_GPIO8), + MP_ROM_PTR(&pin_GPIO10), + MP_ROM_PTR(&pin_GPIO12), + MP_ROM_PTR(&pin_GPIO18), + MP_ROM_PTR(&pin_GPIO17), + MP_ROM_PTR(&pin_GPIO16), + } +}; + +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_GPIO21) }, + + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO1) }, + { 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_A14), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_D14), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_A48), MP_ROM_PTR(&pin_GPIO48) }, + { MP_ROM_QSTR(MP_QSTR_D48), MP_ROM_PTR(&pin_GPIO48) }, + + { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO45) }, + { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_GPIO45) }, + + { 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_ENABLE), MP_ROM_PTR(&pin_GPIO26) }, + + { MP_ROM_QSTR(MP_QSTR_CAM_DATA), MP_ROM_PTR(&camera_data_tuple) }, + { MP_ROM_QSTR(MP_QSTR_CAM_D0), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_CAM_D1), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_CAM_D2), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_CAM_D3), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_CAM_D4), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_CAM_D5), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_CAM_D6), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_CAM_D7), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_CAM_XCLK), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_CAM_HREF), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_CAM_PCLK), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_CAM_VSYNC), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_CAM_SCL), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_CAM_SDA), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_PWDN), MP_ROM_PTR(&pin_GPIO46) }, + + { MP_ROM_QSTR(MP_QSTR_SD_CS), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_SD_MOSI), MP_ROM_PTR(&pin_GPIO38) }, + { MP_ROM_QSTR(MP_QSTR_SD_SCLK), MP_ROM_PTR(&pin_GPIO39) }, + { MP_ROM_QSTR(MP_QSTR_SD_MISO), MP_ROM_PTR(&pin_GPIO40) }, + { MP_ROM_QSTR(MP_QSTR_SD_ENABLE), MP_ROM_PTR(&pin_GPIO3) }, + + { 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/espressif/boards/sensebox_mcu_eye_esp32s3/sdkconfig b/ports/espressif/boards/sensebox_mcu_eye_esp32s3/sdkconfig new file mode 100644 index 00000000000..919f4d9f345 --- /dev/null +++ b/ports/espressif/boards/sensebox_mcu_eye_esp32s3/sdkconfig @@ -0,0 +1,19 @@ +# +# Espressif IoT Development Framework Configuration +# +# +# Component config +# +# +# LWIP +# +# end of LWIP +# Camera configuration +# +CONFIG_OV2640_SUPPORT=y +# 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/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 393b8b75902..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 @@ -160,40 +160,33 @@ void board_init(void) { epaperdisplay_epaperdisplay_obj_t *display = &allocate_display()->epaper_display; display->base.type = &epaperdisplay_epaperdisplay_type; - common_hal_epaperdisplay_epaperdisplay_construct( - display, - bus, - display_start_sequence, sizeof(display_start_sequence), - (double)0.01, // start up time - display_stop_sequence, sizeof(display_stop_sequence), - 200, // width - 200, // height - 200, // ram_width - 296, // ram_height - 0, // colstart - 0, // rowstart - 0, // rotation - 0x44, // set_column_window_command - 0x45, // set_row_window_command - 0x4E, // set_current_column_command - 0x4F, // set_current_row_command - 0x24, // write_black_ram_command - true, // black_bits_inverted - 0x26, // write_color_ram_command - false, // color_bits_inverted - 0x000000, // highlight_color - refresh_sequence, sizeof(refresh_sequence), - (double)1.0, // refresh_time - &pin_GPIO19, // busy_pin - true, // busy_state - (double)5.0, // seconds_per_frame - false, // always_toggle_chip_select - false, // grayscale - false, // acep - false, // spectra6 - false, // two_byte_sequence_length - true // address_little_endian - ); + + epaperdisplay_construct_args_t args = EPAPERDISPLAY_CONSTRUCT_ARGS_DEFAULTS; + args.bus = bus; + args.start_sequence = display_start_sequence; + args.start_sequence_len = sizeof(display_start_sequence); + args.start_up_time = 0.01; + args.stop_sequence = display_stop_sequence; + args.stop_sequence_len = sizeof(display_stop_sequence); + args.width = 200; + args.height = 200; + args.ram_width = 200; + args.ram_height = 296; + 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.black_bits_inverted = true; + args.write_color_ram_command = 0x26; + args.refresh_sequence = refresh_sequence; + args.refresh_sequence_len = sizeof(refresh_sequence); + args.refresh_time = 1.0; + args.busy_pin = &pin_GPIO19; + args.busy_state = true; + args.seconds_per_frame = 5.0; + args.address_little_endian = true; + common_hal_epaperdisplay_epaperdisplay_construct(display, &args); } bool board_requests_safe_mode(void) { 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_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/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_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_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..9ac461ee61d --- /dev/null +++ b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/mpconfigboard.h @@ -0,0 +1,34 @@ +// 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) 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_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_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_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_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_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..296d751ab25 --- /dev/null +++ b/ports/espressif/boards/waveshare_esp32_s3_tiny_n8r8/mpconfigboard.h @@ -0,0 +1,19 @@ +// 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) 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..0dc2ad4a661 --- /dev/null +++ b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_1_47/mpconfigboard.h @@ -0,0 +1,22 @@ +// 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 */} 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_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..3e0db8bf494 --- /dev/null +++ b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/mpconfigboard.h @@ -0,0 +1,19 @@ +// 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) 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/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/sdkconfig b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/sdkconfig new file mode 100755 index 00000000000..e69de29bb2d 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/ports/espressif/boards/yoto_mini_2024/sdkconfig b/ports/espressif/boards/yoto_mini_2024/sdkconfig new file mode 100644 index 00000000000..e69de29bb2d 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/ports/espressif/boards/yoto_player_v3/sdkconfig b/ports/espressif/boards/yoto_player_v3/sdkconfig new file mode 100644 index 00000000000..e69de29bb2d diff --git a/ports/espressif/common-hal/_bleio/Adapter.c b/ports/espressif/common-hal/_bleio/Adapter.c index f604e02c200..4feb6b2b96b 100644 --- a/ports/espressif/common-hal/_bleio/Adapter.c +++ b/ports/espressif/common-hal/_bleio/Adapter.c @@ -44,8 +44,8 @@ #include "esp_nimble_hci.h" #include "nvs_flash.h" -#if CIRCUITPY_OS_GETENV -#include "shared-module/os/__init__.h" +#if CIRCUITPY_SETTINGS_TOML +#include "supervisor/shared/settings.h" #endif // Status variables used while busy-waiting for events. @@ -61,7 +61,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; @@ -105,10 +105,10 @@ void common_hal_bleio_adapter_set_enabled(bleio_adapter_obj_t *self, bool enable ble_svc_gatt_init(); ble_svc_ans_init(); - #if CIRCUITPY_OS_GETENV + #if CIRCUITPY_SETTINGS_TOML 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) { + settings_err_t result = settings_get_str("CIRCUITPY_BLE_NAME", ble_name, sizeof(ble_name)); + if (result == SETTINGS_OK) { ble_svc_gap_device_name_set(ble_name); } else #endif @@ -384,7 +384,7 @@ static int _connect_event(struct ble_gap_event *event, void *self_in) { // 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; @@ -561,10 +561,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 +622,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 +654,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 +735,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 +756,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 +819,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++) { diff --git a/ports/espressif/common-hal/_bleio/Characteristic.c b/ports/espressif/common-hal/_bleio/Characteristic.c index 7e917d6334b..ff9ab35c1b9 100644 --- a/ports/espressif/common-hal/_bleio/Characteristic.c +++ b/ports/espressif/common-hal/_bleio/Characteristic.c @@ -92,7 +92,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); } @@ -120,7 +120,7 @@ void common_hal_bleio_characteristic_deinit(bleio_characteristic_obj_t *self) { return; } if (self->current_value != NULL) { - if (gc_nbytes(self->current_value) > 0) { + if (gc_ptr_on_heap(self->current_value)) { m_free(self->current_value); } else { port_free(self->current_value); @@ -320,7 +320,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/Connection.c b/ports/espressif/common-hal/_bleio/Connection.c index 8c88bfe3ec5..8df4dc26545 100644 --- a/ports/espressif/common-hal/_bleio/Connection.c +++ b/ports/espressif/common-hal/_bleio/Connection.c @@ -65,7 +65,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; @@ -181,17 +181,11 @@ 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(); -} - static int _wait_for_discovery_step_done(void) { - const uint64_t timeout_time_ms = _discovery_start_time + DISCOVERY_TIMEOUT_MS; + const uint64_t timeout_time_ms = common_hal_time_monotonic_ms() + DISCOVERY_TIMEOUT_MS; while ((_last_discovery_status == 0) && (common_hal_time_monotonic_ms() < timeout_time_ms)) { RUN_BACKGROUND_TASKS; if (mp_hal_is_interrupted()) { @@ -199,6 +193,9 @@ static int _wait_for_discovery_step_done(void) { _last_discovery_status = BLE_HS_EDONE; } } + if (_last_discovery_status == 0) { + return BLE_HS_ETIMEOUT; + } return _last_discovery_status; } @@ -207,6 +204,17 @@ static void _set_discovery_step_status(int status) { _last_discovery_status = status; } +static void _check_discovery_status(int status) { + if (status == BLE_HS_EDONE) { + return; + } + if (status < BLE_HS_ERR_ATT_BASE) { + CHECK_NIMBLE_ERROR(status); + return; + } + CHECK_BLE_ERROR(status); +} + static int _discovered_service_cb(uint16_t conn_handle, const struct ble_gatt_error *error, const struct ble_gatt_svc *svc, @@ -350,9 +358,6 @@ static void discover_remote_services(bleio_connection_internal_t *self, mp_obj_t // 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 _set_discovery_step_status(0); @@ -361,9 +366,7 @@ static void discover_remote_services(bleio_connection_internal_t *self, mp_obj_t // 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); - } + _check_discovery_status(status); } else { mp_obj_iter_buf_t iter_buf; mp_obj_t iterable = mp_getiter(service_uuids_whitelist, &iter_buf); @@ -382,9 +385,7 @@ static void discover_remote_services(bleio_connection_internal_t *self, mp_obj_t // 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); - } + _check_discovery_status(status); } } @@ -404,9 +405,7 @@ static void discover_remote_services(bleio_connection_internal_t *self, mp_obj_t // 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); - } + _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,7 +422,7 @@ 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) { @@ -441,9 +440,7 @@ static void discover_remote_services(bleio_connection_internal_t *self, mp_obj_t // 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); - } + _check_discovery_status(status); } } } diff --git a/ports/espressif/common-hal/_bleio/Connection.h b/ports/espressif/common-hal/_bleio/Connection.h index 326eca02ecd..5f33eb43b5d 100644 --- a/ports/espressif/common-hal/_bleio/Connection.h +++ b/ports/espressif/common-hal/_bleio/Connection.h @@ -64,6 +64,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/__init__.c b/ports/espressif/common-hal/_bleio/__init__.c index 119fe55921e..552ba0575b3 100644 --- a/ports/espressif/common-hal/_bleio/__init__.c +++ b/ports/espressif/common-hal/_bleio/__init__.c @@ -32,9 +32,12 @@ static uint64_t _timeout_start_time; background_callback_t bleio_background_callback; 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); + if (!common_hal_bleio_adapter_get_enabled(&common_hal_bleio_adapter_obj)) { + return; + } + // Stop any user scanning or advertising, and stop all connections. + // TODO: Don't stop BLE workflow connection. + bleio_adapter_reset(&common_hal_bleio_adapter_obj); ble_event_remove_heap_handlers(); @@ -155,7 +158,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/alarm/SleepMemory.c b/ports/espressif/common-hal/alarm/SleepMemory.c index 938772e53ca..f2a6aaa7a95 100644 --- a/ports/espressif/common-hal/alarm/SleepMemory.c +++ b/ports/espressif/common-hal/alarm/SleepMemory.c @@ -15,14 +15,45 @@ // 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_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..b2a6e00969a 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(); diff --git a/ports/espressif/common-hal/alarm/pin/PinAlarm.c b/ports/espressif/common-hal/alarm/pin/PinAlarm.c index 45f676fa599..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,24 +102,34 @@ 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) { - pin_number = REG_GET_FIELD(RTC_IO_EXT_WAKEUP0_REG, RTC_IO_EXT_WAKEUP0_SEL); + 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. + // The RTC and GPIO pin numbers match for all other current chips, so we could skip this + // for those chips, but it's not expensive, and maybe there will be another mismatch in the future. + for (gpio_num_t gpio_num = 0; gpio_num < SOC_GPIO_PIN_COUNT; gpio_num++) { + if (rtc_io_number_get(gpio_num) == rtc_io_pin_number) { + pin_number = gpio_num; + break; + } + } } 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 @@ -295,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 @@ -348,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..747d7d53878 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_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..9809962b394 100644 --- a/ports/espressif/common-hal/analogio/AnalogIn.c +++ b/ports/espressif/common-hal/analogio/AnalogIn.c @@ -23,7 +23,7 @@ #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) @@ -32,6 +32,8 @@ #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 +88,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 +137,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/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..2ae34d04960 100644 --- a/ports/espressif/common-hal/audiobusio/__init__.c +++ b/ports/espressif/common-hal/audiobusio/__init__.c @@ -108,7 +108,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; diff --git a/ports/espressif/common-hal/audioi2sin/I2SIn.c b/ports/espressif/common-hal/audioi2sin/I2SIn.c new file mode 100644 index 00000000000..ef8e908e2de --- /dev/null +++ b/ports/espressif/common-hal/audioi2sin/I2SIn.c @@ -0,0 +1,437 @@ +// 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) { + + 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; +} + +// 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/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..21dc8c38379 100644 --- a/ports/espressif/common-hal/busio/SPI.c +++ b/ports/espressif/common-hal/busio/SPI.c @@ -16,26 +16,12 @@ #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); - } - } -} - 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. @@ -61,6 +47,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 +79,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 +98,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 +114,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 +128,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); @@ -162,19 +157,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..ac2f404042b 100644 --- a/ports/espressif/common-hal/busio/SPI.h +++ b/ports/espressif/common-hal/busio/SPI.h @@ -25,5 +25,3 @@ typedef struct { SemaphoreHandle_t mutex; } busio_spi_obj_t; - -void spi_reset(void); 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..80111311bb7 100644 --- a/ports/espressif/common-hal/espcamera/Camera.c +++ b/ports/espressif/common-hal/espcamera/Camera.c @@ -86,7 +86,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]; @@ -153,7 +157,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/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/microcontroller/Pin.c b/ports/espressif/common-hal/microcontroller/Pin.c index 70912afb545..f995e65545d 100644 --- a/ports/espressif/common-hal/microcontroller/Pin.c +++ b/ports/espressif/common-hal/microcontroller/Pin.c @@ -77,6 +77,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. @@ -146,6 +155,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 +204,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. @@ -370,9 +412,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/Processor.c b/ports/espressif/common-hal/microcontroller/Processor.c index 8a6a14c0236..e87025067a3 100644 --- a/ports/espressif/common-hal/microcontroller/Processor.c +++ b/ports/espressif/common-hal/microcontroller/Processor.c @@ -59,7 +59,7 @@ 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}; @@ -126,6 +126,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) + 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 +147,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) + mac_address_part = REG_READ(EFUSE_RD_MAC_SYS1_REG); #else mac_address_part = REG_READ(EFUSE_RD_MAC_SPI_SYS_1_REG); #endif @@ -179,19 +183,18 @@ mcu_reset_reason_t common_hal_mcu_processor_get_reset_reason(void) { 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; + case ESP_RST_DEEPSLEEP: { + uint32_t wakeup_causes = esp_sleep_get_wakeup_causes(); + uint32_t alarm_causes = (1 << ESP_SLEEP_WAKEUP_TIMER) | + (1 << ESP_SLEEP_WAKEUP_EXT0) | + (1 << ESP_SLEEP_WAKEUP_EXT1) | + (1 << ESP_SLEEP_WAKEUP_TOUCHPAD) | + (1 << ESP_SLEEP_WAKEUP_ULP); + if (wakeup_causes & alarm_causes) { + return RESET_REASON_DEEP_SLEEP_ALARM; } + return RESET_REASON_UNKNOWN; + } case ESP_RST_UNKNOWN: default: diff --git a/ports/espressif/common-hal/microcontroller/__init__.c b/ports/espressif/common-hal/microcontroller/__init__.c index 918366b8933..9b50cd7b5d2 100644 --- a/ports/espressif/common-hal/microcontroller/__init__.c +++ b/ports/espressif/common-hal/microcontroller/__init__.c @@ -36,6 +36,9 @@ #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 +86,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_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 +142,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/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/rotaryio/IncrementalEncoder.c b/ports/espressif/common-hal/rotaryio/IncrementalEncoder.c index ba8b70221b7..f65c7fdd9f1 100644 --- a/ports/espressif/common-hal/rotaryio/IncrementalEncoder.c +++ b/ports/espressif/common-hal/rotaryio/IncrementalEncoder.c @@ -21,6 +21,10 @@ void common_hal_rotaryio_incrementalencoder_construct(rotaryio_incrementalencode // // These routines also implicitly configure the weak internal pull-ups, as expected // in CircuitPython. + + // Ensure object starts in its deinit state. + common_hal_rotaryio_incrementalencoder_mark_deinit(self); + pcnt_unit_config_t unit_config = { // Set counter limit .low_limit = INT16_MIN, @@ -87,6 +91,10 @@ void common_hal_rotaryio_incrementalencoder_deinit(rotaryio_incrementalencoder_o pcnt_del_channel(self->channel_a); pcnt_del_channel(self->channel_b); pcnt_del_unit(self->unit); + common_hal_rotaryio_incrementalencoder_mark_deinit(self); +} + +void common_hal_rotaryio_incrementalencoder_mark_deinit(rotaryio_incrementalencoder_obj_t *self) { self->unit = NULL; } diff --git a/ports/espressif/common-hal/sdioio/SDCard.c b/ports/espressif/common-hal/sdioio/SDCard.c index 87ba32f8020..04a9b62ec3e 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)) { @@ -111,6 +113,7 @@ void common_hal_sdioio_sdcard_construct(sdioio_sdcard_obj_t *self, if (err != ESP_OK) { mp_raise_OSError_msg_varg(MP_ERROR_TEXT("SDIO Init Error %x"), err); } + host_initialized = true; } err = sdmmc_host_init_slot(sd_slot, &slot_config); @@ -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/Socket.c b/ports/espressif/common-hal/socketpool/Socket.c index 0a36eff95b4..5128e93c858 100644 --- a/ports/espressif/common-hal/socketpool/Socket.c +++ b/ports/espressif/common-hal/socketpool/Socket.c @@ -483,7 +483,7 @@ void common_hal_socketpool_socket_connect(socketpool_socket_obj_t *self, socklen_t socklen = sizeof(error_code); result = 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); } self->connected = true; 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/Radio.c b/ports/espressif/common-hal/wifi/Radio.c index dc5311bb8ad..31dd7e4317f 100644 --- a/ports/espressif/common-hal/wifi/Radio.c +++ b/ports/espressif/common-hal/wifi/Radio.c @@ -115,7 +115,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 +126,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 +167,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 +181,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 +192,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) { @@ -386,7 +386,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/__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-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-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.defaults b/ports/espressif/esp-idf-config/sdkconfig.defaults index b54f599b2a5..941f879ed42 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 # @@ -71,16 +83,6 @@ CONFIG_LWIP_IPV6_AUTOCONFIG=y CONFIG_LWIP_IPV6_RDNSS_MAX_DNS_SERVERS=0 CONFIG_LWIP_IPV6_DHCP6=y # -# TCP -# -CONFIG_LWIP_MAX_ACTIVE_TCP=4 -CONFIG_LWIP_MAX_LISTENING_TCP=4 -CONFIG_LWIP_TCP_SYNMAXRTX=6 -CONFIG_LWIP_TCP_SND_BUF_DEFAULT=2880 -CONFIG_LWIP_TCP_WND_DEFAULT=2880 -CONFIG_LWIP_TCP_RTO_TIME=3000 -# end of TCP - # end of LWIP # @@ -113,11 +115,7 @@ 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 diff --git a/ports/espressif/boards/m5stack_cardputer/cardputer_keyboard.c b/ports/espressif/module/cardputer_keyboard.c similarity index 83% rename from ports/espressif/boards/m5stack_cardputer/cardputer_keyboard.c rename to ports/espressif/module/cardputer_keyboard.c index 73880f66e19..548275001ac 100644 --- a/ports/espressif/boards/m5stack_cardputer/cardputer_keyboard.c +++ b/ports/espressif/module/cardputer_keyboard.c @@ -16,7 +16,7 @@ #include "shared-module/keypad_demux/DemuxKeyMatrix.h" #include "supervisor/shared/reload.h" -#include "keymap.h" +#include "cardputer_keymap.h" //| """M5Stack Cardputer keyboard integration. //| """ @@ -31,12 +31,13 @@ //| """" //| KEYBOARD: keypad_demux.DemuxKeymatrix //| -keypad_demux_demuxkeymatrix_obj_t cardputer_keyboard_obj; -bool cardputer_keyboard_serial_attached = false; -void cardputer_keyboard_init(void); -void keyboard_seq(const char *seq); -void update_keyboard(keypad_eventqueue_obj_t *queue); +keypad_demux_demuxkeymatrix_obj_t cardputer_keyboard; +static bool cardputer_keyboard_serial_attached = false; + +// Forward declarations. +static void keyboard_seq(const char *seq); +static void update_keyboard(keypad_eventqueue_obj_t *queue); //| def detach_serial() -> None: //| """Stops consuming keyboard events and routing them to sys.stdin.""" @@ -44,7 +45,7 @@ void update_keyboard(keypad_eventqueue_obj_t *queue); //| static mp_obj_t detach_serial(void) { cardputer_keyboard_serial_attached = false; - common_hal_keypad_eventqueue_set_event_handler(cardputer_keyboard_obj.events, NULL); + common_hal_keypad_eventqueue_set_event_handler(cardputer_keyboard.events, NULL); return mp_const_none; } static MP_DEFINE_CONST_FUN_OBJ_0(detach_serial_obj, detach_serial); @@ -54,7 +55,7 @@ static MP_DEFINE_CONST_FUN_OBJ_0(detach_serial_obj, detach_serial); //| ... //| static mp_obj_t attach_serial(void) { - common_hal_keypad_eventqueue_set_event_handler(cardputer_keyboard_obj.events, update_keyboard); + common_hal_keypad_eventqueue_set_event_handler(cardputer_keyboard.events, update_keyboard); cardputer_keyboard_serial_attached = true; return mp_const_none; } @@ -79,20 +80,20 @@ static mp_obj_t key_to_char(mp_obj_t key_obj, mp_obj_t shifted_obj) { static MP_DEFINE_CONST_FUN_OBJ_2(key_to_char_obj, key_to_char); // Ring buffer of characters consumed from keyboard events (when serial attached) -ringbuf_t keyqueue; -char keybuf[32]; +static ringbuf_t keyqueue; +static char keybuf[32]; keypad_event_obj_t event; -char keystate[56]; +static char keystate[56] = {0}; // Keyboard pins -const mcu_pin_obj_t *row_addr_pins[] = { +static const mcu_pin_obj_t *row_addr_pins[] = { &pin_GPIO8, &pin_GPIO9, &pin_GPIO11, }; -const mcu_pin_obj_t *column_pins[] = { +static const mcu_pin_obj_t *column_pins[] = { &pin_GPIO13, &pin_GPIO15, &pin_GPIO3, @@ -102,22 +103,22 @@ const mcu_pin_obj_t *column_pins[] = { &pin_GPIO7 }; -void cardputer_keyboard_init(void) { - cardputer_keyboard_obj.base.type = &keypad_demux_demuxkeymatrix_type; +static void cardputer_keyboard_init(void) { common_hal_keypad_demux_demuxkeymatrix_construct( - &cardputer_keyboard_obj, // self - 3, // num_row_addr_pins - row_addr_pins, // row_addr_pins - 7, // num_column_pins - column_pins, // column_pins - true, // columns_to_anodes - false, // transpose - 0.01f, // interval - 20, // max_events - 2 // debounce_threshold + &cardputer_keyboard, // self + MP_ARRAY_SIZE(row_addr_pins), // num_row_addr_pins + row_addr_pins, // row_addr_pins + MP_ARRAY_SIZE(column_pins), // num_column_pins + column_pins, // column_pins + true, // columns_to_anodes + false, // transpose + 0.01f, // interval + 20, // max_events + 2, // debounce_threshold + false // use_gc_allocator ); - demuxkeymatrix_never_reset(&cardputer_keyboard_obj); + demuxkeymatrix_never_reset(&cardputer_keyboard); ringbuf_init(&keyqueue, (uint8_t *)keybuf, sizeof(keybuf)); attach_serial(); } @@ -150,13 +151,13 @@ char board_serial_read(void) { } } -void keyboard_seq(const char *seq) { +static void keyboard_seq(const char *seq) { while (*seq) { ringbuf_put(&keyqueue, *seq++); } } -void update_keyboard(keypad_eventqueue_obj_t *queue) { +static void update_keyboard(keypad_eventqueue_obj_t *queue) { uint8_t ascii = 0; if (common_hal_keypad_eventqueue_get_length(queue) == 0) { @@ -223,7 +224,7 @@ void update_keyboard(keypad_eventqueue_obj_t *queue) { static const mp_rom_map_elem_t cardputer_keyboard_module_globals_table[] = { {MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_cardputer_keyboard)}, - {MP_ROM_QSTR(MP_QSTR_KEYBOARD), MP_ROM_PTR(&cardputer_keyboard_obj)}, + {MP_ROM_QSTR(MP_QSTR_KEYBOARD), MP_ROM_PTR(&cardputer_keyboard)}, {MP_ROM_QSTR(MP_QSTR_attach_serial), MP_ROM_PTR(&attach_serial_obj)}, {MP_ROM_QSTR(MP_QSTR_detach_serial), MP_ROM_PTR(&detach_serial_obj)}, {MP_ROM_QSTR(MP_QSTR_key_to_char), MP_ROM_PTR(&key_to_char_obj)}, diff --git a/ports/espressif/boards/m5stack_cardputer/keymap.h b/ports/espressif/module/cardputer_keymap.h similarity index 100% rename from ports/espressif/boards/m5stack_cardputer/keymap.h rename to ports/espressif/module/cardputer_keymap.h diff --git a/ports/espressif/mpconfigport.h b/ports/espressif/mpconfigport.h index 712eb67f1f4..7f1a581571e 100644 --- a/ports/espressif/mpconfigport.h +++ b/ports/espressif/mpconfigport.h @@ -27,7 +27,7 @@ // 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_ESP32) #define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0) @@ -68,3 +68,7 @@ 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 diff --git a/ports/espressif/mpconfigport.mk b/ports/espressif/mpconfigport.mk index f05df8c07c8..f7a14f83202 100644 --- a/ports/espressif/mpconfigport.mk +++ b/ports/espressif/mpconfigport.mk @@ -17,6 +17,9 @@ 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,14 +57,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_TOUCH ?= 1 CIRCUITPY_ANALOGBUFIO ?= 1 CIRCUITPY_AUDIOBUSIO ?= 1 -CIRCUITPY_AUDIOBUSIO_PDMIN ?= 0 -CIRCUITPY_AUDIOIO ?= 0 +CIRCUITPY_AUDIOBUSIO_PDMIN ?= 1 +CIRCUITPY_AUDIOI2SIN ?= 1 +CIRCUITPY_AUDIOIO ?= 1 CIRCUITPY_BLEIO_HCI = 0 CIRCUITPY_BLEIO_NATIVE ?= 1 CIRCUITPY_CANIO ?= 1 @@ -72,7 +80,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,24 +92,22 @@ 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 CIRCUITPY_SOCKETPOOL_IPV6 ?= 1 -# Conditionally turn off modules/features +# Conditionally turn off modules/features per chip type +#### esp32 ############################################################ ifeq ($(IDF_TARGET),esp32) # Modules -CIRCUITPY_ALARM_TOUCH = 1 -CIRCUITPY_AUDIOIO ?= 1 CIRCUITPY_RGBMATRIX = 0 -# SDMMC not supported yet -CIRCUITPY_SDIOIO = 0 - # Has no USB CIRCUITPY_USB_DEVICE = 0 +#### esp32c2 ########################################################## else ifeq ($(IDF_TARGET),esp32c2) # C2 ROM spits out the UART at 74880 when connected to a 26mhz crystal! @@ -111,6 +117,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 @@ -127,6 +137,10 @@ CIRCUITPY_ANALOGBUFIO = 0 # No I2S CIRCUITPY_AUDIOBUSIO = 0 +CIRCUITPY_AUDIOI2SIN = 0 + +# No DAC +CIRCUITPY_AUDIOIO = 0 # No RMT CIRCUITPY_NEOPIXEL_WRITE = 0 @@ -136,12 +150,11 @@ 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 +#### esp32c3 ########################################################## else ifeq ($(IDF_TARGET),esp32c3) # Modules CIRCUITPY_ESPCAMERA = 0 @@ -151,6 +164,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 @@ -159,12 +183,11 @@ CIRCUITPY_ROTARYIO = 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 +#### esp32c6 ########################################################## else ifeq ($(IDF_TARGET),esp32c6) # Modules CIRCUITPY_ESPCAMERA = 0 @@ -172,8 +195,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 @@ -181,28 +215,76 @@ 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 -else ifeq ($(IDF_TARGET),esp32h2) +#### 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 -CIRCUITPY_TOUCHIO ?= 1 +# 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 +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 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 + # Features CIRCUITPY_USB_DEVICE = 0 CIRCUITPY_ESP_USB_SERIAL_JTAG ?= 1 @@ -210,21 +292,21 @@ CIRCUITPY_WIFI = 0 CIRCUITPY_MAX3421E = 0 +#### esp32p4 ########################################################## else ifeq ($(IDF_TARGET),esp32p4) +# No DAC +CIRCUITPY_AUDIOIO = 0 + # No wifi # TODO: Support ESP32-C6 coprocessor on some boards. 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 @@ -246,10 +328,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 = 1 CIRCUITPY_AUDIOIO ?= 1 + +# No I2S peripheral PDM-to-PCM hardware support +CIRCUITPY_AUDIOBUSIO_PDMIN = 0 + # No BLE in hw CIRCUITPY_BLEIO_NATIVE = 0 @@ -258,12 +347,20 @@ CIRCUITPY_SDIOIO = 0 CIRCUITPY_ESP_USB_SERIAL_JTAG ?= 0 +#### esp32s3 ########################################################## else ifeq ($(IDF_TARGET),esp32s3) + # Modules -CIRCUITPY_ALARM_TOUCH = 1 -CIRCUITPY_AUDIOBUSIO_PDMIN = 1 CIRCUITPY_ESP_USB_SERIAL_JTAG ?= 0 + +# No DAC +CIRCUITPY_AUDIOIO = 0 + endif +#### end chip-specific choices ######################################## + +# 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. 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/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..431a136545a 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) \ @@ -52,6 +51,8 @@ extern const mp_obj_type_t mcu_pin_type; #include "esp32c3/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..f55c16d3969 100644 --- a/ports/espressif/peripherals/touch.c +++ b/ports/espressif/peripherals/touch.c @@ -4,54 +4,144 @@ // // 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; + touch_channel_read_data(touch_channels[idx], TOUCH_CHAN_DATA_TYPE_RAW, &touch_value); + return UINT16_MAX - (uint16_t)touch_value; + #elif SOC_TOUCH_SENSOR_VERSION == 2 + 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..287fe54cc05 100644 --- a/ports/espressif/supervisor/port.c +++ b/ports/espressif/supervisor/port.c @@ -103,7 +103,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 +216,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 +244,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 +276,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); @@ -351,14 +356,11 @@ void reset_port(void) { ssl_reset(); #endif - reset_all_pins(); - #if CIRCUITPY_ANALOGIO analogout_reset(); #endif #if CIRCUITPY_BUSIO - spi_reset(); uart_reset(); #endif @@ -402,8 +404,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 +483,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 +515,7 @@ 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); + esp_wifi_get_mac(WIFI_IF_STA, mac); 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..0cf609c4d63 100644 --- a/ports/espressif/tools/build_memory_info.py +++ b/ports/espressif/tools/build_memory_info.py @@ -61,6 +61,12 @@ ("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/decode_backtrace.py b/ports/espressif/tools/decode_backtrace.py index 024e636207e..16cef9e0822 100644 --- a/ports/espressif/tools/decode_backtrace.py +++ b/ports/espressif/tools/decode_backtrace.py @@ -12,20 +12,41 @@ board = sys.argv[1] 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..d46514873bd 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.""" @@ -203,7 +202,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) @@ -244,7 +243,7 @@ def update(debug, board, update_all): # noqa: C901: too complex # 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 +320,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 +331,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 +377,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..cc813a49f8e 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)) 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/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..74667fd3d64 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)) 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/rotaryio/IncrementalEncoder.c b/ports/mimxrt10xx/common-hal/rotaryio/IncrementalEncoder.c index c71f8b212e1..211b5c186f3 100644 --- a/ports/mimxrt10xx/common-hal/rotaryio/IncrementalEncoder.c +++ b/ports/mimxrt10xx/common-hal/rotaryio/IncrementalEncoder.c @@ -26,6 +26,9 @@ static void encoder_change(void *self_in) { 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; @@ -49,7 +52,7 @@ void common_hal_rotaryio_incrementalencoder_construct(rotaryio_incrementalencode } bool common_hal_rotaryio_incrementalencoder_deinited(rotaryio_incrementalencoder_obj_t *self) { - return !self->pin_a; + return self->pin_a == NULL; } void common_hal_rotaryio_incrementalencoder_deinit(rotaryio_incrementalencoder_obj_t *self) { @@ -62,6 +65,9 @@ void common_hal_rotaryio_incrementalencoder_deinit(rotaryio_incrementalencoder_o common_hal_reset_pin(self->pin_a); common_hal_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/mimxrt10xx/common-hal/usb_host/Port.c b/ports/mimxrt10xx/common-hal/usb_host/Port.c index 31af4ed5823..a7e73ab5b5c 100644 --- a/ports/mimxrt10xx/common-hal/usb_host/Port.c +++ b/ports/mimxrt10xx/common-hal/usb_host/Port.c @@ -47,5 +47,8 @@ usb_host_port_obj_t *common_hal_usb_host_port_construct(const mcu_pin_obj_t *dp, self->dp = dp; self->dm = dm; + claim_pin(dp); + claim_pin(dm); + return self; } 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..b3f078c7ecf 100644 --- a/ports/mimxrt10xx/mpconfigport.mk +++ b/ports/mimxrt10xx/mpconfigport.mk @@ -2,8 +2,6 @@ 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..1e283fc699c 100755 --- a/ports/nordic/Makefile +++ b/ports/nordic/Makefile @@ -36,8 +36,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) @@ -146,7 +146,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 +157,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 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/electronut_labs_blip/mpconfigboard.mk b/ports/nordic/boards/electronut_labs_blip/mpconfigboard.mk index 0e3b1b90489..fc59a101e45 100644 --- a/ports/nordic/boards/electronut_labs_blip/mpconfigboard.mk +++ b/ports/nordic/boards/electronut_labs_blip/mpconfigboard.mk @@ -11,3 +11,4 @@ INTERNAL_FLASH_FILESYSTEM = 1 CIRCUITPY_AUDIOIO = 0 CIRCUITPY_DISPLAYIO = 1 CIRCUITPY_STAGE = 1 +CIRCUITPY_DIGITALINOUT_PROTOCOL = 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/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/common-hal/_bleio/Adapter.c b/ports/nordic/common-hal/_bleio/Adapter.c index 9cf40ae91b3..2ca9df89710 100644 --- a/ports/nordic/common-hal/_bleio/Adapter.c +++ b/ports/nordic/common-hal/_bleio/Adapter.c @@ -32,9 +32,8 @@ #include "supervisor/usb.h" #endif -#if CIRCUITPY_OS_GETENV -#include "shared-bindings/os/__init__.h" -#include "shared-module/os/__init__.h" +#if CIRCUITPY_SETTINGS_TOML +#include "supervisor/shared/settings.h" #endif #define BLE_MIN_CONN_INTERVAL MSEC_TO_UNITS(15, UNIT_0_625_MS) @@ -324,11 +323,11 @@ static void bleio_adapter_reset_name(bleio_adapter_obj_t *self) { 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 + #if CIRCUITPY_SETTINGS_TOML 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) { + 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; } 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 1975c2c3d79..2e6042e48e7 100644 --- a/ports/nordic/common-hal/_bleio/Characteristic.c +++ b/ports/nordic/common-hal/_bleio/Characteristic.c @@ -80,7 +80,7 @@ void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self, // to allocate. self->initial_value_len = initial_value_bufinfo->len; if (gc_alloc_possible()) { - if (gc_nbytes(initial_value_bufinfo->buf) > 0) { + if (gc_ptr_on_heap(initial_value_bufinfo->buf)) { uint8_t *initial_value = m_malloc_without_collect(self->initial_value_len); memcpy(initial_value, initial_value_bufinfo->buf, self->initial_value_len); self->initial_value = initial_value; @@ -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]; @@ -255,7 +255,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.h b/ports/nordic/common-hal/_bleio/Connection.h index 110677dc78b..ea1edf17603 100644 --- a/ports/nordic/common-hal/_bleio/Connection.h +++ b/ports/nordic/common-hal/_bleio/Connection.h @@ -65,6 +65,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/Service.c b/ports/nordic/common-hal/_bleio/Service.c index edd67a5fe73..1bd75f8a481 100644 --- a/ports/nordic/common-hal/_bleio/Service.c +++ b/ports/nordic/common-hal/_bleio/Service.c @@ -131,7 +131,7 @@ void common_hal_bleio_service_add_characteristic(bleio_service_obj_t *self, BLE_GAP_CONN_SEC_MODE_SET_OPEN(&user_desc_md.read_perm); // If the description is on the Python heap, then have the SD copy it. If not, assume it's // static and will live for longer than the SD. - user_desc_md.vloc = gc_nbytes(user_description) > 0 ? BLE_GATTS_VLOC_STACK : BLE_GATTS_VLOC_USER; + user_desc_md.vloc = gc_ptr_on_heap(user_description) ? BLE_GATTS_VLOC_STACK : BLE_GATTS_VLOC_USER; char_md.p_user_desc_md = &user_desc_md; char_md.p_char_user_desc = (const uint8_t *)user_description; char_md.char_user_desc_max_size = strlen(user_description); diff --git a/ports/nordic/common-hal/_bleio/__init__.c b/ports/nordic/common-hal/_bleio/__init__.c index 454937dcd35..9dc58d7687c 100644 --- a/ports/nordic/common-hal/_bleio/__init__.c +++ b/ports/nordic/common-hal/_bleio/__init__.c @@ -112,14 +112,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 +133,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 +188,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 +213,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/alarm/__init__.c b/ports/nordic/common-hal/alarm/__init__.c index 9753b0321fd..026e117b9a6 100644 --- a/ports/nordic/common-hal/alarm/__init__.c +++ b/ports/nordic/common-hal/alarm/__init__.c @@ -240,7 +240,7 @@ void common_hal_alarm_set_deep_sleep_alarms(size_t n_alarms, const mp_obj_t *ala #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/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..de54dd08a27 100644 --- a/ports/nordic/common-hal/busio/SPI.c +++ b/ports/nordic/common-hal/busio/SPI.c @@ -59,26 +59,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 +112,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); } @@ -178,6 +168,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 +182,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 0dfe6ae3f5d..6939486a5e6 100644 --- a/ports/nordic/common-hal/busio/UART.c +++ b/ports/nordic/common-hal/busio/UART.c @@ -122,7 +122,7 @@ void uart_reset(void) { void common_hal_busio_uart_never_reset(busio_uart_obj_t *self) { // Don't never reset objects on the heap. - if (gc_alloc_possible() && gc_nbytes(self) > 0) { + if (gc_alloc_possible() && gc_ptr_on_heap(self)) { return; } for (size_t i = 0; i < MP_ARRAY_SIZE(nrfx_uartes); i++) { @@ -346,7 +346,7 @@ size_t common_hal_busio_uart_write(busio_uart_obj_t *self, const uint8_t *data, RUN_BACKGROUND_TASKS; } - if (!nrfx_is_in_ram(data) && gc_alloc_possible() && gc_nbytes(tx_buf) > 0) { + if (!nrfx_is_in_ram(data) && gc_alloc_possible() && gc_ptr_on_heap(tx_buf)) { gc_free(tx_buf); } diff --git a/ports/nordic/common-hal/rotaryio/IncrementalEncoder.c b/ports/nordic/common-hal/rotaryio/IncrementalEncoder.c index b0617fae7e5..2e8b308ff64 100644 --- a/ports/nordic/common-hal/rotaryio/IncrementalEncoder.c +++ b/ports/nordic/common-hal/rotaryio/IncrementalEncoder.c @@ -32,6 +32,9 @@ static void _intr_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action) { 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->number; self->pin_b = pin_b->number; @@ -78,6 +81,10 @@ void common_hal_rotaryio_incrementalencoder_deinit(rotaryio_incrementalencoder_o nrfx_gpiote_in_uninit(self->pin_b); reset_pin_number(self->pin_a); reset_pin_number(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 = NO_PIN; - self->pin_b = NO_PIN; } diff --git a/ports/nordic/mpconfigport.mk b/ports/nordic/mpconfigport.mk index 502e71ae4ae..0316e904b38 100644 --- a/ports/nordic/mpconfigport.mk +++ b/ports/nordic/mpconfigport.mk @@ -9,6 +9,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 @@ -63,6 +72,8 @@ CIRCUITPY_MEMORYMAP ?= 1 CIRCUITPY_RGBMATRIX ?= 1 CIRCUITPY_FRAMEBUFFERIO ?= 1 +CIRCUITPY_HASHLIB ?= 1 + CIRCUITPY_COUNTIO ?= 1 CIRCUITPY_WATCHDOG ?= 1 @@ -81,6 +92,8 @@ ifeq ($(INTERNAL_FLASH_FILESYSTEM),1) OPTIMIZATION_FLAGS ?= -Os CIRCUITPY_LTO = 1 CIRCUITPY_LTO_PARTITION = balanced +else + CIRCUITPY_USB_AUDIO ?= 1 endif else diff --git a/ports/nordic/supervisor/port.c b/ports/nordic/supervisor/port.c index ed371c6ad85..1eabfcbe216 100644 --- a/ports/nordic/supervisor/port.c +++ b/ports/nordic/supervisor/port.c @@ -189,7 +189,6 @@ safe_mode_t port_init(void) { void reset_port(void) { #if CIRCUITPY_BUSIO - spi_reset(); uart_reset(); #endif @@ -216,8 +215,6 @@ void reset_port(void) { nrfx_gpiote_uninit(); } nrfx_gpiote_init(NRFX_GPIOTE_CONFIG_IRQ_PRIORITY); - - reset_all_pins(); } void reset_to_bootloader(void) { diff --git a/ports/raspberrypi/Makefile b/ports/raspberrypi/Makefile index ba2db8a7508..d2c550c90fa 100644 --- a/ports/raspberrypi/Makefile +++ b/ports/raspberrypi/Makefile @@ -25,7 +25,8 @@ INC_CYW43 := \ CFLAGS_CYW43 := \ -DCYW43_LWIP=1 \ -DPICO_CYW43_ARCH_THREADSAFE_BACKGROUND=1 \ - -DCYW43_USE_SPI \ + -DCYW43_USE_SPI=1 \ + -DUSE_SDIOIT=0 \ -DIGNORE_GPIO25 \ -DIGNORE_GPIO23 \ -DIGNORE_GPIO24 \ @@ -125,6 +126,7 @@ INC += \ -isystem sdk/src/rp2_common/hardware_powman/include/ \ -isystem sdk/src/rp2_common/hardware_pwm/include/ \ -isystem sdk/src/rp2_common/hardware_resets/include/ \ + -isystem sdk/src/rp2_common/hardware_rcp/include/ \ -isystem sdk/src/rp2_common/hardware_rtc/include/ \ -isystem sdk/src/rp2_common/hardware_spi/include/ \ -isystem sdk/src/rp2_common/hardware_sync/include/ \ @@ -149,6 +151,7 @@ INC += \ -isystem sdk/src/rp2_common/pico_float/include/ \ -isystem sdk/src/rp2_common/pico_runtime/include/ \ -isystem sdk/src/rp2_common/pico_runtime_init/include/ \ + -isystem sdk/src/rp2_common/pico_platform_common/include/ \ -isystem sdk/src/rp2_common/pico_platform_compiler/include/ \ -isystem sdk/src/rp2_common/pico_platform_sections/include/ \ -isystem sdk/src/rp2_common/pico_platform_panic/include/ \ @@ -393,6 +396,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 \ @@ -402,8 +407,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 \ @@ -431,12 +435,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 @@ -446,7 +450,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 \ @@ -470,6 +474,7 @@ endif endif +SRC_C += shared/runtime/gchelper_native.c SRC_SDK := \ src/common/hardware_claim/claim.c \ @@ -669,7 +674,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) diff --git a/ports/raspberrypi/audio_dma.c b/ports/raspberrypi/audio_dma.c index ae3997a128f..36b86cbf844 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) { @@ -233,7 +238,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 +254,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 +340,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 +356,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 +458,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 +470,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 @@ -532,34 +530,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/bindings/rp2pio/StateMachine.h b/ports/raspberrypi/bindings/rp2pio/StateMachine.h index afdffd1eccd..3c775a96449 100644 --- a/ports/raspberrypi/bindings/rp2pio/StateMachine.h +++ b/ports/raspberrypi/bindings/rp2pio/StateMachine.h @@ -42,6 +42,7 @@ void common_hal_rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self, void common_hal_rp2pio_statemachine_deinit(rp2pio_statemachine_obj_t *self); bool common_hal_rp2pio_statemachine_deinited(rp2pio_statemachine_obj_t *self); +void common_hal_rp2pio_statemachine_mark_deinit(rp2pio_statemachine_obj_t *self); void common_hal_rp2pio_statemachine_never_reset(rp2pio_statemachine_obj_t *self); @@ -61,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/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_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_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_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_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/bradanlanestudio_explorer_rp2040/board.c b/ports/raspberrypi/boards/bradanlanestudio_explorer_rp2040/board.c index 19e18bd544b..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 @@ -251,73 +251,62 @@ void board_init(void) { if ((vid_setting == 1) || // DCNextGen SSD1681 BWR rotated 270 (vid_setting == 3) || // Explorer SSD1681 BW rotated 0 (vid_setting == 4)) { // Explorer SSD1681 BWR rotated 0 - common_hal_epaperdisplay_epaperdisplay_construct( - display, - bus, - _start_sequence_ssd1681, sizeof(_start_sequence_ssd1681), - 1.0, // start up time - _stop_sequence_ssd1681, sizeof(_stop_sequence_ssd1681), - WIDTH, // width - HEIGHT, // height - WIDTH, // ram_width - HEIGHT + 0x60, // ram_height RAM is actually only 200 bits high but we use 296 to match the 9 bits - 0, // colstart - 0, // rowstart - rotation, // rotation - SSD_SET_RAMXPOS, // set_column_window_command - SSD_SET_RAMYPOS, // set_row_window_command - SSD_SET_RAMXCOUNT, // set_current_column_command - SSD_SET_RAMYCOUNT, // set_current_row_command - SSD_WRITE_RAM_BLK, // write_black_ram_command - false, // black_bits_inverted - SSD_WRITE_RAM_RED, // write_color_ram_command - false, // color_bits_inverted - 0xFF0000, // highlight_color (RED for tri-color display) - _refresh_sequence_ssd1681, sizeof(_refresh_sequence_ssd1681), // refresh_display_command - refresh_time, // refresh_time - &pin_GPIO9, // DEFAULT_SPI_BUS_BUSY, // busy_pin - true, // busy_state - seconds_per_frame, // seconds_per_frame (does not seem the user can change this) - true, // always_toggle_chip_select - false, // not grayscale - false, // not acep - false, // not spectra6 - false, // not two_byte_sequence_length - true); // address_little_endian + epaperdisplay_construct_args_t args = EPAPERDISPLAY_CONSTRUCT_ARGS_DEFAULTS; + args.bus = bus; + args.start_sequence = _start_sequence_ssd1681; + args.start_sequence_len = sizeof(_start_sequence_ssd1681); + args.start_up_time = 1.0; + args.stop_sequence = _stop_sequence_ssd1681; + args.stop_sequence_len = sizeof(_stop_sequence_ssd1681); + args.width = WIDTH; + args.height = HEIGHT; + args.ram_width = WIDTH; + args.ram_height = HEIGHT + 0x60; + args.rotation = rotation; + args.set_column_window_command = SSD_SET_RAMXPOS; + args.set_row_window_command = SSD_SET_RAMYPOS; + args.set_current_column_command = SSD_SET_RAMXCOUNT; + args.set_current_row_command = SSD_SET_RAMYCOUNT; + args.write_black_ram_command = SSD_WRITE_RAM_BLK; + args.write_color_ram_command = SSD_WRITE_RAM_RED; + args.highlight_color = 0xFF0000; + args.refresh_sequence = _refresh_sequence_ssd1681; + args.refresh_sequence_len = sizeof(_refresh_sequence_ssd1681); + args.refresh_time = refresh_time; + args.busy_pin = &pin_GPIO9; + args.busy_state = true; + args.seconds_per_frame = seconds_per_frame; + args.always_toggle_chip_select = true; + args.address_little_endian = true; + common_hal_epaperdisplay_epaperdisplay_construct(display, &args); } else if (vid_setting == 2) { // Explorer SSD1608 BW - common_hal_epaperdisplay_epaperdisplay_construct( - display, - bus, - _start_sequence_ssd1608, sizeof(_start_sequence_ssd1608), - 1.0, // start up time - _stop_sequence_ssd1608, sizeof(_stop_sequence_ssd1608), - WIDTH, // width - HEIGHT, // height - WIDTH, // ram_width - HEIGHT /* + 0x60 */, // ram_height RAM is actually only 200 bits high but we use 296 to match the 9 bits - 0, // colstart - 0, // rowstart - rotation, // rotation - SSD_SET_RAMXPOS, // set_column_window_command - SSD_SET_RAMYPOS, // set_row_window_command - SSD_SET_RAMXCOUNT, // set_current_column_command - SSD_SET_RAMYCOUNT, // set_current_row_command - SSD_WRITE_RAM_BLK, // write_black_ram_command - false, // black_bits_inverted - NO_COMMAND, // write_color_ram_command - false, // color_bits_inverted - 0x000000, // highlight_color (RED for tri-color display) - _refresh_sequence_ssd1608, sizeof(_refresh_sequence_ssd1608), // refresh_display_command - refresh_time, // refresh_time - &pin_GPIO9, // DEFAULT_SPI_BUS_BUSY, // busy_pin - true, // busy_state - seconds_per_frame, // seconds_per_frame (does not seem the user can change this) - true, // always_toggle_chip_select - false, // not grayscale - false, // not acep - false, // not spectra6 - false, // not two_byte_sequence_length - true); // address_little_endian + epaperdisplay_construct_args_t args = EPAPERDISPLAY_CONSTRUCT_ARGS_DEFAULTS; + args.bus = bus; + args.start_sequence = _start_sequence_ssd1608; + args.start_sequence_len = sizeof(_start_sequence_ssd1608); + args.start_up_time = 1.0; + args.stop_sequence = _stop_sequence_ssd1608; + args.stop_sequence_len = sizeof(_stop_sequence_ssd1608); + args.width = WIDTH; + args.height = HEIGHT; + args.ram_width = WIDTH; + args.ram_height = HEIGHT; + args.rotation = rotation; + args.set_column_window_command = SSD_SET_RAMXPOS; + args.set_row_window_command = SSD_SET_RAMYPOS; + args.set_current_column_command = SSD_SET_RAMXCOUNT; + args.set_current_row_command = SSD_SET_RAMYCOUNT; + args.write_black_ram_command = SSD_WRITE_RAM_BLK; + args.write_color_ram_command = NO_COMMAND; + args.refresh_sequence = _refresh_sequence_ssd1608; + args.refresh_sequence_len = sizeof(_refresh_sequence_ssd1608); + args.refresh_time = refresh_time; + args.busy_pin = &pin_GPIO9; + args.busy_state = true; + args.seconds_per_frame = seconds_per_frame; + args.always_toggle_chip_select = true; + args.address_little_endian = true; + common_hal_epaperdisplay_epaperdisplay_construct(display, &args); } else { // what should happen if this firmware is installed on some other board? // currently, we mark the display as None 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..d8f93922623 100644 --- a/ports/raspberrypi/boards/pajenicko_picopad/board.c +++ b/ports/raspberrypi/boards/pajenicko_picopad/board.c @@ -51,9 +51,9 @@ 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 + 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 60000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/raspberrypi/boards/pajenicko_picopad/mpconfigboard.mk b/ports/raspberrypi/boards/pajenicko_picopad/mpconfigboard.mk index 764e41d4d91..1c3801edaac 100644 --- a/ports/raspberrypi/boards/pajenicko_picopad/mpconfigboard.mk +++ b/ports/raspberrypi/boards/pajenicko_picopad/mpconfigboard.mk @@ -12,6 +12,7 @@ EXTERNAL_FLASH_DEVICES = "W25Q16JVxQ" CIRCUITPY_KEYPAD = 1 CIRCUITPY_STAGE = 1 CIRCUITPY_AUDIOIO = 1 +CIRCUITPY_AUDIOEFFECTS = 0 CIRCUITPY__EVE = 1 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 5950d11da8a..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 @@ -273,39 +273,27 @@ void board_init(void) { // Set up the DisplayIO epaper object epaperdisplay_epaperdisplay_obj_t *display = &allocate_display()->epaper_display; display->base.type = &epaperdisplay_epaperdisplay_type; - common_hal_epaperdisplay_epaperdisplay_construct( - display, - bus, - display_start_sequence, sizeof(display_start_sequence), - 0, // start up time - display_stop_sequence, sizeof(display_stop_sequence), - 296, // width - 128, // height - 160, // ram_width - 296, // ram_height - 0, // colstart - 0, // rowstart - 270, // rotation - NO_COMMAND, // set_column_window_command - NO_COMMAND, // set_row_window_command - NO_COMMAND, // set_current_column_command - NO_COMMAND, // set_current_row_command - DTM2, // write_black_ram_command - true, // black_bits_inverted - DTM1, // write_color_ram_command - false, // color_bits_inverted - 0x000000, // highlight_color - refresh_sequence, sizeof(refresh_sequence), // refresh_display_command - 1.0, // refresh_time - &pin_GPIO26, // busy_pin - false, // busy_state - 2.0, // seconds_per_frame - false, // always_toggle_chip_select - false, // grayscale - false, // acep - false, // spectra6 - false, // two_byte_sequence_length - false); // address_little_endian + + epaperdisplay_construct_args_t args = EPAPERDISPLAY_CONSTRUCT_ARGS_DEFAULTS; + args.bus = bus; + args.start_sequence = display_start_sequence; + args.start_sequence_len = sizeof(display_start_sequence); + args.stop_sequence = display_stop_sequence; + args.stop_sequence_len = sizeof(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 = DTM2; + args.black_bits_inverted = true; + args.write_color_ram_command = DTM1; + args.refresh_sequence = refresh_sequence; + args.refresh_sequence_len = sizeof(refresh_sequence); + args.refresh_time = 1.0; + args.busy_pin = &pin_GPIO26; + args.seconds_per_frame = 2.0; + common_hal_epaperdisplay_epaperdisplay_construct(display, &args); } void board_deinit(void) { diff --git a/ports/raspberrypi/boards/pimoroni_badger2040w/board.c b/ports/raspberrypi/boards/pimoroni_badger2040w/board.c index 7dc11af01ec..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 @@ -273,39 +273,27 @@ void board_init(void) { // Set up the DisplayIO epaper object epaperdisplay_epaperdisplay_obj_t *display = &allocate_display()->epaper_display; display->base.type = &epaperdisplay_epaperdisplay_type; - common_hal_epaperdisplay_epaperdisplay_construct( - display, - bus, - display_start_sequence, sizeof(display_start_sequence), - 0, // start up time - display_stop_sequence, sizeof(display_stop_sequence), - 296, // width - 128, // height - 160, // ram_width - 296, // ram_height - 0, // colstart - 0, // rowstart - 270, // rotation - NO_COMMAND, // set_column_window_command - NO_COMMAND, // set_row_window_command - NO_COMMAND, // set_current_column_command - NO_COMMAND, // set_current_row_command - DTM2, // write_black_ram_command - true, // black_bits_inverted - DTM1, // write_color_ram_command - false, // color_bits_inverted - 0x000000, // highlight_color - refresh_sequence, sizeof(refresh_sequence), // refresh_display_command - 1.0, // refresh_time - &pin_GPIO26, // busy_pin - false, // busy_state - 2.0, // seconds_per_frame - false, // always_toggle_chip_select - false, // grayscale - false, // acep - false, // spectra6 - false, // two_byte_sequence_length - false); // address_little_endian + + epaperdisplay_construct_args_t args = EPAPERDISPLAY_CONSTRUCT_ARGS_DEFAULTS; + args.bus = bus; + args.start_sequence = display_start_sequence; + args.start_sequence_len = sizeof(display_start_sequence); + args.stop_sequence = display_stop_sequence; + args.stop_sequence_len = sizeof(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 = DTM2; + args.black_bits_inverted = true; + args.write_color_ram_command = DTM1; + args.refresh_sequence = refresh_sequence; + args.refresh_sequence_len = sizeof(refresh_sequence); + args.refresh_time = 1.0; + args.busy_pin = &pin_GPIO26; + args.seconds_per_frame = 2.0; + common_hal_epaperdisplay_epaperdisplay_construct(display, &args); } void board_deinit(void) { 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 7969143ec66..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,48 +58,35 @@ 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 epaperdisplay_epaperdisplay_obj_t *display = &allocate_display()->epaper_display; display->base.type = &epaperdisplay_epaperdisplay_type; - common_hal_epaperdisplay_epaperdisplay_construct( - display, - bus, - display_start_sequence, sizeof(display_start_sequence), - 1.0, // start up time - display_stop_sequence, sizeof(display_stop_sequence), - 600, // width - 448, // height - 640, // ram_width - 480, // ram_height - 0, // colstart - 0, // rowstart - 0, // rotation - NO_COMMAND, // set_column_window_command - NO_COMMAND, // set_row_window_command - NO_COMMAND, // set_current_column_command - NO_COMMAND, // set_current_row_command - 0x10, // write_black_ram_command - false, // black_bits_inverted - NO_COMMAND, // write_color_ram_command - false, // color_bits_inverted - 0x000000, // highlight_color - refresh_sequence, sizeof(refresh_sequence), - 28.0, // refresh_time - NULL, // busy_pin - false, // busy_state - 40.0, // seconds_per_frame - false, // always_toggle_chip_select - false, // grayscale - true, // acep - false, // spectra6 - false, // two_byte_sequence_length - false); // address_little_endian + + epaperdisplay_construct_args_t args = EPAPERDISPLAY_CONSTRUCT_ARGS_DEFAULTS; + args.bus = bus; + args.start_sequence = display_start_sequence; + args.start_sequence_len = sizeof(display_start_sequence); + args.start_up_time = 1.0; + args.stop_sequence = display_stop_sequence; + args.stop_sequence_len = sizeof(display_stop_sequence); + args.width = 600; + args.height = 448; + args.ram_width = 640; + args.ram_height = 480; + args.write_black_ram_command = 0x10; + args.refresh_sequence = refresh_sequence; + args.refresh_sequence_len = sizeof(refresh_sequence); + args.refresh_time = 28.0; + args.busy_pin = NULL; + args.seconds_per_frame = 40.0; + args.acep = true; + common_hal_epaperdisplay_epaperdisplay_construct(display, &args); } // Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. 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 7c71e03b428..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,48 +117,36 @@ 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 epaperdisplay_epaperdisplay_obj_t *display = &allocate_display()->epaper_display; display->base.type = &epaperdisplay_epaperdisplay_type; - common_hal_epaperdisplay_epaperdisplay_construct( - display, - bus, - display_start_sequence, sizeof(display_start_sequence), - 1.0, // start up time - display_stop_sequence, sizeof(display_stop_sequence), - 800, // width - 480, // height - 800, // ram_width - 480, // ram_height - 0, // colstart - 0, // rowstart - 180, // rotation - NO_COMMAND, // set_column_window_command - NO_COMMAND, // set_row_window_command - NO_COMMAND, // set_current_column_command - NO_COMMAND, // set_current_row_command - 0x10, // write_black_ram_command - false, // black_bits_inverted - NO_COMMAND, // write_color_ram_command - false, // color_bits_inverted - 0x000000, // highlight_color - refresh_sequence, sizeof(refresh_sequence), - 28.0, // refresh_time - NULL, // busy_pin - false, // busy_state - 30.0, // seconds_per_frame - false, // always_toggle_chip_select - false, // grayscale - true, // acep - false, // spectra6 - false, // two_byte_sequence_length - false); // address_little_endian + + epaperdisplay_construct_args_t args = EPAPERDISPLAY_CONSTRUCT_ARGS_DEFAULTS; + args.bus = bus; + args.start_sequence = display_start_sequence; + args.start_sequence_len = sizeof(display_start_sequence); + args.start_up_time = 1.0; + args.stop_sequence = display_stop_sequence; + args.stop_sequence_len = sizeof(display_stop_sequence); + args.width = 800; + args.height = 480; + args.ram_width = 800; + args.ram_height = 480; + args.rotation = 180; + args.write_black_ram_command = 0x10; + args.refresh_sequence = refresh_sequence; + args.refresh_sequence_len = sizeof(refresh_sequence); + args.refresh_time = 28.0; + args.busy_pin = NULL; + args.seconds_per_frame = 30.0; + args.acep = true; + common_hal_epaperdisplay_epaperdisplay_construct(display, &args); } // Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. 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_plasma2350/mpconfigboard.h b/ports/raspberrypi/boards/pimoroni_plasma2350/mpconfigboard.h index 72b1e1d0439..097cbd8baa3 100644 --- a/ports/raspberrypi/boards/pimoroni_plasma2350/mpconfigboard.h +++ b/ports/raspberrypi/boards/pimoroni_plasma2350/mpconfigboard.h @@ -5,7 +5,7 @@ // SPDX-License-Identifier: MIT #define MICROPY_HW_BOARD_NAME "Pimoroni Plasma 2350" -#define MICROPY_HW_MCU_NAME "rp2350b" +#define MICROPY_HW_MCU_NAME "rp2350a" #define CIRCUITPY_RGB_STATUS_INVERTED_PWM #define CIRCUITPY_RGB_STATUS_R (&pin_GPIO16) 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.h b/ports/raspberrypi/boards/pimoroni_plasma2350w/mpconfigboard.h index d9e62abb1ed..576299d939c 100644 --- a/ports/raspberrypi/boards/pimoroni_plasma2350w/mpconfigboard.h +++ b/ports/raspberrypi/boards/pimoroni_plasma2350w/mpconfigboard.h @@ -5,7 +5,7 @@ // SPDX-License-Identifier: MIT #define MICROPY_HW_BOARD_NAME "Pimoroni Plasma 2350W" -#define MICROPY_HW_MCU_NAME "rp2350A" +#define MICROPY_HW_MCU_NAME "rp2350a" #define CIRCUITPY_RGB_STATUS_INVERTED_PWM #define CIRCUITPY_RGB_STATUS_R (&pin_GPIO16) 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/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/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/common-hal/alarm/__init__.c b/ports/raspberrypi/common-hal/alarm/__init__.c index c47ddc31505..a72b3a368d4 100644 --- a/ports/raspberrypi/common-hal/alarm/__init__.c +++ b/ports/raspberrypi/common-hal/alarm/__init__.c @@ -197,7 +197,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) { bool timealarm_set = alarm_time_timealarm_is_set(); #if CIRCUITPY_CYW43 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..8bdc4cfeb3b --- /dev/null +++ b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c @@ -0,0 +1,742 @@ +// 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 slave +// 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) + +// Master-mode 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 +}; + +// Master-mode 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 +}; + +// Master-mode 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 +}; + +// Master-mode 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 +}; + +// 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) { + + 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; + + 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, + 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, 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 + 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. + 1, -1, // wrap settings + PIO_ANY_OFFSET, + 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); + self->sample_rate = actual_frequency / pio_clocks_per_frame; + self->bit_depth = bit_depth; + self->mono = mono; + self->samples_signed = samples_signed; + self->left_justified = left_justified; + 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; +} + +// 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; + // 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..bd5cdea577e --- /dev/null +++ b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.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 "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 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..97dc9c7f7e9 --- /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 + +; Master-mode I2S RX. Generates BCLK and LRCLK via side-set and samples the +; data pin. The slave updates `data` on BCLK falling edge, so the master +; 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 +; slave 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..f09a02a85c2 --- /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 + +; Master-mode 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 slave updates `data` on BCLK +; falling edge, so the master 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 slave 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..8926d178635 --- /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 + +; Master-mode 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..86fcf79a876 --- /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 + +; Master-mode 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..8b718ebae65 --- /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 + +; Master-mode 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..8ac65a20f90 --- /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 + +; Master-mode 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..f6adc3d5bb8 --- /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 + +; Master-mode 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..ae0ef8b8afb --- /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 + +; Master-mode 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/busio/I2C.c b/ports/raspberrypi/common-hal/busio/I2C.c index 0f7e023f0e9..1441a2a7a06 100644 --- a/ports/raspberrypi/common-hal/busio/I2C.c +++ b/ports/raspberrypi/common-hal/busio/I2C.c @@ -86,7 +86,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); @@ -144,7 +144,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 +174,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 +195,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 d20bc4d7d10..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, @@ -182,7 +174,10 @@ static bool _transfer(busio_spi_obj_t *self, chan_tx = dma_claim_unused_channel(false); chan_rx = dma_claim_unused_channel(false); } - bool use_dma = chan_rx >= 0 && chan_tx >= 0; + bool has_dma_channels = chan_rx >= 0 && chan_tx >= 0; + // Only use DMA if both data buffers are in SRAM. Otherwise, we'll stall the DMA with PSRAM or flash cache misses. + bool data_in_sram = data_in >= (uint8_t *)SRAM_BASE && data_out >= (uint8_t *)SRAM_BASE; + bool use_dma = has_dma_channels && data_in_sram; if (use_dma) { dma_channel_config c = dma_channel_get_default_config(chan_tx); channel_config_set_transfer_data_size(&c, DMA_SIZE_8); 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..7a8ad7d4df2 --- /dev/null +++ b/ports/raspberrypi/common-hal/mcp4822/MCP4822.c @@ -0,0 +1,286 @@ +// 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); + } + + 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/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..5a4e7071544 100644 --- a/ports/raspberrypi/common-hal/microcontroller/Processor.c +++ b/ports/raspberrypi/common-hal/microcontroller/Processor.c @@ -20,11 +20,11 @@ #include "hardware/vreg.h" #include "hardware/watchdog.h" -#ifdef PICO_RP2040 +#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 @@ -80,7 +80,7 @@ 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; - #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) { @@ -96,7 +96,7 @@ mcu_reset_reason_t common_hal_mcu_processor_get_reset_reason(void) { reason = 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) { 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_RP2350.c b/ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c index 79ec315d497..2dc19558314 100644 --- a/ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c +++ b/ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c @@ -54,15 +54,15 @@ #define SYNC_V1_H1 (TMDS_CTRL_11 | (TMDS_CTRL_00 << 10) | (TMDS_CTRL_00 << 20)) #define MODE_720_H_SYNC_POLARITY 0 -#define MODE_720_H_FRONT_PORCH 24 -#define MODE_720_H_SYNC_WIDTH 64 -#define MODE_720_H_BACK_PORCH 88 +#define MODE_720_H_FRONT_PORCH 8 +#define MODE_720_H_SYNC_WIDTH 32 +#define MODE_720_H_BACK_PORCH 40 #define MODE_720_H_ACTIVE_PIXELS 720 #define MODE_720_V_SYNC_POLARITY 0 #define MODE_720_V_FRONT_PORCH 3 #define MODE_720_V_SYNC_WIDTH 4 -#define MODE_720_V_BACK_PORCH 13 +#define MODE_720_V_BACK_PORCH 218 #define MODE_720_V_ACTIVE_LINES 400 #define MODE_640_H_SYNC_POLARITY 0 @@ -74,7 +74,7 @@ #define MODE_640_V_SYNC_POLARITY 0 #define MODE_640_V_FRONT_PORCH 10 #define MODE_640_V_SYNC_WIDTH 2 -#define MODE_640_V_BACK_PORCH 33 +#define MODE_640_V_BACK_PORCH 133 #define MODE_640_V_ACTIVE_LINES 480 #define MODE_720_V_TOTAL_LINES ( \ 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/rotaryio/IncrementalEncoder.c b/ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c index 113bd1900dd..d71ff60b2eb 100644 --- a/ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c +++ b/ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c @@ -43,6 +43,9 @@ void common_hal_rotaryio_incrementalencoder_construct(rotaryio_incrementalencode const mcu_pin_obj_t *pin_a, const mcu_pin_obj_t *pin_b) { const mcu_pin_obj_t *pins[] = { pin_a, pin_b }; + // Ensure object starts in its deinit state. + common_hal_rotaryio_incrementalencoder_mark_deinit(self); + // Start out with swapped to match behavior with other ports. self->swapped = true; if (!common_hal_rp2pio_pins_are_sequential(2, pins)) { @@ -89,6 +92,7 @@ void common_hal_rotaryio_incrementalencoder_construct(rotaryio_incrementalencode } bool common_hal_rotaryio_incrementalencoder_deinited(rotaryio_incrementalencoder_obj_t *self) { + // Use the deinit state of the PIO state machine. return common_hal_rp2pio_statemachine_deinited(&self->state_machine); } @@ -100,6 +104,11 @@ void common_hal_rotaryio_incrementalencoder_deinit(rotaryio_incrementalencoder_o common_hal_rp2pio_statemachine_deinit(&self->state_machine); } +void common_hal_rotaryio_incrementalencoder_mark_deinit(rotaryio_incrementalencoder_obj_t *self) { + // Use the deinit state of the PIO state machine. + common_hal_rp2pio_statemachine_mark_deinit(&self->state_machine); +} + static void incrementalencoder_interrupt_handler(void *self_in) { rotaryio_incrementalencoder_obj_t *self = self_in; diff --git a/ports/raspberrypi/common-hal/rp2pio/StateMachine.c b/ports/raspberrypi/common-hal/rp2pio/StateMachine.c index fefecf05ff7..8e1ea26ab0d 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); @@ -523,9 +574,10 @@ static void consider_instruction(introspect_t *state, uint16_t full_instruction, } } if (instruction == pio_instr_bits_wait) { - uint16_t wait_source = (full_instruction & 0x0060) >> 5; - uint16_t wait_index = (full_instruction & 0x001f) + state->inputs.pio_gpio_offset; - if (wait_source == 0 && !PIO_PINMASK_IS_SET(state->inputs.pins_we_use, wait_index)) { // GPIO + const uint16_t wait_source = (full_instruction & 0x0060) >> 5; + const uint16_t wait_index = full_instruction & 0x001f; + const uint16_t wait_pin = wait_index + state->inputs.pio_gpio_offset; + if (wait_source == 0 && !PIO_PINMASK_IS_SET(state->inputs.pins_we_use, wait_pin)) { // GPIO mp_raise_ValueError_varg(MP_ERROR_TEXT("%q[%u] uses extra pin"), what_program, i); } else if (wait_source == 1) { // Input pin if (!state->inputs.has_in_pin) { @@ -627,6 +679,9 @@ void common_hal_rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self, int mov_status_type, int mov_status_n) { + // Ensure object starts in its deinit state. + 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. 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)); @@ -743,7 +798,7 @@ void common_hal_rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self, mov_status_type, mov_status_n); if (!ok) { // indicate state machine never inited - self->state_machine = NUM_PIO_STATE_MACHINES; + common_hal_rp2pio_statemachine_mark_deinit(self); mp_raise_RuntimeError(MP_ERROR_TEXT("All state machines in use")); } } @@ -826,6 +881,10 @@ void common_hal_rp2pio_statemachine_deinit(rp2pio_statemachine_obj_t *self) { rp2pio_statemachine_deinit(self, false); } +void common_hal_rp2pio_statemachine_mark_deinit(rp2pio_statemachine_obj_t *self) { + self->state_machine = NUM_PIO_STATE_MACHINES; +} + void common_hal_rp2pio_statemachine_never_reset(rp2pio_statemachine_obj_t *self) { rp2pio_statemachine_never_reset(self->pio, self->state_machine); // TODO: never reset all the pins @@ -853,25 +912,64 @@ static bool _transfer(rp2pio_statemachine_obj_t *self, // This implementation is based on SPI but varies because the tx and rx buffers // may be different lengths and occur at different times or speeds. - // Use DMA for large transfers if channels are available. - // Don't exceed FIFO size. - const size_t dma_min_size_threshold = self->fifo_depth; int chan_tx = -1; int chan_rx = -1; size_t len = MAX(out_len, in_len); bool tx = data_out != NULL; bool rx = data_in != NULL; - bool use_dma = len >= dma_min_size_threshold || swap_out || swap_in; + bool free_data_out = false; + bool free_data_in = false; + uint8_t *sram_data_out = (uint8_t *)data_out; + uint8_t *sram_data_in = data_in; + bool tx_fits_in_fifo = (out_len / out_stride_in_bytes) <= self->fifo_depth; + bool rx_fits_in_fifo = (in_len / in_stride_in_bytes) <= self->fifo_depth; + bool use_dma = !(tx_fits_in_fifo && rx_fits_in_fifo) || swap_out || swap_in; + if (use_dma) { - // Use DMA channels to service the two FIFOs + // We can only reliably use DMA for SRAM buffers. So, if we're given PSRAM buffers, + // then copy them to SRAM first. If we can't, then fail. + // Use DMA channels to service the two FIFOs. Fail if we can't allocate DMA channels. if (tx) { + if (data_out < (uint8_t *)SRAM_BASE) { + // Try to allocate a temporary buffer for DMA transfer + uint8_t *temp_buffer = (uint8_t *)port_malloc(len, true); + if (temp_buffer == NULL) { + mp_printf(&mp_plat_print, "Failed to allocate temporary buffer for DMA tx\n"); + return false; + } + memcpy(temp_buffer, data_out, len); + sram_data_out = temp_buffer; + free_data_out = true; + } chan_tx = dma_claim_unused_channel(false); // DMA allocation failed... if (chan_tx < 0) { + if (free_data_out) { + port_free(sram_data_out); + } + if (free_data_in) { + port_free(sram_data_in); + } return false; } } if (rx) { + if (data_in < (uint8_t *)SRAM_BASE) { + // Try to allocate a temporary buffer for DMA transfer + uint8_t *temp_buffer = (uint8_t *)port_malloc(len, true); + if (temp_buffer == NULL) { + mp_printf(&mp_plat_print, "Failed to allocate temporary buffer for DMA rx\n"); + if (chan_tx >= 0) { + dma_channel_unclaim(chan_tx); + } + if (free_data_out) { + port_free(sram_data_out); + } + return false; + } + sram_data_in = temp_buffer; + free_data_in = true; + } chan_rx = dma_claim_unused_channel(false); // DMA allocation failed... if (chan_rx < 0) { @@ -879,6 +977,12 @@ static bool _transfer(rp2pio_statemachine_obj_t *self, if (chan_tx >= 0) { dma_channel_unclaim(chan_tx); } + if (free_data_out) { + port_free(sram_data_out); + } + if (free_data_in) { + port_free(sram_data_in); + } return false; } } @@ -910,7 +1014,7 @@ static bool _transfer(rp2pio_statemachine_obj_t *self, channel_config_set_bswap(&c, swap_out); dma_channel_configure(chan_tx, &c, tx_destination, - data_out, + sram_data_out, out_len / out_stride_in_bytes, false); channel_mask |= 1u << chan_tx; @@ -923,7 +1027,7 @@ static bool _transfer(rp2pio_statemachine_obj_t *self, channel_config_set_write_increment(&c, true); channel_config_set_bswap(&c, swap_in); dma_channel_configure(chan_rx, &c, - data_in, + sram_data_in, rx_source, in_len / in_stride_in_bytes, false); @@ -950,8 +1054,7 @@ static bool _transfer(rp2pio_statemachine_obj_t *self, self->pio->fdebug = stall_mask; } - // If we have claimed only one channel successfully, we should release immediately. This also - // releases the DMA after use_dma has been done. + // Release the DMA channels after use_dma has been done. if (chan_rx >= 0) { dma_channel_unclaim(chan_rx); } @@ -960,31 +1063,31 @@ static bool _transfer(rp2pio_statemachine_obj_t *self, } if (!use_dma && !(self->user_interruptible && mp_hal_is_interrupted())) { - // Use software for small transfers, or if couldn't claim two DMA channels + // Use software for small transfers size_t rx_remaining = in_len / in_stride_in_bytes; size_t tx_remaining = out_len / out_stride_in_bytes; while (rx_remaining || tx_remaining) { while (tx_remaining && !pio_sm_is_tx_fifo_full(self->pio, self->state_machine)) { if (out_stride_in_bytes == 1) { - *tx_destination = *data_out; + *tx_destination = *sram_data_out; } else if (out_stride_in_bytes == 2) { - *((uint16_t *)tx_destination) = *((uint16_t *)data_out); + *((uint16_t *)tx_destination) = *((uint16_t *)sram_data_out); } else if (out_stride_in_bytes == 4) { - *((uint32_t *)tx_destination) = *((uint32_t *)data_out); + *((uint32_t *)tx_destination) = *((uint32_t *)sram_data_out); } - data_out += out_stride_in_bytes; + sram_data_out += out_stride_in_bytes; --tx_remaining; } while (rx_remaining && !pio_sm_is_rx_fifo_empty(self->pio, self->state_machine)) { if (in_stride_in_bytes == 1) { - *data_in = (uint8_t)*rx_source; + *sram_data_in = (uint8_t)*rx_source; } else if (in_stride_in_bytes == 2) { - *((uint16_t *)data_in) = *((uint16_t *)rx_source); + *((uint16_t *)sram_data_in) = *((uint16_t *)rx_source); } else if (in_stride_in_bytes == 4) { - *((uint32_t *)data_in) = *((uint32_t *)rx_source); + *((uint32_t *)sram_data_in) = *((uint32_t *)rx_source); } - data_in += in_stride_in_bytes; + sram_data_in += in_stride_in_bytes; --rx_remaining; } RUN_BACKGROUND_TASKS; @@ -996,7 +1099,7 @@ static bool _transfer(rp2pio_statemachine_obj_t *self, self->pio->fdebug = stall_mask; } // Wait for the state machine to finish transmitting the data we've queued - // up. + // up (either from the CPU or via DMA.) if (tx) { while (!pio_sm_is_tx_fifo_empty(self->pio, self->state_machine) || (self->wait_for_txstall && (self->pio->fdebug & stall_mask) == 0)) { @@ -1006,6 +1109,14 @@ static bool _transfer(rp2pio_statemachine_obj_t *self, } } } + if (free_data_out) { + port_free(sram_data_out); + } + if (free_data_in) { + // Copy the data from the SRAM buffer to the user PSRAM buffer. + memcpy(data_in, sram_data_in, len); + port_free(sram_data_in); + } return true; } @@ -1214,12 +1325,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(); @@ -1378,11 +1485,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(); @@ -1422,6 +1526,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/socketpool/Socket.c b/ports/raspberrypi/common-hal/socketpool/Socket.c index 018365def8c..0543fd53dc3 100644 --- a/ports/raspberrypi/common-hal/socketpool/Socket.c +++ b/ports/raspberrypi/common-hal/socketpool/Socket.c @@ -89,7 +89,7 @@ static mp_obj_t socketpool_ip_addr_and_port_to_tuple(const ip_addr_t *addr, int // socket API. // Extension to lwIP error codes -// Matches lwIP 2.0.3 +// Matches lwIP 2.2.1 #undef _ERR_BADF #define _ERR_BADF -17 static const int error_lookup_table[] = { @@ -251,7 +251,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); @@ -473,7 +473,12 @@ static mp_uint_t lwip_tcp_send(socketpool_socket_obj_t *socket, const byte *buf, MICROPY_PY_LWIP_ENTER - u16_t available = tcp_sndbuf(socket->pcb.tcp); + // If the socket is still connecting then don't let data be written to it. + // Otherwise, get the number of available bytes in the output buffer. + u16_t available = 0; + if (socket->state != STATE_CONNECTING) { + available = tcp_sndbuf(socket->pcb.tcp); + } if (available == 0) { // Non-blocking socket @@ -490,7 +495,8 @@ static mp_uint_t lwip_tcp_send(socketpool_socket_obj_t *socket, const byte *buf, // If peer fully closed socket, we would have socket->state set to ERR_RST (connection // reset) by error callback. // Avoid sending too small packets, so wait until at least 16 bytes available - while (socket->state >= STATE_CONNECTED && (available = tcp_sndbuf(socket->pcb.tcp)) < 16) { + while (socket->state == STATE_CONNECTING + || (socket->state >= STATE_CONNECTED && (available = tcp_sndbuf(socket->pcb.tcp)) < 16)) { MICROPY_PY_LWIP_EXIT if (socket->timeout != (unsigned)-1 && mp_hal_ticks_ms() - start > socket->timeout) { *_errno = MP_ETIMEDOUT; @@ -531,9 +537,10 @@ static mp_uint_t lwip_tcp_send(socketpool_socket_obj_t *socket, const byte *buf, MICROPY_PY_LWIP_REENTER } - // If the output buffer is getting full then send the data to the lower layers - if (err == ERR_OK && tcp_sndbuf(socket->pcb.tcp) < TCP_SND_BUF / 4) { - err = tcp_output(socket->pcb.tcp); + // Use nagle algorithm to determine when to send segment buffer (can be + // disabled with TCP_NODELAY socket option) + if (err == ERR_OK) { + err = tcp_output_nagle(socket->pcb.tcp); } MICROPY_PY_LWIP_EXIT @@ -551,6 +558,12 @@ static mp_uint_t lwip_tcp_receive(socketpool_socket_obj_t *socket, byte *buf, mp // Check for any pending errors STREAM_ERROR_CHECK(socket); + if (socket->state == STATE_LISTENING) { + // original socket in listening state, not the accepted connection. + *_errno = MP_ENOTCONN; + return -1; + } + if (socket->incoming.pbuf == NULL) { // Non-blocking socket diff --git a/ports/raspberrypi/common-hal/usb_host/Port.c b/ports/raspberrypi/common-hal/usb_host/Port.c index 5439b39bf3a..36f255df021 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" @@ -146,6 +146,8 @@ usb_host_port_obj_t *common_hal_usb_host_port_construct(const mcu_pin_obj_t *dp, self->base.type = &usb_host_port_type; self->dp = dp; self->dm = dm; + claim_pin(dp); + claim_pin(dm); PIO pio = pio_get_instance(pio_cfg.pio_tx_num); diff --git a/ports/raspberrypi/common-hal/wifi/Radio.c b/ports/raspberrypi/common-hal/wifi/Radio.c index 3c22c3548d1..73e7794ecc2 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); } 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/lib/Pico-PIO-USB b/ports/raspberrypi/lib/Pico-PIO-USB index 032a469e79f..dc9193fed51 160000 --- a/ports/raspberrypi/lib/Pico-PIO-USB +++ b/ports/raspberrypi/lib/Pico-PIO-USB @@ -1 +1 @@ -Subproject commit 032a469e79f6a4ba40760d7868e6db26e15002d7 +Subproject commit dc9193fed510da5f81f4db520e98282f61db9054 diff --git a/ports/raspberrypi/lib/cyw43-driver b/ports/raspberrypi/lib/cyw43-driver index c1075d4bc44..dd7568229f3 160000 --- a/ports/raspberrypi/lib/cyw43-driver +++ b/ports/raspberrypi/lib/cyw43-driver @@ -1 +1 @@ -Subproject commit c1075d4bc440422cf2b2fd12c64a1f53f77660ee +Subproject commit dd7568229f3bf7a37737b9e1ef250c26efe75b23 diff --git a/ports/raspberrypi/lwip_src/lwip_mem.c b/ports/raspberrypi/lwip_src/lwip_mem.c index 244f51e289b..23b185354b0 100644 --- a/ports/raspberrypi/lwip_src/lwip_mem.c +++ b/ports/raspberrypi/lwip_src/lwip_mem.c @@ -8,10 +8,12 @@ #include #include "lib/tlsf/tlsf.h" #include "lwip_mem.h" +#include "shared-bindings/microcontroller/__init__.h" #include "supervisor/port_heap.h" void *lwip_heap_malloc(size_t size) { - return port_malloc(size, true); + void *ptr = port_malloc(size, true); + return ptr; } void lwip_heap_free(void *ptr) { diff --git a/ports/raspberrypi/mpconfigport.h b/ports/raspberrypi/mpconfigport.h index 3eb576de39e..d0802b25f00 100644 --- a/ports/raspberrypi/mpconfigport.h +++ b/ports/raspberrypi/mpconfigport.h @@ -8,11 +8,11 @@ #include "hardware/platform_defs.h" -#ifdef PICO_RP2040 +#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 +36,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 diff --git a/ports/raspberrypi/mpconfigport.mk b/ports/raspberrypi/mpconfigport.mk index 1404b2b0677..b4d1ed99696 100644 --- a/ports/raspberrypi/mpconfigport.mk +++ b/ports/raspberrypi/mpconfigport.mk @@ -11,11 +11,14 @@ CIRCUITPY_FLOPPYIO ?= 1 CIRCUITPY_FRAMEBUFFERIO ?= $(CIRCUITPY_DISPLAYIO) CIRCUITPY_FULL_BUILD ?= 1 CIRCUITPY_AUDIOMP3 ?= 1 +CIRCUITPY_AUDIOSPEED ?= 1 +CIRCUITPY_AUDIOEFFECTS ?= 1 CIRCUITPY_BITOPS ?= 1 CIRCUITPY_HASHLIB ?= 1 CIRCUITPY_HASHLIB_MBEDTLS ?= 1 CIRCUITPY_IMAGECAPTURE ?= 1 CIRCUITPY_MAX3421E ?= 0 +CIRCUITPY_MCP4822 ?= 0 CIRCUITPY_MEMORYMAP ?= 1 CIRCUITPY_PWMIO ?= 1 CIRCUITPY_RGBMATRIX ?= $(CIRCUITPY_DISPLAYIO) @@ -24,12 +27,14 @@ 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 # Use PWM internally CIRCUITPY_I2CTARGET = 1 +CIRCUITPY_I2CIOEXPANDER = 1 CIRCUITPY_NVM = 1 # Use PIO internally CIRCUITPY_PULSEIO ?= 1 @@ -41,6 +46,7 @@ CIRCUITPY_ANALOGBUFIO = 1 # Audio via PWM CIRCUITPY_AUDIOIO = 0 CIRCUITPY_AUDIOBUSIO ?= 1 +CIRCUITPY_AUDIOI2SIN ?= $(CIRCUITPY_AUDIOBUSIO) CIRCUITPY_AUDIOCORE ?= 1 CIRCUITPY_AUDIOPWMIO ?= 1 @@ -59,6 +65,9 @@ CIRCUITPY_CYW43_INIT_DELAY ?= 1000 endif ifeq ($(CHIP_VARIANT),RP2350) +# RP2350 has PSRAM that is not DMA-capable +CIRCUITPY_ALL_MEMORY_DMA_CAPABLE = 0 + # This needs to be implemented. CIRCUITPY_ALARM = 0 # Default PICODVI on because it doesn't require much code in RAM to talk to HSTX. diff --git a/ports/raspberrypi/sdk b/ports/raspberrypi/sdk index 96b363a1559..a1438dff1d3 160000 --- a/ports/raspberrypi/sdk +++ b/ports/raspberrypi/sdk @@ -1 +1 @@ -Subproject commit 96b363a15598d0a17a77542ba63150b7d3fa5fd5 +Subproject commit a1438dff1d38bd9c65dbd693f0e5db4b9ae91779 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 4be42380491..01940acc079 100644 --- a/ports/raspberrypi/supervisor/port.c +++ b/ports/raspberrypi/supervisor/port.c @@ -53,7 +53,7 @@ #include "pico/bootrom.h" #include "hardware/watchdog.h" -#ifdef PICO_RP2350 +#if PICO_RP2350 #include "RP2350.h" // CMSIS #endif @@ -264,32 +264,51 @@ 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; } } + common_hal_mcu_disable_interrupts(); void *block = tlsf_malloc(_heap, size); + common_hal_mcu_enable_interrupts(); return block; } void port_free(void *ptr) { + common_hal_mcu_disable_interrupts(); if (((size_t)ptr) < SRAM_BASE) { tlsf_free(_psram_heap, ptr); } else { tlsf_free(_heap, ptr); } + common_hal_mcu_enable_interrupts(); } 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))) { + common_hal_mcu_disable_interrupts(); void *block = tlsf_realloc(_psram_heap, ptr, size); + common_hal_mcu_enable_interrupts(); if (block) { return block; } } - return tlsf_realloc(_heap, ptr, size); + common_hal_mcu_disable_interrupts(); + void *new_ptr = tlsf_realloc(_heap, ptr, size); + common_hal_mcu_enable_interrupts(); + return new_ptr; +} + +#if !CIRCUITPY_ALL_MEMORY_DMA_CAPABLE +bool port_buffer_is_dma_capable(const void *ptr) { + // For RP2350, DMA can only access SRAM, not PSRAM + // PSRAM addresses are below SRAM_BASE + return ptr != NULL && ((size_t)ptr) >= SRAM_BASE; } +#endif static bool max_size_walker(void *ptr, size_t size, int used, void *user) { size_t *max_size = (size_t *)user; @@ -317,10 +336,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 @@ -403,7 +422,6 @@ safe_mode_t port_init(void) { void reset_port(void) { #if CIRCUITPY_BUSIO - reset_spi(); reset_uart(); #endif @@ -434,8 +452,6 @@ void reset_port(void) { #if CIRCUITPY_WIFI wifi_reset(); #endif - - reset_all_pins(); } void reset_to_bootloader(void) { @@ -531,7 +547,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) { @@ -572,7 +588,7 @@ void port_idle_until_interrupt(void) { /** * \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.) @@ -584,7 +600,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 @@ -608,7 +624,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/renode/Makefile b/ports/renode/Makefile index 92541c03e77..c4ce66194e9 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 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/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..810ab53f1f3 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)) 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.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..881cf1622eb 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; 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/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/__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..2ed3bddb5b7 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 @@ -212,10 +211,12 @@ ifneq ($(CIRCUITPY_USB),0) 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 +230,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 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..419f073b5ea 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,7 @@ CIRCUITPY_EPAPERDISPLAY = 0 CIRCUITPY_FRAMEBUFFERIO = 0 CIRCUITPY_I2CDISPLAYBUS = 0 CIRCUITPY_KEYPAD_DEMUX = 0 +CIRCUITPY_PIXELMAP = 0 CIRCUITPY_SHARPDISPLAY = 0 CIRCUITPY_TILEPALETTEMAPPER = 0 CIRCUITPY_ULAB = 0 @@ -37,4 +39,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/sparkfun_stm32f405_micromod/mpconfigboard.mk b/ports/stm/boards/sparkfun_stm32f405_micromod/mpconfigboard.mk index d1df685c676..31c2b7e2874 100644 --- a/ports/stm/boards/sparkfun_stm32f405_micromod/mpconfigboard.mk +++ b/ports/stm/boards/sparkfun_stm32f405_micromod/mpconfigboard.mk @@ -1,5 +1,5 @@ USB_VID = 0X1B4F -USB_PID = 0x0027 +USB_PID = 0x0029 USB_PRODUCT = "SparkFun STM32 MicroMod Processor" USB_MANUFACTURER = "SparkFun Electronics" 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..1be8f8dc10d 100644 --- a/ports/stm/common-hal/alarm/__init__.c +++ b/ports/stm/common-hal/alarm/__init__.c @@ -135,7 +135,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_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_spi/__init__.c b/ports/stm/common-hal/audioio/__init__.c similarity index 55% rename from ports/zephyr-cp/common-hal/zephyr_spi/__init__.c rename to ports/stm/common-hal/audioio/__init__.c index d3a4d472733..ebf626832f6 100644 --- a/ports/zephyr-cp/common-hal/zephyr_spi/__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_spi module functions. +// No audioio module functions. 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/sdioio/SDCard.c b/ports/stm/common-hal/sdioio/SDCard.c index 92e552c2e89..2d24f24d825 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" @@ -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..bd2b2238eef 100644 --- a/ports/stm/mpconfigport.mk +++ b/ports/stm/mpconfigport.mk @@ -3,6 +3,8 @@ 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 +12,17 @@ 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 + # 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..1da862cd886 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) @@ -302,14 +305,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,6 +318,9 @@ void reset_port(void) { #if CIRCUITPY_ALARM exti_reset(); #endif + #if CIRCUITPY_AUDIOIO + audioout_reset(); + #endif } void reset_to_bootloader(void) { diff --git a/ports/unix/Makefile b/ports/unix/Makefile index bb1f6a4740a..32e3b44b227 100644 --- a/ports/unix/Makefile +++ b/ports/unix/Makefile @@ -27,6 +27,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,13 +49,18 @@ INC += -I$(BUILD) # compiler settings CWARN = -Wall -Werror -CWARN += -Wextra -Wno-unused-parameter -Wpointer-arith -Wdouble-promotion -Wfloat-conversion +// CIRCUITPY-CHANGE: add -Wno-missing-field-initializers +CWARN += -Wextra -Wno-unused-parameter -Wpointer-arith -Wdouble-promotion -Wfloat-conversion -Wno-missing-field-initializers CFLAGS += $(INC) $(CWARN) -std=gnu99 -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 + # Debugging/Optimization ifdef DEBUG COPT ?= -Og @@ -139,7 +147,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 @@ -208,6 +220,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 +237,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) \ ) @@ -278,7 +293,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..ee983a882cc 100644 --- a/ports/unix/README.md +++ b/ports/unix/README.md @@ -72,6 +72,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 +163,21 @@ 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. diff --git a/ports/unix/coverage.c b/ports/unix/coverage.c index 7f13f9756f1..49426f0f3e8 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,11 @@ 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)); } // GC initialisation and allocation stress test, to check the logic behind ALLOC_TABLE_GAP_BYTE @@ -285,7 +339,7 @@ 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]); @@ -301,7 +355,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 @@ -400,7 +454,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 +518,38 @@ 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); } // runtime utils @@ -481,7 +567,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 +592,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,26 +617,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"); @@ -558,14 +640,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 +716,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 +746,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 +887,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..e42400fe5f9 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)); } @@ -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`. @@ -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]); @@ -811,7 +739,7 @@ MP_NOINLINE int main_(int argc, char **argv) { #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_EXCEPTION + if (ret & PYEXEC_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/modos.c b/ports/unix/modos.c index 896bf351b83..af8a1cc4da8 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); diff --git a/ports/unix/modtime.c b/ports/unix/modtime.c index fbd94b5ecd1..4f0550dbea7 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) { @@ -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..815be76b4e9 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 @@ -78,21 +82,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; @@ -135,6 +124,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 +137,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 +167,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..c836663cd23 100644 --- a/ports/unix/mpconfigport.mk +++ b/ports/unix/mpconfigport.mk @@ -14,6 +14,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 diff --git a/ports/unix/mphalport.h b/ports/unix/mphalport.h index 7f71217632a..d9cd05b3de8 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,6 @@ enum { void mp_hal_get_mac(int idx, uint8_t buf[6]); #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..f6159bb69d5 --- /dev/null +++ b/ports/unix/stack_size.h @@ -0,0 +1,54 @@ +/* + * 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 + +// Double the stack size for 64-bit builds, plus additional scaling +#define UNIX_STACK_MULTIPLIER ((sizeof(void *) / 4) * UNIX_STACK_MUL_ARM * UNIX_STACK_MUL_SANITIZERS) + +#endif // UNIX_STACK_MULTIPLIER + +#endif // MICROPY_INCLUDED_UNIX_STACK_SIZE_H 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..292e4de8169 100644 --- a/ports/unix/variants/coverage/mpconfigvariant.mk +++ b/ports/unix/variants/coverage/mpconfigvariant.mk @@ -106,7 +106,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 \ @@ -164,8 +163,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..d50d360b1fe --- /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 using MICROPY_FORCE_32BIT=1 + +#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..2d2c3706469 --- /dev/null +++ b/ports/unix/variants/longlong/mpconfigvariant.mk @@ -0,0 +1,8 @@ +# build interpreter with "bigints" implemented as "longlong" + +# otherwise, small int is essentially 64-bit +MICROPY_FORCE_32BIT := 1 + +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..1ac59c95572 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 @@ -104,12 +104,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/zephyr-cp/AGENTS.md b/ports/zephyr-cp/AGENTS.md new file mode 100644 index 00000000000..58a3912e2ba --- /dev/null +++ b/ports/zephyr-cp/AGENTS.md @@ -0,0 +1,7 @@ +- Build a board by doing `make BOARD=_`. +- The corresponding configuration files are in `boards//` +- The files (not folders) in `boards/` directory are used by Zephyr. +- 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.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..ab730a8b339 100644 --- a/ports/zephyr-cp/Makefile +++ b/ports/zephyr-cp/Makefile @@ -8,11 +8,27 @@ 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) + +# When DEBUG=1, apply additional Kconfig fragments for debug-friendly settings. +DEBUG_CONF_FILE ?= $(CURDIR)/debug.conf +ifeq ($(DEBUG),1) +WEST_CMAKE_ARGS += -Dzephyr-cp_EXTRA_CONF_FILE=$(DEBUG_CONF_FILE) +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) $(BUILD)/firmware.elf: $(BUILD)/zephyr-cp/zephyr/zephyr.elf cp $^ $@ @@ -20,14 +36,67 @@ $(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 $@ + 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_*) + +test: build-native_native_sim/zephyr-cp/zephyr/zephyr.exe + pytest cptools/tests + pytest tests/ -v diff --git a/ports/zephyr-cp/README.md b/ports/zephyr-cp/README.md index 4d08936cad6..162ed90bcc8 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 diff --git a/ports/zephyr-cp/app.overlay b/ports/zephyr-cp/app.overlay new file mode 100644 index 00000000000..0f34d64a80f --- /dev/null +++ b/ports/zephyr-cp/app.overlay @@ -0,0 +1,10 @@ +&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"; + }; +}; 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/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..d6aca312226 --- /dev/null +++ b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_sense_zephyr/autogen_board_info.toml @@ -0,0 +1,120 @@ +# 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 = 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 +audiofilters = false +audiofreeverb = 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 = false +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 +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 +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_cdc = true +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 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..eacb0f9607d --- /dev/null +++ b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_sense_zephyr/circuitpython.toml @@ -0,0 +1,4 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["elf", "uf2"] +USB_VID=0x239A +USB_PID=0x8088 +NAME="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..dafe7811779 --- /dev/null +++ b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml @@ -0,0 +1,120 @@ +# 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 = 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 +audiofilters = false +audiofreeverb = 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 = false +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 +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 +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_cdc = true +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 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..c4d1099a77e --- /dev/null +++ b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/circuitpython.toml @@ -0,0 +1,4 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["elf", "uf2"] +USB_VID=0x239A +USB_PID=0x802A +NAME="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..cecf8e55a83 --- /dev/null +++ b/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml @@ -0,0 +1,120 @@ +# 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 +audiofilters = false +audiofreeverb = 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 = false +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 +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 +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_cdc = true +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 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..9d3c229ed1b --- /dev/null +++ b/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/circuitpython.toml @@ -0,0 +1 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["elf", "uf2"] diff --git a/ports/zephyr-cp/boards/adafruit_feather_nrf52840_nrf52840_sense_uf2.conf b/ports/zephyr-cp/boards/adafruit_feather_nrf52840_nrf52840_sense_uf2.conf new file mode 100644 index 00000000000..20176b34be0 --- /dev/null +++ b/ports/zephyr-cp/boards/adafruit_feather_nrf52840_nrf52840_sense_uf2.conf @@ -0,0 +1,10 @@ +CONFIG_BT=y +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_CENTRAL=y +CONFIG_BT_BROADCASTER=y +CONFIG_BT_OBSERVER=y +CONFIG_BT_EXT_ADV=y + +CONFIG_USE_DT_CODE_PARTITION=y + +CONFIG_BOARD_SERIAL_BACKEND_CDC_ACM=n diff --git a/ports/zephyr-cp/boards/adafruit_feather_nrf52840_nrf52840_sense_uf2.overlay b/ports/zephyr-cp/boards/adafruit_feather_nrf52840_nrf52840_sense_uf2.overlay new file mode 100644 index 00000000000..e01ebd6df1f --- /dev/null +++ b/ports/zephyr-cp/boards/adafruit_feather_nrf52840_nrf52840_sense_uf2.overlay @@ -0,0 +1,46 @@ +/ { + 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 { + label = "Application"; + reg = <0x00026000 0x000c4000>; + }; + + storage_partition: partition@ea000 { + label = "storage"; + reg = <0x000ea000 0x00008000>; + }; + + nvm_partition: partition@f2000 { + label = "nvm"; + reg = <0x000f2000 0x00002000>; + }; + }; +}; + +&uart0 { + status = "okay"; +}; + +#include "../app.overlay" diff --git a/ports/zephyr-cp/boards/adafruit_feather_nrf52840_uf2.conf b/ports/zephyr-cp/boards/adafruit_feather_nrf52840_uf2.conf new file mode 100644 index 00000000000..20176b34be0 --- /dev/null +++ b/ports/zephyr-cp/boards/adafruit_feather_nrf52840_uf2.conf @@ -0,0 +1,10 @@ +CONFIG_BT=y +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_CENTRAL=y +CONFIG_BT_BROADCASTER=y +CONFIG_BT_OBSERVER=y +CONFIG_BT_EXT_ADV=y + +CONFIG_USE_DT_CODE_PARTITION=y + +CONFIG_BOARD_SERIAL_BACKEND_CDC_ACM=n diff --git a/ports/zephyr-cp/boards/adafruit_feather_nrf52840_uf2.overlay b/ports/zephyr-cp/boards/adafruit_feather_nrf52840_uf2.overlay new file mode 100644 index 00000000000..e01ebd6df1f --- /dev/null +++ b/ports/zephyr-cp/boards/adafruit_feather_nrf52840_uf2.overlay @@ -0,0 +1,46 @@ +/ { + 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 { + label = "Application"; + reg = <0x00026000 0x000c4000>; + }; + + storage_partition: partition@ea000 { + label = "storage"; + reg = <0x000ea000 0x00008000>; + }; + + nvm_partition: partition@f2000 { + label = "nvm"; + reg = <0x000f2000 0x00002000>; + }; + }; +}; + +&uart0 { + status = "okay"; +}; + +#include "../app.overlay" diff --git a/ports/zephyr-cp/boards/adafruit_feather_rp2040.conf b/ports/zephyr-cp/boards/adafruit_feather_rp2040.conf new file mode 100644 index 00000000000..91c3c15b37d --- /dev/null +++ b/ports/zephyr-cp/boards/adafruit_feather_rp2040.conf @@ -0,0 +1 @@ +CONFIG_GPIO=y diff --git a/ports/zephyr-cp/boards/adafruit_feather_rp2040.overlay b/ports/zephyr-cp/boards/adafruit_feather_rp2040.overlay new file mode 100644 index 00000000000..af7295ffe35 --- /dev/null +++ b/ports/zephyr-cp/boards/adafruit_feather_rp2040.overlay @@ -0,0 +1,34 @@ +&flash0 { + /delete-node/ partitions; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* Reserved memory for the second stage bootloader */ + second_stage_bootloader: partition@0 { + label = "second_stage_bootloader"; + reg = <0x00000000 0x100>; + read-only; + }; + + code_partition: partition@100 { + label = "code-partition"; + reg = <0x100 (0x180000 - 0x100)>; + read-only; + }; + + nvm_partition: partition@180000 { + label = "nvm"; + reg = <0x180000 0x1000>; + }; + + circuitpy_partition: partition@181000 { + label = "circuitpy"; + reg = <0x181000 (DT_SIZE_M(8) - 0x181000)>; + }; + }; +}; + +#include "../app.overlay" diff --git a/ports/zephyr-cp/boards/board_aliases.cmake b/ports/zephyr-cp/boards/board_aliases.cmake index b8df9fb87f5..ad0c1b5a57a 100644 --- a/ports/zephyr-cp/boards/board_aliases.cmake +++ b/ports/zephyr-cp/boards/board_aliases.cmake @@ -1,8 +1,53 @@ -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_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_nrf5340bsim nrf5340bsim/nrf5340/cpuapp) +cp_board_alias(nordic_nrf54l15dk nrf54l15dk/nrf54l15/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) diff --git a/ports/zephyr-cp/boards/da14695_dk_usb.conf b/ports/zephyr-cp/boards/da14695_dk_usb.conf new file mode 100644 index 00000000000..145a9393407 --- /dev/null +++ b/ports/zephyr-cp/boards/da14695_dk_usb.conf @@ -0,0 +1,20 @@ +CONFIG_BT=y +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_CENTRAL=y +CONFIG_BT_BROADCASTER=y +CONFIG_BT_OBSERVER=y +CONFIG_BT_EXT_ADV=y + +CONFIG_BT_DEVICE_APPEARANCE_DYNAMIC=y +CONFIG_BT_DEVICE_NAME_DYNAMIC=y +CONFIG_BT_DEVICE_NAME_MAX=28 +CONFIG_BT_L2CAP_TX_MTU=253 + +# BT Buffers +CONFIG_BT_BUF_CMD_TX_SIZE=255 +CONFIG_BT_BUF_EVT_RX_COUNT=16 +CONFIG_BT_BUF_EVT_RX_SIZE=255 +CONFIG_BT_BUF_ACL_TX_COUNT=3 +CONFIG_BT_BUF_ACL_TX_SIZE=251 +CONFIG_BT_BUF_ACL_RX_COUNT_EXTRA=1 +CONFIG_BT_BUF_ACL_RX_SIZE=255 diff --git a/ports/zephyr-cp/boards/da14695_dk_usb.overlay b/ports/zephyr-cp/boards/da14695_dk_usb.overlay new file mode 100644 index 00000000000..fbc1817c759 --- /dev/null +++ b/ports/zephyr-cp/boards/da14695_dk_usb.overlay @@ -0,0 +1,10 @@ +&flash0 { + partitions{ + circuitpy_partition: partition@118000 { + label = "circuitpy"; + reg = <0x118000 (DT_SIZE_M(4) - DT_SIZE_K(1120))>; + }; + }; +}; + +#include "../app.overlay" diff --git a/ports/zephyr-cp/boards/ek_ra8d1.conf b/ports/zephyr-cp/boards/ek_ra8d1.conf new file mode 100644 index 00000000000..f979d31e751 --- /dev/null +++ b/ports/zephyr-cp/boards/ek_ra8d1.conf @@ -0,0 +1,3 @@ + +# Enable Zephyr display subsystem so DT chosen zephyr,display creates a device. +CONFIG_DISPLAY=y diff --git a/ports/zephyr-cp/boards/ek_ra8d1.overlay b/ports/zephyr-cp/boards/ek_ra8d1.overlay index 29735d02b8f..c13dfc457f5 100644 --- a/ports/zephyr-cp/boards/ek_ra8d1.overlay +++ b/ports/zephyr-cp/boards/ek_ra8d1.overlay @@ -1,3 +1,5 @@ &s28hl512t { /delete-node/ partitions; }; + +#include "../app.overlay" diff --git a/ports/zephyr-cp/boards/frdm_mcxn947_mcxn947_cpu0.conf b/ports/zephyr-cp/boards/frdm_mcxn947_mcxn947_cpu0.conf new file mode 100644 index 00000000000..61f2d18ca3c --- /dev/null +++ b/ports/zephyr-cp/boards/frdm_mcxn947_mcxn947_cpu0.conf @@ -0,0 +1 @@ +CONFIG_DMA_TCD_QUEUE_SIZE=4 diff --git a/ports/zephyr-cp/boards/frdm_mcxn947_mcxn947_cpu0.overlay b/ports/zephyr-cp/boards/frdm_mcxn947_mcxn947_cpu0.overlay new file mode 100644 index 00000000000..83242201c5b --- /dev/null +++ b/ports/zephyr-cp/boards/frdm_mcxn947_mcxn947_cpu0.overlay @@ -0,0 +1,5 @@ +&w25q64jvssiq { + /delete-node/ partitions; +}; + +#include "../app.overlay" diff --git a/ports/zephyr-cp/boards/frdm_rw612.conf b/ports/zephyr-cp/boards/frdm_rw612.conf new file mode 100644 index 00000000000..c06f78ae830 --- /dev/null +++ b/ports/zephyr-cp/boards/frdm_rw612.conf @@ -0,0 +1,42 @@ +CONFIG_NETWORKING=y +CONFIG_NET_IPV4=y +CONFIG_NET_DHCPV4=y +CONFIG_NET_SOCKETS=y + +CONFIG_WIFI=y +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_BT=y +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_CENTRAL=y +CONFIG_BT_BROADCASTER=y +CONFIG_BT_OBSERVER=y +CONFIG_BT_EXT_ADV=y + +CONFIG_BT_DEVICE_APPEARANCE_DYNAMIC=y +CONFIG_BT_DEVICE_NAME_DYNAMIC=y +CONFIG_BT_DEVICE_NAME_MAX=28 +CONFIG_BT_L2CAP_TX_MTU=253 + +# BT Buffers +CONFIG_BT_BUF_CMD_TX_SIZE=255 +CONFIG_BT_BUF_EVT_RX_COUNT=16 +CONFIG_BT_BUF_EVT_RX_SIZE=255 +CONFIG_BT_BUF_ACL_TX_COUNT=8 +CONFIG_BT_BUF_ACL_TX_SIZE=251 +CONFIG_BT_BUF_ACL_RX_COUNT_EXTRA=1 +CONFIG_BT_BUF_ACL_RX_SIZE=255 + +CONFIG_UDC_WORKQUEUE_STACK_SIZE=1024 diff --git a/ports/zephyr-cp/boards/frdm_rw612.overlay b/ports/zephyr-cp/boards/frdm_rw612.overlay new file mode 100644 index 00000000000..c6a021d9999 --- /dev/null +++ b/ports/zephyr-cp/boards/frdm_rw612.overlay @@ -0,0 +1,11 @@ +&w25q512jvfiq { + partitions { + /delete-node/ partition@620000; + circuitpy_partition: partition@620000 { + label = "circuitpy"; + reg = <0x00620000 (DT_SIZE_M(58) - DT_SIZE_K(128))>; + }; + }; +}; + +#include "../app.overlay" diff --git a/ports/zephyr-cp/boards/frdm_rw612_rw612_cpu0.overlay b/ports/zephyr-cp/boards/frdm_rw612_rw612_cpu0.overlay new file mode 100644 index 00000000000..9c517e43255 --- /dev/null +++ b/ports/zephyr-cp/boards/frdm_rw612_rw612_cpu0.overlay @@ -0,0 +1,12 @@ +&w25q512jvfiq { + partitions { + /delete-node/ storage_partition; + circuitpy_partition: partition@620000 { + label = "circuitpy"; + reg = <0x00620000 (DT_SIZE_M(58) - DT_SIZE_K(128))>; + }; + } + +}; + +#include "../app.overlay" diff --git a/ports/zephyr-cp/boards/mimxrt1170_evk_mimxrt1176_cm7.conf b/ports/zephyr-cp/boards/mimxrt1170_evk_mimxrt1176_cm7.conf new file mode 100644 index 00000000000..61f2d18ca3c --- /dev/null +++ b/ports/zephyr-cp/boards/mimxrt1170_evk_mimxrt1176_cm7.conf @@ -0,0 +1 @@ +CONFIG_DMA_TCD_QUEUE_SIZE=4 diff --git a/ports/zephyr-cp/boards/mimxrt1170_evk_mimxrt1176_cm7.overlay b/ports/zephyr-cp/boards/mimxrt1170_evk_mimxrt1176_cm7.overlay new file mode 100644 index 00000000000..ac6fdd8654e --- /dev/null +++ b/ports/zephyr-cp/boards/mimxrt1170_evk_mimxrt1176_cm7.overlay @@ -0,0 +1,15 @@ +&is25wp128 { + partitions { + /delete-node/ partition@e20000; + circuitpy_partition: partition@e20000 { + label = "circuitpy"; + reg = <0x00e20000 (DT_SIZE_M(2) - DT_SIZE_K(128))>; + }; + }; +}; + +&sai1 { + mclk-output; +}; + +#include "../app.overlay" 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..b565e8b139f --- /dev/null +++ b/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml @@ -0,0 +1,120 @@ +# This file is autogenerated when a board is built. Do not edit. Do commit it to git. Other scripts use its info. +name = "POSIX/Native Boards 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 +audiofilters = true # Zephyr board has audiobusio +audiofreeverb = true # Zephyr board has audiobusio +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 = false +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 +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 +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_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 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..fbda7c563b8 --- /dev/null +++ b/ports/zephyr-cp/boards/native/native_sim/circuitpython.toml @@ -0,0 +1 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["elf", "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..aa723b53f64 --- /dev/null +++ b/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml @@ -0,0 +1,120 @@ +# This file is autogenerated when a board is built. Do not edit. Do commit it to git. Other scripts use its info. +name = "POSIX/Native Boards 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 +audiofilters = false +audiofreeverb = 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 = false +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 +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 +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_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 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..3272dd4c5f3 --- /dev/null +++ b/ports/zephyr-cp/boards/native/nrf5340bsim/circuitpython.toml @@ -0,0 +1 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["elf"] diff --git a/ports/zephyr-cp/boards/native_sim.conf b/ports/zephyr-cp/boards/native_sim.conf new file mode 100644 index 00000000000..00af0d01ac6 --- /dev/null +++ b/ports/zephyr-cp/boards/native_sim.conf @@ -0,0 +1,43 @@ +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 + +# 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_sim.overlay b/ports/zephyr-cp/boards/native_sim.overlay new file mode 100644 index 00000000000..aee9d17f9d0 --- /dev/null +++ b/ports/zephyr-cp/boards/native_sim.overlay @@ -0,0 +1,56 @@ +/* + * 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 { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + circuitpy_partition: partition@0 { + label = "circuitpy"; + reg = <0x00000000 DT_SIZE_K(2040)>; + }; + + nvm_partition: partition@1fe000 { + 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/nordic/nrf5340dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml index 222a325e346..ee20efa6fee 100644 --- a/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml @@ -2,71 +2,76 @@ 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 +audiofilters = true # Zephyr board has audiobusio +audiofreeverb = true # Zephyr board has audiobusio 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 +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 +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 @@ -76,27 +81,28 @@ 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_cdc = true @@ -105,10 +111,10 @@ 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 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..ca2c90ceb0b --- /dev/null +++ b/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml @@ -0,0 +1,120 @@ +# 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 +audiofilters = false +audiofreeverb = 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 = false +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 +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 +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_cdc = true +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 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..415c471b3d4 --- /dev/null +++ b/ports/zephyr-cp/boards/nordic/nrf54h20dk/circuitpython.toml @@ -0,0 +1,2 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["elf"] +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..69fdc2da903 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 +__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 @@ -24,49 +24,54 @@ 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 +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 +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 @@ -76,27 +81,28 @@ 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 @@ -105,10 +111,10 @@ 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 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..e0b759e01ce 100644 --- a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml @@ -2,8 +2,8 @@ name = "Nordic Semiconductor nRF7002 DK" [modules] -__future__ = false -_bleio = false +__future__ = true +_bleio = true # Zephyr board has _bleio _eve = false _pew = false _pixelmap = false @@ -24,49 +24,54 @@ 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 +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 +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 @@ -76,27 +81,28 @@ 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_cdc = true @@ -105,10 +111,10 @@ 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 diff --git a/ports/zephyr-cp/boards/nordic/nrf7002dk/circuitpython.toml b/ports/zephyr-cp/boards/nordic/nrf7002dk/circuitpython.toml index 76b10578813..761d2631477 100644 --- a/ports/zephyr-cp/boards/nordic/nrf7002dk/circuitpython.toml +++ b/ports/zephyr-cp/boards/nordic/nrf7002dk/circuitpython.toml @@ -2,3 +2,4 @@ CIRCUITPY_BUILD_EXTENSIONS = ["elf"] USB_VID=0x239A USB_PID=0x8168 BLOBS=["nrf_wifi"] +DISABLED_MODULES=["aesio", "adafruit_bus_device", "zlib", "jpegio", "tilepalettemapper", "gifio"] diff --git a/ports/zephyr-cp/boards/nrf5340bsim_nrf5340_cpuapp.conf b/ports/zephyr-cp/boards/nrf5340bsim_nrf5340_cpuapp.conf new file mode 100644 index 00000000000..57628a61e20 --- /dev/null +++ b/ports/zephyr-cp/boards/nrf5340bsim_nrf5340_cpuapp.conf @@ -0,0 +1,35 @@ +# 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=y +CONFIG_BT_HCI=y +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_CENTRAL=y +CONFIG_BT_OBSERVER=y +CONFIG_BT_BROADCASTER=y + +CONFIG_BT_L2CAP_TX_MTU=253 +CONFIG_BT_BUF_CMD_TX_COUNT=2 +CONFIG_BT_BUF_CMD_TX_SIZE=255 +CONFIG_BT_HCI_VS=y +CONFIG_BT_BUF_EVT_RX_COUNT=16 +CONFIG_BT_BUF_EVT_RX_SIZE=255 +CONFIG_BT_BUF_ACL_TX_COUNT=3 +CONFIG_BT_BUF_ACL_TX_SIZE=251 +CONFIG_BT_BUF_ACL_RX_COUNT_EXTRA=1 +CONFIG_BT_BUF_ACL_RX_SIZE=255 + +CONFIG_BT_DEVICE_NAME_DYNAMIC=y +CONFIG_BT_DEVICE_NAME_MAX=28 + +# 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/nrf5340bsim_nrf5340_cpuapp.overlay b/ports/zephyr-cp/boards/nrf5340bsim_nrf5340_cpuapp.overlay new file mode 100644 index 00000000000..eeb043c6f3c --- /dev/null +++ b/ports/zephyr-cp/boards/nrf5340bsim_nrf5340_cpuapp.overlay @@ -0,0 +1,28 @@ +/* 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 { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + circuitpy_partition: partition@0 { + label = "circuitpy"; + reg = <0x00000000 DT_SIZE_K(1024)>; + }; + }; +}; + +/* Note: bsim doesn't have USB, so we don't include app.overlay */ diff --git a/ports/zephyr-cp/boards/nrf5340dk_nrf5340_cpuapp.conf b/ports/zephyr-cp/boards/nrf5340dk_nrf5340_cpuapp.conf index fa0532e8150..145a9393407 100644 --- a/ports/zephyr-cp/boards/nrf5340dk_nrf5340_cpuapp.conf +++ b/ports/zephyr-cp/boards/nrf5340dk_nrf5340_cpuapp.conf @@ -4,3 +4,17 @@ CONFIG_BT_CENTRAL=y CONFIG_BT_BROADCASTER=y CONFIG_BT_OBSERVER=y CONFIG_BT_EXT_ADV=y + +CONFIG_BT_DEVICE_APPEARANCE_DYNAMIC=y +CONFIG_BT_DEVICE_NAME_DYNAMIC=y +CONFIG_BT_DEVICE_NAME_MAX=28 +CONFIG_BT_L2CAP_TX_MTU=253 + +# BT Buffers +CONFIG_BT_BUF_CMD_TX_SIZE=255 +CONFIG_BT_BUF_EVT_RX_COUNT=16 +CONFIG_BT_BUF_EVT_RX_SIZE=255 +CONFIG_BT_BUF_ACL_TX_COUNT=3 +CONFIG_BT_BUF_ACL_TX_SIZE=251 +CONFIG_BT_BUF_ACL_RX_COUNT_EXTRA=1 +CONFIG_BT_BUF_ACL_RX_SIZE=255 diff --git a/ports/zephyr-cp/boards/nrf5340dk_nrf5340_cpuapp.overlay b/ports/zephyr-cp/boards/nrf5340dk_nrf5340_cpuapp.overlay new file mode 100644 index 00000000000..eb899df8cc9 --- /dev/null +++ b/ports/zephyr-cp/boards/nrf5340dk_nrf5340_cpuapp.overlay @@ -0,0 +1,24 @@ +&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"; +}; + +#include "../app.overlay" diff --git a/ports/zephyr-cp/boards/nrf54h20dk_nrf54h20_cpuapp.conf b/ports/zephyr-cp/boards/nrf54h20dk_nrf54h20_cpuapp.conf new file mode 100644 index 00000000000..a55b90c50e7 --- /dev/null +++ b/ports/zephyr-cp/boards/nrf54h20dk_nrf54h20_cpuapp.conf @@ -0,0 +1,8 @@ +CONFIG_FLASH_MSPI_NOR_LAYOUT_PAGE_SIZE=4096 + +# 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/nrf54h20dk_nrf54h20_cpuapp.overlay b/ports/zephyr-cp/boards/nrf54h20dk_nrf54h20_cpuapp.overlay new file mode 100644 index 00000000000..a70eede551e --- /dev/null +++ b/ports/zephyr-cp/boards/nrf54h20dk_nrf54h20_cpuapp.overlay @@ -0,0 +1,47 @@ +&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"; +}; + +#include "../app.overlay" diff --git a/ports/zephyr-cp/boards/nrf54l15dk_nrf54l15_cpuapp.overlay b/ports/zephyr-cp/boards/nrf54l15dk_nrf54l15_cpuapp.overlay new file mode 100644 index 00000000000..39db1e981af --- /dev/null +++ b/ports/zephyr-cp/boards/nrf54l15dk_nrf54l15_cpuapp.overlay @@ -0,0 +1 @@ +// No app.overlay because it doesn't have USB. diff --git a/ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.conf b/ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.conf index 6f01624bb3a..91c956fa676 100644 --- a/ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.conf +++ b/ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.conf @@ -1,8 +1,11 @@ CONFIG_NETWORKING=y CONFIG_WIFI=y -CONFIG_MBEDTLS_TLS_VERSION_1_2=y -CONFIG_MBEDTLS_USE_PSA_CRYPTO=n +CONFIG_MBEDTLS_SSL_PROTO_TLS1_2=y + +CONFIG_BT_DEVICE_APPEARANCE_DYNAMIC=y +CONFIG_BT_DEVICE_NAME_DYNAMIC=y +CONFIG_BT_DEVICE_NAME_MAX=28 CONFIG_BT=y CONFIG_BT_PERIPHERAL=y @@ -10,3 +13,7 @@ CONFIG_BT_CENTRAL=y CONFIG_BT_BROADCASTER=y CONFIG_BT_OBSERVER=y CONFIG_BT_EXT_ADV=y + +CONFIG_LOG=n +CONFIG_ASSERT=n +CONFIG_TEST_RANDOM_GENERATOR=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..b8e2c0601aa --- /dev/null +++ b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml @@ -0,0 +1,120 @@ +# 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 +audiofilters = true # Zephyr board has audiobusio +audiofreeverb = true # Zephyr board has audiobusio +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 = false +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 +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 +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_cdc = true +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 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..557b4f0448f --- /dev/null +++ b/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml @@ -0,0 +1,120 @@ +# 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 +audiofilters = false +audiofreeverb = 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 = false +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 +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 +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_cdc = true +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 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..ee43ef86e8c --- /dev/null +++ b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml @@ -0,0 +1,120 @@ +# 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 +audiofilters = true # Zephyr board has audiobusio +audiofreeverb = true # Zephyr board has audiobusio +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 = false +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 +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 +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_cdc = true +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 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..2215bcf4135 --- /dev/null +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/autogen_board_info.toml @@ -0,0 +1,120 @@ +# 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 +audiofilters = false +audiofreeverb = 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 = false +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 +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 +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_cdc = true +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 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..0f901d1149e --- /dev/null +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/circuitpython.toml @@ -0,0 +1,2 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["elf", "uf2"] +BLOBS=["hal_infineon"] 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..61324042092 --- /dev/null +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/autogen_board_info.toml @@ -0,0 +1,120 @@ +# 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 +audiofilters = false +audiofreeverb = 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 = false +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 +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 +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_cdc = true +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 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..9d3c229ed1b --- /dev/null +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/circuitpython.toml @@ -0,0 +1 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["elf", "uf2"] 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..203f5fd7048 --- /dev/null +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/autogen_board_info.toml @@ -0,0 +1,120 @@ +# 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 +audiofilters = false +audiofreeverb = 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 = false +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 +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 +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_cdc = true +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 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..0f901d1149e --- /dev/null +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/circuitpython.toml @@ -0,0 +1,2 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["elf", "uf2"] +BLOBS=["hal_infineon"] 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..13c77bf2928 --- /dev/null +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/autogen_board_info.toml @@ -0,0 +1,120 @@ +# 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 +audiofilters = false +audiofreeverb = 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 = false +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 +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 +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_cdc = true +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 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..9d3c229ed1b --- /dev/null +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/circuitpython.toml @@ -0,0 +1 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["elf", "uf2"] 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..e596ea1aebc --- /dev/null +++ b/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml @@ -0,0 +1,120 @@ +# 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 +audiofilters = false +audiofreeverb = 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 = false +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 +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 +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_cdc = true +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 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..7751ec96715 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 @@ -24,49 +24,54 @@ 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 +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 +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 @@ -76,39 +81,40 @@ 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_cdc = true 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 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..42bef11db0c 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 @@ -24,49 +24,54 @@ 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 +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 +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 @@ -76,39 +81,40 @@ 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_cdc = true 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 = true # Zephyr board has zephyr_display zephyr_kernel = false -zephyr_serial = true -zlib = false +zlib = true 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/renesas_da14695_dk_usb.conf b/ports/zephyr-cp/boards/renesas_da14695_dk_usb.conf new file mode 100644 index 00000000000..145a9393407 --- /dev/null +++ b/ports/zephyr-cp/boards/renesas_da14695_dk_usb.conf @@ -0,0 +1,20 @@ +CONFIG_BT=y +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_CENTRAL=y +CONFIG_BT_BROADCASTER=y +CONFIG_BT_OBSERVER=y +CONFIG_BT_EXT_ADV=y + +CONFIG_BT_DEVICE_APPEARANCE_DYNAMIC=y +CONFIG_BT_DEVICE_NAME_DYNAMIC=y +CONFIG_BT_DEVICE_NAME_MAX=28 +CONFIG_BT_L2CAP_TX_MTU=253 + +# BT Buffers +CONFIG_BT_BUF_CMD_TX_SIZE=255 +CONFIG_BT_BUF_EVT_RX_COUNT=16 +CONFIG_BT_BUF_EVT_RX_SIZE=255 +CONFIG_BT_BUF_ACL_TX_COUNT=3 +CONFIG_BT_BUF_ACL_TX_SIZE=251 +CONFIG_BT_BUF_ACL_RX_COUNT_EXTRA=1 +CONFIG_BT_BUF_ACL_RX_SIZE=255 diff --git a/ports/zephyr-cp/boards/rpi_pico2_rp2350a_m33.overlay b/ports/zephyr-cp/boards/rpi_pico2_rp2350a_m33.overlay new file mode 100644 index 00000000000..eb94fe7de67 --- /dev/null +++ b/ports/zephyr-cp/boards/rpi_pico2_rp2350a_m33.overlay @@ -0,0 +1,25 @@ +&flash0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + code_partition: partition@0 { + label = "code-partition"; + reg = <0x0 0x180000>; + read-only; + }; + + nvm_partition: partition@180000 { + label = "nvm"; + reg = <0x180000 0x1000>; + }; + + circuitpy_partition: partition@181000 { + label = "circuitpy"; + reg = <0x181000 (DT_SIZE_M(4) - 0x181000)>; + }; + }; +}; + +#include "../app.overlay" diff --git a/ports/zephyr-cp/boards/rpi_pico2_rp2350a_m33_w.conf b/ports/zephyr-cp/boards/rpi_pico2_rp2350a_m33_w.conf new file mode 100644 index 00000000000..d75b1cd20a9 --- /dev/null +++ b/ports/zephyr-cp/boards/rpi_pico2_rp2350a_m33_w.conf @@ -0,0 +1,19 @@ +CONFIG_NETWORKING=y +CONFIG_NET_IPV4=y +CONFIG_NET_DHCPV4=y +CONFIG_NET_SOCKETS=y + +CONFIG_WIFI=y +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/rpi_pico2_rp2350a_m33_w.overlay b/ports/zephyr-cp/boards/rpi_pico2_rp2350a_m33_w.overlay new file mode 100644 index 00000000000..eb94fe7de67 --- /dev/null +++ b/ports/zephyr-cp/boards/rpi_pico2_rp2350a_m33_w.overlay @@ -0,0 +1,25 @@ +&flash0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + code_partition: partition@0 { + label = "code-partition"; + reg = <0x0 0x180000>; + read-only; + }; + + nvm_partition: partition@180000 { + label = "nvm"; + reg = <0x180000 0x1000>; + }; + + circuitpy_partition: partition@181000 { + label = "circuitpy"; + reg = <0x181000 (DT_SIZE_M(4) - 0x181000)>; + }; + }; +}; + +#include "../app.overlay" diff --git a/ports/zephyr-cp/boards/rpi_pico_rp2040.overlay b/ports/zephyr-cp/boards/rpi_pico_rp2040.overlay new file mode 100644 index 00000000000..ce9083dd62d --- /dev/null +++ b/ports/zephyr-cp/boards/rpi_pico_rp2040.overlay @@ -0,0 +1,34 @@ +&flash0 { + /delete-node/ partitions; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* Reserved memory for the second stage bootloader */ + second_stage_bootloader: partition@0 { + label = "second_stage_bootloader"; + reg = <0x00000000 0x100>; + read-only; + }; + + code_partition: partition@100 { + label = "code-partition"; + reg = <0x100 (0x180000 - 0x100)>; + read-only; + }; + + nvm_partition: partition@180000 { + label = "nvm"; + reg = <0x180000 0x1000>; + }; + + circuitpy_partition: partition@181000 { + label = "circuitpy"; + reg = <0x181000 (DT_SIZE_M(2) - 0x181000)>; + }; + }; +}; + +#include "../app.overlay" diff --git a/ports/zephyr-cp/boards/rpi_pico_rp2040_w.conf b/ports/zephyr-cp/boards/rpi_pico_rp2040_w.conf new file mode 100644 index 00000000000..975d6bfd6e1 --- /dev/null +++ b/ports/zephyr-cp/boards/rpi_pico_rp2040_w.conf @@ -0,0 +1,21 @@ +CONFIG_NETWORKING=y +CONFIG_NET_IPV4=y +CONFIG_NET_DHCPV4=y +CONFIG_NET_SOCKETS=y + +CONFIG_WIFI=y +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/rpi_pico_rp2040_w.overlay b/ports/zephyr-cp/boards/rpi_pico_rp2040_w.overlay new file mode 100644 index 00000000000..ce9083dd62d --- /dev/null +++ b/ports/zephyr-cp/boards/rpi_pico_rp2040_w.overlay @@ -0,0 +1,34 @@ +&flash0 { + /delete-node/ partitions; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* Reserved memory for the second stage bootloader */ + second_stage_bootloader: partition@0 { + label = "second_stage_bootloader"; + reg = <0x00000000 0x100>; + read-only; + }; + + code_partition: partition@100 { + label = "code-partition"; + reg = <0x100 (0x180000 - 0x100)>; + read-only; + }; + + nvm_partition: partition@180000 { + label = "nvm"; + reg = <0x180000 0x1000>; + }; + + circuitpy_partition: partition@181000 { + label = "circuitpy"; + reg = <0x181000 (DT_SIZE_M(2) - 0x181000)>; + }; + }; +}; + +#include "../app.overlay" 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..7ad9c4f2111 --- /dev/null +++ b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml @@ -0,0 +1,120 @@ +# 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 +audiofilters = false +audiofreeverb = 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 = false +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 +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 +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_cdc = true +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 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..83e6bcd39c4 --- /dev/null +++ b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/circuitpython.toml @@ -0,0 +1 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["hex"] 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..2796f76782f 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 @@ -24,49 +24,54 @@ 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 +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 +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 @@ -76,27 +81,28 @@ 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_cdc = true @@ -105,10 +111,10 @@ 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 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..2d5385d90b2 --- /dev/null +++ b/ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml @@ -0,0 +1,120 @@ +# 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 +audiofilters = false +audiofreeverb = 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 = false +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 +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 +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_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 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..7f158d6f278 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 @@ -24,49 +24,54 @@ 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 +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 +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 @@ -76,39 +81,40 @@ 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_cdc = true 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 = true # Zephyr board has zephyr_display zephyr_kernel = false -zephyr_serial = true -zlib = false +zlib = true 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..19141f30065 --- /dev/null +++ b/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml @@ -0,0 +1,120 @@ +# 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 = 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 +audiofilters = false +audiofreeverb = 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 = false +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 +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 +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_cdc = true +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 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..83e6bcd39c4 --- /dev/null +++ b/ports/zephyr-cp/boards/st/stm32wba65i_dk1/circuitpython.toml @@ -0,0 +1 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["hex"] diff --git a/ports/zephyr-cp/boards/stm32h750b_dk_stm32h750xx_ext_flash_app.conf b/ports/zephyr-cp/boards/stm32h750b_dk_stm32h750xx_ext_flash_app.conf new file mode 100644 index 00000000000..24afffb8e88 --- /dev/null +++ b/ports/zephyr-cp/boards/stm32h750b_dk_stm32h750xx_ext_flash_app.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/stm32h750b_dk_stm32h750xx_ext_flash_app.overlay b/ports/zephyr-cp/boards/stm32h750b_dk_stm32h750xx_ext_flash_app.overlay new file mode 100644 index 00000000000..fdb4960477b --- /dev/null +++ b/ports/zephyr-cp/boards/stm32h750b_dk_stm32h750xx_ext_flash_app.overlay @@ -0,0 +1,14 @@ +&ext_flash { + partitions { + /delete-node/ partition@7800000; + + circuitpy_partition: partition@7800000 { + label = "circuitpy"; + reg = <0x7800000 DT_SIZE_M(8)>; + }; + }; +}; + +&rng { + status = "okay"; +}; diff --git a/ports/zephyr-cp/boards/stm32h7b3i_dk.conf b/ports/zephyr-cp/boards/stm32h7b3i_dk.conf new file mode 100644 index 00000000000..24afffb8e88 --- /dev/null +++ b/ports/zephyr-cp/boards/stm32h7b3i_dk.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/stm32h7b3i_dk.overlay b/ports/zephyr-cp/boards/stm32h7b3i_dk.overlay index 88ad0415485..c2b5f3129c4 100644 --- a/ports/zephyr-cp/boards/stm32h7b3i_dk.overlay +++ b/ports/zephyr-cp/boards/stm32h7b3i_dk.overlay @@ -2,6 +2,28 @@ /delete-node/ partitions; }; +&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/stm32wba65i_dk1.conf b/ports/zephyr-cp/boards/stm32wba65i_dk1.conf new file mode 100644 index 00000000000..55d951959e6 --- /dev/null +++ b/ports/zephyr-cp/boards/stm32wba65i_dk1.conf @@ -0,0 +1,24 @@ +# 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 +CONFIG_BT_BROADCASTER=y +CONFIG_BT_OBSERVER=y +CONFIG_BT_EXT_ADV=y +CONFIG_BT_STM32WBA_USE_TEMP_BASED_CALIB=n + +CONFIG_BT_DEVICE_APPEARANCE_DYNAMIC=y +CONFIG_BT_DEVICE_NAME_DYNAMIC=y +CONFIG_BT_DEVICE_NAME_MAX=28 +CONFIG_BT_L2CAP_TX_MTU=253 + +# BT Buffers +CONFIG_BT_BUF_CMD_TX_SIZE=255 +CONFIG_BT_BUF_EVT_RX_COUNT=16 +CONFIG_BT_BUF_EVT_RX_SIZE=255 +CONFIG_BT_BUF_ACL_TX_SIZE=251 +CONFIG_BT_BUF_ACL_RX_COUNT_EXTRA=1 +CONFIG_BT_BUF_ACL_RX_SIZE=255 diff --git a/ports/zephyr-cp/boards/stm32wba65i_dk1.overlay b/ports/zephyr-cp/boards/stm32wba65i_dk1.overlay new file mode 100644 index 00000000000..3b72ffc9984 --- /dev/null +++ b/ports/zephyr-cp/boards/stm32wba65i_dk1.overlay @@ -0,0 +1,61 @@ +&flash0 { + /delete-node/ partitions; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 DT_SIZE_K(64)>; + }; + + slot0_partition: partition@10000 { + label = "image-0"; + reg = <0x00010000 DT_SIZE_K(928)>; + }; + + storage_partition: partition@f80000 { + label = "storage"; + reg = <0x001e0000 DT_SIZE_K(64)>; + }; + + circuitpy_partition: partition@108000 { + 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"; +}; + +#include "../app.overlay" 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..d1410f02e1b --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/Adapter.c @@ -0,0 +1,679 @@ +// 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 "py/gc.h" +#include "py/runtime.h" +#include "bindings/zephyr_kernel/__init__.h" +#include "shared-bindings/_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/shared/tick.h" + +bleio_connection_internal_t bleio_connections[BLEIO_TOTAL_CONNECTION_COUNT]; + +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; +static bool ble_adapter_enabled = true; + +#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; +} + +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; +} + +static void bleio_connected_cb(struct bt_conn *conn, uint8_t err) { + if (err != 0) { + return; + } + + if (bleio_connection_track(conn) == NULL) { + bt_conn_disconnect(conn, BT_HCI_ERR_CONN_LIMIT_EXCEEDED); + return; + } + + // 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; + + common_hal_bleio_adapter_obj.connection_objs = NULL; +} + +static void bleio_disconnected_cb(struct bt_conn *conn, uint8_t reason) { + printk("disconnected %p\n", conn); + bleio_connection_release(bleio_connection_find_by_conn(conn), reason); +} + +BT_CONN_CB_DEFINE(bleio_connection_callbacks) = { + .connected = bleio_connected_cb, + .disconnected = bleio_disconnected_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 || + field_len < 1 || + storage_offset + data_len > storage_len) { + mp_raise_ValueError(MP_ERROR_TEXT("Invalid advertising data")); + } + 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; +} + +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]); + } + if (!bt_is_ready()) { + int err = bt_enable(NULL); + if (err != 0) { + raise_zephyr_error(err); + } + } + 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; +} + +void common_hal_bleio_adapter_set_tx_power(bleio_adapter_obj_t *self, 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) { + 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; + 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) { + raise_zephyr_error(err); + } + + net_buf_unref(rsp); +} + +bleio_address_obj_t *common_hal_bleio_adapter_get_address(bleio_adapter_obj_t *self) { + mp_raise_NotImplementedError(NULL); +} + +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); + } +} + +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_NotImplementedError(NULL); + } + + if (timeout != 0) { + mp_raise_NotImplementedError(NULL); + } + + if (ble_advertising) { + raise_zephyr_error(-EALREADY); + } + + 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) { + printk("Failed to create identity address: %d\n", id); + raise_zephyr_error(id); + } + } + + size_t adv_count = bleio_parse_adv_data(advertising_data_bufinfo->buf, + advertising_data_bufinfo->len, + adv_data, + BLEIO_ADV_MAX_FIELDS, + adv_data_storage, + sizeof(adv_data_storage)); + + size_t scan_resp_count = 0; + if (scan_response_data_bufinfo->len > 0) { + scan_resp_count = bleio_parse_adv_data(scan_response_data_bufinfo->buf, + scan_response_data_bufinfo->len, + scan_resp_data, + BLEIO_ADV_MAX_FIELDS, + scan_resp_storage, + sizeof(scan_resp_storage)); + } + + if (anonymous) { + mp_raise_NotImplementedError(NULL); + } + + 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); + } + + common_hal_bleio_adapter_set_tx_power(self, tx_power); + + raise_zephyr_error(bt_le_adv_start(&adv_params, + adv_data, + adv_count, + scan_resp_count > 0 ? scan_resp_data : NULL, + scan_resp_count)); + + ble_advertising = true; +} + +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; +} + +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, + .options = BT_LE_SCAN_OPT_FILTER_DUPLICATE, + .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); + + mp_buffer_info_t address_bufinfo; + mp_get_buffer_raise(address->bytes, &address_bufinfo, MP_BUFFER_READ); + + bt_addr_le_t peer = { + .type = bleio_address_type_to_zephyr(address->type), + }; + memcpy(peer.a.val, address_bufinfo.buf, 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); + + self->connection_objs = NULL; + return bleio_connection_new_from_internal(connection); +} + +void common_hal_bleio_adapter_erase_bonding(bleio_adapter_obj_t *self) { + mp_raise_NotImplementedError(NULL); +} + +bool common_hal_bleio_adapter_is_bonded_to_central(bleio_adapter_obj_t *self) { + 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)); +} + +void bleio_adapter_reset(bleio_adapter_obj_t *adapter) { + if (adapter == NULL) { + return; + } + + common_hal_bleio_adapter_stop_scan(adapter); + common_hal_bleio_adapter_stop_advertising(adapter); + + for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { + bleio_connection_internal_t *connection = &bleio_connections[i]; + if (connection->conn != NULL) { + bt_conn_disconnect(connection->conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + } + if (connection->connection_obj != MP_OBJ_NULL && + 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 = BT_HCI_ERR_REMOTE_USER_TERM_CONN; + } + bleio_connection_clear(connection); + } + + adapter->scan_results = NULL; + adapter->connection_objs = NULL; + active_scan_results = NULL; + ble_advertising = false; + ble_adapter_enabled = bt_is_ready(); +} + +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..c15c698e2a5 --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/Adapter.h @@ -0,0 +1,29 @@ +// 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/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; +} bleio_adapter_obj_t; + +void bleio_adapter_gc_collect(bleio_adapter_obj_t *adapter); +void bleio_adapter_reset(bleio_adapter_obj_t *adapter); 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..386be6004d2 --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/Characteristic.c @@ -0,0 +1,67 @@ +// 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 "py/runtime.h" +#include "shared-bindings/_bleio/Characteristic.h" +#include "shared-bindings/_bleio/Descriptor.h" +#include "shared-bindings/_bleio/Service.h" + +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) { + 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) { + mp_raise_NotImplementedError(NULL); +} + +void common_hal_bleio_characteristic_add_descriptor(bleio_characteristic_obj_t *self, bleio_descriptor_obj_t *descriptor) { + mp_raise_NotImplementedError(NULL); +} + +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) { + mp_raise_NotImplementedError(NULL); +} + +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 +} + +void common_hal_bleio_characteristic_set_cccd(bleio_characteristic_obj_t *self, bool notify, bool indicate) { + mp_raise_NotImplementedError(NULL); +} + +void common_hal_bleio_characteristic_set_value(bleio_characteristic_obj_t *self, mp_buffer_info_t *bufinfo) { + mp_raise_NotImplementedError(NULL); +} + +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..b710a9f2662 --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/Characteristic.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 "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; +} 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); 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..17e000e905e --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/CharacteristicBuffer.c @@ -0,0 +1,73 @@ +// 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 "py/mperrno.h" +#include "py/runtime.h" +#include "shared-bindings/_bleio/CharacteristicBuffer.h" + +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) { + (void)self; + (void)characteristic; + (void)timeout; + (void)buffer; + (void)buffer_size; + (void)static_handler_entry; + (void)watch_for_interrupt_char; + mp_raise_NotImplementedError(NULL); +} + +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) { + (void)self; + (void)characteristic; + (void)timeout; + (void)buffer_size; + mp_raise_NotImplementedError(NULL); +} + +uint32_t common_hal_bleio_characteristic_buffer_read(bleio_characteristic_buffer_obj_t *self, uint8_t *data, size_t len, int *errcode) { + (void)self; + (void)data; + (void)len; + if (errcode != NULL) { + *errcode = MP_EAGAIN; + } + mp_raise_NotImplementedError(NULL); +} + +uint32_t common_hal_bleio_characteristic_buffer_rx_characters_available(bleio_characteristic_buffer_obj_t *self) { + (void)self; + mp_raise_NotImplementedError(NULL); +} + +void common_hal_bleio_characteristic_buffer_clear_rx_buffer(bleio_characteristic_buffer_obj_t *self) { + (void)self; + mp_raise_NotImplementedError(NULL); +} + +bool common_hal_bleio_characteristic_buffer_deinited(bleio_characteristic_buffer_obj_t *self) { + return self->deinited; +} + +void common_hal_bleio_characteristic_buffer_deinit(bleio_characteristic_buffer_obj_t *self) { + if (self == NULL) { + return; + } + self->deinited = true; +} + +bool common_hal_bleio_characteristic_buffer_connected(bleio_characteristic_buffer_obj_t *self) { + (void)self; + return false; +} 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..91ea262945a --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/CharacteristicBuffer.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" +#include "shared-bindings/_bleio/Characteristic.h" + +typedef struct { + mp_obj_base_t base; + bleio_characteristic_obj_t *characteristic; + bool deinited; +} bleio_characteristic_buffer_obj_t; 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..938359c79ca --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/Connection.c @@ -0,0 +1,97 @@ +// 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 "bindings/zephyr_kernel/__init__.h" +#include "shared-bindings/_bleio/__init__.h" +#include "shared-bindings/_bleio/Connection.h" + +void common_hal_bleio_connection_pair(bleio_connection_internal_t *self, bool bond) { + mp_raise_NotImplementedError(NULL); +} + +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) { + return false; +} + +mp_obj_tuple_t *common_hal_bleio_connection_discover_remote_services(bleio_connection_obj_t *self, mp_obj_t service_uuids_whitelist) { + mp_raise_NotImplementedError(NULL); +} + +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..dc14125db5f --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/Connection.h @@ -0,0 +1,27 @@ +// 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 struct { + struct bt_conn *conn; + mp_obj_t connection_obj; +} 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); 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..a3e65a5e006 --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/Descriptor.c @@ -0,0 +1,30 @@ +// 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 "py/runtime.h" +#include "shared-bindings/_bleio/Descriptor.h" +#include "shared-bindings/_bleio/Characteristic.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) { + mp_raise_NotImplementedError(NULL); +} + +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) { + mp_raise_NotImplementedError(NULL); +} + +size_t common_hal_bleio_descriptor_get_value(bleio_descriptor_obj_t *self, uint8_t *buf, size_t len) { + mp_raise_NotImplementedError(NULL); +} + +void common_hal_bleio_descriptor_set_value(bleio_descriptor_obj_t *self, mp_buffer_info_t *bufinfo) { + mp_raise_NotImplementedError(NULL); +} 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..1d29cb27a50 --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/Descriptor.h @@ -0,0 +1,24 @@ +// 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 "py/obj.h" +#include "shared-bindings/_bleio/Attribute.h" +#include "common-hal/_bleio/UUID.h" + +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; +} 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..82fe8a3d176 --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/PacketBuffer.c @@ -0,0 +1,66 @@ +// 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 "py/runtime.h" +#include "shared-bindings/_bleio/PacketBuffer.h" + +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) { + (void)self; + (void)characteristic; + (void)buffer_size; + (void)max_packet_size; + mp_raise_NotImplementedError(NULL); +} + +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) { + (void)self; + (void)data; + (void)len; + (void)header; + (void)header_len; + mp_raise_NotImplementedError(NULL); +} + +mp_int_t common_hal_bleio_packet_buffer_readinto(bleio_packet_buffer_obj_t *self, uint8_t *data, size_t len) { + (void)self; + (void)data; + (void)len; + mp_raise_NotImplementedError(NULL); +} + +mp_int_t common_hal_bleio_packet_buffer_get_incoming_packet_length(bleio_packet_buffer_obj_t *self) { + (void)self; + mp_raise_NotImplementedError(NULL); +} + +mp_int_t common_hal_bleio_packet_buffer_get_outgoing_packet_length(bleio_packet_buffer_obj_t *self) { + (void)self; + mp_raise_NotImplementedError(NULL); +} + +void common_hal_bleio_packet_buffer_flush(bleio_packet_buffer_obj_t *self) { + (void)self; + mp_raise_NotImplementedError(NULL); +} + +bool common_hal_bleio_packet_buffer_deinited(bleio_packet_buffer_obj_t *self) { + return self->deinited; +} + +void common_hal_bleio_packet_buffer_deinit(bleio_packet_buffer_obj_t *self) { + if (self == NULL) { + return; + } + self->deinited = true; +} + +bool common_hal_bleio_packet_buffer_connected(bleio_packet_buffer_obj_t *self) { + (void)self; + return false; +} 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..c8cd763fd61 --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/PacketBuffer.h @@ -0,0 +1,21 @@ +// 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 _bleio_characteristic_obj bleio_characteristic_obj_t; + +typedef void *ble_event_handler_t; + +typedef struct { + mp_obj_base_t base; + bool deinited; +} bleio_packet_buffer_obj_t; 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..cefc85b6df6 --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/Service.c @@ -0,0 +1,46 @@ +// 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 "py/runtime.h" +#include "shared-bindings/_bleio/Service.h" +#include "shared-bindings/_bleio/Characteristic.h" + +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) { + mp_raise_NotImplementedError(NULL); +} + +void common_hal_bleio_service_construct(bleio_service_obj_t *self, bleio_uuid_obj_t *uuid, bool is_secondary) { + mp_raise_NotImplementedError(NULL); +} + +void common_hal_bleio_service_deinit(bleio_service_obj_t *self) { + // Nothing to do +} + +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) { + mp_raise_NotImplementedError(NULL); +} + +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) { + mp_raise_NotImplementedError(NULL); +} 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..86727d3b0f7 --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/Service.h @@ -0,0 +1,23 @@ +// 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 "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; +} bleio_service_obj_t; 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..916eedb2c47 --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/UUID.c @@ -0,0 +1,52 @@ +// 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]) { + if (uuid16 != 0) { + // 16-bit UUID + self->size = 16; + // Convert 16-bit UUID to 128-bit + // Bluetooth Base UUID: 00000000-0000-1000-8000-00805F9B34FB + const uint8_t base_uuid[16] = {0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + memcpy(self->uuid128, base_uuid, 16); + self->uuid128[12] = (uuid16 & 0xff); + self->uuid128[13] = (uuid16 >> 8) & 0xff; + } else { + // 128-bit UUID + self->size = 128; + memcpy(self->uuid128, uuid128, 16); + } +} + +uint32_t common_hal_bleio_uuid_get_uuid16(bleio_uuid_obj_t *self) { + if (self->size == 16) { + return (self->uuid128[13] << 8) | self->uuid128[12]; + } + return 0; +} + +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; +} + +void common_hal_bleio_uuid_pack_into(bleio_uuid_obj_t *self, uint8_t *buf) { + if (self->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..386f5a7b8b9 --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/UUID.h @@ -0,0 +1,16 @@ +// 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 "py/obj.h" + +typedef struct { + mp_obj_base_t base; + uint8_t uuid128[16]; + uint8_t size; +} 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..719564c1cd4 --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/__init__.c @@ -0,0 +1,51 @@ +// 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 "supervisor/shared/bluetooth/bluetooth.h" + +// The singleton _bleio.Adapter object +bleio_adapter_obj_t common_hal_bleio_adapter_obj; + +void common_hal_bleio_init(void) { + common_hal_bleio_adapter_obj.base.type = &bleio_adapter_type; + bleio_adapter_reset(&common_hal_bleio_adapter_obj); +} + +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); + } + + // Maybe start advertising the BLE workflow. + supervisor_bluetooth_background(); +} + +void bleio_reset(void) { + common_hal_bleio_adapter_obj.base.type = &bleio_adapter_type; + if (!common_hal_bleio_adapter_get_enabled(&common_hal_bleio_adapter_obj)) { + return; + } + + supervisor_stop_bluetooth(); + bleio_adapter_reset(&common_hal_bleio_adapter_obj); + common_hal_bleio_adapter_set_enabled(&common_hal_bleio_adapter_obj, false); + supervisor_start_bluetooth(); +} + +void common_hal_bleio_gc_collect(void) { + bleio_adapter_gc_collect(&common_hal_bleio_adapter_obj); +} + +void common_hal_bleio_device_discover_remote_services(mp_obj_t device, mp_obj_t service_uuids_whitelist) { + mp_raise_NotImplementedError(NULL); +} 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..1502767c615 --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/__init__.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 + +// Placeholder for Zephyr-specific BLE defines 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..e858552c524 --- /dev/null +++ b/ports/zephyr-cp/common-hal/audiobusio/I2SOut.c @@ -0,0 +1,299 @@ +// 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) { + 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; + } + + if (result == GET_BUFFER_DONE) { + if (self->loop) { + // Reset to beginning + audiosample_reset_buffer(self->sample, false, 0); + } else { + // Done playing, fill rest with silence + self->stopping = true; + i2s_trigger(self->i2s_dev, I2S_DIR_TX, I2S_TRIGGER_DRAIN); + memset(buffer + bytes_filled, 0, buffer_size - bytes_filled); + return; + } + } + + // Copy data to buffer + 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; + } +} + +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); + } + + // 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..9940853da50 --- /dev/null +++ b/ports/zephyr-cp/common-hal/busio/UART.c @@ -0,0 +1,158 @@ +// 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; + + 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) { + 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..9f512a686ec 100644 --- a/ports/zephyr-cp/common-hal/microcontroller/Processor.c +++ b/ports/zephyr-cp/common-hal/microcontroller/Processor.c @@ -21,7 +21,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) { 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_i2c/__init__.c b/ports/zephyr-cp/common-hal/rotaryio/__init__.c similarity index 84% rename from ports/zephyr-cp/common-hal/zephyr_i2c/__init__.c rename to ports/zephyr-cp/common-hal/rotaryio/__init__.c index db93a442f04..67cae26a8b7 100644 --- a/ports/zephyr-cp/common-hal/zephyr_i2c/__init__.c +++ b/ports/zephyr-cp/common-hal/rotaryio/__init__.c @@ -4,4 +4,4 @@ // // SPDX-License-Identifier: MIT -// No zephyr_i2c 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..ca8ba419839 100644 --- a/ports/zephyr-cp/common-hal/socketpool/Socket.c +++ b/ports/zephyr-cp/common-hal/socketpool/Socket.c @@ -20,165 +20,104 @@ #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 -// 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); +} + +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) { + common_hal_socketpool_socketpool_raise_gaierror_noname(); + } + + memcpy(addr, result_i->ai_addr, sizeof(struct sockaddr_storage)); + zsock_freeaddrinfo(result_i); } -// 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 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 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; +// How long to wait between checks for a socket to connect. +#define SOCKET_CONNECT_POLL_INTERVAL_MS 100 -// uint64_t signal = 1; -// write(socket_change_fd, &signal, sizeof(signal)); -// socketpool_socket_poll_resume(); -// return true; -// } -// return false; -// } +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 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 -// } +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 +151,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; - // // Sockets should be nonblocking in most cases - // lwip_fcntl(socknum, F_SETFL, O_NONBLOCK); + sock->num = socknum; + + // 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, O_NONBLOCK) < 0) { + // Ignore if non-blocking is unsupported. + } return true; } @@ -235,11 +181,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 +201,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 +217,23 @@ 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); + #if CIRCUITPY_HOSTNETWORK + if (self->timeout_ms == 0) { + struct zsock_timeval tv = { + .tv_sec = 0, + .tv_usec = 1000, + }; + zsock_setsockopt(self->num, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); + } + #endif + 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 +245,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, 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 +261,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 +275,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 +290,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 +339,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 +353,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 ----- - - // Emulate SO_CONTIMEO, which is not implemented by lwip. - // All our sockets are non-blocking, so we check the timeout ourselves. + (void)hostlen; + struct sockaddr_storage addr; + resolve_host_or_throw(self, host, &addr, port); - 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 +371,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 +382,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 +407,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 +434,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 +453,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 +478,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 +490,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 +498,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 +546,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 +573,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 +595,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 +640,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..c9a3f008321 100644 --- a/ports/zephyr-cp/common-hal/socketpool/SocketPool.c +++ b/ports/zephyr-cp/common-hal/socketpool/SocketPool.c @@ -8,114 +8,116 @@ #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 + 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) { + 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) { common_hal_socketpool_socketpool_raise_gaierror_noname(); } 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/wifi/Radio.c b/ports/zephyr-cp/common-hal/wifi/Radio.c index 726b406b3ca..35a0b76a362 100644 --- a/ports/zephyr-cp/common-hal/wifi/Radio.c +++ b/ports/zephyr-cp/common-hal/wifi/Radio.c @@ -86,13 +86,19 @@ void common_hal_wifi_radio_set_enabled(wifi_radio_obj_t *self, bool enabled) { // mdns_server_deinit_singleton(); // #endif printk("net_if_down\n"); - CHECK_ZEPHYR_RESULT(net_if_down(self->sta_netif)); + 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)); + 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); diff --git a/ports/zephyr-cp/common-hal/wifi/ScannedNetworks.c b/ports/zephyr-cp/common-hal/wifi/ScannedNetworks.c index 3a6c21c5b83..725bf1fa7cb 100644 --- a/ports/zephyr-cp/common-hal/wifi/ScannedNetworks.c +++ b/ports/zephyr-cp/common-hal/wifi/ScannedNetworks.c @@ -16,6 +16,7 @@ #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 diff --git a/ports/zephyr-cp/common-hal/wifi/__init__.c b/ports/zephyr-cp/common-hal/wifi/__init__.c index 57f073a9cbb..4b967bc2780 100644 --- a/ports/zephyr-cp/common-hal/wifi/__init__.c +++ b/ports/zephyr-cp/common-hal/wifi/__init__.c @@ -22,6 +22,10 @@ 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 @@ -29,6 +33,8 @@ wifi_radio_obj_t common_hal_wifi_radio_obj; #include #include +#include + #define MAC_ADDRESS_LENGTH 6 static void schedule_background_on_cp_core(void *arg) { @@ -44,20 +50,23 @@ 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: + 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) { + 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"); + printk("NET_EVENT_WIFI_SCAN_DONE (thread: %s prio=%d)\n", + 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); } @@ -101,6 +110,9 @@ static void _event_handler(struct net_mgmt_event_callback *cb, uint32_t mgmt_eve case NET_EVENT_WIFI_AP_STA_DISCONNECTED: printk("NET_EVENT_WIFI_AP_STA_DISCONNECTED\n"); break; + default: + printk("unhandled net event %x\n", mgmt_event); + break; } } @@ -281,6 +293,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,16 +304,28 @@ 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) { + printk("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 + printk("Hostname support disabled in Zephyr config\n"); + #endif // set station mode to avoid the default SoftAP common_hal_wifi_radio_start_station(self); // start wifi 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..b7334402b74 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,87 @@ "json", "random", "digitalio", - "zephyr_serial", + "rotaryio", + "rainbowio", + "traceback", + "warnings", + "supervisor", + "errno", + "io", + "math", + "msgpack", + "aesio", + "hashlib", + "zlib", + "adafruit_bus_device", + "getpass", + "storage", ] -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"] + +# 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 +163,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 +248,111 @@ 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 = {} + + 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}" + + 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(): 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 +361,30 @@ 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(f"-DCIRCUITPY_SETTINGS_TOML={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 +401,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 +412,28 @@ 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/vfs_fat.c", "lib/tlsf/tlsf.c", portdir / "background.c", @@ -301,7 +442,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 +463,56 @@ 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")) + if "_bleio" in enabled_modules: + supervisor_source.append(top / "supervisor/shared/bluetooth/bluetooth.c") 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])) + 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("-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") - ) + circuitpython_flags.append("-DCIRCUITPY_USB_CDC_CONSOLE_ENABLED_DEFAULT=1") + circuitpython_flags.append("-DCIRCUITPY_USB_CDC_DATA_ENABLED_DEFAULT=0") - 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") + (portdir / "supervisor/usb.c", srcdir / "supervisor/shared/usb.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 +520,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,25 +563,36 @@ 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")) + 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)) 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(): + if autogen_board_info_fn.parent.exists(): autogen_board_info_fn.write_text(tomlkit.dumps(autogen_board_info)) for mpflag in MPCONFIG_FLAGS: @@ -558,6 +645,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 +679,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/compat2driver.py b/ports/zephyr-cp/cptools/compat2driver.py index 2b818c4c237..7da74ffcf18 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", @@ -117,7 +184,11 @@ "zephyr_bt_hci_uart": "bluetooth/hci", "zephyr_bt_hci_userchan": "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 +203,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 +217,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 +261,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 +275,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 +328,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 +364,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 +443,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 +473,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 +497,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 +551,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 +563,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 +580,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 +591,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 +654,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 +668,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 +710,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 +814,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 +848,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 +861,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 +889,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 +960,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 +981,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 +1021,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 +1053,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 +1075,9 @@ "nxp_lpc_uid": "hwinfo", # # hwspinlock + "nxp_sema42": "hwspinlock", "sqn_hwspinlock": "hwspinlock", + "vnd_hwspinlock": "hwspinlock", # # i2c "adi_max32_i2c": "i2c", @@ -740,47 +1089,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 +1159,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 +1205,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 +1221,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 +1257,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 +1291,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 +1307,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 +1337,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 +1346,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 +1375,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 +1420,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 +1450,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 +1460,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 +1469,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 +1494,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 +1527,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 +1574,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 +1589,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 +1609,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 +1687,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 +1718,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 +1844,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 +1924,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 +1946,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 +1959,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 +1980,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 +2020,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 +2035,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 +2047,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 +2070,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 +2082,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 +2098,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 +2113,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 +2146,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 +2170,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 +2194,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 +2240,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 +2284,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 +2324,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 +2386,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 +2406,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 +2441,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 +2490,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 +2529,7 @@ # # sensor/ti/tmp108 "ams_as6212": "sensor/ti/tmp108", + "ams_as6221": "sensor/ti/tmp108", "ti_tmp108": "sensor/ti/tmp108", # # sensor/ti/tmp112 @@ -1815,8 +2538,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 +2556,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 +2571,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 +2648,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 +2711,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 +2741,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 +2776,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 +2878,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 +2890,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 +2902,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 +2946,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 +3014,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_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..a9b5ecf6e1d 100644 --- a/ports/zephyr-cp/cptools/zephyr2cp.py +++ b/ports/zephyr-cp/cptools/zephyr2cp.py @@ -1,16 +1,29 @@ import logging import pathlib -import cpbuild -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 + +MINIMUM_RAM_SIZE = 1024 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 +33,10 @@ "nordic,nrf-spim", ) +BUSIO_CLASSES = {"serial": "UART", "i2c": "I2C", "spi": "SPI"} + +AUDIOBUSIO_CLASSES = {"i2s": "I2SOut"} + CONNECTORS = { "mikro-bus": [ "AN", @@ -82,6 +99,94 @@ "D12", "D13", ], + "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,25 +194,306 @@ "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 + @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"] + 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"] vendor_index = zephyr_board_dir.parent / "index.rst" if vendor_index.exists(): vendor_index = vendor_index.read_text() @@ -116,9 +502,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 +514,42 @@ 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 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 +564,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 +594,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 +625,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,6 +666,7 @@ 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: @@ -273,15 +683,21 @@ def zephyr_dts_to_cp_board(builddir, zephyrbuilddir): # noqa: C901 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 + 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"] @@ -302,7 +718,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 +734,171 @@ 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 = "" 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} """ if not header.exists() or header.read_text() != new_header_content: header.write_text(new_header_content) @@ -348,16 +908,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 +946,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 +958,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..90c1f52d4db --- /dev/null +++ b/ports/zephyr-cp/debug.conf @@ -0,0 +1,15 @@ +CONFIG_DEBUG=y +CONFIG_DEBUG_OPTIMIZATIONS=y +CONFIG_LOG_MAX_LEVEL=4 + +CONFIG_STACK_SENTINEL=y +CONFIG_DEBUG_THREAD_INFO=y +CONFIG_DEBUG_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 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..765132742bb 100644 --- a/ports/zephyr-cp/prj.conf +++ b/ports/zephyr-cp/prj.conf @@ -1,28 +1,58 @@ -CONFIG_SYS_HEAP_RUNTIME_STATS=y +CONFIG_SYS_HEAP_RUNTIME_STATS=n CONFIG_FLASH=y CONFIG_FLASH_MAP=y -CONFIG_STD_C23=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 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=n +CONFIG_USB_DEVICE_STACK_NEXT=y +CONFIG_USBD_CDC_ACM_CLASS=y +CONFIG_USBD_MSC_STACK_SIZE=1536 +CONFIG_CDC_ACM_SERIAL_INITIALIZE_AT_BOOT=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_LOG_BLOCK_IN_THREAD=y +CONFIG_ASSERT=n +CONFIG_LOG_BLOCK_IN_THREAD=n CONFIG_EVENTS=y + +CONFIG_SERIAL=y +CONFIG_UART_LINE_CTRL=y + +CONFIG_I2C=y +CONFIG_SPI=y +CONFIG_SPI_ASYNC=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_I2S=y +CONFIG_DYNAMIC_THREAD=y +CONFIG_DYNAMIC_THREAD_ALLOC=y +CONFIG_DYNAMIC_THREAD_PREFER_ALLOC=y + +CONFIG_MBEDTLS=y +CONFIG_MBEDTLS_BUILTIN=y +CONFIG_MBEDTLS_PSA_CRYPTO_C=y +CONFIG_PSA_WANT_ALG_SHA_1=y +CONFIG_PSA_WANT_ALG_SHA_256=y 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..1ecde0b0141 100644 --- a/ports/zephyr-cp/supervisor/port.c +++ b/ports/zephyr-cp/supervisor/port.c @@ -7,15 +7,41 @@ #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 "cmdline.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,10 +49,98 @@ 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_vm_runs = INT32_MAX; +static uint32_t native_sim_reset_port_count = 0; + +static struct args_struct_t native_sim_reset_port_args[] = { + { + .option = "vm-runs", + .name = "count", + .type = 'i', + .dest = &native_sim_vm_runs, + .descript = "Exit native_sim after this many VM runs. " + "Example: --vm-runs=2" + }, + ARG_TABLE_ENDMARKER +}; + +static void native_sim_register_cmdline_opts(void) { + native_add_command_line_opts(native_sim_reset_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(); +} + safe_mode_t port_init(void) { + // 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; } @@ -42,7 +156,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_vm_runs != INT32_MAX && + native_sim_vm_runs > 0 && + native_sim_reset_port_count >= (uint32_t)(native_sim_vm_runs + 1)) { + printk("posix: exiting after %d VM runs\n", native_sim_vm_runs); + posix_exit(0); + } + #endif } void reset_to_bootloader(void) { @@ -57,23 +183,27 @@ 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; + return (uint32_t *)(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. @@ -85,6 +215,10 @@ uint32_t port_get_saved_word(void) { } 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 +228,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 +257,110 @@ 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); 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 +373,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..a42a5192f4f 100644 --- a/ports/zephyr-cp/supervisor/usb.c +++ b/ports/zephyr-cp/supervisor/usb.c @@ -1,202 +1,380 @@ #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 -#endif +#include "supervisor/zephyr-cp.h" -#if CFG_TUSB_MCU == OPT_MCU_NRF5X -#include -#include -#endif +#include "extmod/vfs.h" +#include "extmod/vfs_fat.h" +#include "lib/oofatfs/diskio.h" +#include "lib/oofatfs/ff.h" #include +#include #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 -#endif +#include "shared-module/storage/__init__.h" +#include "supervisor/filesystem.h" +#include "supervisor/shared/reload.h" -#if DT_HAS_COMPAT_STATUS_OKAY(renesas_ra_usb) -#define USB_NAME usbhs -#else -#define USB_NAME zephyr_udc0 -#endif +#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); + +USBD_DESC_CONFIG_DEFINE(fs_cfg_desc, "FS Configuration"); +USBD_DESC_CONFIG_DEFINE(hs_cfg_desc, "HS Configuration"); -#define USB_DEVICE DT_NODELABEL(USB_NAME) +/* doc configuration instantiation start */ +static const uint8_t attributes = 0; -#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) +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); + + if (start_sector + num_sector > disk_block_count) { + return -EIO; + } + disk_read(root, data_buf, start_sector, num_sector); + return 0; +} - R_ICU->IELSR[UDC_IRQ] = ELC_EVENT_USBHS_USB_INT_RESUME; +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; +} + +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; +} +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) { + if (usbd_enable(ctx)) { + LOG_ERR("Failed to enable device support"); + } + } + + if (msg->type == USBD_MSG_VBUS_REMOVED) { + if (usbd_disable(ctx)) { + LOG_ERR("Failed to disable device support"); + } + } + } +} - IRQ_CONNECT(UDC_IRQ, UDC_IRQ_PRI, usb_irq_handler, 0, 0); +void usb_init(void) { + printk("Initializing USB\n"); + int err; + + 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; + } - /* 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"); + err = usbd_add_descriptor(&main_usbd, &main_mfr); + if (err) { + LOG_ERR("Failed to initialize manufacturer descriptor (%d)", err); + return; } -// #ifdef USB_DRD_FS -// // STM32U535/STM32U545 + err = usbd_add_descriptor(&main_usbd, &main_product); + if (err) { + LOG_ERR("Failed to initialize product descriptor (%d)", err); + return; + } -// /* Enable USB power on Pwrctrl CR2 register */ -// HAL_PWREx_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_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"); + } + + usbd_device_set_code_triple(&main_usbd, USBD_SPEED_HS, + USB_BCC_MISCELLANEOUS, 0x02, 0x01); + } - #if CFG_TUSB_MCU == OPT_MCU_STM32U5 && defined(USB_OTG_FS) - /* Enable USB power on Pwrctrl CR2 register */ - // HAL_PWREx_EnableVddUSB(); - LL_PWR_EnableVddUSB(); + /* 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_FS_CLK_ENABLE(); + /* doc functions register start */ - #endif + 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; + } + } -// #ifdef USB_OTG_HS -// // STM59x/Ax/Fx/Gx only have 1 USB HS port + 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; + } + } -// #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 + 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 */ -// /* USB clock enable */ -// __HAL_RCC_USB_OTG_HS_CLK_ENABLE(); -// __HAL_RCC_USBPHYC_CLK_ENABLE(); + 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); -// /* Enable USB power on Pwrctrl CR2 register */ -// HAL_PWREx_EnableVddUSB(); -// HAL_PWREx_EnableUSBHSTranceiverSupply(); + printk("Registering callback\n"); + err = usbd_msg_register_cb(&main_usbd, _msg_cb); + if (err) { + LOG_ERR("Failed to register message callback"); + return; + } -// /*Configuring the SYSCFG registers OTG_HS PHY*/ -// HAL_SYSCFG_EnableOTGPHY(SYSCFG_OTG_HS_PHY_ENABLE); + printk("usbd_init\n"); + err = usbd_init(&main_usbd); + if (err) { + LOG_ERR("Failed to initialize device support"); + return; + } -// // Disable VBUS sense (B device) -// USB_OTG_HS->GCCFG &= ~USB_OTG_GCCFG_VBDEN; + printk("USB initialized\n"); -// // 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 + if (!usbd_can_detect_vbus(&main_usbd)) { + err = usbd_enable(&main_usbd); + if (err) { + LOG_ERR("Failed to enable device support"); + return; + } + printk("usbd enabled\n"); + } +} +bool usb_connected(void) { + return false; +} - #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); - #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; - #else - usb_reg = NRF_POWER->USBREGSTATUS; - #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); - } - - 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..3c3acf0a803 100644 --- a/ports/zephyr-cp/sysbuild.cmake +++ b/ports/zephyr-cp/sysbuild.cmake @@ -18,4 +18,6 @@ if(SB_CONFIG_NET_CORE_IMAGE_HCI_IPC) 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/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..e9039dd88b3 --- /dev/null +++ b/ports/zephyr-cp/tests/__init__.py @@ -0,0 +1,162 @@ +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() + + @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._reader = threading.Thread(target=self._reader_loop, daemon=True) + self._reader.start() + + def _reader_loop(self): + while not self._stop.is_set(): + try: + read = self.serial.read(1) + 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" + ) + + 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/ports/zephyr-cp/tests/bsim/__init__.py b/ports/zephyr-cp/tests/bsim/__init__.py new file mode 100644 index 00000000000..75136bccf43 --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/__init__.py @@ -0,0 +1,3 @@ +import pytest + +pytestmark = pytest.mark.circuitpython_board("native_nrf5340bsim") diff --git a/ports/zephyr-cp/tests/bsim/conftest.py b/ports/zephyr-cp/tests/bsim/conftest.py new file mode 100644 index 00000000000..493f4c92b3b --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/conftest.py @@ -0,0 +1,227 @@ +# 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_BUILD_DIR = ZEPHYR_CP / "build-native_nrf5340bsim" +BSIM_SYSBUILD_BINARY = BSIM_BUILD_DIR / "zephyr/zephyr.exe" +BSIM_BINARY = BSIM_BUILD_DIR / "zephyr-cp/zephyr/zephyr.exe" +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 +def bsim_binary(): + """Return path to nrf5340bsim binary, skip if not built.""" + if BSIM_SYSBUILD_BINARY.exists(): + return BSIM_SYSBUILD_BINARY + if not BSIM_BINARY.exists(): + pytest.skip(f"nrf5340bsim not built: {BSIM_BINARY}") + return BSIM_BINARY + + +@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(): + 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" + + if not binary.exists(): + 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) + + +# 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/test_bsim_basics.py b/ports/zephyr-cp/tests/bsim/test_bsim_basics.py new file mode 100644 index 00000000000..477292ddd54 --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/test_bsim_basics.py @@ -0,0 +1,31 @@ +# SPDX-FileCopyrightText: 2025 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""Basic BabbleSim connectivity tests for nrf5340bsim.""" + +import pytest + +pytestmark = pytest.mark.circuitpython_board("native_nrf5340bsim") + +BSIM_CODE = """\ +print("bsim ready") +""" + + +@pytest.mark.circuitpy_drive({"code.py": BSIM_CODE}) +@pytest.mark.circuitpy_drive({"code.py": BSIM_CODE}) +@pytest.mark.duration(3) +def test_bsim_dual_instance_connect(bsim_phy, circuitpython1, circuitpython2): + """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 "Board ID:native_nrf5340bsim" in output0 + assert "Board ID:native_nrf5340bsim" in output1 + assert "bsim ready" in output0 + assert "bsim ready" in output1 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..33680fe2506 --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_advertising.py @@ -0,0 +1,174 @@ +# SPDX-FileCopyrightText: 2025 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""BLE advertising tests for nrf5340bsim.""" + +import logging +import re + +import pytest + +pytestmark = pytest.mark.circuitpython_board("native_nrf5340bsim") + +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") +""" + + +@pytest.mark.zephyr_sample("bluetooth/observer") +@pytest.mark.circuitpy_drive({"code.py": BSIM_ADV_CODE}) +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("bluetooth/observer") +@pytest.mark.code_py_runs(2) +@pytest.mark.duration(25) +@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") + circuitpython.serial.wait_for("KeyboardInterrupt") + + 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("bluetooth/observer") +@pytest.mark.circuitpy_drive({"code.py": BSIM_TX_POWER_DEFAULT_CODE}) +def test_bsim_tx_power_default_rssi(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 + 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 RSSI -39 (0 dBm TX), got {all_rssi[0]}" + + +@pytest.mark.zephyr_sample("bluetooth/observer") +@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]}" 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..21cfeaf79da --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_connect.py @@ -0,0 +1,119 @@ +# SPDX-FileCopyrightText: 2026 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""BLE central connection tests for nrf5340bsim.""" + +import pytest + +pytestmark = pytest.mark.circuitpython_board("native_nrf5340bsim") + +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.code_py_runs(2) +@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_name.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_name.py new file mode 100644 index 00000000000..69435d38256 --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_name.py @@ -0,0 +1,25 @@ +# SPDX-FileCopyrightText: 2026 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""BLE name tests for nrf5340bsim.""" + +import pytest + +pytestmark = pytest.mark.circuitpython_board("native_nrf5340bsim") + +BSIM_NAME_CODE = """\ +import _bleio + +adapter = _bleio.adapter +adapter.enabled = True +adapter.name = "CPNAME" +print("name", adapter.name) +""" + + +@pytest.mark.circuitpy_drive({"code.py": BSIM_NAME_CODE}) +def test_bsim_set_name(bsim_phy, circuitpython): + """Set the BLE name and read it back on bsim.""" + circuitpython.wait_until_done() + + assert "name CPNAME" in circuitpython.serial.all_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..7a4bbfaecd9 --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_peripheral.py @@ -0,0 +1,120 @@ +# SPDX-FileCopyrightText: 2026 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""BLE peripheral connection tests for nrf5340bsim.""" + +import pytest + +pytestmark = pytest.mark.circuitpython_board("native_nrf5340bsim") + +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}) +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(14) +@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..19455b7bfa3 --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_scan.py @@ -0,0 +1,112 @@ +# SPDX-FileCopyrightText: 2025 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""BLE scanning tests for nrf5340bsim.""" + +import pytest + +pytestmark = pytest.mark.circuitpython_board("native_nrf5340bsim") + +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) +""" + + +@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.code_py_runs(2) +@pytest.mark.duration(4) +@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.xfail(strict=False, reason="scan without stop_scan may fail on reload") +@pytest.mark.zephyr_sample("bluetooth/beacon") +@pytest.mark.code_py_runs(2) +@pytest.mark.duration(8) +@pytest.mark.circuitpy_drive({"code.py": BSIM_SCAN_RELOAD_NO_STOP_CODE}) +def test_bsim_scan_zephyr_beacon_reload_no_stop(bsim_phy, circuitpython, zephyr_sample): + """Scan for Zephyr beacon without explicit stop, 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 diff --git a/ports/zephyr-cp/tests/conftest.py b/ports/zephyr-cp/tests/conftest.py new file mode 100644 index 00000000000..03451048324 --- /dev/null +++ b/ports/zephyr-cp/tests/conftest.py @@ -0,0 +1,381 @@ +# 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", + "code_py_runs(count): stop native_sim after count code.py runs (default: 1)", + ) + 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)), + ) + + +@pytest.fixture +def board(request): + board = request.node.get_closest_marker("circuitpython_board") + if board is not None: + board = board.args[0] + else: + board = "native_native_sim" + return board + + +@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]: + return {} + + +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] + + runs_marker = request.node.get_closest_marker("code_py_runs") + if runs_marker is None: + code_py_runs = 1 + else: + code_py_runs = int(runs_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) + + for name, content in files.items(): + src = tmp_drive / name + if isinstance(content, bytes): + src.write_bytes(content) + else: + src.write_text(content) + subprocess.run(["mcopy", "-i", str(flash), str(src), f"::{name}"], check=True) + + trace_file = tmp_path / f"trace-{i}.perfetto" + + if "bsim" in board: + cmd = [str(native_sim_binary), f"--flash_app={flash}"] + if instance_count > 1: + cmd.append("-disconnect_on_exit=1") + cmd.extend( + ( + f"-s={sim_id}", + f"-d={i}", + "-uart0_pty", + "-uart0_pty_wait_for_readers", + "-uart_pty_wait", + f"--vm-runs={code_py_runs + 1}", + ) + ) + else: + cmd = [str(native_sim_binary), f"--flash={flash}"] + # native_sim vm-runs includes the boot VM setup run. + realtime_flag = "-rt" if use_realtime else "-no-rt" + cmd.extend( + ( + realtime_flag, + "-display_headless", + "-i2s_earless", + "-wait_uart", + f"--vm-runs={code_py_runs + 1}", + ) + ) + + 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..5a899139c22 --- /dev/null +++ b/ports/zephyr-cp/tests/test_audiobusio.py @@ -0,0 +1,216 @@ +# 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.code_py_runs(2) +@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 diff --git a/ports/zephyr-cp/tests/test_basics.py b/ports/zephyr-cp/tests/test_basics.py new file mode 100644 index 00000000000..84b31849a8e --- /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(circuitpython): + """Test that an erased flash shows code.py output header.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "Board ID:native_native_sim" 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.code_py_runs(2) +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..5de304afc1b --- /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.code_py_runs(2) +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_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_storage.py b/ports/zephyr-cp/tests/test_storage.py new file mode 100644 index 00000000000..33e63e5ea85 --- /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.code_py_runs(2) +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..f3fd586a375 100644 --- a/py/asmarm.h +++ b/py/asmarm.h @@ -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,28 @@ 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)) #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..1d0cea6c026 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) @@ -450,18 +452,24 @@ 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); +static const uint8_t RV32_LOAD_OPCODE_TABLE[3] = { + 0x04, 0x05, 0x02 +}; - if (scaled_offset >= 0 && RV32_IS_IN_C_REGISTER_WINDOW(rd) && RV32_IS_IN_C_REGISTER_WINDOW(rs) && FIT_UNSIGNED(scaled_offset, 6)) { +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."); + + 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_TABLE[operation_size], rd, rs, scaled_offset)); return; } @@ -469,12 +477,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_TABLE[operation_size], rd, rd, lower)); } void asm_rv32_emit_jump(asm_rv32_t *state, mp_uint_t label) { @@ -497,12 +505,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."); - if (FIT_SIGNED(scaled_offset, 12)) { - // sw rd, offset(rs) - asm_rv32_opcode_sw(state, rd, rs, scaled_offset); + 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.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 +526,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 +546,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 +557,39 @@ 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); } +static bool asm_rv32_allow_zba_opcodes(void) { + return asm_rv32_allowed_extensions() & RV32_EXT_ZBA; +} + +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, rs1, rs2, rs1)); + } else { + if (operation_size > 0) { + asm_rv32_opcode_cslli(state, rs2, operation_size); + } + asm_rv32_opcode_cadd(state, 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, rs1, 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, rs1, 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 +600,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..6f709daa11b 100644 --- a/py/asmrv32.h +++ b/py/asmrv32.h @@ -122,6 +122,18 @@ 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_ALL = RV32_EXT_ZBA +}; + +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); @@ -583,6 +595,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 +709,19 @@ 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) + +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) @@ -702,6 +745,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 +754,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 +776,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 +795,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_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..58cc7aea880 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); } @@ -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..cb786694f0b 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,44 @@ 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_index), (reg_index), 1); \ + asm_thumb_ldrh_rlo_rlo_rlo((as), (reg_dest), (reg_base), (reg_index)); \ + } while (0) +#define ASM_LOAD32_REG_REG_REG(as, reg_dest, reg_base, reg_index) \ + do { \ + asm_thumb_lsl_rlo_rlo_i5((as), (reg_index), (reg_index), 2); \ + asm_thumb_ldr_rlo_rlo_rlo((as), (reg_dest), (reg_base), (reg_index)); \ + } 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_lsl_rlo_rlo_i5((as), (reg_index), (reg_index), 1); \ + asm_thumb_strh_rlo_rlo_rlo((as), (reg_val), (reg_base), (reg_index)); \ + } while (0) +#define ASM_STORE32_REG_REG_REG(as, reg_val, reg_base, reg_index) \ + do { \ + 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)); \ + } while (0) #endif // GENERIC_ASM_API diff --git a/py/asmx64.h b/py/asmx64.h index 03070b5f63d..1e8cb0c905f 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,21 @@ 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)) #endif // GENERIC_ASM_API diff --git a/py/asmx86.h b/py/asmx86.h index 7796d697626..f5d37228a2f 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,21 @@ 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)) #endif // GENERIC_ASM_API diff --git a/py/asmxtensa.c b/py/asmxtensa.c index 0fbe351dcf3..bc3e717d9f3 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; @@ -146,22 +159,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; } - asm_xtensa_op_bccz(as, cond, reg, 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_bccz); + } + + // ~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; + } + + // 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); } - asm_xtensa_op_bcc(as, cond, reg1, reg2, rel); + + // ~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 +230,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 +293,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 { - mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("asm overflow")); + 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 { + asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRI8(2, 0x04 | operation_size, REG_TEMP, reg_src, 0)); } } @@ -264,4 +353,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..ed98c9d7305 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,51 @@ 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_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_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) #endif // GENERIC_ASM_API diff --git a/py/bc.c b/py/bc.c index c2956030e38..4caa022e3d8 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; 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..180a13beec7 100644 --- a/py/binary.c +++ b/py/binary.c @@ -71,8 +71,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 +127,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 +206,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 +287,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 +347,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 +361,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 +368,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); @@ -430,8 +420,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 +438,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 { @@ -507,14 +497,11 @@ void mp_binary_set_val_array(char typecode, void *p, size_t index, mp_obj_t val_ 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; @@ -582,18 +569,15 @@ void mp_binary_set_val_array_from_int(char typecode, void *p, size_t index, mp_i case 'f': ((float *)p)[index] = (float)val; break; - #if MICROPY_PY_DOUBLE_TYPECODE case 'd': ((double *)p)[index] = (double)val; 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 } } 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..9ab2a12d214 100644 --- a/py/builtinhelp.c +++ b/py/builtinhelp.c @@ -162,9 +162,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 17b3f11c4a0..5d77ac42859 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; @@ -270,7 +289,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 +298,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 +306,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 +389,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 +425,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 +434,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"); @@ -451,7 +472,9 @@ static mp_obj_t process_import_at_level(qstr full_mod_name, qstr level_mod_name, if (stat == MP_IMPORT_STAT_NO_EXIST) { // Not found -- fail. - #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE + // CIRCUITPY-CHANGE: always the use more verbose error message that names missing module. + // Otherwise `import a` where `a` imports `b`, but `b` is missing will give a confusing error. + #if 0 && (MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE) mp_raise_msg(&mp_type_ImportError, MP_ERROR_TEXT("module not found")); #else mp_raise_msg_varg(&mp_type_ImportError, MP_ERROR_TEXT("no module named '%q'"), full_mod_name); @@ -575,10 +598,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) { @@ -654,11 +686,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 index d6569bc39bd..4c91ed102c2 100644 --- 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,9 @@ endif ifeq ($(CIRCUITPY_AUDIOMP3),1) SRC_PATTERNS += audiomp3/% endif +ifeq ($(CIRCUITPY_AUDIOSPEED),1) +SRC_PATTERNS += audiospeed/% +endif ifeq ($(CIRCUITPY_AURORA_EPAPER),1) SRC_PATTERNS += aurora_epaper/% endif @@ -201,6 +207,9 @@ 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 @@ -255,6 +264,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 +294,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 +309,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 +366,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/% @@ -432,6 +450,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 @@ -490,6 +511,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 \ @@ -523,6 +546,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 +556,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 +571,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 \ @@ -606,6 +636,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 \ @@ -673,6 +704,9 @@ SRC_SHARED_MODULE_ALL = \ 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/PitchShift.c \ @@ -719,6 +753,9 @@ SRC_SHARED_MODULE_ALL = \ dotclockframebuffer/__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 \ @@ -946,7 +983,6 @@ SRC_SHARED_MODULE_INTERNAL = \ $(filter $(SRC_PATTERNS), \ displayio/bus_core.c \ displayio/display_core.c \ - os/getenv.c \ usb/utf16le.c \ ) @@ -992,7 +1028,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 +1039,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 3ca06f7a0fd..381cb9538e4 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. @@ -84,7 +96,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) @@ -137,6 +148,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) @@ -189,21 +201,6 @@ extern void common_hal_mcu_enable_interrupts(void); // 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 +262,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 +300,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 +316,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 @@ -345,6 +351,9 @@ typedef long mp_off_t; #endif +// For easy debugging printf's. +#define PLAT_PRINTF(...) mp_printf(&mp_plat_print, __VA_ARGS__) + #if MICROPY_PY_ASYNC_AWAIT && !CIRCUITPY_TRACEBACK #error CIRCUITPY_ASYNCIO requires CIRCUITPY_TRACEBACK #endif @@ -380,9 +389,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 @@ -453,6 +464,7 @@ void background_callback_run_all(void); #define MICROPY_VM_HOOK_LOOP RUN_BACKGROUND_TASKS; #define MICROPY_VM_HOOK_RETURN RUN_BACKGROUND_TASKS; +#define MICROPY_INTERNAL_EVENT_HOOK (RUN_BACKGROUND_TASKS) // CIRCUITPY_AUTORELOAD_DELAY_MS = 0 will completely disable autoreload. #ifndef CIRCUITPY_AUTORELOAD_DELAY_MS @@ -513,6 +525,18 @@ void background_callback_run_all(void); // USB settings +#ifndef CIRCUITPY_SDCARD_USB +#if CIRCUITPY_USB_DEVICE +#define CIRCUITPY_SDCARD_USB (CIRCUITPY_SDCARDIO && CIRCUITPY_USB_MSC) +#else +#define CIRCUITPY_SDCARD_USB (0) +#endif +#endif + +#if CIRCUITPY_SDCARD_USB && !(CIRCUITPY_SDCARDIO) +#error CIRCUITPY_SDCARD_USB requires CIRCUITPY_SDCARDIO +#endif + // Debug level for TinyUSB. Only outputs over debug UART so it doesn't cause // additional USB logging. #ifndef CIRCUITPY_DEBUG_TINYUSB @@ -523,10 +547,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 @@ -626,7 +658,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 index 2009c4e177d..4f5a4bbd64d 100644 --- 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 @@ -98,6 +107,11 @@ CFLAGS += -DCIRCUITPY_ALARM=$(CIRCUITPY_ALARM) CIRCUITPY_ALARM_TOUCH ?= $(CIRCUITPY_ALARM) CFLAGS += -DCIRCUITPY_ALARM_TOUCH=$(CIRCUITPY_ALARM_TOUCH) +# Enable DMA buffer management for platforms where not all memory is DMA-capable +# Platforms with PSRAM or other non-DMA memory should set this to 0 +CIRCUITPY_ALL_MEMORY_DMA_CAPABLE ?= 1 +CFLAGS += -DCIRCUITPY_ALL_MEMORY_DMA_CAPABLE=$(CIRCUITPY_ALL_MEMORY_DMA_CAPABLE) + CIRCUITPY_ANALOGBUFIO ?= 0 CFLAGS += -DCIRCUITPY_ANALOGBUFIO=$(CIRCUITPY_ANALOGBUFIO) @@ -121,6 +135,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) @@ -141,6 +159,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) @@ -227,6 +248,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) @@ -242,6 +269,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) @@ -275,9 +306,6 @@ CFLAGS += -DCIRCUITPY_DUALBANK=$(CIRCUITPY_DUALBANK) 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) @@ -329,9 +357,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) @@ -391,6 +425,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) @@ -509,6 +546,9 @@ CFLAGS += -DCIRCUITPY_SERIAL_BLE=$(CIRCUITPY_SERIAL_BLE) 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) @@ -634,6 +674,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) @@ -677,6 +720,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) diff --git a/py/compile.c b/py/compile.c index c7dd2fd4761..c8704131234 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, }; @@ -3295,7 +3296,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; } @@ -3587,6 +3590,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 +3629,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 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..ab155a13875 100644 --- a/py/dynruntime.h +++ b/py/dynruntime.h @@ -70,7 +70,7 @@ #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) { +static MP_NORETURN inline void m_malloc_fail_dyn(size_t num_bytes) { mp_fun_table.raise_msg( 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..030728cfc9a 100644 --- a/py/dynruntime.mk +++ b/py/dynruntime.mk @@ -63,14 +63,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) @@ -124,6 +124,10 @@ else $(error architecture '$(ARCH)' not supported) endif +ifneq ($(findstring -musl,$(shell $(CROSS)gcc -dumpmachine)),) +USE_MUSL := 1 +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) @@ -147,6 +151,8 @@ ifeq ($(LINK_RUNTIME),1) # distribution. ifeq ($(USE_PICOLIBC),1) LIBM_NAME := libc.a +else ifeq ($(USE_MUSL),1) +LIBM_NAME := libc.a else LIBM_NAME := libm.a endif @@ -166,6 +172,9 @@ endif endif MPY_LD_FLAGS += $(addprefix -l, $(LIBGCC_PATH) $(LIBM_PATH)) endif +ifneq ($(MPY_EXTERN_SYM_FILE),) +MPY_LD_FLAGS += --externs "$(realpath $(MPY_EXTERN_SYM_FILE))" +endif CFLAGS += $(CFLAGS_EXTRA) 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..c6ad3e3bc38 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" @@ -133,6 +134,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 (MICROPY_EMIT_RV32 || MICROPY_EMIT_INLINE_RV32) && defined(MP_HAL_CLEAN_DCACHE) + // Flush the D-cache. + MP_HAL_CLEAN_DCACHE(fun_data, fun_len); #endif rc->kind = kind; diff --git a/py/emitinlinerv32.c b/py/emitinlinerv32.c index a539242b84d..e81b152087d 100644 --- a/py/emitinlinerv32.c +++ b/py/emitinlinerv32.c @@ -196,7 +196,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 +209,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 +223,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 +232,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 +296,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 +390,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 +437,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 +468,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 +488,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,7 +501,7 @@ 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; } @@ -516,7 +520,7 @@ static bool validate_argument(emit_inline_asm_t *emit, qstr opcode_qstr, goto zero_immediate; } - return true; + serialised_value = immediate; } break; @@ -524,7 +528,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 +538,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 +552,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,186 +602,97 @@ 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); + case CALL_RII: + ((call_rii_t)opcode_data->emitter)(&emit->as, arguments[0], arguments[1], arguments[2]); 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); - 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)) { - 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_uint_t rd = 0; - mp_uint_t rs1 = 0; - if (!parse_register_node(nodes[0], &rd, opcode_data->argument1_kind & C)) { - return false; - } - if (!parse_register_node(nodes[1], &rs1, opcode_data->argument3_kind & C)) { - 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; - } - 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)); - return false; - } - - ((call_rri_t)opcode_data->emitter)(&emit->as, rd, rs1, immediate); - return true; -} - static void emit_inline_rv32_opcode(emit_inline_asm_t *emit, qstr opcode, mp_uint_t arguments_count, mp_parse_node_t *argument_nodes) { const opcode_t *opcode_data = NULL; for (mp_uint_t index = 0; index < MP_ARRAY_SIZE(OPCODES); index++) { @@ -785,10 +702,9 @@ 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 (!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 +712,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 7818bb4f46d..d6596337ae5 100644 --- a/py/emitinlinethumb.c +++ b/py/emitinlinethumb.c @@ -150,27 +150,27 @@ typedef struct _reg_name_t { byte reg; byte name[3]; } reg_name_t; static const reg_name_t reg_name_table[] = { - {0, "r0\0"}, - {1, "r1\0"}, - {2, "r2\0"}, - {3, "r3\0"}, - {4, "r4\0"}, - {5, "r5\0"}, - {6, "r6\0"}, - {7, "r7\0"}, - {8, "r8\0"}, - {9, "r9\0"}, - {10, "r10"}, - {11, "r11"}, - {12, "r12"}, - {13, "r13"}, - {14, "r14"}, - {15, "r15"}, - {10, "sl\0"}, - {11, "fp\0"}, - {13, "sp\0"}, - {14, "lr\0"}, - {15, "pc\0"}, + {0, {'r', '0' }}, + {1, {'r', '1' }}, + {2, {'r', '2' }}, + {3, {'r', '3' }}, + {4, {'r', '4' }}, + {5, {'r', '5' }}, + {6, {'r', '6' }}, + {7, {'r', '7' }}, + {8, {'r', '8' }}, + {9, {'r', '9' }}, + {10, {'r', '1', '0' }}, + {11, {'r', '1', '1' }}, + {12, {'r', '1', '2' }}, + {13, {'r', '1', '3' }}, + {14, {'r', '1', '4' }}, + {15, {'r', '1', '5' }}, + {10, {'s', 'l' }}, + {11, {'f', 'p' }}, + {13, {'s', 'p' }}, + {14, {'l', 'r' }}, + {15, {'p', 'c' }}, }; #define MAX_SPECIAL_REGISTER_NAME_LENGTH 7 @@ -368,20 +368,20 @@ 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, "eq" }, - { ASM_THUMB_CC_NE, "ne" }, - { ASM_THUMB_CC_CS, "cs" }, - { ASM_THUMB_CC_CC, "cc" }, - { ASM_THUMB_CC_MI, "mi" }, - { ASM_THUMB_CC_PL, "pl" }, - { ASM_THUMB_CC_VS, "vs" }, - { ASM_THUMB_CC_VC, "vc" }, - { ASM_THUMB_CC_HI, "hi" }, - { ASM_THUMB_CC_LS, "ls" }, - { ASM_THUMB_CC_GE, "ge" }, - { ASM_THUMB_CC_LT, "lt" }, - { ASM_THUMB_CC_GT, "gt" }, - { ASM_THUMB_CC_LE, "le" }, + { 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' }}, }; typedef struct _format_4_op_t { byte op; @@ -389,21 +389,21 @@ typedef struct _format_4_op_t { byte op; } format_4_op_t; #define X(x) (((x) >> 4) & 0xff) // only need 1 byte to distinguish these ops static const format_4_op_t format_4_op_table[] = { - { X(ASM_THUMB_FORMAT_4_EOR), "eor" }, - { X(ASM_THUMB_FORMAT_4_LSL), "lsl" }, - { X(ASM_THUMB_FORMAT_4_LSR), "lsr" }, - { X(ASM_THUMB_FORMAT_4_ASR), "asr" }, - { X(ASM_THUMB_FORMAT_4_ADC), "adc" }, - { X(ASM_THUMB_FORMAT_4_SBC), "sbc" }, - { X(ASM_THUMB_FORMAT_4_ROR), "ror" }, - { X(ASM_THUMB_FORMAT_4_TST), "tst" }, - { X(ASM_THUMB_FORMAT_4_NEG), "neg" }, - { X(ASM_THUMB_FORMAT_4_CMP), "cmp" }, - { X(ASM_THUMB_FORMAT_4_CMN), "cmn" }, - { X(ASM_THUMB_FORMAT_4_ORR), "orr" }, - { X(ASM_THUMB_FORMAT_4_MUL), "mul" }, - { X(ASM_THUMB_FORMAT_4_BIC), "bic" }, - { X(ASM_THUMB_FORMAT_4_MVN), "mvn" }, + { X(ASM_THUMB_FORMAT_4_EOR), {'e', 'o', 'r' }}, + { X(ASM_THUMB_FORMAT_4_LSL), {'l', 's', 'l' }}, + { X(ASM_THUMB_FORMAT_4_LSR), {'l', 's', 'r' }}, + { X(ASM_THUMB_FORMAT_4_ASR), {'a', 's', 'r' }}, + { X(ASM_THUMB_FORMAT_4_ADC), {'a', 'd', 'c' }}, + { X(ASM_THUMB_FORMAT_4_SBC), {'s', 'b', 'c' }}, + { X(ASM_THUMB_FORMAT_4_ROR), {'r', 'o', 'r' }}, + { X(ASM_THUMB_FORMAT_4_TST), {'t', 's', 't' }}, + { X(ASM_THUMB_FORMAT_4_NEG), {'n', 'e', 'g' }}, + { X(ASM_THUMB_FORMAT_4_CMP), {'c', 'm', 'p' }}, + { X(ASM_THUMB_FORMAT_4_CMN), {'c', 'm', 'n' }}, + { X(ASM_THUMB_FORMAT_4_ORR), {'o', 'r', 'r' }}, + { X(ASM_THUMB_FORMAT_4_MUL), {'m', 'u', 'l' }}, + { X(ASM_THUMB_FORMAT_4_BIC), {'b', 'i', 'c' }}, + { X(ASM_THUMB_FORMAT_4_MVN), {'m', 'v', 'n' }}, }; #undef X @@ -428,10 +428,10 @@ typedef struct _format_vfp_op_t { char name[3]; } format_vfp_op_t; static const format_vfp_op_t format_vfp_op_table[] = { - { 0x30, "add" }, - { 0x34, "sub" }, - { 0x20, "mul" }, - { 0x80, "div" }, + { 0x30, {'a', 'd', 'd' }}, + { 0x34, {'s', 'u', 'b' }}, + { 0x20, {'m', 'u', 'l' }}, + { 0x80, {'d', 'i', 'v' }}, }; // shorthand alias for whether we allow ARMv7-M instructions diff --git a/py/emitinlinextensa.c b/py/emitinlinextensa.c index fed259cfc6b..d0eb3d566fc 100644 --- a/py/emitinlinextensa.c +++ b/py/emitinlinextensa.c @@ -173,7 +173,7 @@ static int get_arg_label(emit_inline_asm_t *emit, const char *op, mp_parse_node_ #define RRI8_B (2) typedef struct _opcode_table_3arg_t { - uint16_t name; // actually a qstr, which should fit in 16 bits + qstr_short_t name; uint8_t type; uint8_t a0 : 4; uint8_t a1 : 4; @@ -187,6 +187,13 @@ static const opcode_table_3arg_t opcode_table_3arg[] = { {MP_QSTR_add, RRR, 0, 8}, {MP_QSTR_sub, RRR, 0, 12}, {MP_QSTR_mull, RRR, 2, 8}, + {MP_QSTR_addx2, RRR, 0, 9}, + {MP_QSTR_addx4, RRR, 0, 10}, + {MP_QSTR_addx8, RRR, 0, 11}, + {MP_QSTR_subx2, RRR, 0, 13}, + {MP_QSTR_subx4, RRR, 0, 14}, + {MP_QSTR_subx8, RRR, 0, 15}, + {MP_QSTR_src, RRR, 1, 8}, // load/store/addi opcodes: reg, reg, imm // upper nibble of type encodes the range of the immediate arg @@ -208,21 +215,62 @@ static const opcode_table_3arg_t opcode_table_3arg[] = { {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_bltu, RRI8_B, ASM_XTENSA_CC_LTU, 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}, }; +// 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 +}; + +#if MICROPY_EMIT_INLINE_XTENSA_UNCOMMON_OPCODES +typedef struct _single_opcode_t { + qstr_short_t name; + uint16_t value; +} single_opcode_t; + +static const single_opcode_t NOARGS_OPCODES[] = { + {MP_QSTR_dsync, 0x2030}, + {MP_QSTR_esync, 0x2020}, + {MP_QSTR_extw, 0x20D0}, + {MP_QSTR_ill, 0x0000}, + {MP_QSTR_isync, 0x2000}, + {MP_QSTR_memw, 0x20C0}, + {MP_QSTR_rsync, 0x2010}, +}; +#endif + 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) { + if (op == MP_QSTR_ret_n || op == MP_QSTR_ret) { asm_xtensa_op_ret_n(&emit->as); - } else { - goto unknown_op; + return; + } else if (op == MP_QSTR_nop) { + asm_xtensa_op24(&emit->as, 0x20F0); + return; + } else if (op == MP_QSTR_nop_n) { + asm_xtensa_op16(&emit->as, 0xF03D); + return; } + #if MICROPY_EMIT_INLINE_XTENSA_UNCOMMON_OPCODES + for (size_t index = 0; index < MP_ARRAY_SIZE(NOARGS_OPCODES); index++) { + const single_opcode_t *opcode = &NOARGS_OPCODES[index]; + if (op == opcode->name) { + asm_xtensa_op24(&emit->as, opcode->value); + return; + } + } + #endif + + goto unknown_op; } else if (n_args == 1) { if (op == MP_QSTR_callx0) { @@ -234,19 +282,45 @@ static void emit_inline_xtensa_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_ } 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_ssl) { + mp_uint_t r0 = get_arg_reg(emit, op_str, pn_args[0]); + asm_xtensa_op_ssl(&emit->as, r0); + } else if (op == MP_QSTR_ssr) { + mp_uint_t r0 = get_arg_reg(emit, op_str, pn_args[0]); + asm_xtensa_op_ssr(&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_ssa8b) { + mp_uint_t r0 = get_arg_reg(emit, op_str, pn_args[0]); + asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, 0, 4, 3, r0, 0)); + } else if (op == MP_QSTR_ssa8l) { + mp_uint_t r0 = get_arg_reg(emit, op_str, pn_args[0]); + asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, 0, 4, 2, r0, 0)); + } 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)); + } else if (op == MP_QSTR_ill_n) { + asm_xtensa_op16(&emit->as, 0xF06D); + #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) { + 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_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); @@ -254,7 +328,53 @@ static void emit_inline_xtensa_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_ // 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_abs_) { + mp_uint_t r1 = get_arg_reg(emit, op_str, pn_args[1]); + asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, 0, 6, r0, 1, r1)); + } else if (op == MP_QSTR_neg) { + mp_uint_t r1 = get_arg_reg(emit, op_str, pn_args[1]); + asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, 0, 6, r0, 0, r1)); + } else if (op == MP_QSTR_sll) { + mp_uint_t r1 = get_arg_reg(emit, op_str, pn_args[1]); + asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, 1, 10, r0, r1, 0)); + } else if (op == MP_QSTR_sra) { + mp_uint_t r1 = get_arg_reg(emit, op_str, pn_args[1]); + asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, 1, 11, r0, 0, r1)); + } else if (op == MP_QSTR_srl) { + mp_uint_t r1 = get_arg_reg(emit, op_str, pn_args[1]); + asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, 1, 9, r0, 0, r1)); + } else if (op == MP_QSTR_nsa) { + mp_uint_t r1 = get_arg_reg(emit, op_str, pn_args[1]); + asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, 0, 4, 14, r1, r0)); + } else if (op == MP_QSTR_nsau) { + mp_uint_t r1 = get_arg_reg(emit, op_str, pn_args[1]); + asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, 0, 4, 15, r1, r0)); + } 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; } @@ -288,7 +408,72 @@ static void emit_inline_xtensa_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_ return; } } - goto unknown_op; + + if (op == MP_QSTR_add_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 r2 = get_arg_reg(emit, op_str, pn_args[2]); + asm_xtensa_op16(&emit->as, ASM_XTENSA_ENCODE_RRRN(10, r0, r1, r2)); + } else 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..6f12200f7e1 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, @@ -335,12 +329,27 @@ struct _emit_t { #define ASM_CLR_REG(state, rd) ASM_XOR_REG_REG(state, rd, rd) #endif +#if N_RV32 +#define ASM_MOV_LOCAL_MP_OBJ_NULL(as, local_num, reg_temp) \ + ASM_MOV_LOCAL_REG(as, local_num, REG_ZERO) +#else +#define ASM_MOV_LOCAL_MP_OBJ_NULL(as, local_num, reg_temp) \ + ASM_MOV_REG_IMM(as, reg_temp, (mp_uint_t)MP_OBJ_NULL); \ + 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); static void emit_native_global_exc_entry(emit_t *emit); 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 +476,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 +546,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 +617,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 +649,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 +715,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) { @@ -1311,8 +1348,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 +1615,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 +1679,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 +1851,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 +1922,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: @@ -2328,8 +2264,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 +2371,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); } @@ -3122,8 +3056,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..e49c5cdbffa 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) { @@ -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) \ 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 338803dc245..757c27e3de6 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 @@ -158,6 +170,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); @@ -284,6 +322,7 @@ void gc_init(void *start, void *end) { #endif GC_MUTEX_INIT(); + gc_perfetto_emit_heap_stats(); } #if MICROPY_GC_SPLIT_HEAP @@ -311,8 +350,9 @@ void gc_add(void *start, void *end) { #if MICROPY_GC_SPLIT_HEAP_AUTO // CIRCUITPY-CHANGE: Added function to compute heap size with selective collect table static size_t compute_heap_size(size_t total_blocks) { - // Add two blocks to account for allocation alignment. - total_blocks += 2; + // Round up to the nearest multiple of BLOCKS_PER_ATB. Partial ATB blocks aren't supported and + // will result in a heap that is too small. + total_blocks = ((total_blocks + BLOCKS_PER_ATB - 1) / BLOCKS_PER_ATB) * BLOCKS_PER_ATB; size_t atb_bytes = (total_blocks + BLOCKS_PER_ATB - 1) / BLOCKS_PER_ATB; size_t ftb_bytes = 0; size_t ctb_bytes = 0; @@ -326,12 +366,13 @@ static size_t compute_heap_size(size_t total_blocks) { // Compute bytes needed to build a heap with total_blocks blocks. size_t total_heap = - atb_bytes + sizeof(mp_state_mem_area_t) + + atb_bytes + + ALLOC_TABLE_GAP_BYTE + ftb_bytes + ctb_bytes + pool_bytes - + ALLOC_TABLE_GAP_BYTE - + sizeof(mp_state_mem_area_t); + + BYTES_PER_BLOCK; // Extra block of bytes to account for end pointer alignment // Round up size to the nearest multiple of BYTES_PER_BLOCK. total_heap = (total_heap + BYTES_PER_BLOCK - 1) / BYTES_PER_BLOCK; @@ -423,6 +464,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))); } @@ -444,7 +486,7 @@ bool gc_is_locked(void) { } // CIRCUITPY-CHANGE: additional function -bool gc_ptr_on_heap(void *ptr) { +bool gc_ptr_on_heap(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 @@ -652,6 +694,7 @@ void gc_collect_end(void) { } MP_STATE_THREAD(gc_lock_depth) &= ~GC_COLLECT_FLAG; GC_EXIT(); + gc_perfetto_emit_heap_stats(); } static void gc_deal_with_stack_overflow(void) { @@ -1067,6 +1110,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; } @@ -1148,6 +1193,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); @@ -1288,6 +1334,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; } @@ -1325,6 +1373,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; } @@ -1397,7 +1447,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 @@ -1440,7 +1490,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 ebc32b080fb..f9028d637c5 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 @@ -87,7 +92,7 @@ void *gc_realloc(void *ptr, size_t n_bytes, bool allow_move); // CIRCUITPY-CHANGE // True if the pointer is on the MP heap. Doesn't require that it is the start // of a block. -bool gc_ptr_on_heap(void *ptr); +bool gc_ptr_on_heap(const void *ptr); typedef struct _gc_info_t { size_t total; 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..8c07899baf8 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 @@ -139,6 +137,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 +291,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 +306,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..c3c3442e311 100644 --- a/py/maketranslationdata.py +++ b/py/maketranslationdata.py @@ -527,11 +527,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..fc9795043a8 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 { @@ -237,6 +275,7 @@ typedef struct _m_tracked_node_t { #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 +288,7 @@ static size_t m_tracked_count_links(size_t *nb) { #endif node = node->next; } + m_tracked_node_unlock(); return n; } #endif @@ -263,12 +303,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 @@ -294,7 +336,8 @@ void m_tracked_free(void *ptr_in) { 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 +346,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/misc.h b/py/misc.h index eb7fc54be6f..d5d7950574f 100644 --- a/py/misc.h +++ b/py/misc.h @@ -26,6 +26,8 @@ #ifndef MICROPY_INCLUDED_PY_MISC_H #define MICROPY_INCLUDED_PY_MISC_H +#include "py/mpconfig.h" + // a mini library of useful types and functions /** types *******************************************************/ @@ -33,13 +35,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,7 +68,15 @@ 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 +#define MP_STATIC_ASSERT(cond) _Static_assert((cond), #cond) +#else #define MP_STATIC_ASSERT(cond) ((void)sizeof(char[1 - 2 * !(cond)])) +#endif + // In C++ things like comparing extern const pointers are not constant-expressions so cannot be used // in MP_STATIC_ASSERT. Note that not all possible compiler versions will reject this. Some gcc versions // do, others only with -Werror=vla, msvc always does. @@ -63,7 +85,11 @@ typedef unsigned int uint; #if defined(_MSC_VER) || defined(__cplusplus) #define MP_STATIC_ASSERT_NONCONSTEXPR(cond) ((void)1) #else -#define MP_STATIC_ASSERT_NONCONSTEXPR(cond) MP_STATIC_ASSERT(cond) +// CIRCUITPY-CHANGE: defined() +#if defined(__clang__) +#pragma GCC diagnostic ignored "-Wgnu-folding-constant" +#endif +#define MP_STATIC_ASSERT_NONCONSTEXPR(cond) ((void)sizeof(char[1 - 2 * !(cond)])) #endif // Round-up integer division @@ -88,9 +114,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)))) @@ -116,9 +142,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); @@ -128,7 +158,7 @@ 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 @@ -151,7 +181,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 *********************************************/ @@ -298,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 *************/ @@ -403,26 +452,28 @@ static inline bool mp_check(bool 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) { @@ -438,16 +489,107 @@ 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) - // 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); +#if MICROPY_USE_GCC_MUL_OVERFLOW_INTRINSIC + +#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 #endif // MICROPY_INCLUDED_PY_MISC_H diff --git a/py/mkrules.cmake b/py/mkrules.cmake index 4374b8b4da3..e3d769cc59b 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,11 +219,41 @@ 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} ) diff --git a/py/mkrules.mk b/py/mkrules.mk index f364297f0f2..03988996c71 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'" @@ -112,6 +113,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 +188,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 $@ @@ -260,7 +269,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/modio.c b/py/modio.c index d3e563dbcf4..9aeb42d30aa 100644 --- a/py/modio.c +++ b/py/modio.c @@ -169,12 +169,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..67bb32626c3 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(); 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/mpconfig.h b/py/mpconfig.h index a4895820061..0e440066d78 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 27 #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 */ @@ -418,6 +502,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 +517,9 @@ #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 enable the RISC-V RV32 inline assembler @@ -438,6 +527,11 @@ #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) @@ -497,6 +591,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 +828,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 +1004,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 +1057,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 +1126,16 @@ typedef double mp_float_t; #define MICROPY_STREAMS_POSIX_API (0) #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 @@ -1030,6 +1223,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) @@ -1065,6 +1268,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) @@ -1105,7 +1313,15 @@ typedef double mp_float_t; #define MICROPY_PY_FUNCTION_ATTRS_CODE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_FULL_FEATURES) #endif -// Whether to support the descriptors __get__, __set__, __delete__ +// 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__, __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 @@ -1362,11 +1578,6 @@ 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) -#endif - // Whether to provide mem-info related functions in micropython module #ifndef MICROPY_PY_MICROPYTHON_MEM_INFO #define MICROPY_PY_MICROPYTHON_MEM_INFO (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) @@ -1482,6 +1693,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 +1730,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 +1748,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() @@ -1800,11 +2013,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 +2025,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 @@ -1935,6 +2148,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 +2245,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))). @@ -2166,25 +2384,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 +2411,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)) @@ -2279,4 +2491,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..7934e843f06 100644 --- a/py/mpstate.h +++ b/py/mpstate.h @@ -71,6 +71,12 @@ 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; @@ -369,4 +375,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..74fd1754636 100644 --- a/py/mpz.c +++ b/py/mpz.c @@ -1541,7 +1541,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 +1557,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 +1583,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; } @@ -1646,7 +1649,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 +1680,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 +1727,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.h b/py/nativeglue.h index 00ed9f3f4fc..01825ac60ed 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); 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..446e78c7ebb 100644 --- a/py/nlr.h +++ b/py/nlr.h @@ -233,18 +233,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/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..cf140400e68 100644 --- a/py/nlrpowerpc.c +++ b/py/nlrpowerpc.c @@ -78,7 +78,7 @@ unsigned int nlr_push(nlr_buf_t *nlr) { return 0; } -NORETURN void nlr_jump(void *val) { +MP_NORETURN void nlr_jump(void *val) { MP_NLR_JUMP_HEAD(val, top) __asm__ volatile ( @@ -167,7 +167,7 @@ unsigned int nlr_push(nlr_buf_t *nlr) { return 0; } -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/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..26bf0dc6ccb 100644 --- a/py/nlrx86.c +++ b/py/nlrx86.c @@ -78,7 +78,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/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..ba3e6a9a996 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_impl((mp_obj_t)arg, MP_ENDIANNESS_BIG, sizeof(res), (byte *)&res); + 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..eb7143bd43f 100644 --- a/py/obj.h +++ b/py/obj.h @@ -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, @@ -827,7 +851,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 @@ -847,7 +871,7 @@ 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 +933,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 +941,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 +951,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 +1016,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 @@ -1032,7 +1057,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,10 +1077,10 @@ 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_BUILTINS_FLOAT @@ -1092,7 +1116,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 +1124,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 +1138,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 +1189,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); @@ -1240,7 +1266,7 @@ 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 +// CIRCUITPY-CHANGE: public routine 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); @@ -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..1e259a20ac8 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 @@ -298,7 +300,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 +495,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 +569,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 +671,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 +807,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 +846,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/objdeque.c b/py/objdeque.c index 264c795801b..4e1ee82e9d4 100644 --- a/py/objdeque.c +++ b/py/objdeque.c @@ -46,6 +46,11 @@ static mp_obj_t mp_obj_deque_extend(mp_obj_t self_in, mp_obj_t arg_in); static mp_obj_t mp_obj_new_deque_it(mp_obj_t deque, mp_obj_iter_buf_t *iter_buf); #endif +// CIRCUITPY-CHANGE +static mp_obj_deque_t *native_deque(mp_obj_t self_in) { + return MP_OBJ_TO_PTR(mp_obj_cast_to_native_base(self_in, MP_OBJ_FROM_PTR(&mp_type_deque))); +} + static mp_obj_t deque_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { mp_arg_check_num(n_args, n_kw, 2, 3, false); @@ -79,7 +84,8 @@ static size_t deque_len(mp_obj_deque_t *self) { } static mp_obj_t deque_unary_op(mp_unary_op_t op, mp_obj_t self_in) { - mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in); + // CIRCUITPY-CHANGE + mp_obj_deque_t *self = native_deque(self_in); switch (op) { case MP_UNARY_OP_BOOL: return mp_obj_new_bool(self->i_get != self->i_put); @@ -98,7 +104,8 @@ static mp_obj_t deque_unary_op(mp_unary_op_t op, mp_obj_t self_in) { } static mp_obj_t mp_obj_deque_append(mp_obj_t self_in, mp_obj_t arg) { - mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in); + // CIRCUITPY-CHANGE + mp_obj_deque_t *self = native_deque(self_in); size_t new_i_put = self->i_put + 1; if (new_i_put == self->alloc) { @@ -123,7 +130,8 @@ static mp_obj_t mp_obj_deque_append(mp_obj_t self_in, mp_obj_t arg) { static MP_DEFINE_CONST_FUN_OBJ_2(deque_append_obj, mp_obj_deque_append); static mp_obj_t mp_obj_deque_appendleft(mp_obj_t self_in, mp_obj_t arg) { - mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in); + // CIRCUITPY-CHANGE + mp_obj_deque_t *self = native_deque(self_in); size_t new_i_get = self->i_get - 1; if (self->i_get == 0) { @@ -162,7 +170,8 @@ static mp_obj_t mp_obj_deque_extend(mp_obj_t self_in, mp_obj_t arg_in) { static MP_DEFINE_CONST_FUN_OBJ_2(deque_extend_obj, mp_obj_deque_extend); static mp_obj_t deque_popleft(mp_obj_t self_in) { - mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in); + // CIRCUITPY-CHANGE + mp_obj_deque_t *self = native_deque(self_in); if (self->i_get == self->i_put) { mp_raise_msg(&mp_type_IndexError, MP_ERROR_TEXT("empty")); @@ -180,7 +189,8 @@ static mp_obj_t deque_popleft(mp_obj_t self_in) { static MP_DEFINE_CONST_FUN_OBJ_1(deque_popleft_obj, deque_popleft); static mp_obj_t deque_pop(mp_obj_t self_in) { - mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in); + // CIRCUITPY-CHANGE + mp_obj_deque_t *self = native_deque(self_in); if (self->i_get == self->i_put) { mp_raise_msg(&mp_type_IndexError, MP_ERROR_TEXT("empty")); @@ -205,7 +215,8 @@ static mp_obj_t deque_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { // delete not supported, fall back to mp_obj_subscr() error message return MP_OBJ_NULL; } - mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in); + // CIRCUITPY-CHANGE + mp_obj_deque_t *self = native_deque(self_in); size_t offset = mp_get_index(self->base.type, deque_len(self), index, false); size_t index_val = self->i_get + offset; @@ -226,7 +237,8 @@ static mp_obj_t deque_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { #if 0 static mp_obj_t deque_clear(mp_obj_t self_in) { - mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in); + // CIRCUITPY-CHANGE + mp_obj_deque_t *self = native_deque(self_in); self->i_get = self->i_put = 0; mp_seq_clear(self->items, 0, self->alloc, sizeof(*self->items)); return mp_const_none; @@ -286,7 +298,8 @@ typedef struct _mp_obj_deque_it_t { static mp_obj_t deque_it_iternext(mp_obj_t self_in) { mp_obj_deque_it_t *self = MP_OBJ_TO_PTR(self_in); - mp_obj_deque_t *deque = MP_OBJ_TO_PTR(self->deque); + // CIRCUITPY-CHANGE + mp_obj_deque_t *deque = native_deque(self->deque); if (self->cur != deque->i_put) { mp_obj_t o_out = deque->items[self->cur]; if (++self->cur == deque->alloc) { @@ -298,9 +311,10 @@ static mp_obj_t deque_it_iternext(mp_obj_t self_in) { } } -static mp_obj_t mp_obj_new_deque_it(mp_obj_t deque, mp_obj_iter_buf_t *iter_buf) { - mp_obj_deque_t *deque_ = MP_OBJ_TO_PTR(deque); - size_t i_get = deque_->i_get; +static mp_obj_t mp_obj_new_deque_it(mp_obj_t deque_in, mp_obj_iter_buf_t *iter_buf) { + // CIRCUITPY-CHANGE + mp_obj_deque_t *deque = native_deque(deque_in); + size_t i_get = deque->i_get; assert(sizeof(mp_obj_deque_it_t) <= sizeof(mp_obj_iter_buf_t)); mp_obj_deque_it_t *o = (mp_obj_deque_it_t *)iter_buf; o->base.type = &mp_type_polymorph_iter; 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/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..34565cf6336 100644 --- a/py/objfun.c +++ b/py/objfun.c @@ -184,7 +184,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_get_name(o_in), o); } #endif diff --git a/py/objint.c b/py/objint.c index b12f09c9d38..cabbd7b8f0e 100644 --- a/py/objint.c +++ b/py/objint.c @@ -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; @@ -211,7 +217,7 @@ static const uint8_t log_base2_floor[] = { 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; } diff --git a/py/objint_longlong.c b/py/objint_longlong.c index 0fad693c7ad..f24aa0cc186 100644 --- a/py/objint_longlong.c +++ b/py/objint_longlong.c @@ -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)); @@ -132,7 +136,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 +162,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 +176,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 +236,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 >= (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 +262,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 +291,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 +320,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 +336,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 diff --git a/py/objint_mpz.c b/py/objint_mpz.c index 111f53009fb..1bede811a4a 100644 --- a/py/objint_mpz.c +++ b/py/objint_mpz.c @@ -364,9 +364,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 +390,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 diff --git a/py/objlist.c b/py/objlist.c index 3137e9fa534..a29fc51b104 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; } 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..221392ccce4 100644 --- a/py/objmodule.h +++ b/py/objmodule.h @@ -32,10 +32,16 @@ // 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); 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..bd650bbe18a 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); @@ -372,8 +373,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; @@ -1018,7 +1018,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 @@ -1205,7 +1205,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 +1250,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 == '.') { @@ -1324,7 +1325,7 @@ static vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar } 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; @@ -2395,7 +2396,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/objtuple.c b/py/objtuple.c index 42e8d56a806..b2ccbbb2990 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 */ @@ -250,6 +247,9 @@ MP_DEFINE_CONST_OBJ_TYPE( // the zero-length tuple const mp_obj_tuple_t mp_const_empty_tuple_obj = {{&mp_type_tuple}, 0}; +// CIRCUITPY-CHANGE: No change here, but implementation was copied for +// mp_obj_new_port_tuple in supervisor/shared/port.c, which allocates using port_malloc(). +// Change that to match if this changes. mp_obj_t mp_obj_new_tuple(size_t n, const mp_obj_t *items) { if (n == 0) { return mp_const_empty_tuple; diff --git a/py/objtuple.h b/py/objtuple.h index e2d010e6c5a..783522a6222 100644 --- a/py/objtuple.h +++ b/py/objtuple.h @@ -57,7 +57,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) } \ } @@ -68,4 +68,7 @@ void mp_obj_attrtuple_print_helper(const mp_print_t *print, const qstr *fields, mp_obj_t mp_obj_new_attrtuple(const qstr *fields, size_t n, const mp_obj_t *items); +// 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) + #endif // MICROPY_INCLUDED_PY_OBJTUPLE_H diff --git a/py/objtype.c b/py/objtype.c index 074d6f39293..b1a984b50e0 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); @@ -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); } diff --git a/py/parse.c b/py/parse.c index a393b0ee8c1..36150ef468b 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) { @@ -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 @@ -860,7 +883,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 +894,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 1976729f4d8..5c3de3174bc 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_MACHINE_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; @@ -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); } @@ -471,13 +477,16 @@ void mp_raw_code_load(mp_reader_t *reader, mp_compiled_module_t *cm) { read_bytes(reader, header, sizeof(header)); byte arch = MPY_FEATURE_DECODE_ARCH(header[2]); // CIRCUITPY-CHANGE: 'C', not 'M' + if (header[0] == 'M') { + mp_raise_ValueError(MP_ERROR_TEXT("MicroPython .mpy file; use CircuitPython mpy-cross")); + } if (header[0] != 'C' || header[1] != MPY_VERSION || (arch != MP_NATIVE_ARCH_NONE && MPY_FEATURE_DECODE_SUB_VERSION(header[2]) != MPY_SUB_VERSION) || 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 @@ -489,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); @@ -510,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. @@ -679,7 +706,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 @@ -688,6 +715,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); @@ -766,7 +797,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) { @@ -777,7 +808,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 { diff --git a/py/persistentcode.h b/py/persistentcode.h index 46b474e57f7..85668e608c8 100644 --- a/py/persistentcode.h +++ b/py/persistentcode.h @@ -50,7 +50,7 @@ // 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 @@ -90,6 +90,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 +107,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 }; diff --git a/py/profile.c b/py/profile.c index 397d0291f9f..b5a0c54728c 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) ); } diff --git a/py/py.cmake b/py/py.cmake index 6c180ae53e6..b99d2d24b5d 100644 --- a/py/py.cmake +++ b/py/py.cmake @@ -58,6 +58,7 @@ set(MICROPY_SOURCE_PY ${MICROPY_PY_DIR}/mpz.c ${MICROPY_PY_DIR}/nativeglue.c ${MICROPY_PY_DIR}/nlr.c + ${MICROPY_PY_DIR}/nlraarch64.c ${MICROPY_PY_DIR}/nlrmips.c ${MICROPY_PY_DIR}/nlrpowerpc.c ${MICROPY_PY_DIR}/nlrrv32.c diff --git a/py/py.mk b/py/py.mk index c05327bf81d..21be07c794f 100644 --- a/py/py.mk +++ b/py/py.mk @@ -191,6 +191,7 @@ PY_CORE_O_BASENAME = $(addprefix py/,\ objnamedtuple.o \ objrange.o \ objreversed.o \ + objringio.o \ objset.o \ objsingleton.o \ objslice.o \ @@ -289,7 +290,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/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..81abc3de875 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -134,7 +134,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_MACHINE_CODE && (MICROPY_PERSISTENT_CODE_TRACK_FUN_DATA || MICROPY_PERSISTENT_CODE_TRACK_BSS_RODATA) MP_STATE_VM(persistent_code_root_pointers) = MP_OBJ_NULL; #endif @@ -446,7 +446,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 +505,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 +554,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 +962,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 +1287,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'"), @@ -1619,7 +1618,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 +1638,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 +1681,36 @@ 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; + + #if MICROPY_MODULE___ALL__ + mp_map_elem_t *elem = mp_map_lookup(map, MP_OBJ_NEW_QSTR(MP_QSTR___all__), MP_MAP_LOOKUP); + if (elem != 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(elem->value, &len, &items); + for (size_t i = 0; i < len; i++) { + qstr qname = mp_obj_str_get_qstr(items[i]); + mp_obj_t dest[2]; + mp_load_method(module, qname, dest); + mp_store_name(qname, dest[0]); + } + return; + } + #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 ('_') 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 +1766,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 +1780,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 +1811,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 +1837,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 +1855,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 +1873,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 +1881,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 +1894,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 +1908,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 +1916,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 +1940,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 +1948,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 +1960,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 +1971,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 +1986,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..22ed9c3eaf9 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,12 @@ typedef enum { MP_ARG_KW_ONLY = 0x200, } mp_arg_flag_t; +typedef enum { + MP_HANDLE_PENDING_CALLBACKS_ONLY, + MP_HANDLE_PENDING_CALLBACKS_AND_EXCEPTIONS, + MP_HANDLE_PENDING_CALLBACKS_AND_CLEAR_EXCEPTIONS, +} mp_handle_pending_behaviour_t; + typedef union _mp_arg_val_t { bool u_bool; mp_int_t u_int; @@ -106,7 +113,14 @@ 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_internal(mp_handle_pending_behaviour_t behavior); + +static inline void mp_handle_pending(bool raise_exc) { + mp_handle_pending_internal(raise_exc ? + MP_HANDLE_PENDING_CALLBACKS_AND_EXCEPTIONS : + MP_HANDLE_PENDING_CALLBACKS_AND_CLEAR_EXCEPTIONS); +} #if MICROPY_ENABLE_SCHEDULER void mp_sched_lock(void); @@ -134,7 +148,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 +156,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 +208,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 +295,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 +306,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 5984346a6f6..ee9cd96b331 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_internal(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); } @@ -277,10 +284,6 @@ void mp_event_wait_indefinite(void) { MICROPY_EVENT_POLL_HOOK #else mp_event_handle_nowait(); - - // CIRCUITPY-CHANGE: don't starve CircuitPython background tasks - RUN_BACKGROUND_TASKS; - MICROPY_INTERNAL_WFE(-1); #endif } @@ -293,10 +296,6 @@ void mp_event_wait_ms(mp_uint_t timeout_ms) { MICROPY_EVENT_POLL_HOOK #else mp_event_handle_nowait(); - - // CIRCUITPY-CHANGE: don't starve CircuitPython background tasks - RUN_BACKGROUND_TASKS; - MICROPY_INTERNAL_WFE(timeout_ms); #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..792fccd0133 100644 --- a/py/showbc.c +++ b/py/showbc.c @@ -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); } } 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..520422cc92f 100644 --- a/py/stream.c +++ b/py/stream.c @@ -260,9 +260,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 +280,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); diff --git a/py/stream.h b/py/stream.h index 5e1cd5d4413..6e60e849b5f 100644 --- a/py/stream.h +++ b/py/stream.h @@ -87,10 +87,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/vm.c b/py/vm.c index 6fd17782619..860aa36e397 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 diff --git a/py/vstr.c b/py/vstr.c index 00972edf897..522509d0d05 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); } diff --git a/pyproject.toml b/pyproject.toml index 0db7eb70a78..5f84ca104ac 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,35 +1,26 @@ -# 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(*) +# 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,9 +31,32 @@ extend-exclude = [ ] # Exclude third-party code, and exclude the following tests: # basics: needs careful attention before applying automatic formatting -format.exclude = [ "tests/basics/*.py" ] +# repl_: not real python files +# viper_args: uses f(*) +format.exclude = [ + "tests/*/repl_*.py", + "tests/basics/*.py", + "tests/cmdline/cmd_compile_only_error.py", + "tests/micropython/test_normalize_newlines.py", + "tests/micropython/viper_args.py", +] lint.extend-select = [ "C9", "PLC" ] -lint.ignore = [ +lint.exclude = [ + # Ruff finds Python SyntaxError in these files + "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_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/micropython/viper_args.py", +] +lint.extend-ignore = [ "E401", "E402", "E722", @@ -51,11 +65,27 @@ lint.ignore = [ "F401", "F403", "F405", - "PLC1901", + "PLC0206", + "PLC0415", # conditional imports are common in MicroPython ] # 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/stm\ + 32/usbhost,./tests,ACKNOWLEDGEMENTS,\ + """ diff --git a/requirements-dev.txt b/requirements-dev.txt index 261a5cc2c7f..6a33c49daec 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -4,7 +4,7 @@ jinja2 typer sh -click +click<8.2.0 cpp-coveralls requests @@ -40,3 +40,6 @@ setuptools # For zephyr port tomlkit +pytest +pytest-rerunfailures +perfetto diff --git a/shared-bindings/_bleio/Adapter.c b/shared-bindings/_bleio/Adapter.c index 92b910c8b2e..a1f81a063fd 100644 --- a/shared-bindings/_bleio/Adapter.c +++ b/shared-bindings/_bleio/Adapter.c @@ -215,7 +215,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 +223,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 +306,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 +317,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 +329,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")); } @@ -339,12 +339,14 @@ static mp_obj_t bleio_adapter_start_scan(size_t n_args, const mp_obj_t *pos_args if (args[ARG_prefixes].u_obj != MP_OBJ_NULL) { mp_get_buffer_raise(args[ARG_prefixes].u_obj, &prefix_bufinfo, MP_BUFFER_READ); // An empty buffer may not be on the heap, but that doesn't matter. - if (prefix_bufinfo.len > 0 && gc_nbytes(prefix_bufinfo.buf) == 0) { + if (prefix_bufinfo.len > 0 && !gc_ptr_on_heap(prefix_bufinfo.buf)) { mp_raise_ValueError(MP_ERROR_TEXT("Prefix buffer must be on the heap")); } } - 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 +418,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/Address.c b/shared-bindings/_bleio/Address.c index 58f8a8adc1e..10500bec9cb 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); 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/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/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..1ec9fd96e76 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); diff --git a/shared-bindings/_bleio/__init__.h b/shared-bindings/_bleio/__init__.h index faf11ea1d06..0c5a5fec06b 100644 --- a/shared-bindings/_bleio/__init__.h +++ b/shared-bindings/_bleio/__init__.h @@ -45,19 +45,11 @@ 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..75f2850a7ef 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,10 @@ static mp_obj_t aesio_aes_make_new(const mp_obj_type_t *type, size_t n_args, iv = bufinfo.buf; } + 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, args[ARG_counter].u_int); + 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..d229246e781 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. diff --git a/shared-bindings/alarm/__init__.h b/shared-bindings/alarm/__init__.h index af92b381137..37bfd9c51b7 100644 --- a/shared-bindings/alarm/__init__.h +++ b/shared-bindings/alarm/__init__.h @@ -24,7 +24,7 @@ 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); // 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..a3df6ddf7fd 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} }, @@ -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..2c42ee1f325 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); diff --git a/shared-bindings/audiobusio/I2SOut.c b/shared-bindings/audiobusio/I2SOut.c index 9aaf7421c65..952a00e2903 100644 --- a/shared-bindings/audiobusio/I2SOut.c +++ b/shared-bindings/audiobusio/I2SOut.c @@ -144,6 +144,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/PDMIn.c b/shared-bindings/audiobusio/PDMIn.c index 2a3fd3540c3..aba8a019f35 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,9 +96,6 @@ 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) { @@ -115,6 +112,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 +153,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 +174,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..c93bedd4213 100644 --- a/shared-bindings/audiocore/WaveFile.c +++ b/shared-bindings/audiocore/WaveFile.c @@ -60,7 +60,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")); } @@ -72,6 +71,8 @@ static mp_obj_t audioio_wavefile_make_new(const mp_obj_type_t *type, size_t n_ar buffer = bufinfo.buf; buffer_size = mp_arg_validate_length_range(bufinfo.len, 8, 1024, MP_QSTR_buffer); } + + 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/audiodelays/Chorus.c b/shared-bindings/audiodelays/Chorus.c index c6bfa2ffa7e..87922ff110b 100644 --- a/shared-bindings/audiodelays/Chorus.c +++ b/shared-bindings/audiodelays/Chorus.c @@ -206,11 +206,15 @@ MP_DEFINE_CONST_FUN_OBJ_1(audiodelays_chorus_get_playing_obj, audiodelays_chorus MP_PROPERTY_GETTER(audiodelays_chorus_playing_obj, (mp_obj_t)&audiodelays_chorus_get_playing_obj); -//| def play(self, sample: circuitpython_typing.AudioSample, *, loop: bool = False) -> None: +//| def play(self, sample: circuitpython_typing.AudioSample, *, loop: bool = False) -> Chorus: //| """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.""" +//| 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: Chorus""" //| ... //| static mp_obj_t audiodelays_chorus_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { @@ -228,7 +232,7 @@ static mp_obj_t audiodelays_chorus_obj_play(size_t n_args, const mp_obj_t *pos_a mp_obj_t sample = args[ARG_sample].u_obj; common_hal_audiodelays_chorus_play(self, sample, args[ARG_loop].u_bool); - return mp_const_none; + return MP_OBJ_FROM_PTR(self); } MP_DEFINE_CONST_FUN_OBJ_KW(audiodelays_chorus_play_obj, 1, audiodelays_chorus_obj_play); 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 5ae849b19aa..dbb496c61b9 100644 --- a/shared-bindings/audiodelays/Echo.c +++ b/shared-bindings/audiodelays/Echo.c @@ -230,11 +230,15 @@ MP_DEFINE_CONST_FUN_OBJ_1(audiodelays_echo_get_playing_obj, audiodelays_echo_obj MP_PROPERTY_GETTER(audiodelays_echo_playing_obj, (mp_obj_t)&audiodelays_echo_get_playing_obj); -//| def play(self, sample: circuitpython_typing.AudioSample, *, loop: bool = False) -> None: +//| def play(self, sample: circuitpython_typing.AudioSample, *, loop: bool = False) -> Echo: //| """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.""" +//| 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: Echo""" //| ... //| static mp_obj_t audiodelays_echo_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { @@ -252,7 +256,7 @@ static mp_obj_t audiodelays_echo_obj_play(size_t n_args, const mp_obj_t *pos_arg mp_obj_t sample = args[ARG_sample].u_obj; common_hal_audiodelays_echo_play(self, sample, args[ARG_loop].u_bool); - return mp_const_none; + return MP_OBJ_FROM_PTR(self); } MP_DEFINE_CONST_FUN_OBJ_KW(audiodelays_echo_play_obj, 1, audiodelays_echo_obj_play); diff --git a/shared-bindings/audiodelays/MultiTapDelay.c b/shared-bindings/audiodelays/MultiTapDelay.c index 5b057eaf80d..2126dbf9904 100644 --- a/shared-bindings/audiodelays/MultiTapDelay.c +++ b/shared-bindings/audiodelays/MultiTapDelay.c @@ -233,11 +233,15 @@ MP_DEFINE_CONST_FUN_OBJ_1(audiodelays_multi_tap_delay_get_playing_obj, audiodela MP_PROPERTY_GETTER(audiodelays_multi_tap_delay_playing_obj, (mp_obj_t)&audiodelays_multi_tap_delay_get_playing_obj); -//| def play(self, sample: circuitpython_typing.AudioSample, *, loop: bool = False) -> None: +//| def play(self, sample: circuitpython_typing.AudioSample, *, loop: bool = False) -> MultiTapDelay: //| """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.""" +//| 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: MultiTapDelay""" //| ... //| static mp_obj_t audiodelays_multi_tap_delay_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { @@ -255,7 +259,7 @@ static mp_obj_t audiodelays_multi_tap_delay_obj_play(size_t n_args, const mp_obj mp_obj_t sample = args[ARG_sample].u_obj; common_hal_audiodelays_multi_tap_delay_play(self, sample, args[ARG_loop].u_bool); - return mp_const_none; + return MP_OBJ_FROM_PTR(self); } MP_DEFINE_CONST_FUN_OBJ_KW(audiodelays_multi_tap_delay_play_obj, 1, audiodelays_multi_tap_delay_obj_play); diff --git a/shared-bindings/audiodelays/PitchShift.c b/shared-bindings/audiodelays/PitchShift.c index df2189945aa..ee3bf5afdd7 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); } @@ -190,11 +200,15 @@ MP_PROPERTY_GETTER(audiodelays_pitch_shift_playing_obj, (mp_obj_t)&audiodelays_pitch_shift_get_playing_obj); -//| def play(self, sample: circuitpython_typing.AudioSample, *, loop: bool = False) -> None: +//| def play(self, sample: circuitpython_typing.AudioSample, *, loop: bool = False) -> PitchShift: //| """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.""" +//| 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: PitchShift""" //| ... //| static mp_obj_t audiodelays_pitch_shift_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { @@ -211,7 +225,7 @@ static mp_obj_t audiodelays_pitch_shift_obj_play(size_t n_args, const mp_obj_t * mp_obj_t sample = args[ARG_sample].u_obj; common_hal_audiodelays_pitch_shift_play(self, sample, args[ARG_loop].u_bool); - return mp_const_none; + return MP_OBJ_FROM_PTR(self); } MP_DEFINE_CONST_FUN_OBJ_KW(audiodelays_pitch_shift_play_obj, 1, audiodelays_pitch_shift_obj_play); diff --git a/shared-bindings/audiofilters/Distortion.c b/shared-bindings/audiofilters/Distortion.c index cb888d0c71b..bed28f5ed49 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_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); } @@ -309,11 +322,15 @@ MP_DEFINE_CONST_FUN_OBJ_1(audiofilters_distortion_get_playing_obj, audiofilters_ MP_PROPERTY_GETTER(audiofilters_distortion_playing_obj, (mp_obj_t)&audiofilters_distortion_get_playing_obj); -//| def play(self, sample: circuitpython_typing.AudioSample, *, loop: bool = False) -> None: +//| def play(self, sample: circuitpython_typing.AudioSample, *, loop: bool = False) -> Distortion: //| """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.""" +//| 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: Distortion""" //| ... //| static mp_obj_t audiofilters_distortion_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { @@ -331,7 +348,7 @@ static mp_obj_t audiofilters_distortion_obj_play(size_t n_args, const mp_obj_t * mp_obj_t sample = args[ARG_sample].u_obj; common_hal_audiofilters_distortion_play(self, sample, args[ARG_loop].u_bool); - return mp_const_none; + return MP_OBJ_FROM_PTR(self); } MP_DEFINE_CONST_FUN_OBJ_KW(audiofilters_distortion_play_obj, 1, audiofilters_distortion_obj_play); diff --git a/shared-bindings/audiofilters/Filter.c b/shared-bindings/audiofilters/Filter.c index 2a4887a4d42..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); } @@ -179,11 +186,15 @@ MP_DEFINE_CONST_FUN_OBJ_1(audiofilters_filter_get_playing_obj, audiofilters_filt MP_PROPERTY_GETTER(audiofilters_filter_playing_obj, (mp_obj_t)&audiofilters_filter_get_playing_obj); -//| def play(self, sample: circuitpython_typing.AudioSample, *, loop: bool = False) -> None: +//| def play(self, sample: circuitpython_typing.AudioSample, *, loop: bool = False) -> Filter: //| """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.""" +//| 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: Filter""" //| ... //| static mp_obj_t audiofilters_filter_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { @@ -201,7 +212,7 @@ static mp_obj_t audiofilters_filter_obj_play(size_t n_args, const mp_obj_t *pos_ mp_obj_t sample = args[ARG_sample].u_obj; common_hal_audiofilters_filter_play(self, sample, args[ARG_loop].u_bool); - return mp_const_none; + return MP_OBJ_FROM_PTR(self); } MP_DEFINE_CONST_FUN_OBJ_KW(audiofilters_filter_play_obj, 1, audiofilters_filter_obj_play); diff --git a/shared-bindings/audiofilters/Phaser.c b/shared-bindings/audiofilters/Phaser.c index e7ddd986176..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); } @@ -214,11 +223,15 @@ MP_DEFINE_CONST_FUN_OBJ_1(audiofilters_phaser_get_playing_obj, audiofilters_phas MP_PROPERTY_GETTER(audiofilters_phaser_playing_obj, (mp_obj_t)&audiofilters_phaser_get_playing_obj); -//| def play(self, sample: circuitpython_typing.AudioSample, *, loop: bool = False) -> None: +//| def play(self, sample: circuitpython_typing.AudioSample, *, loop: bool = False) -> Phaser: //| """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.""" +//| 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: Phaser""" //| ... //| static mp_obj_t audiofilters_phaser_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { @@ -236,7 +249,7 @@ static mp_obj_t audiofilters_phaser_obj_play(size_t n_args, const mp_obj_t *pos_ mp_obj_t sample = args[ARG_sample].u_obj; common_hal_audiofilters_phaser_play(self, sample, args[ARG_loop].u_bool); - return mp_const_none; + return MP_OBJ_FROM_PTR(self); } MP_DEFINE_CONST_FUN_OBJ_KW(audiofilters_phaser_play_obj, 1, audiofilters_phaser_obj_play); diff --git a/shared-bindings/audiofreeverb/Freeverb.c b/shared-bindings/audiofreeverb/Freeverb.c index 62c9237a0d2..12eb7ef70ab 100644 --- a/shared-bindings/audiofreeverb/Freeverb.c +++ b/shared-bindings/audiofreeverb/Freeverb.c @@ -196,11 +196,15 @@ MP_DEFINE_CONST_FUN_OBJ_1(audiofreeverb_freeverb_get_playing_obj, audiofreeverb_ MP_PROPERTY_GETTER(audiofreeverb_freeverb_playing_obj, (mp_obj_t)&audiofreeverb_freeverb_get_playing_obj); -//| def play(self, sample: circuitpython_typing.AudioSample, *, loop: bool = False) -> None: +//| def play(self, sample: circuitpython_typing.AudioSample, *, loop: bool = False) -> Freeverb: //| """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.""" +//| 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: Freeverb""" //| ... //| static mp_obj_t audiofreeverb_freeverb_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { @@ -218,7 +222,7 @@ static mp_obj_t audiofreeverb_freeverb_obj_play(size_t n_args, const mp_obj_t *p mp_obj_t sample = args[ARG_sample].u_obj; common_hal_audiofreeverb_freeverb_play(self, sample, args[ARG_loop].u_bool); - return mp_const_none; + return MP_OBJ_FROM_PTR(self); } MP_DEFINE_CONST_FUN_OBJ_KW(audiofreeverb_freeverb_play_obj, 1, audiofreeverb_freeverb_obj_play); diff --git a/shared-bindings/audiofreeverb/Freeverb.h b/shared-bindings/audiofreeverb/Freeverb.h index 913953ebecf..bde6cfffda7 100644 --- a/shared-bindings/audiofreeverb/Freeverb.h +++ b/shared-bindings/audiofreeverb/Freeverb.h @@ -18,10 +18,6 @@ void common_hal_audiofreeverb_freeverb_construct(audiofreeverb_freeverb_obj_t *s 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); diff --git a/shared-bindings/audioi2sin/I2SIn.c b/shared-bindings/audioi2sin/I2SIn.c new file mode 100644 index 00000000000..056aa859abe --- /dev/null +++ b/shared-bindings/audioi2sin/I2SIn.c @@ -0,0 +1,314 @@ +// 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, +//| ) -> 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). +//| +//| 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 }; + 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_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); + 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); + + 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); + +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) }, +}; +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..c0fc48a6d09 --- /dev/null +++ b/shared-bindings/audioi2sin/I2SIn.h @@ -0,0 +1,42 @@ +// 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); +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); + +// 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 dda6d06bd50..516d079cd2a 100644 --- a/shared-bindings/audiomixer/Mixer.c +++ b/shared-bindings/audiomixer/Mixer.c @@ -160,13 +160,17 @@ MP_PROPERTY_GETTER(audiomixer_mixer_voice_obj, //| def play( //| self, sample: circuitpython_typing.AudioSample, *, voice: int = 0, loop: bool = False -//| ) -> None: +//| ) -> Mixer: //| """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 must match the Mixer's encoding settings given in the constructor.""" +//| The sample must match the Mixer's encoding settings given in the constructor. +//| +//| :return: The mixer object itself. Can be used for chaining, ie: +//| ``audio.play(mixer.play(sample))``. +//| :rtype: Chorus""" //| ... //| static mp_obj_t audiomixer_mixer_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { @@ -189,7 +193,7 @@ static mp_obj_t audiomixer_mixer_obj_play(size_t n_args, const mp_obj_t *pos_arg mp_obj_t sample = args[ARG_sample].u_obj; common_hal_audiomixer_mixervoice_play(voice, sample, args[ARG_loop].u_bool); - return mp_const_none; + return MP_OBJ_FROM_PTR(self); } MP_DEFINE_CONST_FUN_OBJ_KW(audiomixer_mixer_play_obj, 1, audiomixer_mixer_obj_play); diff --git a/shared-bindings/audiomixer/MixerVoice.c b/shared-bindings/audiomixer/MixerVoice.c index fc292d4ea2f..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); @@ -114,6 +114,31 @@ MP_PROPERTY_GETSET(audiomixer_mixervoice_level_obj, (mp_obj_t)&audiomixer_mixervoice_get_level_obj, (mp_obj_t)&audiomixer_mixervoice_set_level_obj); +//| panning: synthio.BlockInput +//| """Defines the channel(s) in which the voice appears, as a floating point number between +//| -1 and 1. If your board does not support synthio, this property will only accept a float +//| value. This property is ignored if ``audiomixer.Mixer.channel_count=1``. +//| +//| -1 is left channel only, 0 is both channels, and 1 is right channel. For fractional values, +//| the note plays at full amplitude in one channel and partial amplitude in the other channel. +//| For instance -.5 plays at full amplitude in the left channel and 1/2 amplitude in the right +//| channel.""" +static mp_obj_t audiomixer_mixervoice_obj_get_panning(mp_obj_t self_in) { + return common_hal_audiomixer_mixervoice_get_panning(self_in); +} +MP_DEFINE_CONST_FUN_OBJ_1(audiomixer_mixervoice_get_panning_obj, audiomixer_mixervoice_obj_get_panning); + +static mp_obj_t audiomixer_mixervoice_obj_set_panning(mp_obj_t self_in, mp_obj_t panning_in) { + audiomixer_mixervoice_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_audiomixer_mixervoice_set_panning(self, panning_in); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(audiomixer_mixervoice_set_panning_obj, audiomixer_mixervoice_obj_set_panning); + +MP_PROPERTY_GETSET(audiomixer_mixervoice_panning_obj, + (mp_obj_t)&audiomixer_mixervoice_get_panning_obj, + (mp_obj_t)&audiomixer_mixervoice_set_panning_obj); + //| loop: bool //| """Get or set the loop status of the currently playing sample.""" static mp_obj_t audiomixer_mixervoice_obj_get_loop(mp_obj_t self_in) { @@ -158,6 +183,7 @@ static const mp_rom_map_elem_t audiomixer_mixervoice_locals_dict_table[] = { // Properties { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&audiomixer_mixervoice_playing_obj) }, { MP_ROM_QSTR(MP_QSTR_level), MP_ROM_PTR(&audiomixer_mixervoice_level_obj) }, + { MP_ROM_QSTR(MP_QSTR_panning), MP_ROM_PTR(&audiomixer_mixervoice_panning_obj) }, { MP_ROM_QSTR(MP_QSTR_loop), MP_ROM_PTR(&audiomixer_mixervoice_loop_obj) }, }; static MP_DEFINE_CONST_DICT(audiomixer_mixervoice_locals_dict, audiomixer_mixervoice_locals_dict_table); diff --git a/shared-bindings/audiomixer/MixerVoice.h b/shared-bindings/audiomixer/MixerVoice.h index fe350eb1a75..d60820f7f57 100644 --- a/shared-bindings/audiomixer/MixerVoice.h +++ b/shared-bindings/audiomixer/MixerVoice.h @@ -18,6 +18,8 @@ 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); void common_hal_audiomixer_mixervoice_set_level(audiomixer_mixervoice_obj_t *self, mp_obj_t gain); +mp_obj_t common_hal_audiomixer_mixervoice_get_panning(audiomixer_mixervoice_obj_t *self); +void common_hal_audiomixer_mixervoice_set_panning(audiomixer_mixervoice_obj_t *self, mp_obj_t value); bool common_hal_audiomixer_mixervoice_get_playing(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/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/ports/zephyr-cp/bindings/zephyr_serial/__init__.h b/shared-bindings/audiospeed/__init__.h similarity index 67% rename from ports/zephyr-cp/bindings/zephyr_serial/__init__.h rename to shared-bindings/audiospeed/__init__.h index 370e233985f..c4a52e5819d 100644 --- a/ports/zephyr-cp/bindings/zephyr_serial/__init__.h +++ b/shared-bindings/audiospeed/__init__.h @@ -1,6 +1,6 @@ // This file is part of the CircuitPython project: https://circuitpython.org // -// SPDX-FileCopyrightText: Copyright (c) 2016 Scott Shawcroft +// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt // // SPDX-License-Identifier: MIT 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..e1413392699 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,10 @@ 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); - 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, args[ARG_frequency].u_int, 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..de021867f3c 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: 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/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..5fa62f9df38 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; @@ -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..962080648ce 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")); } @@ -466,6 +466,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 +494,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 5f1d301b675..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; @@ -368,14 +368,14 @@ static mp_obj_t busio_uart_obj_reset_input_buffer(mp_obj_t self_in) { return mp_const_none; } static MP_DEFINE_CONST_FUN_OBJ_1(busio_uart_reset_input_buffer_obj, busio_uart_obj_reset_input_buffer); -//| class Parity: -//| """Enum-like class to define the parity used to verify correct data transfer.""" +//| class Parity: +//| """Enum-like class to define the parity used to verify correct data transfer.""" //| -//| ODD: int -//| """Total number of ones should be odd.""" +//| ODD: int +//| """Total number of ones should be odd.""" //| -//| EVEN: int -//| """Total number of ones should be even.""" +//| EVEN: int +//| """Total number of ones should be even.""" //| //| const mp_obj_type_t busio_uart_parity_type; 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..58f90b0b141 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); @@ -190,9 +191,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 +255,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); @@ -341,12 +342,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 eddf3f66c4e..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 @@ -49,7 +49,7 @@ void displayio_tilegrid_validate_pixel_shader(mp_obj_t pixel_shader) { //| self, //| bitmap: Union[Bitmap, OnDiskBitmap], //| *, -//| pixel_shader: Union[ColorConverter, Palette], +//| pixel_shader: Union[ColorConverter, Palette, tilepalettemapper.TilePaletteMapper], //| width: int = 1, //| height: int = 1, //| tile_width: Optional[int] = None, @@ -68,7 +68,7 @@ void displayio_tilegrid_validate_pixel_shader(mp_obj_t pixel_shader) { //| tile_width and tile_height match the height of the bitmap by default. //| //| :param Bitmap,OnDiskBitmap bitmap: The bitmap storing one or more tiles. -//| :param ColorConverter,Palette pixel_shader: The pixel shader that produces colors from values +//| :param ColorConverter,Palette,tilepalettemapper.TilePaletteMapper pixel_shader: The pixel shader that produces colors from values //| :param int width: Width of the grid in tiles. //| :param int height: Height of the grid in tiles. //| :param int tile_width: Width of a single tile in pixels. Defaults to the full Bitmap and must evenly divide into the Bitmap's dimensions. @@ -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); } @@ -330,7 +331,7 @@ static mp_obj_t displayio_tilegrid_obj_contains(mp_obj_t self_in, mp_obj_t touch } MP_DEFINE_CONST_FUN_OBJ_2(displayio_tilegrid_contains_obj, displayio_tilegrid_obj_contains); -//| pixel_shader: Union[ColorConverter, Palette] +//| pixel_shader: Union[ColorConverter, Palette, tilepalettemapper.TilePaletteMapper] //| """The pixel shader of the tilegrid.""" static mp_obj_t displayio_tilegrid_obj_get_pixel_shader(mp_obj_t self_in) { displayio_tilegrid_t *self = native_tilegrid(self_in); 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/__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/epaperdisplay/EPaperDisplay.c b/shared-bindings/epaperdisplay/EPaperDisplay.c index 5d72df815d0..cd9c18e27d5 100644 --- a/shared-bindings/epaperdisplay/EPaperDisplay.c +++ b/shared-bindings/epaperdisplay/EPaperDisplay.c @@ -54,6 +54,7 @@ //| write_color_ram_command: Optional[int] = None, //| color_bits_inverted: bool = False, //| highlight_color: int = 0x000000, +//| highlight_color2: int = 0x000000, //| refresh_display_command: Union[int, circuitpython_typing.ReadableBuffer], //| refresh_time: float = 40, //| busy_pin: Optional[microcontroller.Pin] = None, @@ -97,6 +98,7 @@ //| :param int write_color_ram_command: Command used to write pixels values into the update region //| :param bool color_bits_inverted: True if 0 bits are used to show the color. Otherwise, 1 means to show color. //| :param int highlight_color: RGB888 of source color to highlight with third ePaper color. +//| :param int highlight_color2: RGB888 of source color to highlight with fourth ePaper color. //| :param int refresh_display_command: Command used to start a display refresh. Single int or byte-packed command sequence //| :param float refresh_time: Time it takes to refresh the display before the stop_sequence should be sent. Ignored when busy_pin is provided. //| :param microcontroller.Pin busy_pin: Pin used to signify the display is busy @@ -117,7 +119,7 @@ static mp_obj_t epaperdisplay_epaperdisplay_make_new(const mp_obj_type_t *type, ARG_ram_width, ARG_ram_height, ARG_colstart, ARG_rowstart, ARG_rotation, ARG_set_column_window_command, ARG_set_row_window_command, ARG_set_current_column_command, ARG_set_current_row_command, ARG_write_black_ram_command, ARG_black_bits_inverted, - ARG_write_color_ram_command, ARG_color_bits_inverted, ARG_highlight_color, + ARG_write_color_ram_command, ARG_color_bits_inverted, ARG_highlight_color, ARG_highlight_color2, ARG_refresh_display_command, ARG_refresh_time, ARG_busy_pin, ARG_busy_state, ARG_seconds_per_frame, ARG_always_toggle_chip_select, ARG_grayscale, ARG_advanced_color_epaper, ARG_spectra6, ARG_two_byte_sequence_length, ARG_start_up_time, ARG_address_little_endian }; @@ -141,6 +143,7 @@ static mp_obj_t epaperdisplay_epaperdisplay_make_new(const mp_obj_type_t *type, { MP_QSTR_write_color_ram_command, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} }, { MP_QSTR_color_bits_inverted, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, { MP_QSTR_highlight_color, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x000000} }, + { MP_QSTR_highlight_color2, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x000000} }, { MP_QSTR_refresh_display_command, MP_ARG_OBJ | MP_ARG_REQUIRED }, { MP_QSTR_refresh_time, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NEW_SMALL_INT(40)} }, { MP_QSTR_busy_pin, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} }, @@ -181,6 +184,7 @@ static mp_obj_t epaperdisplay_epaperdisplay_make_new(const mp_obj_type_t *type, mp_int_t write_color_ram_command = NO_COMMAND; mp_int_t highlight_color = args[ARG_highlight_color].u_int; + mp_int_t highlight_color2 = args[ARG_highlight_color2].u_int; if (args[ARG_write_color_ram_command].u_obj != mp_const_none) { write_color_ram_command = mp_obj_get_int(args[ARG_write_color_ram_command].u_obj); } @@ -207,20 +211,43 @@ static mp_obj_t epaperdisplay_epaperdisplay_make_new(const mp_obj_type_t *type, } self->base.type = &epaperdisplay_epaperdisplay_type; - common_hal_epaperdisplay_epaperdisplay_construct( - self, - display_bus, - start_bufinfo.buf, start_bufinfo.len, start_up_time, stop_bufinfo.buf, stop_bufinfo.len, - args[ARG_width].u_int, args[ARG_height].u_int, args[ARG_ram_width].u_int, args[ARG_ram_height].u_int, - args[ARG_colstart].u_int, args[ARG_rowstart].u_int, rotation, - args[ARG_set_column_window_command].u_int, args[ARG_set_row_window_command].u_int, - args[ARG_set_current_column_command].u_int, args[ARG_set_current_row_command].u_int, - args[ARG_write_black_ram_command].u_int, args[ARG_black_bits_inverted].u_bool, write_color_ram_command, - args[ARG_color_bits_inverted].u_bool, highlight_color, refresh_buf, refresh_buf_len, refresh_time, - busy_pin, args[ARG_busy_state].u_bool, seconds_per_frame, - args[ARG_always_toggle_chip_select].u_bool, args[ARG_grayscale].u_bool, args[ARG_advanced_color_epaper].u_bool, args[ARG_spectra6].u_bool, - two_byte_sequence_length, args[ARG_address_little_endian].u_bool - ); + epaperdisplay_construct_args_t construct_args = EPAPERDISPLAY_CONSTRUCT_ARGS_DEFAULTS; + construct_args.bus = display_bus; + construct_args.start_sequence = start_bufinfo.buf; + construct_args.start_sequence_len = start_bufinfo.len; + construct_args.start_up_time = start_up_time; + construct_args.stop_sequence = stop_bufinfo.buf; + construct_args.stop_sequence_len = stop_bufinfo.len; + construct_args.width = args[ARG_width].u_int; + construct_args.height = args[ARG_height].u_int; + construct_args.ram_width = args[ARG_ram_width].u_int; + construct_args.ram_height = args[ARG_ram_height].u_int; + construct_args.colstart = args[ARG_colstart].u_int; + construct_args.rowstart = args[ARG_rowstart].u_int; + construct_args.rotation = rotation; + construct_args.set_column_window_command = args[ARG_set_column_window_command].u_int; + construct_args.set_row_window_command = args[ARG_set_row_window_command].u_int; + construct_args.set_current_column_command = args[ARG_set_current_column_command].u_int; + construct_args.set_current_row_command = args[ARG_set_current_row_command].u_int; + construct_args.write_black_ram_command = args[ARG_write_black_ram_command].u_int; + construct_args.black_bits_inverted = args[ARG_black_bits_inverted].u_bool; + construct_args.write_color_ram_command = write_color_ram_command; + construct_args.color_bits_inverted = args[ARG_color_bits_inverted].u_bool; + construct_args.highlight_color = highlight_color; + construct_args.highlight_color2 = highlight_color2; + construct_args.refresh_sequence = refresh_buf; + construct_args.refresh_sequence_len = refresh_buf_len; + construct_args.refresh_time = refresh_time; + construct_args.busy_pin = busy_pin; + construct_args.busy_state = args[ARG_busy_state].u_bool; + construct_args.seconds_per_frame = seconds_per_frame; + construct_args.always_toggle_chip_select = args[ARG_always_toggle_chip_select].u_bool; + construct_args.grayscale = args[ARG_grayscale].u_bool; + construct_args.acep = args[ARG_advanced_color_epaper].u_bool; + construct_args.spectra6 = args[ARG_spectra6].u_bool; + construct_args.two_byte_sequence_length = two_byte_sequence_length; + construct_args.address_little_endian = args[ARG_address_little_endian].u_bool; + common_hal_epaperdisplay_epaperdisplay_construct(self, &construct_args); return self; } diff --git a/shared-bindings/epaperdisplay/EPaperDisplay.h b/shared-bindings/epaperdisplay/EPaperDisplay.h index 016a07f1490..83f0b0377fe 100644 --- a/shared-bindings/epaperdisplay/EPaperDisplay.h +++ b/shared-bindings/epaperdisplay/EPaperDisplay.h @@ -15,19 +15,84 @@ extern const mp_obj_type_t epaperdisplay_epaperdisplay_type; #define NO_COMMAND 0x100 +typedef struct { + mp_obj_t bus; + const uint8_t *start_sequence; + uint16_t start_sequence_len; + mp_float_t start_up_time; + const uint8_t *stop_sequence; + uint16_t stop_sequence_len; + uint16_t width; + uint16_t height; + uint16_t ram_width; + uint16_t ram_height; + int16_t colstart; + int16_t rowstart; + uint16_t rotation; + uint16_t set_column_window_command; + uint16_t set_row_window_command; + uint16_t set_current_column_command; + uint16_t set_current_row_command; + uint16_t write_black_ram_command; + bool black_bits_inverted; + uint16_t write_color_ram_command; + bool color_bits_inverted; + uint32_t highlight_color; + uint32_t highlight_color2; + const uint8_t *refresh_sequence; + uint16_t refresh_sequence_len; + mp_float_t refresh_time; + const mcu_pin_obj_t *busy_pin; + bool busy_state; + mp_float_t seconds_per_frame; + bool always_toggle_chip_select; + bool grayscale; + bool acep; + bool spectra6; + bool two_byte_sequence_length; + bool address_little_endian; +} epaperdisplay_construct_args_t; + +#define EPAPERDISPLAY_CONSTRUCT_ARGS_DEFAULTS { \ + .bus = mp_const_none, \ + .start_sequence = NULL, \ + .start_sequence_len = 0, \ + .start_up_time = 0.0, \ + .stop_sequence = NULL, \ + .stop_sequence_len = 0, \ + .width = 0, \ + .height = 0, \ + .ram_width = 0, \ + .ram_height = 0, \ + .colstart = 0, \ + .rowstart = 0, \ + .rotation = 0, \ + .set_column_window_command = NO_COMMAND, \ + .set_row_window_command = NO_COMMAND, \ + .set_current_column_command = NO_COMMAND, \ + .set_current_row_command = NO_COMMAND, \ + .write_black_ram_command = NO_COMMAND, \ + .black_bits_inverted = false, \ + .write_color_ram_command = NO_COMMAND, \ + .color_bits_inverted = false, \ + .highlight_color = 0x000000, \ + .highlight_color2 = 0x000000, \ + .refresh_sequence = NULL, \ + .refresh_sequence_len = 0, \ + .refresh_time = 0.0, \ + .busy_pin = NULL, \ + .busy_state = false, \ + .seconds_per_frame = 0.0, \ + .always_toggle_chip_select = false, \ + .grayscale = false, \ + .acep = false, \ + .spectra6 = false, \ + .two_byte_sequence_length = false, \ + .address_little_endian = false \ +} + void common_hal_epaperdisplay_epaperdisplay_construct(epaperdisplay_epaperdisplay_obj_t *self, - mp_obj_t bus, const uint8_t *start_sequence, uint16_t start_sequence_len, mp_float_t start_up_time, - const uint8_t *stop_sequence, uint16_t stop_sequence_len, - uint16_t width, uint16_t height, uint16_t ram_width, uint16_t ram_height, - int16_t colstart, int16_t rowstart, uint16_t rotation, - uint16_t set_column_window_command, uint16_t set_row_window_command, - uint16_t set_current_column_command, uint16_t set_current_row_command, - uint16_t write_black_ram_command, bool black_bits_inverted, - uint16_t write_color_ram_command, bool color_bits_inverted, uint32_t highlight_color, - const uint8_t *refresh_sequence, uint16_t refresh_sequence_len, mp_float_t refresh_time, - const mcu_pin_obj_t *busy_pin, bool busy_state, mp_float_t seconds_per_frame, - bool always_toggle_chip_select, bool grayscale, bool acep, bool spectra6, bool two_byte_sequence_length, - bool address_little_endian); + const epaperdisplay_construct_args_t *args); bool common_hal_epaperdisplay_epaperdisplay_refresh(epaperdisplay_epaperdisplay_obj_t *self); 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/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..7705e500e7e 100644 --- a/shared-bindings/ipaddress/IPv4Address.c +++ b/shared-bindings/ipaddress/IPv4Address.c @@ -59,7 +59,6 @@ static mp_obj_t ipaddress_ipv4address_make_new(const mp_obj_type_t *type, size_t 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/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/EventQueue.h b/shared-bindings/keypad/EventQueue.h index 893165e3220..02c3414b076 100644 --- a/shared-bindings/keypad/EventQueue.h +++ b/shared-bindings/keypad/EventQueue.h @@ -11,7 +11,7 @@ extern const mp_obj_type_t keypad_eventqueue_type; -void common_hal_keypad_eventqueue_construct(keypad_eventqueue_obj_t *self, size_t max_events); +void common_hal_keypad_eventqueue_construct(keypad_eventqueue_obj_t *self, size_t max_events, bool use_gc_allocator); void common_hal_keypad_eventqueue_clear(keypad_eventqueue_obj_t *self); size_t common_hal_keypad_eventqueue_get_length(keypad_eventqueue_obj_t *self); diff --git a/shared-bindings/keypad/KeyMatrix.c b/shared-bindings/keypad/KeyMatrix.c index edb32c2c5c7..01416a2f8a1 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); 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 d76a20aec9d..554e461c228 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,7 +122,10 @@ static mp_obj_t keypad_demux_demuxkeymatrix_make_new(const mp_obj_type_t *type, column_pins_array[column] = pin; } - 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); + 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); } diff --git a/shared-bindings/keypad_demux/DemuxKeyMatrix.h b/shared-bindings/keypad_demux/DemuxKeyMatrix.h index 8bdaa597dc0..25d36283e90 100644 --- a/shared-bindings/keypad_demux/DemuxKeyMatrix.h +++ b/shared-bindings/keypad_demux/DemuxKeyMatrix.h @@ -11,7 +11,7 @@ extern const mp_obj_type_t keypad_demux_demuxkeymatrix_type; -void common_hal_keypad_demux_demuxkeymatrix_construct(keypad_demux_demuxkeymatrix_obj_t *self, mp_uint_t num_row_addr_pins, const mcu_pin_obj_t *row_addr_pins[], mp_uint_t num_column_pins, const mcu_pin_obj_t *column_pins[], bool columns_to_anodes, bool transpose, mp_float_t interval, size_t max_events, uint8_t debounce_threshold); +void common_hal_keypad_demux_demuxkeymatrix_construct(keypad_demux_demuxkeymatrix_obj_t *self, mp_uint_t num_row_addr_pins, const mcu_pin_obj_t *row_addr_pins[], mp_uint_t num_column_pins, const mcu_pin_obj_t *column_pins[], bool columns_to_anodes, bool transpose, mp_float_t interval, size_t max_events, uint8_t debounce_threshold, bool use_gc_allocator); void common_hal_keypad_demux_demuxkeymatrix_deinit(keypad_demux_demuxkeymatrix_obj_t *self); 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/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/__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/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/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/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/rotaryio/IncrementalEncoder.h b/shared-bindings/rotaryio/IncrementalEncoder.h index 1c60dd69a19..b3ceb3eeb15 100644 --- a/shared-bindings/rotaryio/IncrementalEncoder.h +++ b/shared-bindings/rotaryio/IncrementalEncoder.h @@ -13,11 +13,15 @@ extern const mp_obj_type_t rotaryio_incrementalencoder_type; extern 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); + extern void common_hal_rotaryio_incrementalencoder_deinit(rotaryio_incrementalencoder_obj_t *self); extern bool common_hal_rotaryio_incrementalencoder_deinited(rotaryio_incrementalencoder_obj_t *self); +extern void common_hal_rotaryio_incrementalencoder_mark_deinit(rotaryio_incrementalencoder_obj_t *self); + extern mp_int_t common_hal_rotaryio_incrementalencoder_get_position(rotaryio_incrementalencoder_obj_t *self); extern void common_hal_rotaryio_incrementalencoder_set_position(rotaryio_incrementalencoder_obj_t *self, mp_int_t new_position); + extern mp_int_t common_hal_rotaryio_incrementalencoder_get_divisor(rotaryio_incrementalencoder_obj_t *self); extern void common_hal_rotaryio_incrementalencoder_set_divisor(rotaryio_incrementalencoder_obj_t *self, mp_int_t new_divisor); 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/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..1fc9e2c3335 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,7 +189,7 @@ MP_DEFINE_CONST_OBJ_TYPE( locals_dict, &socketpool_socketpool_locals_dict ); -MP_WEAK NORETURN +MP_WEAK MP_NORETURN void common_hal_socketpool_socketpool_raise_gaierror_noname(void) { vstr_t vstr; mp_print_t print; diff --git a/shared-bindings/socketpool/SocketPool.h b/shared-bindings/socketpool/SocketPool.h index 36035ed00e1..60d58372b91 100644 --- a/shared-bindings/socketpool/SocketPool.h +++ b/shared-bindings/socketpool/SocketPool.h @@ -25,6 +25,6 @@ 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_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 ee0fb4ab53c..14ec16f3096 100644 --- a/shared-bindings/storage/__init__.c +++ b/shared-bindings/storage/__init__.c @@ -54,15 +54,11 @@ static mp_obj_t storage_mount(size_t n_args, const mp_obj_t *pos_args, mp_map_t // get the mount point const char *mnt_str = mp_obj_str_get_str(args[ARG_mount_path].u_obj); - // Make sure we're given an object we can mount. - // TODO(tannewt): Make sure we have all the methods we need to operating it - // as a file system. + mp_obj_t vfs_obj = args[ARG_filesystem].u_obj; - mp_obj_t dest[2]; - mp_load_method_maybe(vfs_obj, MP_QSTR_mount, dest); - if (dest[0] == MP_OBJ_NULL) { - mp_raise_ValueError(MP_ERROR_TEXT("filesystem must provide mount method")); - } + + // Currently, the only supported filesystem is VfsFat. + mp_arg_validate_type(vfs_obj, &mp_fat_vfs_type, MP_QSTR_filesystem); common_hal_storage_mount(vfs_obj, mnt_str, args[ARG_readonly].u_bool); diff --git a/shared-bindings/storage/__init__.h b/shared-bindings/storage/__init__.h index ed3e8d44e4a..6df60426295 100644 --- a/shared-bindings/storage/__init__.h +++ b/shared-bindings/storage/__init__.h @@ -16,7 +16,7 @@ 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_enable_usb_drive(void); diff --git a/shared-bindings/supervisor/Runtime.c b/shared-bindings/supervisor/Runtime.c index 7b497639939..20cfd2e8200 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 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 9add8f1745c..0304df12a81 100644 --- a/shared-bindings/synthio/MidiTrack.c +++ b/shared-bindings/synthio/MidiTrack.c @@ -70,7 +70,6 @@ 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, @@ -115,6 +114,27 @@ static void check_for_deinit(synthio_miditrack_obj_t *self) { //| """32 bit value that tells how quickly samples are played in Hertz (cycles per second).""" //| +//| tempo: int +//| """Tempo of the streamed events, in MIDI ticks per second.""" +//| +static mp_obj_t synthio_miditrack_obj_get_tempo(mp_obj_t self_in) { + synthio_miditrack_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return mp_obj_new_int(common_hal_synthio_miditrack_get_tempo(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(synthio_miditrack_get_tempo_obj, synthio_miditrack_obj_get_tempo); + +static mp_obj_t synthio_miditrack_obj_set_tempo(mp_obj_t self_in, mp_obj_t arg) { + synthio_miditrack_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + common_hal_synthio_miditrack_set_tempo(self, mp_obj_get_int(arg)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(synthio_miditrack_set_tempo_obj, synthio_miditrack_obj_set_tempo); +MP_PROPERTY_GETSET(synthio_miditrack_tempo_obj, + (mp_obj_t)&synthio_miditrack_get_tempo_obj, + (mp_obj_t)&synthio_miditrack_set_tempo_obj); + //| error_location: Optional[int] //| """Offset, in bytes within the midi data, of a decoding error""" //| @@ -141,6 +161,7 @@ static const mp_rom_map_elem_t synthio_miditrack_locals_dict_table[] = { // Properties { MP_ROM_QSTR(MP_QSTR_error_location), MP_ROM_PTR(&synthio_miditrack_error_location_obj) }, + { MP_ROM_QSTR(MP_QSTR_tempo), MP_ROM_PTR(&synthio_miditrack_tempo_obj) }, AUDIOSAMPLE_FIELDS, }; static MP_DEFINE_CONST_DICT(synthio_miditrack_locals_dict, synthio_miditrack_locals_dict_table); diff --git a/shared-bindings/synthio/MidiTrack.h b/shared-bindings/synthio/MidiTrack.h index 72b217e9613..cb154d3996b 100644 --- a/shared-bindings/synthio/MidiTrack.h +++ b/shared-bindings/synthio/MidiTrack.h @@ -15,3 +15,6 @@ void common_hal_synthio_miditrack_construct(synthio_miditrack_obj_t *self, const void common_hal_synthio_miditrack_deinit(synthio_miditrack_obj_t *self); mp_int_t common_hal_synthio_miditrack_get_error_location(synthio_miditrack_obj_t *self); + +mp_int_t common_hal_synthio_miditrack_get_tempo(synthio_miditrack_obj_t *self); +void common_hal_synthio_miditrack_set_tempo(synthio_miditrack_obj_t *self, mp_int_t value); 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..35cc42a2037 100644 --- a/shared-bindings/synthio/Synthesizer.c +++ b/shared-bindings/synthio/Synthesizer.c @@ -62,7 +62,6 @@ 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, args[ARG_channel_count].u_int, diff --git a/shared-bindings/synthio/__init__.c b/shared-bindings/synthio/__init__.c index 6d42880541d..6a21834751b 100644 --- a/shared-bindings/synthio/__init__.c +++ b/shared-bindings/synthio/__init__.c @@ -252,7 +252,6 @@ 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, 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 504cd07d901..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). @@ -83,6 +83,16 @@ static mp_obj_t struct_time_make_new(const mp_obj_type_t *type, size_t n_args, s } //| class struct_time: +//| tm_year: int +//| tm_mon: int +//| tm_mday: int +//| tm_hour: int +//| tm_min: int +//| tm_sec: int +//| tm_wday: int +//| tm_yday: int +//| tm_isdst: int +//| //| def __init__(self, time_tuple: Sequence[int]) -> None: //| """Structure used to capture a date and time. Can be constructed from a `struct_time`, `tuple`, `list`, or `namedtuple` with 9 elements. //| @@ -196,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 @@ -210,7 +220,7 @@ static mp_obj_t time_monotonic_ns(void) { } MP_DEFINE_CONST_FUN_OBJ_0(time_monotonic_ns_obj, time_monotonic_ns); -//| def localtime(secs: int) -> struct_time: +//| def localtime(secs: Optional[int] = None) -> struct_time: //| """Convert a time expressed in seconds since Jan 1, 1970 to a struct_time in //| local time. If secs is not provided or None, the current time as returned //| by time() is used. 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/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..ff53d812e49 --- /dev/null +++ b/shared-bindings/usb_audio/USBMicrophone.c @@ -0,0 +1,177 @@ +// 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" + +//| 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..d9302886c64 --- /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, bits_per_sample=16, +//| 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..49eaa9716f2 --- /dev/null +++ b/shared-bindings/usb_audio/__init__.c @@ -0,0 +1,160 @@ +// 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 1 IN endpoint 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, channel_count=1, bits_per_sample=16) +//| +//| .. 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, +//| bits_per_sample: int = 16, +//| 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. Only mono (1) is supported initially. +//| :param int bits_per_sample: Bits per signed PCM sample. Only 16 is supported initially. +//| :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_bits_per_sample, 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_bits_per_sample, MP_ARG_INT, { .u_int = 16 } }, + { 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); + mp_int_t bits_per_sample = mp_arg_validate_int(args[ARG_bits_per_sample].u_int, USB_AUDIO_BITS_PER_SAMPLE, MP_QSTR_bits_per_sample); + 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, bits_per_sample, 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 7c9c354e4de..66c9c01ad6e 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 }, @@ -98,7 +97,7 @@ static mp_obj_t usb_hid_device_make_new(const mp_obj_type_t *type, size_t n_args const uint16_t usage_page = usage_page_arg; const mp_int_t usage_arg = args[ARG_usage].u_int; - mp_arg_validate_int_range(usage_arg, 1, 0xFFFF, MP_QSTR_usage); + mp_arg_validate_int_range(usage_arg, 0, 0xFFFF, MP_QSTR_usage); const uint16_t usage = usage_arg; mp_obj_t report_ids = args[ARG_report_ids].u_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); } 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/Radio.c b/shared-bindings/wifi/Radio.c index a267dea11c1..9a7d445fd04 100644 --- a/shared-bindings/wifi/Radio.c +++ b/shared-bindings/wifi/Radio.c @@ -99,7 +99,7 @@ MP_PROPERTY_GETSET(wifi_radio_enabled_obj, (mp_obj_t)&wifi_radio_get_enabled_obj, (mp_obj_t)&wifi_radio_set_enabled_obj); -//| hostname: Union[str | ReadableBuffer] +//| hostname: Union[str, ReadableBuffer] //| """Hostname for wifi interface. When the hostname is altered after interface started/connected //| the changes would only be reflected once the interface restarts/reconnects.""" static mp_obj_t wifi_radio_get_hostname(mp_obj_t self_in) { @@ -325,8 +325,8 @@ MP_DEFINE_CONST_FUN_OBJ_1(wifi_radio_stop_station_obj, wifi_radio_stop_station); //| def start_ap( //| self, -//| ssid: Union[str | ReadableBuffer], -//| password: Union[str | ReadableBuffer] = b"", +//| ssid: Union[str, ReadableBuffer], +//| password: Union[str, ReadableBuffer] = b"", //| *, //| channel: int = 1, //| authmode: Iterable[AuthMode] = (), @@ -438,11 +438,11 @@ MP_PROPERTY_GETTER(wifi_radio_ap_active_obj, //| def connect( //| self, -//| ssid: Union[str | ReadableBuffer], -//| password: Union[str | ReadableBuffer] = b"", +//| ssid: Union[str, ReadableBuffer], +//| password: Union[str, ReadableBuffer] = b"", //| *, //| channel: int = 0, -//| bssid: Optional[Union[str | ReadableBuffer]] = None, +//| bssid: Optional[Union[str, ReadableBuffer]] = None, //| timeout: Optional[float] = None, //| ) -> None: //| """Connects to the given ssid and waits for an ip address. Reconnections are handled diff --git a/shared-module/audiocore/__init__.c b/shared-module/audiocore/__init__.c index bf804031379..3a80d6b6f42 100644 --- a/shared-module/audiocore/__init__.c +++ b/shared-module/audiocore/__init__.c @@ -13,6 +13,10 @@ #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" @@ -196,12 +200,16 @@ 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) { +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); + #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 (other->channel_count != self->channel_count) { + if ((!allow_mono_to_stereo || (allow_mono_to_stereo && self->channel_count != 2)) && other->channel_count != self->channel_count) { mp_raise_ValueError_varg(MP_ERROR_TEXT("The sample's %q does not match"), MP_QSTR_channel_count); } if (other->bits_per_sample != self->bits_per_sample) { @@ -210,4 +218,11 @@ void audiosample_must_match(audiosample_base_t *self, mp_obj_t other_in) { 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 875ac90ecc5..920fe752c38 100644 --- a/shared-module/audiocore/__init__.h +++ b/shared-module/audiocore/__init__.h @@ -89,7 +89,7 @@ static inline void audiosample_get_buffer_structure_checked(mp_obj_t self_in, bo audiosample_get_buffer_structure(audiosample_check(self_in), single_channel_output, single_buffer, samples_signed, max_buffer_length, spacing); } -void audiosample_must_match(audiosample_base_t *self, mp_obj_t other); +void audiosample_must_match(audiosample_base_t *self, mp_obj_t other, bool allow_mono_to_stereo); void audiosample_convert_u8m_s16s(int16_t *buffer_out, const uint8_t *buffer_in, size_t nframes); void audiosample_convert_u8s_s16s(int16_t *buffer_out, const uint8_t *buffer_in, size_t nframes); diff --git a/shared-module/audiodelays/Chorus.c b/shared-module/audiodelays/Chorus.c index 1609cc5f946..3c35b902189 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; @@ -166,7 +165,7 @@ bool common_hal_audiodelays_chorus_get_playing(audiodelays_chorus_obj_t *self) { } void common_hal_audiodelays_chorus_play(audiodelays_chorus_obj_t *self, mp_obj_t sample, bool loop) { - audiosample_must_match(&self->base, sample); + audiosample_must_match(&self->base, sample, false); self->sample = sample; self->loop = loop; diff --git a/shared-module/audiodelays/Echo.c b/shared-module/audiodelays/Echo.c index 78764d9099a..0ca5fc8a750 100644 --- a/shared-module/audiodelays/Echo.c +++ b/shared-module/audiodelays/Echo.c @@ -204,7 +204,7 @@ bool common_hal_audiodelays_echo_get_playing(audiodelays_echo_obj_t *self) { } void common_hal_audiodelays_echo_play(audiodelays_echo_obj_t *self, mp_obj_t sample, bool loop) { - audiosample_must_match(&self->base, sample); + audiosample_must_match(&self->base, sample, false); self->sample = sample; self->loop = loop; diff --git a/shared-module/audiodelays/MultiTapDelay.c b/shared-module/audiodelays/MultiTapDelay.c index 7b702ecf115..9c33a5eaee7 100644 --- a/shared-module/audiodelays/MultiTapDelay.c +++ b/shared-module/audiodelays/MultiTapDelay.c @@ -285,7 +285,7 @@ bool common_hal_audiodelays_multi_tap_delay_get_playing(audiodelays_multi_tap_de } void common_hal_audiodelays_multi_tap_delay_play(audiodelays_multi_tap_delay_obj_t *self, mp_obj_t sample, bool loop) { - audiosample_must_match(&self->base, sample); + audiosample_must_match(&self->base, sample, false); self->sample = sample; self->loop = loop; diff --git a/shared-module/audiodelays/PitchShift.c b/shared-module/audiodelays/PitchShift.c index ac349da0dd5..3b8c1a07c7b 100644 --- a/shared-module/audiodelays/PitchShift.c +++ b/shared-module/audiodelays/PitchShift.c @@ -143,7 +143,7 @@ bool common_hal_audiodelays_pitch_shift_get_playing(audiodelays_pitch_shift_obj_ } void common_hal_audiodelays_pitch_shift_play(audiodelays_pitch_shift_obj_t *self, mp_obj_t sample, bool loop) { - audiosample_must_match(&self->base, sample); + audiosample_must_match(&self->base, sample, false); self->sample = sample; self->loop = loop; diff --git a/shared-module/audiofilters/Distortion.c b/shared-module/audiofilters/Distortion.c index ec5fe084e56..c4b6b7566ad 100644 --- a/shared-module/audiofilters/Distortion.c +++ b/shared-module/audiofilters/Distortion.c @@ -141,7 +141,7 @@ bool common_hal_audiofilters_distortion_get_playing(audiofilters_distortion_obj_ } void common_hal_audiofilters_distortion_play(audiofilters_distortion_obj_t *self, mp_obj_t sample, bool loop) { - audiosample_must_match(&self->base, sample); + audiosample_must_match(&self->base, sample, false); self->sample = sample; self->loop = loop; diff --git a/shared-module/audiofilters/Filter.c b/shared-module/audiofilters/Filter.c index 19b567532eb..f9c899e2995 100644 --- a/shared-module/audiofilters/Filter.c +++ b/shared-module/audiofilters/Filter.c @@ -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 @@ -106,9 +106,9 @@ void common_hal_audiofilters_filter_set_filter(audiofilters_filter_obj_t *self, 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; + self->filter_objs_len * self->base.channel_count, + n_items * self->base.channel_count); + self->filter_objs_len = n_items; } mp_obj_t common_hal_audiofilters_filter_get_filter(audiofilters_filter_obj_t *self) { @@ -129,10 +129,10 @@ 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++) { + for (uint8_t i = 0; i < self->filter_objs_len * self->base.channel_count; i++) { synthio_biquad_filter_reset(&self->filter_states[i]); } } @@ -143,7 +143,7 @@ bool common_hal_audiofilters_filter_get_playing(audiofilters_filter_obj_t *self) } void common_hal_audiofilters_filter_play(audiofilters_filter_obj_t *self, mp_obj_t sample, bool loop) { - audiosample_must_match(&self->base, sample); + audiosample_must_match(&self->base, sample, false); self->sample = sample; self->loop = loop; @@ -207,7 +207,7 @@ 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++) { + for (uint8_t j = 0; j < self->filter_objs_len; j++) { common_hal_synthio_biquad_tick(self->filter_objs[j]); } if (self->base.samples_signed) { @@ -248,46 +248,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++) { + for (uint8_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..e24827e44a8 100644 --- a/shared-module/audiofilters/Filter.h +++ b/shared-module/audiofilters/Filter.h @@ -21,7 +21,7 @@ typedef struct { synthio_block_slot_t mix; mp_obj_t *filter_objs; - size_t filter_states_len; + size_t filter_objs_len; biquad_filter_state *filter_states; int8_t *buffer[2]; diff --git a/shared-module/audiofilters/Phaser.c b/shared-module/audiofilters/Phaser.c index 81d9c0bea30..01b938c3a00 100644 --- a/shared-module/audiofilters/Phaser.c +++ b/shared-module/audiofilters/Phaser.c @@ -130,7 +130,7 @@ bool common_hal_audiofilters_phaser_get_playing(audiofilters_phaser_obj_t *self) } void common_hal_audiofilters_phaser_play(audiofilters_phaser_obj_t *self, mp_obj_t sample, bool loop) { - audiosample_must_match(&self->base, sample); + audiosample_must_match(&self->base, sample, false); self->sample = sample; self->loop = loop; diff --git a/shared-module/audiofreeverb/Freeverb.c b/shared-module/audiofreeverb/Freeverb.c index d9105360136..b57e82cdca2 100644 --- a/shared-module/audiofreeverb/Freeverb.c +++ b/shared-module/audiofreeverb/Freeverb.c @@ -8,6 +8,7 @@ // 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 @@ -124,9 +125,7 @@ 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); self->buffer[0] = NULL; self->buffer[1] = NULL; } @@ -195,7 +194,7 @@ bool common_hal_audiofreeverb_freeverb_get_playing(audiofreeverb_freeverb_obj_t } void common_hal_audiofreeverb_freeverb_play(audiofreeverb_freeverb_obj_t *self, mp_obj_t sample, bool loop) { - audiosample_must_match(&self->base, sample); + audiosample_must_match(&self->base, sample, false); self->sample = sample; self->loop = loop; 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 2c727a5c0cd..b6cb3318e54 100644 --- a/shared-module/audiomixer/Mixer.c +++ b/shared-module/audiomixer/Mixer.c @@ -92,22 +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) { +static inline uint32_t mult16signed(uint32_t val, int32_t lomul, int32_t himul) { #if (defined(__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) - mul <<= 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), "r" (val)); - asm volatile ("smulwt %0, %1, %2" : "=r" (hi) : "r" (mul), "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; - float mod_mul = (float)mul / (float)((1 << 15) - 1); for (int8_t i = 0; i < 2; i++) { + 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) { @@ -154,9 +155,30 @@ static inline uint32_t pack8(uint32_t val) { return ((val & 0xff000000) >> 16) | ((val & 0xff00) >> 8); } +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 +} + +#define ALMOST_ONE (MICROPY_FLOAT_CONST(32767.) / 32768) + static void mix_down_one_voice(audiomixer_mixer_obj_t *self, audiomixer_mixervoice_obj_t *voice, bool voices_active, uint32_t *word_buffer, uint32_t length) { + audiosample_base_t *sample = MP_OBJ_TO_PTR(voice->sample); while (length != 0) { if (voice->buffer_length == 0) { if (!voice->more_data) { @@ -179,75 +201,164 @@ static void mix_down_one_voice(audiomixer_mixer_obj_t *self, uint32_t *src = voice->remaining_buffer; #if CIRCUITPY_SYNTHIO - uint32_t n = MIN(MIN(voice->buffer_length, length), SYNTHIO_MAX_DUR * self->base.channel_count); + uint32_t n; + if (MP_LIKELY(self->base.channel_count == sample->channel_count)) { + n = MIN(MIN(voice->buffer_length, length), SYNTHIO_MAX_DUR * self->base.channel_count); + } else { + n = MIN(MIN(voice->buffer_length << 1, length), SYNTHIO_MAX_DUR * self->base.channel_count); + } // Get the current level from the BlockInput. These may change at run time so you need to do bounds checking if required. shared_bindings_synthio_lfo_tick(self->base.sample_rate, n / self->base.channel_count); uint16_t level = (uint16_t)(synthio_block_slot_get_limited(&voice->level, MICROPY_FLOAT_CONST(0.0), MICROPY_FLOAT_CONST(1.0)) * (1 << 15)); + int16_t panning = synthio_block_slot_get_scaled(&voice->panning, -ALMOST_ONE, ALMOST_ONE); #else - uint32_t n = MIN(voice->buffer_length, length); + uint32_t n; + if (MP_LIKELY(self->base.channel_count == sample->channel_count)) { + n = MIN(voice->buffer_length, length); + } else { + n = MIN(voice->buffer_length << 1, length); + } uint16_t level = voice->level; + int16_t panning = voice->panning; #endif + uint16_t left_panning_scaled = 32768, right_panning_scaled = 32768; + if (MP_LIKELY(self->base.channel_count == 2)) { + if (panning >= 0) { + left_panning_scaled = 32767 - panning; + } else { + right_panning_scaled = 32767 + panning; + } + } + + int32_t lo_level = level; + int32_t hi_level = level; + if (MP_LIKELY(self->base.channel_count == 2)) { + lo_level = (left_panning_scaled * lo_level) >> 15; + hi_level = (right_panning_scaled * hi_level) >> 15; + } + // 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)) { - for (uint32_t i = 0; i < n; i++) { - uint32_t v = src[i]; - word_buffer[i] = mult16signed(v, level); + 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, lo_level, hi_level); + } + } else { + for (uint32_t i = 0; i < n; i += 2) { + uint32_t v = src[i >> 1]; + word_buffer[i] = mult16signed(copy16lsb(v), lo_level, hi_level); + word_buffer[i + 1] = mult16signed(copy16msb(v), lo_level, hi_level); + } } } else { - for (uint32_t i = 0; i < n; i++) { - uint32_t v = src[i]; - v = tosigned16(v); - word_buffer[i] = mult16signed(v, level); + 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, lo_level, 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), lo_level, hi_level); + word_buffer[i + 1] = mult16signed(copy16msb(v), lo_level, hi_level); + } } } } else { uint16_t *hword_buffer = (uint16_t *)word_buffer; uint16_t *hsrc = (uint16_t *)src; - for (uint32_t i = 0; i < n * 2; i++) { - uint32_t word = unpack8(hsrc[i]); - if (MP_LIKELY(!self->base.samples_signed)) { - word = tosigned16(word); + if (MP_LIKELY(self->base.channel_count == sample->channel_count)) { + for (uint32_t i = 0; i < n * 2; i++) { + uint32_t word = unpack8(hsrc[i]); + if (MP_LIKELY(!self->base.samples_signed)) { + word = tosigned16(word); + } + word = mult16signed(word, lo_level, hi_level); + hword_buffer[i] = pack8(word); + } + } else { + for (uint32_t i = 0; i + 1 < n * 2; i += 2) { + uint32_t word = unpack8(hsrc[i >> 1]); + if (MP_LIKELY(!self->base.samples_signed)) { + word = tosigned16(word); + } + hword_buffer[i] = pack8(mult16signed(copy16lsb(word), lo_level, hi_level)); + hword_buffer[i + 1] = pack8(mult16signed(copy16msb(word), lo_level, hi_level)); } - word = mult16signed(word, level); - hword_buffer[i] = pack8(word); } } } else { if (MP_LIKELY(self->base.bits_per_sample == 16)) { if (MP_LIKELY(self->base.samples_signed)) { - for (uint32_t i = 0; i < n; i++) { - uint32_t word = src[i]; - word_buffer[i] = add16signed(mult16signed(word, level), word_buffer[i]); + 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, lo_level, 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), lo_level, hi_level), word_buffer[i]); + word_buffer[i + 1] = add16signed(mult16signed(copy16msb(word), lo_level, hi_level), word_buffer[i + 1]); + } } } else { - for (uint32_t i = 0; i < n; i++) { - uint32_t word = src[i]; - word = tosigned16(word); - word_buffer[i] = add16signed(mult16signed(word, level), word_buffer[i]); + if (MP_LIKELY(self->base.channel_count == sample->channel_count)) { + for (uint32_t i = 0; i < n; i++) { + uint32_t word = src[i]; + word = tosigned16(word); + word_buffer[i] = add16signed(mult16signed(word, lo_level, 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), lo_level, hi_level), word_buffer[i]); + word_buffer[i + 1] = add16signed(mult16signed(copy16msb(word), lo_level, hi_level), word_buffer[i + 1]); + } } } } else { uint16_t *hword_buffer = (uint16_t *)word_buffer; uint16_t *hsrc = (uint16_t *)src; - for (uint32_t i = 0; i < n * 2; i++) { - uint32_t word = unpack8(hsrc[i]); - if (MP_LIKELY(!self->base.samples_signed)) { - word = tosigned16(word); + if (MP_LIKELY(self->base.channel_count == sample->channel_count)) { + for (uint32_t i = 0; i < n * 2; i++) { + uint32_t word = unpack8(hsrc[i]); + if (MP_LIKELY(!self->base.samples_signed)) { + word = tosigned16(word); + } + word = mult16signed(word, lo_level, hi_level); + word = add16signed(word, unpack8(hword_buffer[i])); + hword_buffer[i] = pack8(word); + } + } else { + for (uint32_t i = 0; i + 1 < n * 2; i += 2) { + uint32_t word = unpack8(hsrc[i >> 1]); + if (MP_LIKELY(!self->base.samples_signed)) { + word = tosigned16(word); + } + hword_buffer[i] = pack8(add16signed(mult16signed(copy16lsb(word), lo_level, hi_level), unpack8(hword_buffer[i]))); + hword_buffer[i + 1] = pack8(add16signed(mult16signed(copy16msb(word), lo_level, hi_level), unpack8(hword_buffer[i + 1]))); } - word = mult16signed(word, level); - word = add16signed(word, unpack8(hword_buffer[i])); - hword_buffer[i] = pack8(word); } } } length -= n; word_buffer += n; - voice->remaining_buffer += n; - voice->buffer_length -= n; + if (MP_LIKELY(self->base.channel_count == sample->channel_count)) { + voice->remaining_buffer += n; + voice->buffer_length -= n; + } else { + voice->remaining_buffer += n >> 1; + voice->buffer_length -= n >> 1; + } } if (length && !voices_active) { diff --git a/shared-module/audiomixer/MixerVoice.c b/shared-module/audiomixer/MixerVoice.c index e0be869aa8e..3a598516e7c 100644 --- a/shared-module/audiomixer/MixerVoice.c +++ b/shared-module/audiomixer/MixerVoice.c @@ -16,6 +16,7 @@ void common_hal_audiomixer_mixervoice_construct(audiomixer_mixervoice_obj_t *self) { self->sample = NULL; common_hal_audiomixer_mixervoice_set_level(self, mp_obj_new_float(1.0)); + common_hal_audiomixer_mixervoice_set_panning(self, mp_obj_new_float(0.0)); } void common_hal_audiomixer_mixervoice_set_parent(audiomixer_mixervoice_obj_t *self, audiomixer_mixer_obj_t *parent) { @@ -38,6 +39,22 @@ void common_hal_audiomixer_mixervoice_set_level(audiomixer_mixervoice_obj_t *sel #endif } +mp_obj_t common_hal_audiomixer_mixervoice_get_panning(audiomixer_mixervoice_obj_t *self) { + #if CIRCUITPY_SYNTHIO + return self->panning.obj; + #else + return mp_obj_new_float((mp_float_t)self->panning / ((1 << 15) - 1)); + #endif +} + +void common_hal_audiomixer_mixervoice_set_panning(audiomixer_mixervoice_obj_t *self, mp_obj_t arg) { + #if CIRCUITPY_SYNTHIO + synthio_block_assign_slot(arg, &self->panning, MP_QSTR_panning); + #else + self->panning = (int16_t)(mp_arg_validate_obj_float_range(arg, -1, 1, MP_QSTR_panning) * ((1 << 15) - 1)); + #endif +} + bool common_hal_audiomixer_mixervoice_get_loop(audiomixer_mixervoice_obj_t *self) { return self->loop; } @@ -47,7 +64,7 @@ void common_hal_audiomixer_mixervoice_set_loop(audiomixer_mixervoice_obj_t *self } void common_hal_audiomixer_mixervoice_play(audiomixer_mixervoice_obj_t *self, mp_obj_t sample_in, bool loop) { - audiosample_must_match(&self->parent->base, sample_in); + audiosample_must_match(&self->parent->base, sample_in, true); // cast is safe, checked by must_match audiosample_base_t *sample = MP_OBJ_TO_PTR(sample_in); self->sample = sample; diff --git a/shared-module/audiomixer/MixerVoice.h b/shared-module/audiomixer/MixerVoice.h index dd909551545..75e7d47faa3 100644 --- a/shared-module/audiomixer/MixerVoice.h +++ b/shared-module/audiomixer/MixerVoice.h @@ -23,7 +23,9 @@ typedef struct { uint32_t buffer_length; #if CIRCUITPY_SYNTHIO synthio_block_slot_t level; + synthio_block_slot_t panning; #else uint16_t level; + int16_t panning; #endif } audiomixer_mixervoice_obj_t; 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..d88455729e2 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,18 +224,28 @@ 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; } @@ -215,7 +267,9 @@ 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)) { 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..9b89d1d4a1b 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)) { + 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)) { + 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)) { + 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/ColorConverter.c b/shared-module/displayio/ColorConverter.c index ae7d3f02d51..d4e64ee286e 100644 --- a/shared-module/displayio/ColorConverter.c +++ b/shared-module/displayio/ColorConverter.c @@ -163,8 +163,13 @@ uint8_t displayio_colorconverter_compute_sevencolor(uint32_t color_rgb888) { } } -void displayio_colorconverter_compute_tricolor(const _displayio_colorspace_t *colorspace, uint8_t pixel_hue, uint32_t *color) { - +void displayio_colorconverter_compute_tricolor(const _displayio_colorspace_t *colorspace, uint8_t pixel_chroma, uint8_t pixel_hue, uint32_t *color) { + if (pixel_chroma <= 16) { + if (!colorspace->grayscale) { + *color = 0; + } + return; + } int16_t hue_diff = colorspace->tricolor_hue - pixel_hue; if ((-10 <= hue_diff && hue_diff <= 10) || hue_diff <= -220 || hue_diff >= 220) { if (colorspace->grayscale) { @@ -177,6 +182,21 @@ void displayio_colorconverter_compute_tricolor(const _displayio_colorspace_t *co } } +void displayio_colorconverter_compute_fourcolor(const _displayio_colorspace_t *colorspace, uint8_t pixel_chroma, uint8_t pixel_hue, uint32_t *color) { + *color >>= 1; + if (pixel_chroma <= 16) { + return; + } + int16_t hue_diff = colorspace->tricolor_hue - pixel_hue; + if ((-10 <= hue_diff && hue_diff <= 10) || hue_diff <= -220 || hue_diff >= 220) { + *color = 2; + } + int16_t hue_diff2 = colorspace->fourcolor_hue - pixel_hue; + if ((-10 <= hue_diff2 && hue_diff2 <= 10) || hue_diff2 <= -220 || hue_diff2 >= 220) { + *color = 3; + } +} + void common_hal_displayio_colorconverter_convert(displayio_colorconverter_t *self, const _displayio_colorspace_t *colorspace, uint32_t input_color, uint32_t *output_color) { displayio_input_pixel_t input_pixel; input_pixel.pixel = input_color; @@ -313,18 +333,17 @@ void displayio_convert_color(const _displayio_colorspace_t *colorspace, bool dit output_color->pixel = packed; output_color->opaque = true; return; - } else if (colorspace->tricolor) { + } else if (colorspace->tricolor || colorspace->fourcolor) { uint8_t luma = displayio_colorconverter_compute_luma(pixel); + uint8_t pixel_chroma = displayio_colorconverter_compute_chroma(pixel); output_color->pixel = luma >> (8 - colorspace->depth); - if (displayio_colorconverter_compute_chroma(pixel) <= 16) { - if (!colorspace->grayscale) { - output_color->pixel = 0; - } - output_color->opaque = true; - return; - } uint8_t pixel_hue = displayio_colorconverter_compute_hue(pixel); - displayio_colorconverter_compute_tricolor(colorspace, pixel_hue, &output_color->pixel); + if (colorspace->tricolor) { + displayio_colorconverter_compute_tricolor(colorspace, pixel_chroma, pixel_hue, &output_color->pixel); + } else if (colorspace->fourcolor) { + displayio_colorconverter_compute_fourcolor(colorspace, pixel_chroma, pixel_hue, &output_color->pixel); + } + output_color->opaque = true; return; } else if (colorspace->grayscale && colorspace->depth <= 8) { uint8_t luma = displayio_colorconverter_compute_luma(pixel); diff --git a/shared-module/displayio/ColorConverter.h b/shared-module/displayio/ColorConverter.h index d3dbedfe160..304004d566a 100644 --- a/shared-module/displayio/ColorConverter.h +++ b/shared-module/displayio/ColorConverter.h @@ -43,4 +43,5 @@ uint8_t displayio_colorconverter_compute_chroma(uint32_t color_rgb888); uint8_t displayio_colorconverter_compute_hue(uint32_t color_rgb888); uint8_t displayio_colorconverter_compute_sixcolor(uint32_t color_rgb888); uint8_t displayio_colorconverter_compute_sevencolor(uint32_t color_rgb888); -void displayio_colorconverter_compute_tricolor(const _displayio_colorspace_t *colorspace, uint8_t pixel_hue, uint32_t *color); +void displayio_colorconverter_compute_tricolor(const _displayio_colorspace_t *colorspace, uint8_t pixel_chroma, uint8_t pixel_hue, uint32_t *color); +void displayio_colorconverter_compute_fourcolor(const _displayio_colorspace_t *colorspace, uint8_t pixel_chroma, uint8_t pixel_hue, uint32_t *color); diff --git a/shared-module/displayio/Palette.h b/shared-module/displayio/Palette.h index bb87a93d981..24ae5c4b7a5 100644 --- a/shared-module/displayio/Palette.h +++ b/shared-module/displayio/Palette.h @@ -15,10 +15,11 @@ typedef struct { uint8_t depth; uint8_t bytes_per_cell; uint8_t tricolor_hue; - uint8_t tricolor_luma; + uint8_t fourcolor_hue; uint8_t grayscale_bit; // The lowest grayscale bit. Normally 8 - depth. bool grayscale; bool tricolor; + bool fourcolor; bool sixcolor; // Spectra6 e-ink screens. bool sevencolor; // Acep e-ink screens. bool pixels_in_byte_share_row; 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 4b467b75589..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,13 +221,15 @@ 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++) { mp_const_obj_t display_bus_type = display_buses[i].bus_base.type; if (display_bus_type == NULL || display_bus_type == &mp_type_NoneType) { + display_buses[i].bus_base.type = &mp_type_NoneType; continue; #if CIRCUITPY_FOURWIRE } else if (display_bus_type == &fourwire_fourwire_type) { @@ -205,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 && @@ -227,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 @@ -236,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. @@ -272,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)) { @@ -319,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; @@ -353,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 } } } @@ -404,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/epaperdisplay/EPaperDisplay.c b/shared-module/epaperdisplay/EPaperDisplay.c index a5a303d82ae..d34be9d5c7c 100644 --- a/shared-module/epaperdisplay/EPaperDisplay.c +++ b/shared-module/epaperdisplay/EPaperDisplay.c @@ -26,71 +26,73 @@ #define DELAY 0x80 void common_hal_epaperdisplay_epaperdisplay_construct(epaperdisplay_epaperdisplay_obj_t *self, - mp_obj_t bus, const uint8_t *start_sequence, uint16_t start_sequence_len, mp_float_t start_up_time, - const uint8_t *stop_sequence, uint16_t stop_sequence_len, - uint16_t width, uint16_t height, uint16_t ram_width, uint16_t ram_height, - int16_t colstart, int16_t rowstart, uint16_t rotation, - uint16_t set_column_window_command, uint16_t set_row_window_command, - uint16_t set_current_column_command, uint16_t set_current_row_command, - uint16_t write_black_ram_command, bool black_bits_inverted, - uint16_t write_color_ram_command, bool color_bits_inverted, uint32_t highlight_color, - const uint8_t *refresh_sequence, uint16_t refresh_sequence_len, mp_float_t refresh_time, - const mcu_pin_obj_t *busy_pin, bool busy_state, mp_float_t seconds_per_frame, - bool chip_select, bool grayscale, bool acep, bool spectra6, bool two_byte_sequence_length, bool address_little_endian) { + const epaperdisplay_construct_args_t *args) { uint16_t color_depth = 1; bool core_grayscale = true; - if (highlight_color != 0x000000) { + if (args->highlight_color != 0x000000) { self->core.colorspace.tricolor = true; - self->core.colorspace.tricolor_hue = displayio_colorconverter_compute_hue(highlight_color); - self->core.colorspace.tricolor_luma = displayio_colorconverter_compute_luma(highlight_color); + self->core.colorspace.tricolor_hue = displayio_colorconverter_compute_hue(args->highlight_color); } else { self->core.colorspace.tricolor = false; } - self->acep = acep || spectra6; - self->core.colorspace.sixcolor = spectra6; - self->core.colorspace.sevencolor = acep; + if (args->highlight_color != 0x000000 && args->highlight_color2 != 0x000000) { + self->core.colorspace.tricolor = false; + self->core.colorspace.fourcolor = true; + self->core.colorspace.fourcolor_hue = displayio_colorconverter_compute_hue(args->highlight_color2); + } else { + self->core.colorspace.fourcolor = false; + } + self->acep = args->acep || args->spectra6; + self->core.colorspace.sixcolor = args->spectra6; + self->core.colorspace.sevencolor = args->acep; + bool grayscale = args->grayscale; if (self->acep) { color_depth = 4; // bits. 7 colors + clean grayscale = false; core_grayscale = false; } + if ((args->highlight_color != 0x000000 || args->highlight_color2 != 0x000000) && args->write_color_ram_command == NO_COMMAND) { + color_depth = 2; + core_grayscale = false; + grayscale = false; + } - displayio_display_core_construct(&self->core, width, height, rotation, color_depth, core_grayscale, true, 1, true, true); - displayio_display_bus_construct(&self->bus, bus, ram_width, ram_height, - colstart, rowstart, - set_column_window_command, set_row_window_command, set_current_column_command, set_current_row_command, - false /* data_as_commands */, chip_select, - false /* SH1107_addressing */, address_little_endian); + displayio_display_core_construct(&self->core, args->width, args->height, args->rotation, color_depth, core_grayscale, true, 1, true, true); + displayio_display_bus_construct(&self->bus, args->bus, args->ram_width, args->ram_height, + args->colstart, args->rowstart, + args->set_column_window_command, args->set_row_window_command, args->set_current_column_command, args->set_current_row_command, + false /* data_as_commands */, args->always_toggle_chip_select, + false /* SH1107_addressing */, args->address_little_endian); - self->write_black_ram_command = write_black_ram_command; - self->black_bits_inverted = black_bits_inverted; - self->write_color_ram_command = write_color_ram_command; - self->color_bits_inverted = color_bits_inverted; - self->refresh_time = refresh_time * 1000; - self->busy_state = busy_state; + self->write_black_ram_command = args->write_black_ram_command; + self->black_bits_inverted = args->black_bits_inverted; + self->write_color_ram_command = args->write_color_ram_command; + self->color_bits_inverted = args->color_bits_inverted; + self->refresh_time = args->refresh_time * 1000; + self->busy_state = args->busy_state; self->refreshing = false; - self->milliseconds_per_frame = seconds_per_frame * 1000; - self->chip_select = chip_select ? CHIP_SELECT_TOGGLE_EVERY_BYTE : CHIP_SELECT_UNTOUCHED; + self->milliseconds_per_frame = args->seconds_per_frame * 1000; + self->chip_select = args->always_toggle_chip_select ? CHIP_SELECT_TOGGLE_EVERY_BYTE : CHIP_SELECT_UNTOUCHED; self->grayscale = grayscale; - self->start_sequence = start_sequence; - self->start_sequence_len = start_sequence_len; - self->start_up_time_ms = start_up_time * 1000; - self->stop_sequence = stop_sequence; - self->stop_sequence_len = stop_sequence_len; - self->refresh_sequence = refresh_sequence; - self->refresh_sequence_len = refresh_sequence_len; + self->start_sequence = args->start_sequence; + self->start_sequence_len = args->start_sequence_len; + self->start_up_time_ms = args->start_up_time * 1000; + self->stop_sequence = args->stop_sequence; + self->stop_sequence_len = args->stop_sequence_len; + self->refresh_sequence = args->refresh_sequence; + self->refresh_sequence_len = args->refresh_sequence_len; self->busy.base.type = &mp_type_NoneType; - self->two_byte_sequence_length = two_byte_sequence_length; - if (busy_pin != NULL) { + self->two_byte_sequence_length = args->two_byte_sequence_length; + if (args->busy_pin != NULL) { self->busy.base.type = &digitalio_digitalinout_type; - common_hal_digitalio_digitalinout_construct(&self->busy, busy_pin); - common_hal_never_reset_pin(busy_pin); + common_hal_digitalio_digitalinout_construct(&self->busy, args->busy_pin); + common_hal_never_reset_pin(args->busy_pin); } // Clear the color memory if it isn't in use. - if (highlight_color == 0x00 && write_color_ram_command != NO_COMMAND) { + if (args->highlight_color == 0x00 && args->highlight_color2 == 0x00 && args->write_color_ram_command != NO_COMMAND) { // TODO: Clear } @@ -151,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); @@ -189,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); @@ -199,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) { @@ -306,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); @@ -383,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/hashlib/Hash.c b/shared-module/hashlib/Hash.c index a454966d993..64fcf2d941f 100644 --- a/shared-module/hashlib/Hash.c +++ b/shared-module/hashlib/Hash.c @@ -7,11 +7,55 @@ #include "shared-bindings/hashlib/Hash.h" #include "shared-module/hashlib/__init__.h" +#include "mbedtls/version.h" + +#if MBEDTLS_VERSION_MAJOR >= 4 + +#include "psa/crypto.h" + +void common_hal_hashlib_hash_update(hashlib_hash_obj_t *self, const uint8_t *data, size_t datalen) { + 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; + } + // 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) { + return PSA_HASH_LENGTH(self->hash_alg); +} + +#else + #include "mbedtls/ssl.h" +// In mbedtls 2.x, the _ret suffix functions are the recommended API. +// In mbedtls 3.x, the _ret suffix was removed and the base names return int. +#if MBEDTLS_VERSION_MAJOR < 3 +#define SHA1_UPDATE mbedtls_sha1_update_ret +#define SHA1_FINISH mbedtls_sha1_finish_ret +#define SHA256_UPDATE mbedtls_sha256_update_ret +#define SHA256_FINISH mbedtls_sha256_finish_ret +#else +#define SHA1_UPDATE mbedtls_sha1_update +#define SHA1_FINISH mbedtls_sha1_finish +#define SHA256_UPDATE mbedtls_sha256_update +#define SHA256_FINISH mbedtls_sha256_finish +#endif + 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); + SHA1_UPDATE(&self->sha1, data, datalen); + return; + } else if (self->hash_type == MBEDTLS_SSL_HASH_SHA256) { + SHA256_UPDATE(&self->sha256, data, datalen); return; } } @@ -25,14 +69,23 @@ void common_hal_hashlib_hash_digest(hashlib_hash_obj_t *self, uint8_t *data, siz // the digest a second time. mbedtls_sha1_context copy; mbedtls_sha1_clone(©, &self->sha1); - mbedtls_sha1_finish_ret(&self->sha1, data); + SHA1_FINISH(&self->sha1, data); mbedtls_sha1_clone(&self->sha1, ©); + } else if (self->hash_type == MBEDTLS_SSL_HASH_SHA256) { + mbedtls_sha256_context copy; + mbedtls_sha256_clone(©, &self->sha256); + SHA256_FINISH(&self->sha256, data); + mbedtls_sha256_clone(&self->sha256, ©); } } size_t common_hal_hashlib_hash_get_digest_size(hashlib_hash_obj_t *self) { if (self->hash_type == MBEDTLS_SSL_HASH_SHA1) { return 20; + } else if (self->hash_type == MBEDTLS_SSL_HASH_SHA256) { + return 32; } return 0; } + +#endif diff --git a/shared-module/hashlib/Hash.h b/shared-module/hashlib/Hash.h index ccc82037cb7..035368e7c2f 100644 --- a/shared-module/hashlib/Hash.h +++ b/shared-module/hashlib/Hash.h @@ -6,13 +6,31 @@ #pragma once +#include "mbedtls/version.h" + +#if MBEDTLS_VERSION_MAJOR >= 4 + +#include "psa/crypto.h" + +typedef struct { + mp_obj_base_t base; + psa_hash_operation_t hash_op; + psa_algorithm_t hash_alg; +} hashlib_hash_obj_t; + +#else + #include "mbedtls/sha1.h" +#include "mbedtls/sha256.h" typedef struct { mp_obj_base_t base; union { mbedtls_sha1_context sha1; + mbedtls_sha256_context sha256; }; // Of MBEDTLS_SSL_HASH_* uint8_t hash_type; } hashlib_hash_obj_t; + +#endif diff --git a/shared-module/hashlib/__init__.c b/shared-module/hashlib/__init__.c index be3a9f18959..d2a19386431 100644 --- a/shared-module/hashlib/__init__.c +++ b/shared-module/hashlib/__init__.c @@ -7,15 +7,52 @@ #include "shared-bindings/hashlib/__init__.h" #include "shared-module/hashlib/__init__.h" +#include "mbedtls/version.h" + +#if MBEDTLS_VERSION_MAJOR >= 4 + +#include "psa/crypto.h" + +bool common_hal_hashlib_new(hashlib_hash_obj_t *self, const char *algorithm) { + if (strcmp(algorithm, "sha1") == 0) { + self->hash_alg = PSA_ALG_SHA_1; + } else if (strcmp(algorithm, "sha256") == 0) { + self->hash_alg = PSA_ALG_SHA_256; + } else { + return false; + } + self->hash_op = psa_hash_operation_init(); + psa_hash_setup(&self->hash_op, self->hash_alg); + return true; +} + +#else + #include "mbedtls/ssl.h" +// In mbedtls 2.x, the _ret suffix functions are the recommended API. +// In mbedtls 3.x, the _ret suffix was removed and the base names return int. +#if MBEDTLS_VERSION_MAJOR < 3 +#define SHA1_STARTS mbedtls_sha1_starts_ret +#define SHA256_STARTS mbedtls_sha256_starts_ret +#else +#define SHA1_STARTS mbedtls_sha1_starts +#define SHA256_STARTS mbedtls_sha256_starts +#endif 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); + SHA1_STARTS(&self->sha1); + return true; + } else if (strcmp(algorithm, "sha256") == 0) { + self->hash_type = MBEDTLS_SSL_HASH_SHA256; + mbedtls_sha256_init(&self->sha256); + SHA256_STARTS(&self->sha256, 0); return true; } return false; } + +#endif diff --git a/shared-module/hashlib/__init__.h b/shared-module/hashlib/__init__.h index f72882a1c03..847bd8a8347 100644 --- a/shared-module/hashlib/__init__.h +++ b/shared-module/hashlib/__init__.h @@ -13,4 +13,9 @@ #define mbedtls_sha1_starts_ret mbedtls_sha1_starts #define mbedtls_sha1_update_ret mbedtls_sha1_update #define mbedtls_sha1_finish_ret mbedtls_sha1_finish + +#define mbedtls_sha256_starts_ret mbedtls_sha256_starts +#define mbedtls_sha256_update_ret mbedtls_sha256_update +#define mbedtls_sha256_finish_ret mbedtls_sha256_finish + #endif 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..89cb624a8d0 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); diff --git a/shared-module/keypad/EventQueue.c b/shared-module/keypad/EventQueue.c index e5b362a045d..3130d8b59a1 100644 --- a/shared-module/keypad/EventQueue.c +++ b/shared-module/keypad/EventQueue.c @@ -15,9 +15,14 @@ #define EVENT_SIZE_BYTES (sizeof(uint16_t) + sizeof(mp_obj_t)) -void common_hal_keypad_eventqueue_construct(keypad_eventqueue_obj_t *self, size_t max_events) { +void common_hal_keypad_eventqueue_construct(keypad_eventqueue_obj_t *self, size_t max_events, bool use_gc_allocator) { // Event queue is 16-bit values. - ringbuf_alloc(&self->encoded_events, max_events * EVENT_SIZE_BYTES); + const size_t size = max_events * EVENT_SIZE_BYTES; + if (use_gc_allocator) { + ringbuf_alloc(&self->encoded_events, size); + } else { + ringbuf_init(&self->encoded_events, port_malloc(size, false), size); + } self->overflowed = false; self->event_handler = NULL; } diff --git a/shared-module/keypad/KeyMatrix.c b/shared-module/keypad/KeyMatrix.c index 67a55468535..28830f591b1 100644 --- a/shared-module/keypad/KeyMatrix.c +++ b/shared-module/keypad/KeyMatrix.c @@ -56,7 +56,7 @@ void common_hal_keypad_keymatrix_construct(keypad_keymatrix_obj_t *self, mp_uint self->columns_to_anodes = columns_to_anodes; self->funcs = &keymatrix_funcs; - keypad_construct_common((keypad_scanner_obj_t *)self, interval, max_events, debounce_threshold); + keypad_construct_common((keypad_scanner_obj_t *)self, interval, max_events, debounce_threshold, true); } void common_hal_keypad_keymatrix_deinit(keypad_keymatrix_obj_t *self) { diff --git a/shared-module/keypad/Keys.c b/shared-module/keypad/Keys.c index 39d50f95e32..80dcf36e163 100644 --- a/shared-module/keypad/Keys.c +++ b/shared-module/keypad/Keys.c @@ -41,7 +41,7 @@ void common_hal_keypad_keys_construct(keypad_keys_obj_t *self, mp_uint_t num_pin self->value_when_pressed = value_when_pressed; self->funcs = &keys_funcs; - keypad_construct_common((keypad_scanner_obj_t *)self, interval, max_events, debounce_threshold); + keypad_construct_common((keypad_scanner_obj_t *)self, interval, max_events, debounce_threshold, true); } diff --git a/shared-module/keypad/ShiftRegisterKeys.c b/shared-module/keypad/ShiftRegisterKeys.c index 97917434ff8..aa0c14dd36b 100644 --- a/shared-module/keypad/ShiftRegisterKeys.c +++ b/shared-module/keypad/ShiftRegisterKeys.c @@ -71,7 +71,7 @@ void common_hal_keypad_shiftregisterkeys_construct(keypad_shiftregisterkeys_obj_ self->value_when_pressed = value_when_pressed; self->funcs = &shiftregisterkeys_funcs; - keypad_construct_common((keypad_scanner_obj_t *)self, interval, max_events, debounce_threshold); + keypad_construct_common((keypad_scanner_obj_t *)self, interval, max_events, debounce_threshold, true); } void common_hal_keypad_shiftregisterkeys_deinit(keypad_shiftregisterkeys_obj_t *self) { diff --git a/shared-module/keypad/__init__.c b/shared-module/keypad/__init__.c index 3ffa0433174..f1d5d395df7 100644 --- a/shared-module/keypad/__init__.c +++ b/shared-module/keypad/__init__.c @@ -85,14 +85,20 @@ void keypad_deregister_scanner(keypad_scanner_obj_t *scanner) { supervisor_release_lock(&keypad_scanners_linked_list_lock); } -void keypad_construct_common(keypad_scanner_obj_t *self, mp_float_t interval, size_t max_events, uint8_t debounce_threshold) { +void keypad_construct_common(keypad_scanner_obj_t *self, mp_float_t interval, size_t max_events, uint8_t debounce_threshold, bool use_gc_allocator) { size_t key_count = common_hal_keypad_generic_get_key_count(self); - self->debounce_counter = (int8_t *)m_malloc_without_collect(sizeof(int8_t) * key_count); + self->debounce_counter = + use_gc_allocator + ? (int8_t *)m_malloc_without_collect(sizeof(int8_t) * key_count) + : (int8_t *)port_malloc_zero(sizeof(int8_t) * key_count, false); self->interval_ticks = (mp_uint_t)(interval * 1024); // interval * 1000 * (1024/1000) - keypad_eventqueue_obj_t *events = mp_obj_malloc(keypad_eventqueue_obj_t, &keypad_eventqueue_type); - common_hal_keypad_eventqueue_construct(events, max_events); + keypad_eventqueue_obj_t *events = + use_gc_allocator + ? mp_obj_malloc(keypad_eventqueue_obj_t, &keypad_eventqueue_type) + : mp_obj_port_malloc(keypad_eventqueue_obj_t, &keypad_eventqueue_type); + common_hal_keypad_eventqueue_construct(events, max_events, use_gc_allocator); self->events = events; self->debounce_threshold = debounce_threshold; diff --git a/shared-module/keypad/__init__.h b/shared-module/keypad/__init__.h index a7d21753f66..66fea487854 100644 --- a/shared-module/keypad/__init__.h +++ b/shared-module/keypad/__init__.h @@ -39,7 +39,7 @@ void keypad_reset(void); void keypad_register_scanner(keypad_scanner_obj_t *scanner); void keypad_deregister_scanner(keypad_scanner_obj_t *scanner); -void keypad_construct_common(keypad_scanner_obj_t *scanner, mp_float_t interval, size_t max_events, uint8_t debounce_cycles); +void keypad_construct_common(keypad_scanner_obj_t *scanner, mp_float_t interval, size_t max_events, uint8_t debounce_cycles, bool use_gc_allocator); bool keypad_debounce(keypad_scanner_obj_t *self, mp_uint_t key_number, bool current); void keypad_never_reset(keypad_scanner_obj_t *self); diff --git a/shared-module/keypad_demux/DemuxKeyMatrix.c b/shared-module/keypad_demux/DemuxKeyMatrix.c index b90669d772f..329f7679d3f 100644 --- a/shared-module/keypad_demux/DemuxKeyMatrix.c +++ b/shared-module/keypad_demux/DemuxKeyMatrix.c @@ -31,38 +31,45 @@ static mp_uint_t row_column_to_key_number(keypad_demux_demuxkeymatrix_obj_t *sel return row * common_hal_keypad_demux_demuxkeymatrix_get_column_count(self) + column; } -void common_hal_keypad_demux_demuxkeymatrix_construct(keypad_demux_demuxkeymatrix_obj_t *self, mp_uint_t num_row_addr_pins, const mcu_pin_obj_t *row_addr_pins[], mp_uint_t num_column_pins, const mcu_pin_obj_t *column_pins[], bool columns_to_anodes, bool transpose, mp_float_t interval, size_t max_events, uint8_t debounce_threshold) { - +void common_hal_keypad_demux_demuxkeymatrix_construct(keypad_demux_demuxkeymatrix_obj_t *self, mp_uint_t num_row_addr_pins, const mcu_pin_obj_t *row_addr_pins[], mp_uint_t num_column_pins, const mcu_pin_obj_t *column_pins[], bool columns_to_anodes, bool transpose, mp_float_t interval, size_t max_events, uint8_t debounce_threshold, bool use_gc_allocator) { // the multiplexed pins are outputs so we can set the address for the target row // the sense of the address pins themselves doesn't change with columns_to_anodes // but the value output on the selected row line will be !columns_to_anodes mp_obj_t row_addr_dios[num_row_addr_pins]; for (size_t row = 0; row < num_row_addr_pins; row++) { digitalio_digitalinout_obj_t *dio = - mp_obj_malloc(digitalio_digitalinout_obj_t, &digitalio_digitalinout_type); + use_gc_allocator + ? mp_obj_malloc(digitalio_digitalinout_obj_t, &digitalio_digitalinout_type) + : mp_obj_port_malloc(digitalio_digitalinout_obj_t, &digitalio_digitalinout_type); common_hal_digitalio_digitalinout_construct(dio, row_addr_pins[row]); common_hal_digitalio_digitalinout_switch_to_output(dio, false, DRIVE_MODE_PUSH_PULL); row_addr_dios[row] = dio; } - self->row_addr_digitalinouts = mp_obj_new_tuple(num_row_addr_pins, row_addr_dios); + self->row_addr_digitalinouts = + use_gc_allocator + ? mp_obj_new_tuple(num_row_addr_pins, row_addr_dios) + : mp_obj_new_port_tuple(num_row_addr_pins, row_addr_dios); // the column pins are always inputs, with default state based on columns_to_anodes mp_obj_t column_dios[num_column_pins]; for (size_t column = 0; column < num_column_pins; column++) { digitalio_digitalinout_obj_t *dio = - mp_obj_malloc(digitalio_digitalinout_obj_t, &digitalio_digitalinout_type); - dio->base.type = &digitalio_digitalinout_type; + use_gc_allocator + ? mp_obj_malloc(digitalio_digitalinout_obj_t, &digitalio_digitalinout_type) + : mp_obj_port_malloc(digitalio_digitalinout_obj_t, &digitalio_digitalinout_type); common_hal_digitalio_digitalinout_construct(dio, column_pins[column]); common_hal_digitalio_digitalinout_switch_to_input(dio, columns_to_anodes ? PULL_UP : PULL_DOWN); column_dios[column] = dio; } - self->column_digitalinouts = mp_obj_new_tuple(num_column_pins, column_dios); - + self->column_digitalinouts = + use_gc_allocator + ? mp_obj_new_tuple(num_column_pins, column_dios) + : mp_obj_new_port_tuple(num_column_pins, column_dios); self->columns_to_anodes = columns_to_anodes; self->transpose = transpose; self->funcs = &keymatrix_funcs; - keypad_construct_common((keypad_scanner_obj_t *)self, interval, max_events, debounce_threshold); + keypad_construct_common((keypad_scanner_obj_t *)self, interval, max_events, debounce_threshold, use_gc_allocator); } void common_hal_keypad_demux_demuxkeymatrix_deinit(keypad_demux_demuxkeymatrix_obj_t *self) { diff --git a/shared-module/lvfontio/OnDiskFont.c b/shared-module/lvfontio/OnDiskFont.c index 0cf65301d22..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]++; @@ -253,9 +259,16 @@ static bool load_font_header(lvfontio_ondiskfont_t *self, FIL *file, size_t *max *max_slots = advance_count[1] * 2 + advance_count[0]; } } + } else { + *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; } @@ -343,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; } @@ -573,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; @@ -721,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; @@ -738,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/msgpack/__init__.c b/shared-module/msgpack/__init__.c index a98fb02de39..7c3e664bb6c 100644 --- a/shared-module/msgpack/__init__.c +++ b/shared-module/msgpack/__init__.c @@ -394,7 +394,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); } @@ -462,7 +464,9 @@ static mp_obj_t unpack(msgpack_stream_t *s, mp_obj_t ext_hook, bool use_list) { size_t len = read_size(s, code - 0xde + 1); 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..3a9c0e31f8e 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. @@ -281,4 +285,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/sdcardio/SDCard.c b/shared-module/sdcardio/SDCard.c index bd3ea62d141..40d09aa99ca 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 @@ -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 a49a1506712..751e6f58127 100644 --- a/shared-module/sdcardio/__init__.c +++ b/shared-module/sdcardio/__init__.c @@ -6,8 +6,11 @@ #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" @@ -22,7 +25,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; @@ -45,7 +48,7 @@ void automount_sd_card(void) { 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 +66,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 +84,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 +109,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 +127,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; - #endif + _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/SSLSocket.c b/shared-module/ssl/SSLSocket.c index 8911fa2f454..70275945803 100644 --- a/shared-module/ssl/SSLSocket.c +++ b/shared-module/ssl/SSLSocket.c @@ -44,7 +44,7 @@ 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) { +static MP_NORETURN void mbedtls_raise_error(int err) { // _mbedtls_ssl_send and _mbedtls_ssl_recv (below) turn positive error codes from the // underlying socket into negative codes to pass them through mbedtls. Here we turn them // positive again so they get interpreted as the OSError they really are. The @@ -200,7 +200,7 @@ static int _mbedtls_ssl_recv(void *ctx, byte *buf, size_t len) { } -#if MBEDTLS_VERSION_MAJOR >= 3 +#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) { @@ -238,18 +238,24 @@ 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); + #if MBEDTLS_VERSION_MAJOR < 4 mbedtls_ctr_drbg_init(&o->ctr_drbg); + #endif #ifdef MBEDTLS_DEBUG_C // Debug level (0-4) 1=warning, 2=info, 3=debug, 4=verbose mbedtls_debug_set_threshold(4); #endif + #if MBEDTLS_VERSION_MAJOR < 4 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; } + #else + int ret; + #endif ret = mbedtls_ssl_config_defaults(&o->conf, server_side ? MBEDTLS_SSL_IS_SERVER : MBEDTLS_SSL_IS_CLIENT, @@ -273,7 +279,9 @@ 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); } + #if MBEDTLS_VERSION_MAJOR < 4 mbedtls_ssl_conf_rng(&o->conf, mbedtls_ctr_drbg_random, &o->ctr_drbg); + #endif #ifdef MBEDTLS_DEBUG_C mbedtls_ssl_conf_dbg(&o->conf, mbedtls_debug, NULL); #endif @@ -293,7 +301,9 @@ 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 + #if MBEDTLS_VERSION_MAJOR >= 4 + ret = mbedtls_pk_parse_key(&o->pkey, self->key_buf.buf, self->key_buf.len + 1, NULL, 0); + #elif 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); @@ -318,8 +328,10 @@ 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); + #if MBEDTLS_VERSION_MAJOR < 4 mbedtls_ctr_drbg_free(&o->ctr_drbg); mbedtls_entropy_free(&o->entropy); + #endif if (ret == MBEDTLS_ERR_SSL_ALLOC_FAILED) { mp_raise_type(&mp_type_MemoryError); @@ -382,8 +394,10 @@ 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); + #if MBEDTLS_VERSION_MAJOR < 4 mbedtls_ctr_drbg_free(&self->ctr_drbg); mbedtls_entropy_free(&self->entropy); + #endif } static void do_handshake(ssl_sslsocket_obj_t *self) { @@ -408,8 +422,10 @@ static void do_handshake(ssl_sslsocket_obj_t *self) { mbedtls_x509_crt_free(&self->cacert); mbedtls_ssl_free(&self->ssl); mbedtls_ssl_config_free(&self->conf); + #if MBEDTLS_VERSION_MAJOR < 4 mbedtls_ctr_drbg_free(&self->ctr_drbg); mbedtls_entropy_free(&self->entropy); + #endif if (ret == MBEDTLS_ERR_SSL_ALLOC_FAILED) { mp_raise_type(&mp_type_MemoryError); diff --git a/shared-module/ssl/SSLSocket.h b/shared-module/ssl/SSLSocket.h index f7f3d1ae83c..9373734d27c 100644 --- a/shared-module/ssl/SSLSocket.h +++ b/shared-module/ssl/SSLSocket.h @@ -15,15 +15,20 @@ #include "mbedtls/ssl.h" #include "mbedtls/x509_crt.h" #include "mbedtls/pk.h" +#include "mbedtls/version.h" +#if MBEDTLS_VERSION_MAJOR < 4 #include "mbedtls/entropy.h" #include "mbedtls/ctr_drbg.h" +#endif typedef struct ssl_sslsocket_obj { mp_obj_base_t base; mp_obj_t sock_obj; ssl_sslcontext_obj_t *ssl_context; + #if MBEDTLS_VERSION_MAJOR < 4 mbedtls_entropy_context entropy; mbedtls_ctr_drbg_context ctr_drbg; + #endif 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 9a2c8271222..dedcee1ff23 100644 --- a/shared-module/storage/__init__.c +++ b/shared-module/storage/__init__.c @@ -126,6 +126,11 @@ void common_hal_storage_mount(mp_obj_t vfs_obj, const char *mount_path, bool rea // call the underlying object to do any mounting operation mp_vfs_proxy_call(vfs, MP_QSTR_mount, 2, (mp_obj_t *)&args); + fs_user_mount_t *vfs_fat = MP_OBJ_TO_PTR(vfs_obj); + // Filesystem is read-only to USB if writable by CircuitPython, and vice versa. + filesystem_set_writable_by_usb(vfs_fat, readonly); + filesystem_set_concurrent_write_protection(vfs_fat, true); + // Insert the vfs into the mount table by pushing it onto the front of the // mount table. mp_vfs_mount_t **vfsp = &MP_STATE_VM(vfs_mount_table); diff --git a/shared-module/struct/__init__.c b/shared-module/struct/__init__.c index 715b5043021..4b6b2b589ef 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")); } diff --git a/shared-module/synthio/MidiTrack.c b/shared-module/synthio/MidiTrack.c index 94430289bda..1cccd440fad 100644 --- a/shared-module/synthio/MidiTrack.c +++ b/shared-module/synthio/MidiTrack.c @@ -116,6 +116,16 @@ mp_int_t common_hal_synthio_miditrack_get_error_location(synthio_miditrack_obj_t return self->error_location; } +mp_int_t common_hal_synthio_miditrack_get_tempo(synthio_miditrack_obj_t *self) { + return self->tempo; +} + +void common_hal_synthio_miditrack_set_tempo(synthio_miditrack_obj_t *self, mp_int_t value) { + mp_int_t val = mp_arg_validate_int_min(value, 1, MP_QSTR_tempo); + self->synth.span.dur = (uint32_t)self->synth.span.dur * self->tempo / val; + self->tempo = val; +} + void synthio_miditrack_reset_buffer(synthio_miditrack_obj_t *self, bool single_channel_output, uint8_t channel) { synthio_synth_reset_buffer(&self->synth, single_channel_output, channel); diff --git a/shared-module/usb/core/Device.c b/shared-module/usb/core/Device.c index c9df0cf7380..83def37de91 100644 --- a/shared-module/usb/core/Device.c +++ b/shared-module/usb/core/Device.c @@ -1,12 +1,15 @@ // 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) 2025 Sam Blenny // // SPDX-License-Identifier: MIT #include "shared-bindings/usb/core/Device.h" #include "tusb_config.h" +#include "supervisor/port.h" +#include "supervisor/port_heap.h" #include "lib/tinyusb/src/host/hcd.h" #include "lib/tinyusb/src/host/usbh.h" @@ -32,6 +35,28 @@ void tuh_umount_cb(uint8_t dev_addr) { static xfer_result_t _xfer_result; static size_t _actual_len; + +#if !CIRCUITPY_ALL_MEMORY_DMA_CAPABLE +// Helper to ensure buffer is DMA-capable for transfer operations +static uint8_t *_ensure_dma_buffer(usb_core_device_obj_t *self, const uint8_t *buffer, size_t len, bool for_write) { + if (port_buffer_is_dma_capable(buffer)) { + return (uint8_t *)buffer; // Already DMA-capable, use directly + } + + uint8_t *dma_buffer = port_malloc(len, true); // true = DMA capable + if (dma_buffer == NULL) { + return NULL; // Allocation failed + } + + // Copy data to DMA buffer if writing + if (for_write && buffer != NULL) { + memcpy(dma_buffer, buffer, len); + } + + return dma_buffer; +} + +#endif bool common_hal_usb_core_device_construct(usb_core_device_obj_t *self, uint8_t device_address) { if (!tuh_inited()) { mp_raise_RuntimeError(MP_ERROR_TEXT("No usb host port initialized")); @@ -45,7 +70,7 @@ bool common_hal_usb_core_device_construct(usb_core_device_obj_t *self, uint8_t d } self->device_address = device_address; self->first_langid = 0; - _xfer_result = 0xff; + _xfer_result = XFER_RESULT_INVALID; return true; } @@ -70,14 +95,18 @@ void common_hal_usb_core_device_deinit(usb_core_device_obj_t *self) { uint16_t common_hal_usb_core_device_get_idVendor(usb_core_device_obj_t *self) { uint16_t vid; uint16_t pid; - tuh_vid_pid_get(self->device_address, &vid, &pid); + if (!tuh_vid_pid_get(self->device_address, &vid, &pid)) { + mp_raise_usb_core_USBError(NULL); + } return vid; } uint16_t common_hal_usb_core_device_get_idProduct(usb_core_device_obj_t *self) { uint16_t vid; uint16_t pid; - tuh_vid_pid_get(self->device_address, &vid, &pid); + if (!tuh_vid_pid_get(self->device_address, &vid, &pid)) { + mp_raise_usb_core_USBError(NULL); + } return pid; } @@ -91,14 +120,109 @@ static void _transfer_done_cb(tuh_xfer_t *xfer) { static bool _wait_for_callback(void) { while (!mp_hal_is_interrupted() && - _xfer_result == 0xff) { + _xfer_result == XFER_RESULT_INVALID) { + // The background tasks include TinyUSB which will call the function + // we provided above. In other words, the callback isn't in an interrupt. + RUN_BACKGROUND_TASKS; + } + if (mp_hal_is_interrupted()) { + // Handle case of VM being interrupted by Ctrl-C or autoreload + return false; + } + // Handle callback result code from TinyUSB + xfer_result_t result = _xfer_result; + _xfer_result = XFER_RESULT_INVALID; + switch (result) { + case XFER_RESULT_SUCCESS: + return true; + case XFER_RESULT_FAILED: + mp_raise_usb_core_USBError(NULL); + break; + case XFER_RESULT_STALLED: + mp_raise_usb_core_USBError(MP_ERROR_TEXT("Pipe error")); + break; + case XFER_RESULT_TIMEOUT: + case XFER_RESULT_INVALID: + mp_raise_usb_core_USBTimeoutError(); + break; + } + return false; +} + +static void _prepare_for_transfer(void) { + // Prepare for transfer. Unless there is a timeout, these static globals will + // get modified by the _transfer_done_cb() callback when tinyusb finishes the + // transfer or encounters an error condition. + _xfer_result = XFER_RESULT_INVALID; + _actual_len = 0; +} + +static void _abort_transfer(tuh_xfer_t *xfer) { + bool aborted = tuh_edpt_abort_xfer(xfer->daddr, xfer->ep_addr); + if (aborted) { + // If the transfer was aborted, then we can continue. + return; + } + uint32_t start_time = supervisor_ticks_ms32(); + // If not, we need to wait for it to finish, otherwise we may free memory out from under it. + // Limit the wait time to 10 milliseconds to avoid blocking indefinitely. + while (_xfer_result == XFER_RESULT_INVALID && (supervisor_ticks_ms32() - start_time < 10)) { + // The background tasks include TinyUSB which will call the function + // we provided above. In other words, the callback isn't in an interrupt. + RUN_BACKGROUND_TASKS; + } +} + +// 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) { + if (xfer == NULL) { + mp_raise_usb_core_USBError(NULL); + return 0; + } + uint32_t start_time = supervisor_ticks_ms32(); + while ((timeout == 0 || supervisor_ticks_ms32() - start_time < (uint32_t)timeout) && + !mp_hal_is_interrupted() && + _xfer_result == XFER_RESULT_INVALID) { // The background tasks include TinyUSB which will call the function // we provided above. In other words, the callback isn't in an interrupt. RUN_BACKGROUND_TASKS; } + if (mp_hal_is_interrupted()) { + // Handle case of VM being interrupted by Ctrl-C or autoreload + _abort_transfer(xfer); + return 0; + } + // Handle transfer result code from TinyUSB xfer_result_t result = _xfer_result; - _xfer_result = 0xff; - return result == XFER_RESULT_SUCCESS; + _xfer_result = XFER_RESULT_INVALID; + if (our_buffer && result != XFER_RESULT_SUCCESS && result != XFER_RESULT_INVALID) { + port_free(xfer->buffer); + } + switch (result) { + case XFER_RESULT_SUCCESS: + return _actual_len; + case XFER_RESULT_FAILED: + mp_raise_usb_core_USBError(NULL); + break; + case XFER_RESULT_STALLED: + mp_raise_usb_core_USBError(MP_ERROR_TEXT("Pipe error")); + break; + 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) + 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. + _abort_transfer(xfer); + if (our_buffer) { + port_free(xfer->buffer); + } + mp_raise_usb_core_USBTimeoutError(); + break; + } + return 0; } static mp_obj_t _get_string(const uint16_t *temp_buf) { @@ -115,41 +239,75 @@ static void _get_langid(usb_core_device_obj_t *self) { } // Two control bytes and one uint16_t language code. uint16_t temp_buf[2]; - if (!tuh_descriptor_get_string(self->device_address, 0, 0, temp_buf, sizeof(temp_buf), _transfer_done_cb, 0) || - !_wait_for_callback()) { - return; + _prepare_for_transfer(); + if (!tuh_descriptor_get_string(self->device_address, 0, 0, temp_buf, sizeof(temp_buf), _transfer_done_cb, 0)) { + mp_raise_usb_core_USBError(NULL); + } else if (_wait_for_callback()) { + self->first_langid = temp_buf[1]; } - self->first_langid = temp_buf[1]; } mp_obj_t common_hal_usb_core_device_get_serial_number(usb_core_device_obj_t *self) { uint16_t temp_buf[127]; - _get_langid(self); - if (!tuh_descriptor_get_serial_string(self->device_address, self->first_langid, temp_buf, sizeof(temp_buf), _transfer_done_cb, 0) || - !_wait_for_callback()) { + tusb_desc_device_t descriptor; + // First, be sure not to ask TinyUSB for a non-existent string (avoid error) + if (!tuh_descriptor_get_device_local(self->device_address, &descriptor)) { return mp_const_none; } - return _get_string(temp_buf); + if (descriptor.iSerialNumber == 0) { + return mp_const_none; + } + // Device does provide this string, so continue + _get_langid(self); + _prepare_for_transfer(); + if (!tuh_descriptor_get_serial_string(self->device_address, self->first_langid, temp_buf, sizeof(temp_buf), _transfer_done_cb, 0)) { + mp_raise_usb_core_USBError(NULL); + } else if (_wait_for_callback()) { + return _get_string(temp_buf); + } + return mp_const_none; } mp_obj_t common_hal_usb_core_device_get_product(usb_core_device_obj_t *self) { uint16_t temp_buf[127]; - _get_langid(self); - if (!tuh_descriptor_get_product_string(self->device_address, self->first_langid, temp_buf, sizeof(temp_buf), _transfer_done_cb, 0) || - !_wait_for_callback()) { + tusb_desc_device_t descriptor; + // First, be sure not to ask TinyUSB for a non-existent string (avoid error) + if (!tuh_descriptor_get_device_local(self->device_address, &descriptor)) { + return mp_const_none; + } + if (descriptor.iProduct == 0) { return mp_const_none; } - return _get_string(temp_buf); + // Device does provide this string, so continue + _get_langid(self); + _prepare_for_transfer(); + if (!tuh_descriptor_get_product_string(self->device_address, self->first_langid, temp_buf, sizeof(temp_buf), _transfer_done_cb, 0)) { + mp_raise_usb_core_USBError(NULL); + } else if (_wait_for_callback()) { + return _get_string(temp_buf); + } + return mp_const_none; } mp_obj_t common_hal_usb_core_device_get_manufacturer(usb_core_device_obj_t *self) { uint16_t temp_buf[127]; - _get_langid(self); - if (!tuh_descriptor_get_manufacturer_string(self->device_address, self->first_langid, temp_buf, sizeof(temp_buf), _transfer_done_cb, 0) || - !_wait_for_callback()) { + tusb_desc_device_t descriptor; + // First, be sure not to ask TinyUSB for a non-existent string (avoid error) + if (!tuh_descriptor_get_device_local(self->device_address, &descriptor)) { + return mp_const_none; + } + if (descriptor.iManufacturer == 0) { return mp_const_none; } - return _get_string(temp_buf); + // Device does provide this string, so continue + _get_langid(self); + _prepare_for_transfer(); + if (!tuh_descriptor_get_manufacturer_string(self->device_address, self->first_langid, temp_buf, sizeof(temp_buf), _transfer_done_cb, 0)) { + mp_raise_usb_core_USBError(NULL); + } else if (_wait_for_callback()) { + return _get_string(temp_buf); + } + return mp_const_none; } @@ -224,39 +382,18 @@ void common_hal_usb_core_device_set_configuration(usb_core_device_obj_t *self, m _wait_for_callback(); } -static size_t _xfer(tuh_xfer_t *xfer, mp_int_t timeout) { - _xfer_result = 0xff; +// 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) { + _prepare_for_transfer(); xfer->complete_cb = _transfer_done_cb; if (!tuh_edpt_xfer(xfer)) { + if (our_buffer) { + port_free(xfer->buffer); + } mp_raise_usb_core_USBError(NULL); return 0; } - uint32_t start_time = supervisor_ticks_ms32(); - while ((timeout == 0 || supervisor_ticks_ms32() - start_time < (uint32_t)timeout) && - !mp_hal_is_interrupted() && - _xfer_result == 0xff) { - // The background tasks include TinyUSB which will call the function - // we provided above. In other words, the callback isn't in an interrupt. - RUN_BACKGROUND_TASKS; - } - if (mp_hal_is_interrupted()) { - tuh_edpt_abort_xfer(xfer->daddr, xfer->ep_addr); - return 0; - } - xfer_result_t result = _xfer_result; - _xfer_result = 0xff; - if (result == XFER_RESULT_STALLED) { - mp_raise_usb_core_USBError(MP_ERROR_TEXT("Pipe error")); - } - if (result == 0xff) { - tuh_edpt_abort_xfer(xfer->daddr, xfer->ep_addr); - mp_raise_usb_core_USBTimeoutError(); - } - if (result == XFER_RESULT_SUCCESS) { - return _actual_len; - } - - return 0; + return _handle_timed_transfer_callback(xfer, timeout, our_buffer); } static bool _open_endpoint(usb_core_device_obj_t *self, mp_int_t endpoint) { @@ -313,12 +450,30 @@ mp_int_t common_hal_usb_core_device_write(usb_core_device_obj_t *self, mp_int_t mp_raise_usb_core_USBError(NULL); return 0; } + + #if !CIRCUITPY_ALL_MEMORY_DMA_CAPABLE + // Ensure buffer is in DMA-capable memory + uint8_t *dma_buffer = _ensure_dma_buffer(self, buffer, len, true); // true = for write + if (dma_buffer == NULL) { + mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT("Could not allocate DMA capable buffer")); + return 0; + } + #else + uint8_t *dma_buffer = (uint8_t *)buffer; // All memory is DMA-capable + #endif + tuh_xfer_t xfer; xfer.daddr = self->device_address; xfer.ep_addr = endpoint; - xfer.buffer = (uint8_t *)buffer; + xfer.buffer = dma_buffer; xfer.buflen = len; - return _xfer(&xfer, timeout); + size_t result = _xfer(&xfer, timeout, dma_buffer != buffer); + #if !CIRCUITPY_ALL_MEMORY_DMA_CAPABLE + if (dma_buffer != buffer) { + port_free(dma_buffer); + } + #endif + 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) { @@ -326,12 +481,34 @@ mp_int_t common_hal_usb_core_device_read(usb_core_device_obj_t *self, mp_int_t e mp_raise_usb_core_USBError(NULL); return 0; } + + #if !CIRCUITPY_ALL_MEMORY_DMA_CAPABLE + // Ensure buffer is in DMA-capable memory + uint8_t *dma_buffer = _ensure_dma_buffer(self, buffer, len, false); // false = for read + if (dma_buffer == NULL) { + mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT("Could not allocate DMA capable buffer")); + return 0; + } + #else + uint8_t *dma_buffer = buffer; // All memory is DMA-capable + #endif + tuh_xfer_t xfer; xfer.daddr = self->device_address; xfer.ep_addr = endpoint; - xfer.buffer = buffer; + xfer.buffer = dma_buffer; xfer.buflen = len; - return _xfer(&xfer, timeout); + mp_int_t result = _xfer(&xfer, timeout, dma_buffer != buffer); + + #if !CIRCUITPY_ALL_MEMORY_DMA_CAPABLE + // Copy data back to original buffer if needed + if (dma_buffer != buffer) { + memcpy(buffer, dma_buffer, result); + port_free(dma_buffer); + } + #endif + + return result; } mp_int_t common_hal_usb_core_device_ctrl_transfer(usb_core_device_obj_t *self, @@ -340,6 +517,23 @@ mp_int_t common_hal_usb_core_device_ctrl_transfer(usb_core_device_obj_t *self, uint8_t *buffer, mp_int_t len, mp_int_t timeout) { // Timeout is in ms. + #if !CIRCUITPY_ALL_MEMORY_DMA_CAPABLE + // Determine if this is a write (host-to-device) or read (device-to-host) transfer + bool is_write = (bmRequestType & 0x80) == 0; // Bit 7: 0=host-to-device, 1=device-to-host + + // Ensure buffer is in DMA-capable memory + uint8_t *dma_buffer = NULL; + if (len > 0 && buffer != NULL) { + dma_buffer = _ensure_dma_buffer(self, buffer, len, is_write); + if (dma_buffer == NULL) { + mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT("Could not allocate DMA capable buffer")); + return 0; + } + } + #else + uint8_t *dma_buffer = buffer; // All memory is DMA-capable + #endif + tusb_control_request_t request = { .bmRequestType = bmRequestType, .bRequest = bRequest, @@ -351,42 +545,28 @@ mp_int_t common_hal_usb_core_device_ctrl_transfer(usb_core_device_obj_t *self, .daddr = self->device_address, .ep_addr = 0, .setup = &request, - .buffer = buffer, + .buffer = dma_buffer, .complete_cb = _transfer_done_cb, }; - _xfer_result = 0xff; - + _prepare_for_transfer(); if (!tuh_control_xfer(&xfer)) { mp_raise_usb_core_USBError(NULL); return 0; } - uint32_t start_time = supervisor_ticks_ms32(); - while ((timeout == 0 || supervisor_ticks_ms32() - start_time < (uint32_t)timeout) && - !mp_hal_is_interrupted() && - _xfer_result == 0xff) { - // The background tasks include TinyUSB which will call the function - // we provided above. In other words, the callback isn't in an interrupt. - RUN_BACKGROUND_TASKS; - } - if (mp_hal_is_interrupted()) { - tuh_edpt_abort_xfer(xfer.daddr, xfer.ep_addr); - return 0; - } - xfer_result_t result = _xfer_result; - _xfer_result = 0xff; - if (result == XFER_RESULT_STALLED) { - mp_raise_usb_core_USBError(MP_ERROR_TEXT("Pipe error")); - } - if (result == 0xff) { - tuh_edpt_abort_xfer(xfer.daddr, xfer.ep_addr); - mp_raise_usb_core_USBTimeoutError(); - } - if (result == XFER_RESULT_SUCCESS) { - return len; + mp_int_t result = (mp_int_t)_handle_timed_transfer_callback(&xfer, timeout, dma_buffer != buffer); + + #if !CIRCUITPY_ALL_MEMORY_DMA_CAPABLE + if (dma_buffer != buffer) { + // Copy data back to original buffer if this was a read transfer + if (buffer != NULL && !is_write) { + memcpy(buffer, dma_buffer, result); + } + port_free(dma_buffer); } + #endif - return 0; + return result; } bool common_hal_usb_core_device_is_kernel_driver_active(usb_core_device_obj_t *self, mp_int_t interface) { diff --git a/shared-module/usb_audio/USBMicrophone.c b/shared-module/usb_audio/USBMicrophone.c new file mode 100644 index 00000000000..fd5309abeb9 --- /dev/null +++ b/shared-module/usb_audio/USBMicrophone.c @@ -0,0 +1,149 @@ +// 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/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 mono PCM. For this step the + // bound sample is assumed to already be in that format (e.g. a 16-bit signed + // mono 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; + } + } + + size_t n = MIN(self->buffer_length, max_bytes - filled); + memcpy(out + filled, self->buffer, n); + self->buffer += n; + self->buffer_length -= n; + filled += n; + } + + 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..12921430bc3 --- /dev/null +++ b/shared-module/usb_audio/USBSpeaker.c @@ -0,0 +1,227 @@ +// 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(). + size_t bytes_per_frame = (self->base.bits_per_sample / 8) * self->base.channel_count; + size_t want = (size_t)length * 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 % bytes_per_frame; + + size_t first = MIN(to_copy, USB_AUDIO_SPEAKER_RING_SIZE - self->ring_tail); + memcpy(buffer, &self->ring[self->ring_tail], first); + if (to_copy > first) { + memcpy((uint8_t *)buffer + first, &self->ring[0], to_copy - first); + } + 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 / bytes_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); + + size_t first = MIN(to_copy, USB_AUDIO_SPEAKER_RING_SIZE - self->ring_tail); + memcpy(out, &self->ring[self->ring_tail], first); + if (to_copy > first) { + memcpy(out + first, &self->ring[0], to_copy - first); + } + self->ring_tail = (self->ring_tail + to_copy) % USB_AUDIO_SPEAKER_RING_SIZE; + self->ring_count -= to_copy; + + if (to_copy < half) { + // 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 + to_copy, 0, half - to_copy); + } + + // Mono only for v1, so the single-channel offset is always 0; 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 = half; + // 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..8c06cff519d --- /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 (mono 16-bit for v1). +#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..5964b8acf78 --- /dev/null +++ b/shared-module/usb_audio/__init__.c @@ -0,0 +1,623 @@ +// 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/shared/tick.h" +#include "tusb.h" + +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; +uint8_t usb_audio_bits_per_sample; +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, mp_int_t bits_per_sample, bool microphone, bool speaker) { + if (tud_connected()) { + return false; + } + + usb_audio_sample_rate = sample_rate; + usb_audio_channel_count = channel_count; + usb_audio_bits_per_sample = bits_per_sample; + 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; + 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 mono speaker (host -> board) descriptor WITHOUT an async +// feedback endpoint. This mirrors TinyUSB's TUD_AUDIO_SPEAKER_MONO_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_AUDIO_DESC_IAD(/*_firstitf*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00), \ + /* Standard AC Interface Descriptor(4.7.1) */ \ + TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx), \ + /* Class-Specific AC Interface Header Descriptor(4.7.2) */ \ + TUD_AUDIO_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO_FUNC_DESKTOP_SPEAKER, /*_totallen*/ TUD_AUDIO_DESC_CLK_SRC_LEN + TUD_AUDIO_DESC_INPUT_TERM_LEN + TUD_AUDIO_DESC_OUTPUT_TERM_LEN + TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN, /*_ctrl*/ AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS), \ + /* Clock Source Descriptor(4.7.2.1) */ \ + TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_attr*/ AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK, /*_ctrl*/ (AUDIO_CTRL_R << AUDIO_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_AUDIO_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*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00), \ + /* Output Terminal Descriptor(4.7.2.5) -- desktop speaker */ \ + TUD_AUDIO_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_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL(/*_unitid*/ USB_AUDIO_ENTITY_FEATURE_UNIT, /*_srcid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_ctrlch0master*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_stridx*/ 0x00), \ + /* Standard AS Interface Descriptor(4.9.1) -- alt 0, zero bandwidth */ \ + TUD_AUDIO_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_AUDIO_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_AUDIO_DESC_CS_AS_INT(/*_termid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00), \ + /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */ \ + TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample), \ + /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */ \ + TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_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_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000) + +// Hand-rolled UAC2 mono 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 +// TUD_AUDIO_MIC_ONE_CH_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_AUDIO_DESC_IAD(/*_firstitf*/ _itfnum, /*_nitfs*/ 0x03, /*_stridx*/ 0x00), \ + /* Standard AC Interface Descriptor(4.7.1) */ \ + TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx), \ + /* Class-Specific AC Interface Header Descriptor(4.7.2) -- clock + both chains */ \ + TUD_AUDIO_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO_FUNC_HEADSET, /*_totallen*/ TUD_AUDIO_DESC_CLK_SRC_LEN + 2 * (TUD_AUDIO_DESC_INPUT_TERM_LEN + TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN + TUD_AUDIO_DESC_OUTPUT_TERM_LEN), /*_ctrl*/ AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS), \ + /* Clock Source Descriptor(4.7.2.1) -- shared by both chains */ \ + TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ USB_AUDIO_HS_ENTITY_CLOCK_SOURCE, /*_attr*/ AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK, /*_ctrl*/ (AUDIO_CTRL_R << AUDIO_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_AUDIO_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*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00), \ + /* Feature Unit Descriptor(4.7.2.8) */ \ + TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL(/*_unitid*/ USB_AUDIO_HS_ENTITY_SPK_FEATURE_UNIT, /*_srcid*/ USB_AUDIO_HS_ENTITY_SPK_INPUT_TERMINAL, /*_ctrlch0master*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_stridx*/ 0x00), \ + /* Output Terminal Descriptor(4.7.2.5) -- desktop speaker */ \ + TUD_AUDIO_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_AUDIO_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*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS, /*_stridx*/ 0x00), \ + /* Feature Unit Descriptor(4.7.2.8) */ \ + TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL(/*_unitid*/ USB_AUDIO_HS_ENTITY_MIC_FEATURE_UNIT, /*_srcid*/ USB_AUDIO_HS_ENTITY_MIC_INPUT_TERMINAL, /*_ctrlch0master*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_stridx*/ 0x00), \ + /* Output Terminal Descriptor(4.7.2.5) -- USB streaming out to the host */ \ + TUD_AUDIO_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_AUDIO_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_AUDIO_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_AUDIO_DESC_CS_AS_INT(/*_termid*/ USB_AUDIO_HS_ENTITY_SPK_INPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00), \ + /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */ \ + TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample), \ + /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */ \ + TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_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_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_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_AUDIO_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_AUDIO_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_AUDIO_DESC_CS_AS_INT(/*_termid*/ USB_AUDIO_HS_ENTITY_MIC_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00), \ + /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */ \ + TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample), \ + /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */ \ + TUD_AUDIO_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_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_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 TUD_AUDIO_MIC_ONE_CH_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. This + // needs two isochronous endpoints, so it cannot be served by ports that + // pin ISO to a single dedicated endpoint number (forced_iso_ep, e.g. + // nRF52, which has only one ISO-capable endpoint). On those ports the + // sequential numbers below will not match the hardware's required ISO + // endpoint and the stream will not open; INPUT_OUTPUT is effectively + // unsupported there. The sequential-allocation ports (e.g. RP2) take a + // distinct number for each direction. + const uint8_t ep_out = descriptor_counts->current_endpoint; + const uint8_t ep_in = 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 + // one OUT and one IN endpoint. + descriptor_counts->current_interface += 3; + descriptor_counts->num_out_endpoints++; + descriptor_counts->num_in_endpoints++; + 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"); + 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) + }; + + // The AudioStreaming interface follows the AudioControl interface. + usb_audio_spk_as_itf = descriptor_counts->current_interface + 1; + + (*current_interface_string)++; + // One IAD wrapping an AudioControl + an AudioStreaming interface, plus one OUT endpoint. + descriptor_counts->current_interface += 2; + if (!forced_iso_ep) { + descriptor_counts->num_out_endpoints++; + descriptor_counts->current_endpoint++; + } + + memcpy(descriptor_buf, usb_audio_descriptor, sizeof(usb_audio_descriptor)); + + return sizeof(usb_audio_descriptor); + } + + usb_add_interface_string(*current_interface_string, "CircuitPython Microphone"); + const uint8_t usb_audio_descriptor[] = { + TUD_AUDIO_MIC_ONE_CH_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) + }; + + // The AudioStreaming interface follows the AudioControl interface. + usb_audio_mic_as_itf = descriptor_counts->current_interface + 1; + + (*current_interface_string)++; + // One IAD wrapping an AudioControl + an AudioStreaming interface, plus one IN endpoint. + descriptor_counts->current_interface += 2; + if (!forced_iso_ep) { + descriptor_counts->num_in_endpoints++; + descriptor_counts->current_endpoint++; + } + + 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; + + // One scratch chunk (1 ms at the max rate); we loop until the FIFO reaches + // the setpoint. Sized for the highest rate enable() accepts. + static int16_t samples[USB_AUDIO_MAX_SAMPLE_RATE / 1000 * USB_AUDIO_N_CHANNELS]; + + uint16_t count; + while ((count = tu_fifo_count(ep_in_ff)) < target) { + size_t want = target - count; + if (want > sizeof(samples)) { + want = sizeof(samples); + } + + // Pull the next chunk from whichever USBMicrophone is playing. + bool underran = false; + size_t filled = usb_audio_usbmicrophone_background_fill((uint8_t *)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 *)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 *)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; + } + 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 == AUDIO_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 (mono, cosmetic for now). + 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 AUDIO_FU_CTRL_MUTE: + TU_VERIFY(p_request->wLength == sizeof(audio_control_cur_1_t)); + usb_audio_mute[channelNum] = ((audio_control_cur_1_t *)pBuff)->bCur; + return true; + + case AUDIO_FU_CTRL_VOLUME: + TU_VERIFY(p_request->wLength == sizeof(audio_control_cur_2_t)); + usb_audio_volume[channelNum] = ((audio_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 AUDIO_TE_CTRL_CONNECTOR: { + audio_desc_channel_cluster_t ret; + ret.bNrChannels = USB_AUDIO_N_CHANNELS; + ret.bmChannelConfig = (audio_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 AUDIO_FU_CTRL_MUTE: + return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &usb_audio_mute[channelNum], sizeof(usb_audio_mute[channelNum])); + + case AUDIO_FU_CTRL_VOLUME: + switch (p_request->bRequest) { + case AUDIO_CS_REQ_CUR: + return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &usb_audio_volume[channelNum], sizeof(usb_audio_volume[channelNum])); + + case AUDIO_CS_REQ_RANGE: { + audio_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 AUDIO_CS_CTRL_SAM_FREQ: + switch (p_request->bRequest) { + case AUDIO_CS_REQ_CUR: { + audio_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 AUDIO_CS_REQ_RANGE: { + audio_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 AUDIO_CS_CTRL_CLK_VALID: { + audio_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..8ec13f90853 --- /dev/null +++ b/shared-module/usb_audio/__init__.h @@ -0,0 +1,60 @@ +// 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, mp_int_t bits_per_sample, 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; +extern uint8_t usb_audio_bits_per_sample; + +// 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..1313e198959 --- /dev/null +++ b/shared-module/usb_audio/usb_audio_descriptors.h @@ -0,0 +1,127 @@ +// 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). Declared here -- in the +// dependency-free header tusb_config.h already includes -- because TinyUSB's +// audio class driver reads CFG_TUD_AUDIO_FUNC_1_DESC_LEN at enumeration time and +// returns it to the device core as the number of configuration-descriptor bytes +// the function owns. 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 core 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) + +// 16-bit signed LE PCM, mono. +#define USB_AUDIO_N_BYTES_PER_SAMPLE (2) +#define USB_AUDIO_N_CHANNELS (1) +#define USB_AUDIO_BITS_PER_SAMPLE (USB_AUDIO_N_BYTES_PER_SAMPLE * 8) + +// 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 TUD_AUDIO_MIC_ONE_CH_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 mono speaker descriptor. It uses the same set of +// sub-descriptors as TUD_AUDIO_MIC_ONE_CH_DESCRIPTOR (one isochronous data +// endpoint, no feedback endpoint), so this is identical to +// TUD_AUDIO_MIC_ONE_CH_DESC_LEN -- but spell it out independently so the two +// can diverge later (e.g. stereo) without silently mis-sizing the descriptor. +// These TUD_AUDIO_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_AUDIO_DESC_IAD_LEN \ + + TUD_AUDIO_DESC_STD_AC_LEN \ + + TUD_AUDIO_DESC_CS_AC_LEN \ + + TUD_AUDIO_DESC_CLK_SRC_LEN \ + + TUD_AUDIO_DESC_INPUT_TERM_LEN \ + + TUD_AUDIO_DESC_OUTPUT_TERM_LEN \ + + TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN \ + + TUD_AUDIO_DESC_STD_AS_INT_LEN \ + + TUD_AUDIO_DESC_STD_AS_INT_LEN \ + + TUD_AUDIO_DESC_CS_AS_INT_LEN \ + + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN \ + + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN \ + + TUD_AUDIO_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_AUDIO_DESC_IAD_LEN \ + + TUD_AUDIO_DESC_STD_AC_LEN \ + + TUD_AUDIO_DESC_CS_AC_LEN \ + + TUD_AUDIO_DESC_CLK_SRC_LEN \ + /* speaker chain: USB-streaming input terminal -> feature unit -> speaker */ \ + + TUD_AUDIO_DESC_INPUT_TERM_LEN \ + + TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN \ + + TUD_AUDIO_DESC_OUTPUT_TERM_LEN \ + /* mic chain: microphone input terminal -> feature unit -> USB-streaming out */ \ + + TUD_AUDIO_DESC_INPUT_TERM_LEN \ + + TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN \ + + TUD_AUDIO_DESC_OUTPUT_TERM_LEN \ + /* speaker AudioStreaming interface (alt 0 + alt 1 with OUT endpoint) */ \ + + TUD_AUDIO_DESC_STD_AS_INT_LEN \ + + TUD_AUDIO_DESC_STD_AS_INT_LEN \ + + TUD_AUDIO_DESC_CS_AS_INT_LEN \ + + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN \ + + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN \ + + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN \ + /* mic AudioStreaming interface (alt 0 + alt 1 with IN endpoint) */ \ + + TUD_AUDIO_DESC_STD_AS_INT_LEN \ + + TUD_AUDIO_DESC_STD_AS_INT_LEN \ + + TUD_AUDIO_DESC_CS_AS_INT_LEN \ + + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN \ + + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN \ + + TUD_AUDIO_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_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/memzip/make-memzip.py b/shared/memzip/make-memzip.py index 92a5d6168bb..e406c55a43c 100755 --- a/shared/memzip/make-memzip.py +++ b/shared/memzip/make-memzip.py @@ -7,8 +7,6 @@ # 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 subprocess 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/runtime/gchelper_generic.c b/shared/runtime/gchelper_generic.c index 45b2e4f7d84..230a2444005 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; 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..bc5f89bdc81 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_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,22 +158,19 @@ 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) nlr_pop(); - // CIRCUITPY-CHANGE - ret = 0; + ret = PYEXEC_NORMAL_EXIT; if (exec_flags & EXEC_FLAG_PRINT_EOF) { mp_hal_stdout_tx_strn("\x04", 1); } @@ -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 (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 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(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 @@ -570,10 +614,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 +642,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 +655,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 +676,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 +695,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 +724,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) { @@ -705,6 +754,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 +768,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 +813,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..9d1ef2a3cb0 100644 --- a/shared/runtime/pyexec.h +++ b/shared/runtime/pyexec.h @@ -51,6 +51,17 @@ extern pyexec_mode_kind_t pyexec_mode_kind; #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/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/filesystem.h b/supervisor/filesystem.h index a0445b0510d..30cd83d4438 100644 --- a/supervisor/filesystem.h +++ b/supervisor/filesystem.h @@ -21,6 +21,7 @@ void filesystem_set_internal_writable_by_usb(bool usb_writable); void filesystem_set_internal_concurrent_write_protection(bool concurrent_write_protection); void filesystem_set_writable_by_usb(fs_user_mount_t *vfs, bool usb_writable); void filesystem_set_concurrent_write_protection(fs_user_mount_t *vfs, bool concurrent_write_protection); +void filesystem_set_ignore_write_protection(fs_user_mount_t *vfs, bool ignore_write_protection); // Whether user code can modify the filesystem. It doesn't depend on the state // of USB. Don't use this for a workflow. In workflows, grab the shared file diff --git a/supervisor/port.h b/supervisor/port.h index cc49538218f..f0e13e167cc 100644 --- a/supervisor/port.h +++ b/supervisor/port.h @@ -9,6 +9,7 @@ #include #include +#include "py/obj.h" #include "supervisor/shared/safe_mode.h" // Provided by the linker; @@ -23,13 +24,13 @@ 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 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); @@ -91,9 +92,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. @@ -107,3 +116,15 @@ void port_gc_collect(void); // this function to sense the button. Ports that need to can override this // function to provide their own implementation. bool port_boot_button_pressed(void); + +// Allocating objects on the port heap, not the VM heap. +#define mp_obj_port_malloc(struct_type, obj_type) ((struct_type *)mp_obj_port_malloc_helper(sizeof(struct_type), obj_type)) +#define mp_obj_port_malloc_var(struct_type, var_field, var_type, var_num, obj_type) ((struct_type *)mp_obj_port_malloc_helper(offsetof(struct_type, var_field) + sizeof(var_type) * (var_num), obj_type)) + +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/port_heap.h b/supervisor/port_heap.h index 07a3c884e24..3e6b5a660fa 100644 --- a/supervisor/port_heap.h +++ b/supervisor/port_heap.h @@ -21,9 +21,16 @@ void port_heap_init(void); void *port_malloc(size_t size, bool dma_capable); +void *port_malloc_zero(size_t size, bool dma_capable); void port_free(void *ptr); void *port_realloc(void *ptr, size_t size, bool dma_capable); +#if !CIRCUITPY_ALL_MEMORY_DMA_CAPABLE +// Check if a buffer pointer is in DMA-capable memory. DMA-capable memory is also accessible during +// flash operations. +bool port_buffer_is_dma_capable(const void *ptr); +#endif + size_t port_heap_get_largest_free_size(void); diff --git a/supervisor/shared/bluetooth/bluetooth.c b/supervisor/shared/bluetooth/bluetooth.c index 055a5cdf1fd..cccb371fc4d 100644 --- a/supervisor/shared/bluetooth/bluetooth.c +++ b/supervisor/shared/bluetooth/bluetooth.c @@ -36,8 +36,8 @@ #include "supervisor/shared/status_bar.h" #endif -#if CIRCUITPY_WEB_WORKFLOW && CIRCUITPY_WIFI && CIRCUITPY_OS_GETENV -#include "shared-module/os/__init__.h" +#if CIRCUITPY_WEB_WORKFLOW && CIRCUITPY_WIFI && CIRCUITPY_SETTINGS_TOML +#include "supervisor/shared/settings.h" #endif @@ -216,11 +216,11 @@ void supervisor_bluetooth_init(void) { // 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 + #if CIRCUITPY_WEB_WORKFLOW && CIRCUITPY_WIFI && CIRCUITPY_SETTINGS_TOML 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; + 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 (!bonded && !wifi_workflow_active) { boot_in_discovery_mode = true; 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 0df600e77fd..1d2a6180a94 100644 --- a/supervisor/shared/filesystem.c +++ b/supervisor/shared/filesystem.c @@ -148,8 +148,7 @@ bool filesystem_init(bool create_allowed, bool force_create) { res = f_mkdir(&circuitpy->fatfs, "/sd"); #if CIRCUITPY_FULL_BUILD MAKE_FILE_WITH_OPTIONAL_CONTENTS(&circuitpy->fatfs, "/sd/placeholder.txt", - "SD cards mounted at /sd will hide this file from Python." - " SD cards are not visible via USB CIRCUITPY.\n"); + "SD cards mounted at /sd will hide this file from Python.\n"); #endif #endif @@ -173,7 +172,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 @@ -220,6 +219,13 @@ 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(); + #endif #endif return true; @@ -248,13 +254,15 @@ void filesystem_set_writable_by_usb(fs_user_mount_t *vfs, bool usb_writable) { } bool filesystem_is_writable_by_python(fs_user_mount_t *vfs) { - return (vfs->blockdev.flags & MP_BLOCKDEV_FLAG_CONCURRENT_WRITE_PROTECTED) == 0 || - (vfs->blockdev.flags & MP_BLOCKDEV_FLAG_USB_WRITABLE) == 0; + return ((vfs->blockdev.flags & MP_BLOCKDEV_FLAG_CONCURRENT_WRITE_PROTECTED) == 0) || + ((vfs->blockdev.flags & MP_BLOCKDEV_FLAG_USB_WRITABLE) == 0) || + ((vfs->blockdev.flags & MP_BLOCKDEV_FLAG_IGNORE_WRITE_PROTECTION) != 0); } bool filesystem_is_writable_by_usb(fs_user_mount_t *vfs) { - return (vfs->blockdev.flags & MP_BLOCKDEV_FLAG_CONCURRENT_WRITE_PROTECTED) == 0 || - (vfs->blockdev.flags & MP_BLOCKDEV_FLAG_USB_WRITABLE) != 0; + return ((vfs->blockdev.flags & MP_BLOCKDEV_FLAG_CONCURRENT_WRITE_PROTECTED) == 0) || + ((vfs->blockdev.flags & MP_BLOCKDEV_FLAG_USB_WRITABLE) != 0) || + ((vfs->blockdev.flags & MP_BLOCKDEV_FLAG_IGNORE_WRITE_PROTECTION) != 0); } void filesystem_set_internal_concurrent_write_protection(bool concurrent_write_protection) { @@ -269,6 +277,14 @@ void filesystem_set_concurrent_write_protection(fs_user_mount_t *vfs, bool concu } } +void filesystem_set_ignore_write_protection(fs_user_mount_t *vfs, bool ignore_write_protection) { + if (ignore_write_protection) { + vfs->blockdev.flags |= MP_BLOCKDEV_FLAG_IGNORE_WRITE_PROTECTION; + } else { + vfs->blockdev.flags &= ~MP_BLOCKDEV_FLAG_IGNORE_WRITE_PROTECTION; + } +} + bool filesystem_present(void) { return _circuitpy_vfs.len > 0; } @@ -311,12 +327,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 3b9f0c87181..3c95f2b7409 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" @@ -25,7 +27,11 @@ 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) { @@ -43,10 +49,35 @@ MP_WEAK void *port_malloc(size_t size, bool dma_capable) { return block; } +// Ensure allocated memory is zero. +MP_WEAK void *port_malloc_zero(size_t size, bool dma_capable) { + void *ptr = port_malloc(size, dma_capable); + if (ptr) { + memset(ptr, 0, size); + } + return ptr; +} + 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); } @@ -80,3 +111,30 @@ MP_WEAK bool port_boot_button_pressed(void) { return false; #endif } + +// Ports may provide an implementation of this function if it is needed +MP_WEAK void port_gc_collect(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); + base->type = type; + return base; +} + +// Creates a tuple on the port heap, not the VM heap. +// Implementation copied from py/objtuple.c. +mp_obj_t mp_obj_new_port_tuple(size_t n, const mp_obj_t *items) { + if (n == 0) { + return mp_const_empty_tuple; + } + mp_obj_tuple_t *o = mp_obj_port_malloc_var(mp_obj_tuple_t, items, mp_obj_t, n, &mp_type_tuple); + o->len = n; + if (items) { + for (size_t i = 0; i < n; i++) { + o->items[i] = items[i]; + } + } + return MP_OBJ_FROM_PTR(o); +} diff --git a/supervisor/shared/safe_mode.c b/supervisor/shared/safe_mode.c index 5f24618f7f3..da528d27df7 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 @@ -61,10 +69,22 @@ safe_mode_t wait_for_safe_mode_reset(void) { #if CIRCUITPY_STATUS_LED status_led_init(); #endif + + uint32_t safe_mode_delay_msecs = 1000; + + #if CIRCUITPY_SETTINGS_TOML + mp_float_t safe_mode_delay_secs = 1.0f; + // Will update 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; @@ -99,10 +119,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..5728a95e08f 100644 --- a/supervisor/shared/serial.c +++ b/supervisor/shared/serial.c @@ -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; } @@ -235,11 +235,11 @@ bool serial_connected(void) { } #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); @@ -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(); } @@ -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); } @@ -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_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/translate/translate.c b/supervisor/shared/translate/translate.c index 958e0a2144f..b590b385a71 100644 --- a/supervisor/shared/translate/translate.c +++ b/supervisor/shared/translate/translate.c @@ -114,7 +114,7 @@ static void decompress_vstr(mp_rom_error_text_t compressed, vstr_t *decompressed } 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"... + qstr q = get_nbits(&b, translation_qstr_bits); vstr_add_str(decompressed, qstr_str(q)); } 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/tusb_config.h b/supervisor/shared/usb/tusb_config.h index ac2fd9f4f25..a10cd712226 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,52 @@ 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" + +// Single audio function. The emitted descriptor is chosen at boot from the +// stored direction: a mic (1 AS interface, IN endpoint), a speaker (1 AS +// interface, OUT endpoint), or a combined headset (2 AS interfaces, one IN and +// one OUT endpoint). The class driver returns this length to the device core as +// the span of config descriptor the function owns, so it 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 core +// skip the interfaces that follow audio. usb_audio_descriptor_length() returns +// the live length for the stored direction; it is only read at enumeration time +// (audiod_open), by which point usb_audio.enable() has fixed the direction. +#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN usb_audio_descriptor_length() +// The headset presents two AudioStreaming interfaces; the single-direction +// descriptors use only the first. The class driver sizes its per-interface alt +// tracking from this, so it must cover the largest case. +#define CFG_TUD_AUDIO_FUNC_1_N_AS_INT 2 +// EP0 buffer for class-specific control requests (sample-freq range, volume range, ...). +#define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ 64 + +#define CFG_TUD_AUDIO_ENABLE_EP_IN 1 +#define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX USB_AUDIO_N_BYTES_PER_SAMPLE +#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX USB_AUDIO_N_CHANNELS +// wMaxPacketSize, sized for the highest supported sample rate. +#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX TUD_AUDIO_EP_SIZE(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 +#define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_RX USB_AUDIO_N_BYTES_PER_SAMPLE +#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX USB_AUDIO_N_CHANNELS +// wMaxPacketSize, sized for the highest supported sample rate. +#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX TUD_AUDIO_EP_SIZE(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 +199,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..e8a4422bb36 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,6 +178,9 @@ 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 } } 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..16ae137edde 100644 --- a/supervisor/shared/usb/usb_device.c +++ b/supervisor/shared/usb/usb_device.c @@ -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 0b02faa5c18..6f15b508095 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 @@ -45,6 +46,11 @@ static bool ejected[LUN_COUNT] = { [0 ... (LUN_COUNT - 1)] = true}; static bool eject_once[LUN_COUNT] = { [0 ... (LUN_COUNT - 1)] = false}; 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}; + #include "tusb.h" static const uint8_t usb_msc_descriptor_template[] = { @@ -67,7 +73,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 @@ -80,7 +86,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 @@ -132,7 +138,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_nbytes(saves) == 0) { + if (saves != root && + (saves->blockdev.flags & MP_BLOCKDEV_FLAG_NATIVE) != 0 && !gc_ptr_on_heap(saves)) { return saves; } } @@ -141,7 +148,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 (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. @@ -190,20 +205,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); @@ -243,7 +263,7 @@ bool tud_msc_is_writable_cb(uint8_t lun) { if (vfs == NULL) { return false; } - if (vfs->blockdev.writeblocks[0] == MP_OBJ_NULL || !filesystem_is_writable_by_usb(vfs)) { + if (!filesystem_is_writable_by_usb(vfs)) { return false; } // Lock the blockdev once we say we're writable. @@ -290,16 +310,19 @@ int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t * if (vfs == NULL) { return -1; } + disk_write(vfs, buffer, lba, block_count); // Since by getting here we assume the mount is read-only to - // MicroPython let's update the cached FatFs sector if it's the one + // CircuitPython let's update the cached FatFs sector if it's the one // we just wrote. + if #if FF_MAX_SS != FF_MIN_SS - if (vfs->fatfs.ssize == MSC_FLASH_BLOCK_SIZE) { + (vfs->fatfs.ssize == MSC_FLASH_BLOCK_SIZE) #else // The compiler can optimize this away. - if (FF_MAX_SS == FILESYSTEM_BLOCK_SIZE) { - #endif + (FF_MAX_SS == FILESYSTEM_BLOCK_SIZE) + #endif + { if (lba == vfs->fatfs.winsect && lba > 0) { memcpy(vfs->fatfs.win, buffer + MSC_FLASH_BLOCK_SIZE * (vfs->fatfs.winsect - lba), @@ -307,17 +330,30 @@ int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t * } } + // 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 (lba >= vfs->fatfs.fatbase) { + content_write[lun] = true; + } + return block_count * MSC_FLASH_BLOCK_SIZE; } // Callback invoked when WRITE10 command is completed (status received and accepted by host). // used to flush any pending cache. void tud_msc_write10_complete_cb(uint8_t lun) { - (void)lun; - - // This write is complete; initiate an autoreload. autoreload_resume(AUTORELOAD_SUSPEND_USB); - autoreload_trigger(); + + // 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] && + // Fast path: lun == 0 is CIRCUITPY, which can always trigger auto-reload if enabled. + // Don't autoreload if this lun was mounted by the user: that will cause a VM stop and an unmount. + (lun == 0 || !gc_ptr_on_heap(get_vfs(lun)))) { + autoreload_trigger(); + content_write[lun] = false; + } } // Invoked when received SCSI_CMD_INQUIRY @@ -330,6 +366,32 @@ 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) { + bool setting = true; + (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) { @@ -337,17 +399,16 @@ bool tud_msc_test_unit_ready_cb(uint8_t lun) { return false; } - #if CIRCUITPY_SDCARDIO - 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] + #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..8da8dcc5184 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,6 +335,7 @@ 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. const mcu_reset_reason_t reset_reason = common_hal_mcu_processor_get_reset_reason(); @@ -289,17 +350,17 @@ bool supervisor_start_web_workflow(void) { 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 +368,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); @@ -373,7 +434,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); } } } @@ -847,7 +908,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 +1040,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 +1051,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 +1160,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..28ce682efd9 100644 --- a/supervisor/shared/workflow.c +++ b/supervisor/shared/workflow.c @@ -23,8 +23,10 @@ #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 @@ -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..1f40cebd0d2 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 @@ -113,6 +120,7 @@ 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) @@ -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..534e7e0a059 100644 --- a/tests/README.md +++ b/tests/README.md @@ -1,6 +1,7 @@ # 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. 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. @@ -67,16 +68,14 @@ 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 +135,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 +203,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 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/assign_expr.py.exp b/tests/basics/assign_expr.py.exp deleted file mode 100644 index 47da56b80d4..00000000000 --- a/tests/basics/assign_expr.py.exp +++ /dev/null @@ -1,16 +0,0 @@ -4 -True -2 -4 5 -5 -1 5 5 -5 -2 1 -1 0 -any True -8 -123 -any True -8 -[(1, 0), (2, 2), (3, 6), (4, 12)] -4 diff --git a/tests/basics/assign_expr_scope.py.exp b/tests/basics/assign_expr_scope.py.exp deleted file mode 100644 index 5c780b38221..00000000000 --- a/tests/basics/assign_expr_scope.py.exp +++ /dev/null @@ -1,23 +0,0 @@ -scope0 -1 -None -scope1 -[1] -1 -None -scope2 -[0, 1] -1 -1 -scope3 -[0, 1] -None -None -scope4 -[0, 1] -1 -1 -scope5 -[0, 1] -1 -None diff --git a/tests/basics/async_await.py.exp b/tests/basics/async_await.py.exp deleted file mode 100644 index b51c388a933..00000000000 --- a/tests/basics/async_await.py.exp +++ /dev/null @@ -1,32 +0,0 @@ -4 -3 -2 -1 -0 -0 -1 -0 -0 -2 -1 -0 -0 -1 -0 -0 -3 -2 -1 -0 -0 -1 -0 -0 -2 -1 -0 -0 -1 -0 -0 -finished diff --git a/tests/basics/async_await2.py.exp b/tests/basics/async_await2.py.exp deleted file mode 100644 index fc9ff0aa535..00000000000 --- a/tests/basics/async_await2.py.exp +++ /dev/null @@ -1,5 +0,0 @@ -wait value: 1 -return from send: message from wait(1) -wait got back: message from main -x = 100 -got StopIteration diff --git a/tests/basics/async_def.py.exp b/tests/basics/async_def.py.exp deleted file mode 100644 index f555ace99ab..00000000000 --- a/tests/basics/async_def.py.exp +++ /dev/null @@ -1,3 +0,0 @@ -decorator -foo -StopIteration diff --git a/tests/basics/async_for.py.exp b/tests/basics/async_for.py.exp deleted file mode 100644 index 6f59979c065..00000000000 --- a/tests/basics/async_for.py.exp +++ /dev/null @@ -1,51 +0,0 @@ -== start == -init -aiter -init -anext -a -anext -b -anext -c -anext -== finish == -== start == -init -aiter -init -anext -d -anext -e -anext -f -anext -AsyncIteratorWrapper-def -== finish == -init -== start == -aiter -init -anext -g -anext -h -anext -i -anext -AsyncIteratorWrapper-ghi -== finish == -init -== start == -aiter -init -anext -j -anext -k -anext -l -anext -AsyncIteratorWrapper-jkl -== finish == diff --git a/tests/basics/async_for2.py b/tests/basics/async_for2.py index bbdb02c49b2..82232d52fc2 100644 --- a/tests/basics/async_for2.py +++ b/tests/basics/async_for2.py @@ -1,7 +1,7 @@ # test waiting within "async for" __anext__ function # 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_for2.py.exp b/tests/basics/async_for2.py.exp deleted file mode 100644 index 52bbe90c853..00000000000 --- a/tests/basics/async_for2.py.exp +++ /dev/null @@ -1,32 +0,0 @@ -init -aiter -anext -f start: 20 -coro yielded: 21 -coro yielded: 22 -f returned: 23 -x 0 -anext -f start: 20 -coro yielded: 21 -coro yielded: 22 -f returned: 23 -x 1 -anext -f start: 20 -coro yielded: 21 -coro yielded: 22 -f returned: 23 -x 2 -anext -f start: 20 -coro yielded: 21 -coro yielded: 22 -f returned: 23 -x 3 -anext -f start: 20 -coro yielded: 21 -coro yielded: 22 -f returned: 23 -finished diff --git a/tests/basics/async_syntaxerror.py.exp b/tests/basics/async_syntaxerror.py.exp deleted file mode 100644 index 5275689b413..00000000000 --- a/tests/basics/async_syntaxerror.py.exp +++ /dev/null @@ -1,2 +0,0 @@ -SyntaxError -SyntaxError diff --git a/tests/basics/async_with.py.exp b/tests/basics/async_with.py.exp deleted file mode 100644 index 6bbf84cb4b5..00000000000 --- a/tests/basics/async_with.py.exp +++ /dev/null @@ -1,11 +0,0 @@ -enter -body -exit None None -finished -enter -1 -exit 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_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_intbig.py b/tests/basics/builtin_pow3_intbig.py index bedc8b36b7e..41d2acbc0cc 100644 --- a/tests/basics/builtin_pow3_intbig.py +++ b/tests/basics/builtin_pow3_intbig.py @@ -20,3 +20,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/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/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/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_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_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/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/int_64_basics.py b/tests/basics/int_64_basics.py new file mode 100644 index 00000000000..ef76793317e --- /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(e) + +try: + print((1 << 48) << -6) +except ValueError as e: + print(e) + +# 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/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/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_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_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/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_continue.py.exp b/tests/basics/try_finally_continue.py.exp deleted file mode 100644 index 2901997b1aa..00000000000 --- a/tests/basics/try_finally_continue.py.exp +++ /dev/null @@ -1,9 +0,0 @@ -4 0 -continue -4 1 -continue -4 2 -continue -4 3 -continue -None 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/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_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/deque_subclass.py b/tests/circuitpython/deque_subclass.py new file mode 100644 index 00000000000..5708407a9b6 --- /dev/null +++ b/tests/circuitpython/deque_subclass.py @@ -0,0 +1,40 @@ +try: + from collections import deque +except ImportError: + print("SKIP") + raise SystemExit + + +class DequeSubclass(deque): + def __init__(self, values, maxlen): + super().__init__(values, maxlen) + + def pop(self): + print("pop") + return super().pop() + + def popleft(self): + print("popleft") + return super().popleft() + + def append(self, value): + print("append") + return super().append(value) + + def appendleft(self, value): + print("appendleft") + return super().appendleft(value) + + def extend(self, value): + print("extend") + return super().extend(value) + + +d = DequeSubclass([1, 2, 3], 10) +print(d.append(4)) +print(d.appendleft(0)) +print(d.pop()) +print(d.popleft()) +d.extend([6, 7]) +# calling list() tests iteration. +print(list(d)) 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/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..6807569f662 --- /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..2a0f756b1e7 --- /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..6320d9d2d30 --- /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_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/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..e685a7fe7ff --- /dev/null +++ b/tests/cmdline/repl_autocomplete_underscore.py @@ -0,0 +1,33 @@ +# 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..98e6c2aeb05 --- /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_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..7cec450fce7 --- /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') + + print('After blank line') + + + 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 + + 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() +{\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 + +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..cc5ac2f0800 --- /dev/null +++ b/tests/cmdline/repl_paste.py.exp @@ -0,0 +1,133 @@ + +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_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_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_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_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_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_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..e53d5fd4088 --- /dev/null +++ b/tests/cpydiff/types_range_limits.py @@ -0,0 +1,26 @@ +""" +categories: Types,range +description: Range objects with large start or stop arguments misbehave. +cause: Intermediate calculations overflow the C mp_int_t type +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 `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_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/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_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_hard_timer.py b/tests/extmod/machine_hard_timer.py new file mode 100644 index 00000000000..8fe42ea8508 --- /dev/null +++ b/tests/extmod/machine_hard_timer.py @@ -0,0 +1,45 @@ +import sys + +try: + from machine import Timer + from time import sleep_ms +except: + print("SKIP") + raise SystemExit + +if sys.platform == "esp8266": + timer = Timer(0) +else: + # Hardware timers are not implemented. + print("SKIP") + raise SystemExit + +# Test both hard and soft IRQ handlers and both one-shot and periodic +# timers. We adjust period in tests/extmod/machine_soft_timer.py, so try +# adjusting freq here instead. The heap should be locked in hard callbacks +# and unlocked in soft callbacks. + + +def callback(t): + print("callback", mode[1], kind[1], freq, end=" ") + try: + allocate = bytearray(1) + print("unlocked") + except MemoryError: + print("locked") + + +modes = [(Timer.ONE_SHOT, "one-shot"), (Timer.PERIODIC, "periodic")] +kinds = [(False, "soft"), (True, "hard")] + +for mode in modes: + for kind in kinds: + for freq in 50, 25: + timer.init( + mode=mode[0], + freq=freq, + hard=kind[0], + callback=callback, + ) + sleep_ms(90) + timer.deinit() diff --git a/tests/extmod/machine_hard_timer.py.exp b/tests/extmod/machine_hard_timer.py.exp new file mode 100644 index 00000000000..26cdc644fdd --- /dev/null +++ b/tests/extmod/machine_hard_timer.py.exp @@ -0,0 +1,16 @@ +callback one-shot soft 50 unlocked +callback one-shot soft 25 unlocked +callback one-shot hard 50 locked +callback one-shot hard 25 locked +callback periodic soft 50 unlocked +callback periodic soft 50 unlocked +callback periodic soft 50 unlocked +callback periodic soft 50 unlocked +callback periodic soft 25 unlocked +callback periodic soft 25 unlocked +callback periodic hard 50 locked +callback periodic hard 50 locked +callback periodic hard 50 locked +callback periodic hard 50 locked +callback periodic hard 25 locked +callback periodic hard 25 locked diff --git a/tests/extmod/machine_timer.py b/tests/extmod/machine_timer.py new file mode 100644 index 00000000000..ef97ea4e949 --- /dev/null +++ b/tests/extmod/machine_timer.py @@ -0,0 +1,48 @@ +import sys + +try: + from machine import Timer + from time import sleep_ms +except: + print("SKIP") + raise SystemExit + +if sys.platform in ("esp32", "esp8266", "nrf"): + # Software timers aren't implemented on the esp32 and esp8266 ports. + # The nrf port doesn't support selection of hard and soft callbacks, + # and only allows Timer(period=N), not Timer(freq=N). + print("SKIP") + raise SystemExit +else: + timer_id = -1 + +# Test both hard and soft IRQ handlers and both one-shot and periodic +# timers. We adjust period in tests/extmod/machine_soft_timer.py, so try +# adjusting freq here instead. The heap should be locked in hard callbacks +# and unlocked in soft callbacks. + + +def callback(t): + print("callback", mode[1], kind[1], freq, end=" ") + try: + allocate = bytearray(1) + print("unlocked") + except MemoryError: + print("locked") + + +modes = [(Timer.ONE_SHOT, "one-shot"), (Timer.PERIODIC, "periodic")] +kinds = [(False, "soft"), (True, "hard")] + +for mode in modes: + for kind in kinds: + for freq in 50, 25: + timer = Timer( + timer_id, + mode=mode[0], + freq=freq, + hard=kind[0], + callback=callback, + ) + sleep_ms(90) + timer.deinit() diff --git a/tests/extmod/machine_timer.py.exp b/tests/extmod/machine_timer.py.exp new file mode 100644 index 00000000000..26cdc644fdd --- /dev/null +++ b/tests/extmod/machine_timer.py.exp @@ -0,0 +1,16 @@ +callback one-shot soft 50 unlocked +callback one-shot soft 25 unlocked +callback one-shot hard 50 locked +callback one-shot hard 25 locked +callback periodic soft 50 unlocked +callback periodic soft 50 unlocked +callback periodic soft 50 unlocked +callback periodic soft 50 unlocked +callback periodic soft 25 unlocked +callback periodic soft 25 unlocked +callback periodic hard 50 locked +callback periodic hard 50 locked +callback periodic hard 50 locked +callback periodic hard 50 locked +callback periodic hard 25 locked +callback periodic hard 25 locked 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_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/socket_badconstructor.py b/tests/extmod/socket_badconstructor.py new file mode 100644 index 00000000000..4a9d2668c7f --- /dev/null +++ b/tests/extmod/socket_badconstructor.py @@ -0,0 +1,22 @@ +# 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") + +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_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..695352da579 100644 --- a/tests/extmod/uctypes_array_load_store.py +++ b/tests/extmod/uctypes_array_load_store.py @@ -6,6 +6,13 @@ 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 + N = 5 for endian in ("NATIVE", "LITTLE_ENDIAN", "BIG_ENDIAN"): diff --git a/tests/extmod/vfs_blockdev_invalid.py b/tests/extmod/vfs_blockdev_invalid.py index 4d00f4b0027..29d6bd6b2f9 100644 --- a/tests/extmod/vfs_blockdev_invalid.py +++ b/tests/extmod/vfs_blockdev_invalid.py @@ -70,8 +70,8 @@ def test(vfs_class): try: with fs.open("test", "r") as f: print("opened") - except OSError as e: - print("OSError", e) + except Exception as e: + print(type(e), e) # This variant should succeed on open, may fail on read # unless the filesystem cached the contents already @@ -81,8 +81,8 @@ def test(vfs_class): bdev.read_res = res print("read 1", f.read(1)) print("read rest", f.read()) - except OSError as e: - print("OSError", e) + except Exception as e: + print(type(e), e) test(vfs.VfsLfs2) diff --git a/tests/extmod/vfs_blockdev_invalid.py.exp b/tests/extmod/vfs_blockdev_invalid.py.exp index 13695e0d889..0ea0353501d 100644 --- a/tests/extmod/vfs_blockdev_invalid.py.exp +++ b/tests/extmod/vfs_blockdev_invalid.py.exp @@ -2,27 +2,27 @@ opened read 1 a read rest aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -OSError [Errno 5] EIO + [Errno 5] EIO read 1 a read rest aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -OSError [Errno 22] EINVAL + [Errno 22] EINVAL read 1 a read rest aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -OSError [Errno 22] EINVAL + [Errno 22] EINVAL read 1 a read rest aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -OSError [Errno 22] EINVAL + can't convert str to int 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 + [Errno 5] EIO + [Errno 5] EIO + [Errno 5] EIO + [Errno 5] EIO + [Errno 5] EIO + [Errno 5] EIO + can't convert str to int + can't convert str to int 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..b3ca2753ba9 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) 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_counter.py b/tests/extmod_hardware/machine_counter.py new file mode 100644 index 00000000000..62ac1fed47c --- /dev/null +++ b/tests/extmod_hardware/machine_counter.py @@ -0,0 +1,90 @@ +# 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 +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 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_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()) + + 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) + + 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..c218c8bfb64 --- /dev/null +++ b/tests/extmod_hardware/machine_encoder.py @@ -0,0 +1,153 @@ +# 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 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 + + @unittest.skipIf(sys.platform == "mimxrt", "cannot read back the pin") + 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()) + + 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/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/inlineasm_rv32_zba.py b/tests/feature_check/inlineasm_rv32_zba.py new file mode 100644 index 00000000000..81228819042 --- /dev/null +++ b/tests/feature_check/inlineasm_rv32_zba.py @@ -0,0 +1,10 @@ +# check if RISC-V 32 inline asm supported Zba opcodes + + +@micropython.asm_rv32 +def f(): + sh1add(a0, a0, a0) + + +f() +print("rv32_zba") diff --git a/tests/feature_check/inlineasm_rv32_zba.py.exp b/tests/feature_check/inlineasm_rv32_zba.py.exp new file mode 100644 index 00000000000..fde22f5f400 --- /dev/null +++ b/tests/feature_check/inlineasm_rv32_zba.py.exp @@ -0,0 +1 @@ +rv32_zba 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_64.py.exp b/tests/feature_check/int_64.py.exp new file mode 100644 index 00000000000..aef5454e662 --- /dev/null +++ b/tests/feature_check/int_64.py.exp @@ -0,0 +1 @@ +4611686018427387904 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/repl_emacs_check.py.exp b/tests/feature_check/repl_emacs_check.py.exp index 82a4e28ee4f..5fe8ba1cd2d 100644 --- a/tests/feature_check/repl_emacs_check.py.exp +++ b/tests/feature_check/repl_emacs_check.py.exp @@ -1,5 +1,5 @@ MicroPython \.\+ version -Use \.\+ +Type "help()" for more information. >>> # Check for emacs keys in REPL >>> t = \.\+ >>> t == 2 diff --git a/tests/feature_check/repl_words_move_check.py.exp b/tests/feature_check/repl_words_move_check.py.exp index 82a4e28ee4f..5fe8ba1cd2d 100644 --- a/tests/feature_check/repl_words_move_check.py.exp +++ b/tests/feature_check/repl_words_move_check.py.exp @@ -1,5 +1,5 @@ MicroPython \.\+ version -Use \.\+ +Type "help()" for more information. >>> # Check for emacs keys in REPL >>> t = \.\+ >>> t == 2 diff --git a/tests/feature_check/target_info.py b/tests/feature_check/target_info.py index f60f3b31919..e95530023d7 100644 --- a/tests/feature_check/target_info.py +++ b/tests/feature_check/target_info.py @@ -19,5 +19,21 @@ "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 + +print(platform, arch, arch_flags, build, thread, float_prec, len("α") == 1) 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/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..7b7b30c4b34 100644 --- a/tests/float/float_format_ints.py +++ b/tests/float/float_format_ints.py @@ -12,14 +12,42 @@ 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" + +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/frozen/frozentest.py b/tests/frozen/frozentest.py index 78cdd60bf04..74bdfb3b267 100644 --- a/tests/frozen/frozentest.py +++ b/tests/frozen/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/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..2cb21b877d7 --- /dev/null +++ b/tests/import/import_star.py @@ -0,0 +1,59 @@ +# 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") 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/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/import/shared_name/spritesheet.bmp b/tests/import/shared_name/spritesheet.bmp new file mode 100644 index 00000000000..e69de29bb2d 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/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..b185e30520c --- /dev/null +++ b/tests/inlineasm/xtensa/asmloadstore.py @@ -0,0 +1,98 @@ +import array + +# On the 8266 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. + +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) + label(ENTRY) + l32i(a2, a0, 0) + + +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..e6672df6f81 --- /dev/null +++ b/tests/inlineasm/xtensa/asmloadstore.py.exp @@ -0,0 +1,9 @@ +0x4030201 +0xf8002022 +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/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_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..d6ac26aa829 --- /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..59181b203bb 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 + ( 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/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/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..ddbbae12a63 --- /dev/null +++ b/tests/micropython/ringio_big.py @@ -0,0 +1,29 @@ +# Check that micropython.RingIO works correctly. + +try: + import micropython + + micropython.RingIO +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit + +try: + # The maximum possible size + micropython.RingIO(bytearray(65535)) + micropython.RingIO(65534) + + try: + # Buffer may not be too big + micropython.RingIO(bytearray(65536)) + except ValueError as ex: + print(type(ex)) + + try: + # Size may not be too big + micropython.RingIO(65535) + except ValueError as ex: + print(type(ex)) +except MemoryError: + print("SKIP") + raise SystemExit 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..f3dd3266126 100644 --- a/tests/micropython/schedule.py +++ b/tests/micropython/schedule.py @@ -1,10 +1,10 @@ # test micropython.schedule() function -import micropython - try: + import micropython + micropython.schedule -except AttributeError: +except (ImportError, AttributeError): print("SKIP") raise SystemExit 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_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_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/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..33aa4edb742 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,70 +47,36 @@ 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 @@ -130,10 +88,15 @@ def singleTraj(system, trajStart, h=0.02, tend=1.0): 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_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..67deec05088 100644 --- a/tests/perf_bench/core_import_mpy_multi.py +++ b/tests/perf_bench/core_import_mpy_multi.py @@ -6,7 +6,7 @@ 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,7 +23,7 @@ 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): diff --git a/tests/perf_bench/core_import_mpy_single.py b/tests/perf_bench/core_import_mpy_single.py index 4d9aa67bf2f..f472bb64762 100644 --- a/tests/perf_bench/core_import_mpy_single.py +++ b/tests/perf_bench/core_import_mpy_single.py @@ -8,7 +8,7 @@ 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,7 +78,7 @@ 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): diff --git a/tests/run-internalbench.py b/tests/run-internalbench.py index c9f783e474c..99c6304afe9 100755 --- a/tests/run-internalbench.py +++ b/tests/run-internalbench.py @@ -8,6 +8,10 @@ from glob import glob from collections import defaultdict +run_tests_module = __import__("run-tests") +sys.path.append(run_tests_module.base_path("../tools")) +import pyboard + if os.name == "nt": MICROPYTHON = os.getenv( "MICROPY_MICROPYTHON", "../ports/windows/build-standard/micropython.exe" @@ -15,13 +19,39 @@ else: MICROPYTHON = os.getenv("MICROPY_MICROPYTHON", "../ports/unix/build-standard/micropython") +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(pyb, 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 pyb.exec(code).replace(b"\r\n", b"\n") + + +def run_tests(pyb, 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: @@ -36,20 +66,25 @@ def run_tests(pyb, test_dict): # run on pyboard pyb.enter_raw_repl() try: - output_mupy = pyb.execfile(test_file).replace(b"\r\n", b"\n") + output_mupy = execbench(pyb, 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 +93,47 @@ 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. + +{run_tests_module.test_instance_description} +{run_tests_module.test_directory_description} +""", + epilog=run_tests_module.test_instance_epilog, + ) + 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() - else: - pyb = None + pyb = run_tests_module.get_test_instance( + args.test_instance, args.baudrate, args.user, args.password + ) 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 +150,7 @@ def main(): continue test_dict[m.group(1)].append([t, None]) - if not run_tests(pyb, test_dict): + if not run_tests(pyb, test_dict, args.iters): sys.exit(1) diff --git a/tests/run-multitests.py b/tests/run-multitests.py index 387eec7018b..e5458ffe0d0 100755 --- a/tests/run-multitests.py +++ b/tests/run-multitests.py @@ -15,6 +15,8 @@ import subprocess import tempfile +run_tests_module = __import__("run-tests") + test_dir = os.path.abspath(os.path.dirname(__file__)) if os.path.abspath(sys.path[0]) == test_dir: @@ -130,6 +132,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 +195,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 +222,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 +234,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 +260,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() @@ -281,13 +279,13 @@ def readline(self): if out.endswith(b"\x04"): self.finished = True out = out[:-1] - err = str(self.pyb.read_until(1, b"\x04"), "ascii") + 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 str(out.rstrip(), "ascii"), err + return decode(out.rstrip()), err def write(self, data): self.pyb.serial.write(data) @@ -297,7 +295,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): @@ -488,9 +486,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 +522,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 +545,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 +553,24 @@ def main(): cmd_parser = argparse.ArgumentParser( description="Run network tests for MicroPython", + epilog=( + run_tests_module.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,13 +579,11 @@ 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=run_tests_module.base_path("results"), + help="directory for test results", ) cmd_parser.add_argument("files", nargs="+", help="input test files") cmd_args = cmd_parser.parse_args() @@ -603,33 +597,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 = run_tests_module.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 &= run_tests_module.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..6d2a975b82a 100755 --- a/tests/run-natmodtests.py +++ b/tests/run-natmodtests.py @@ -9,7 +9,7 @@ import sys import argparse -# CIRCUITPY-CHANGE: no pyboard +run_tests_module = __import__("run-tests") # Paths for host executables CPYTHON3 = os.getenv("MICROPY_CPYTHON3", "python3") @@ -72,6 +72,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') """ @@ -108,7 +109,7 @@ def run_script(self, script): output = self.pyb.exec_(script) output = output.replace(b"\r\n", b"\n") return output, None - except pyboard.PyboardError as er: + except run_tests_module.pyboard.PyboardError as er: return b"", er @@ -131,7 +132,15 @@ 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): + global injected_import_hook_code + + prelude = "" + if args.begin: + prelude = args.begin.read() + injected_import_hook_code = injected_import_hook_code.replace("{import_prelude}", prelude) + + test_results = [] for test_file in args.files: # Find supported test test_file_basename = os.path.basename(test_file) @@ -154,9 +163,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,8 +175,18 @@ 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) @@ -186,40 +207,63 @@ 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)) + return test_results + def main(): cmd_parser = argparse.ArgumentParser( - description="Run dynamic-native-module tests under MicroPython" + description="Run dynamic-native-module tests under MicroPython", + epilog=run_tests_module.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", + type=argparse.FileType("rt"), + default=None, + help="prologue python file to execute before module import", + ) + cmd_parser.add_argument( + "-r", + "--result-dir", + default=run_tests_module.base_path("results"), + help="directory for test results", ) cmd_parser.add_argument("files", nargs="*", help="input test files") args = cmd_parser.parse_args() target_truth = TargetSubprocess([CPYTHON3]) - if args.pyboard: - target = TargetPyboard(pyboard.Pyboard(args.device)) - else: + target = run_tests_module.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 @@ -235,20 +279,14 @@ def main(): 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 = run_tests_module.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..039d11a3611 100755 --- a/tests/run-perfbench.py +++ b/tests/run-perfbench.py @@ -10,10 +10,9 @@ import argparse from glob import glob -sys.path.append("../tools") -import pyboard +run_tests_module = __import__("run-tests") -prepare_script_for_target = __import__("run-tests").prepare_script_for_target +prepare_script_for_target = run_tests_module.prepare_script_for_target # Paths for host executables if os.name == "nt": @@ -45,12 +44,12 @@ 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() output = target.exec_(script) - except pyboard.PyboardError as er: + except run_tests_module.pyboard.PyboardError as er: err = er else: # Run local executable @@ -90,9 +89,9 @@ 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="") @@ -105,6 +104,7 @@ def run_benchmarks(args, target, param_n, param_m, n_average, test_list): and test_file.find("viper_") != -1 ) if skip: + test_results.append((test_file, "skip", "")) print("SKIP") continue @@ -122,9 +122,10 @@ def run_benchmarks(args, target, param_n, param_m, n_average, test_list): f.write(test_script) # Process script through mpy-cross if needed - if isinstance(target, pyboard.Pyboard) or args.via_mpy: + if hasattr(target, "enter_raw_repl") or args.via_mpy: crash, test_script_target = prepare_script_for_target(args, script_text=test_script) if crash: + test_results.append((test_file, "fail", "preparation")) print("CRASH:", test_script_target) continue else: @@ -162,10 +163,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 +183,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 +194,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 +256,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 +274,12 @@ 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( + "-r", + "--result-dir", + default=run_tests_module.base_path("results"), + help="directory for test results", + ) cmd_parser.add_argument( "N", nargs=1, help="N parameter (approximate target CPU frequency in MHz)" ) @@ -282,15 +298,18 @@ 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 = run_tests_module.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",) @@ -307,13 +326,15 @@ def main(): 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 = run_tests_module.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..71570292ce7 100755 --- a/tests/run-tests.py +++ b/tests/run-tests.py @@ -15,13 +15,15 @@ import threading import tempfile -# Maximum time to run a PC-based test, in seconds. -TEST_TIMEOUT = 30 +# Maximum time to run a single test, in seconds. +TEST_TIMEOUT = float(os.environ.get("MICROPY_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))) +RV32_ARCH_FLAGS = {"zba": 1 << 0} + def base_path(*p): return os.path.abspath(os.path.join(BASEPATH, *p)).replace("\\", "/") @@ -58,6 +60,23 @@ def base_path(*p): # Set PYTHONIOENCODING so that CPython will use utf-8 on systems which set another encoding in the locale os.environ["PYTHONIOENCODING"] = "utf-8" + +def normalize_newlines(data): + """Normalize newline variations to \\n. + + Only normalizes actual line endings, not literal \\r characters in strings. + Handles \\r\\r\\n and \\r\\n cases to ensure consistent comparison + across different platforms and terminals. + """ + if isinstance(data, bytes): + # Handle PTY double-newline issue first + data = data.replace(b"\r\r\n", b"\n") + # Then handle standard Windows line endings + data = data.replace(b"\r\n", b"\n") + # Don't convert standalone \r as it might be literal content + return data + + # 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. @@ -88,31 +107,82 @@ def getcwd(self): return "" def stat(self, path): if path == '__injected_test.mpy': - return tuple(0 for _ in range(10)) + return (0,0,0,0,0,0,0,0,0,0) else: - raise OSError(-2) # ENOENT + raise OSError(2) # ENOENT def open(self, path, mode): + self.stat(path) return __File() vfs.mount(__FS(), '/__vfstest') os.chdir('/__vfstest') +{import_prologue} __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/gen_yield_from_close.py", + "basics/try_finally_return2.py", + "basics/try_reraise.py", + "basics/try_reraise2.py", + "misc/features.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 running the scheduler. + "micropython/schedule.py", + "extmod/asyncio_event_queue.py", + "extmod/asyncio_iterator_event.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 - ), "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,14 +210,6 @@ 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 @@ -162,6 +224,9 @@ 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", @@ -184,6 +249,89 @@ def open(self, path, mode): ), } +# 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", + "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_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", + "misc/non_compliant.py", + "misc/rge_sm.py", +) + +# Tests that require `import target_wiring` to work. +tests_requiring_target_wiring = ( + "extmod/machine_uart_irq_txidle.py", + "extmod/machine_uart_tx.py", + "extmod_hardware/machine_encoder.py", + "extmod_hardware/machine_uart_irq_break.py", + "extmod_hardware/machine_uart_irq_rx.py", + "extmod_hardware/machine_uart_irq_rxidle.py", +) + def rm_f(fname): if os.path.exists(fname): @@ -210,22 +358,31 @@ def convert_regex_escapes(line): return bytes("".join(cs), "utf8") +def platform_to_port(platform): + return platform_to_port_map.get(platform, platform) + + +def convert_device_shortcut_to_real_device(device): + if device.startswith("port:"): + return device.split(":", 1)[1] + elif device.startswith("a") and device[1:].isdigit(): + return "/dev/ttyACM" + device[1:] + elif device.startswith("u") and device[1:].isdigit(): + return "/dev/ttyUSB" + device[1:] + elif device.startswith("c") and device[1:].isdigit(): + return "COM" + device[1:] + else: + return device + + def get_test_instance(test_instance, baudrate, user, password): - if test_instance.startswith("port:"): - _, port = test_instance.split(":", 1) - elif test_instance == "unix": + if 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 + port = convert_device_shortcut_to_real_device(test_instance) global pyboard sys.path.append(base_path("../tools")) @@ -245,46 +402,114 @@ def detect_inline_asm_arch(pyb, args): 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): # Run a script to detect various bits of information about the target test instance. 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() + platform, arch, arch_flags, build, thread, float_prec, unicode = ( + str(output, "ascii").strip().split() + ) if arch == "None": arch = None inlineasm_arch = 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.build = build + args.thread = thread + args.float_prec = float_prec + args.unicode = unicode + # 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 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: + 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 + + +def prepare_script_for_target(args, *, 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() + # A plain test to run as-is, no processing needed. + pass 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 + script_filename = tempname + ".py" + with open(script_filename, "wb") as f: + f.write(script_text) try: subprocess.check_output( @@ -300,8 +525,7 @@ def prepare_script_for_target(args, *, script_filename=None, script_text=None, f script_text = b"__buf=" + bytes(repr(f.read()), "ascii") + b"\n" rm_f(mpy_filename) - if cleanup_script_filename: - rm_f(script_filename) + rm_f(script_filename) script_text += bytes(injected_import_hook_code, "ascii") else: @@ -312,34 +536,61 @@ def prepare_script_for_target(args, *, script_filename=None, script_text=None, f 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 - ) + with open(test_file, "rb") as f: + script = f.read() + + # If the test is not a special test, prepend it with a print to indicate that it started. + # If the print does not execute this means that the test did not even start, eg it was + # too large for the target. + prepend_start_test = not is_special + if prepend_start_test: + if script.startswith(b"#"): + script = b"print('START TEST')" + script + else: + script = b"print('START TEST')\n" + script + + had_crash, script = prepare_script_for_target(args, script_text=script, force_plain=is_special) + if had_crash: return True, script try: had_crash = False pyb.enter_raw_repl() - output_mupy = pyb.exec_(script) + if test_file.endswith(tests_requiring_target_wiring) and pyb.target_wiring_script: + pyb.exec_( + "import sys;sys.modules['target_wiring']=__build_class__(lambda:exec(" + + repr(pyb.target_wiring_script) + + "),'target_wiring')" + ) + output_mupy = pyb.exec_(script, timeout=TEST_TIMEOUT) 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" + if prepend_start_test and e.args[1] == b"" and b"MemoryError" in e.args[2]: + output_mupy = b"SKIP-TOO-LARGE\n" + else: + output_mupy = e.args[1] + e.args[2] + b"CRASH" else: output_mupy = bytes(e.args[0], "ascii") + b"\nCRASH" + + if prepend_start_test: + if output_mupy.startswith(b"START TEST\r\n"): + output_mupy = output_mupy.removeprefix(b"START TEST\r\n") + else: + had_crash = True + return had_crash, output_mupy -special_tests = [ +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", "thread/thread_exc2.py", - # CIRCUITPY-CHANGE: removal and additions - # REMOVE "esp32/partition_ota.py", "circuitpython/traceback_test.py", "circuitpython/traceback_test_chained.py", ) @@ -350,10 +601,7 @@ def run_micropython(pyb, args, test_file, test_file_abspath, is_special=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 @@ -392,6 +640,10 @@ def get(required=False): return rv def send_get(what): + # Detect {\x00} pattern and convert to ctrl-key codes. + ctrl_code = lambda m: bytes([int(m.group(1))]) + what = re.sub(rb"{\\x(\d\d)}", ctrl_code, what) + os.write(master, what) return get() @@ -471,17 +723,17 @@ def send_get(what): ) # 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) # 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: lines_exp = [] @@ -603,30 +855,25 @@ def run_script_on_remote_target(self, args, test_file, is_special): 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([]) + 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_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 +889,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,11 +924,6 @@ 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": @@ -690,13 +937,20 @@ def run_tests(pyb, tests, args, result_dir, num_threads=1): 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/asmit.py") + skip_tests.add("inlineasm/thumb/asmspecialregs.py") + if args.arch not in ("armv7emsp", "armv7emdp"): 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") + + if args.inlineasm_arch == "rv32": + # Check if @micropython.asm_rv32 supports Zba instructions, and skip such tests if it doesn't + output = run_feature_check(pyb, args, "inlineasm_rv32_zba.py") + if output != b"rv32_zba\n": + skip_tests.add("inlineasm/rv32/asmzba.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 +963,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( @@ -723,24 +972,6 @@ def run_tests(pyb, tests, args, result_dir, num_threads=1): 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", - ) - # 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 @@ -749,30 +980,31 @@ def run_tests(pyb, tests, args, result_dir, num_threads=1): # 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: + skip_tests.add("extmod/json_loads.py") # tests loading a utf-8 character + + 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") @@ -788,8 +1020,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,6 +1030,15 @@ 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, ())) @@ -812,49 +1053,6 @@ 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 - def run_one_test(test_file): test_file = test_file.replace("\\", "/") test_file_abspath = os.path.abspath(test_file).replace("\\", "/") @@ -870,19 +1068,19 @@ 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_inlineasm = test_name.startswith("asm") @@ -890,19 +1088,19 @@ def run_one_test(test_file): 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_inlineasm and is_inlineasm if skip_it: print("skip ", test_file) - skipped_tests.append(test_name) + test_results.append((test_file, "skip", "")) return # Run the test on the MicroPython target. @@ -917,7 +1115,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 +1156,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,7 +1218,7 @@ 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: @@ -1024,9 +1230,7 @@ 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: @@ -1053,17 +1257,49 @@ def run_one_test(test_file): print(line) sys.exit(1) - print( - "{} tests performed ({} individual testcases)".format( - test_count.value, testcase_count.value - ) + # Return test results. + return test_results.value, testcase_count.value + + +# Print a summary of the results and save them to a JSON file. +# Returns True if everything succeeded, False otherwise. +def create_test_report(args, test_results, testcase_count=None): + passed_tests = list(r for r in test_results if r[1] == "pass") + skipped_tests = list(r for r in test_results if r[1] == "skip" and r[2] != "too large") + skipped_tests_too_large = list( + r for r in test_results if r[1] == "skip" and r[2] == "too large" ) - print("{} tests passed".format(passed_count.value)) + failed_tests = list(r for r in test_results if r[1] == "fail") + + num_tests_performed = len(passed_tests) + len(failed_tests) + + testcase_count_info = "" + if testcase_count is not None: + testcase_count_info = " ({} individual testcases)".format(testcase_count) + print("{} tests performed{}".format(num_tests_performed, testcase_count_info)) + + print("{} tests passed".format(len(passed_tests))) - 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) + print( + "{} tests skipped: {}".format( + len(skipped_tests), " ".join(test[0] for test in skipped_tests) + ) + ) + + if len(skipped_tests_too_large) > 0: + print( + "{} tests skipped because they are too large: {}".format( + len(skipped_tests_too_large), " ".join(test[0] for test in skipped_tests_too_large) + ) + ) + + if len(failed_tests) > 0: + print( + "{} tests failed: {}".format( + len(failed_tests), " ".join(test[0] for test in failed_tests) + ) + ) # Serialize regex added by append_filter. def to_json(obj): @@ -1071,23 +1307,22 @@ def to_json(obj): return obj.pattern return obj - with open(os.path.join(result_dir, RESULTS_FILE), "w") as f: + with open(os.path.join(args.result_dir, RESULTS_FILE), "w") as f: json.dump( - {"args": vars(args), "failed_tests": [test[1] for test in failed_tests]}, + { + # The arguments passed on the command-line. + "args": vars(args), + # A list of all results of the form [(test, result, reason), ...]. + "results": list(test for test in test_results), + # A list of failed tests. This is deprecated, use the "results" above instead. + "failed_tests": [test[0] for test in failed_tests], + }, f, default=to_json, ) - 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 True only if all tests succeeded. + return len(failed_tests) == 0 class append_filter(argparse.Action): @@ -1104,27 +1339,11 @@ def __call__(self, parser, args, value, option): args.filters.append((option, re.compile(value))) -def main(): - cmd_parser = argparse.ArgumentParser( - formatter_class=argparse.RawDescriptionHelpFormatter, - description="""Run and manage tests for MicroPython. - +test_instance_description = """\ 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. - -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. - -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="""\ +""" +test_instance_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 @@ -1140,7 +1359,35 @@ def main(): - execpty: - execute a command and attach to the printed /dev/pts/ device - ... - connect to the given IPv4 address - anything else specifies a serial port +""" + +test_directory_description = """\ +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. +""" + +def main(): + global injected_import_hook_code + + cmd_parser = argparse.ArgumentParser( + formatter_class=argparse.RawDescriptionHelpFormatter, + description=f"""Run and manage tests for MicroPython. + +{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 (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=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: @@ -1214,8 +1461,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() + injected_import_hook_code = injected_import_hook_code.replace("{import_prologue}", prologue) + if args.print_failures: for out in glob(os.path.join(args.result_dir, "*.out")): testbase = out[:-4] @@ -1256,7 +1520,7 @@ def main(): results_file = os.path.join(args.result_dir, RESULTS_FILE) 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: @@ -1267,47 +1531,27 @@ def main(): if args.test_dirs is 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") + test_dirs += ("import",) + if args.build != "minimal": + test_dirs += ("cmdline", "io") else: # run tests from these directories test_dirs = args.test_dirs @@ -1322,6 +1566,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 +1593,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..3b5940d91a9 --- /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 + +run_tests_module = __import__("run-tests") + +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=run_tests_module.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 = run_tests_module.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..0a72b66fa05 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(repr(er)) 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..50511665f00 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..c7bd437f3ad 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("RuntimeError", er, 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("RuntimeError", er, 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("RuntimeError", er, 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("RuntimeError", er, l) try: print(hasattr(a, id), getattr(a, id)) - except RuntimeError: - print("RuntimeError", l) + except RuntimeError as er: + print("RuntimeError", er, 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("RuntimeError", er, 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("RuntimeError", er, 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("RuntimeError", er, l) diff --git a/tests/stress/qstr_limit.py.exp b/tests/stress/qstr_limit.py.exp index 455761bc71e..2349adf220f 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 +RuntimeError name too long 256 +RuntimeError name too long 257 +RuntimeError name too long 258 {'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrst': 1} {'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstu': 1} -RuntimeError 256 -RuntimeError 257 -RuntimeError 258 -abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrst -abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstu -RuntimeError 256 -RuntimeError 257 -RuntimeError 258 +RuntimeError name too long 256 +RuntimeError name too long 257 +RuntimeError name too long 258 + + +RuntimeError name too long 256 +RuntimeError name too long 257 +RuntimeError name too long 258 True 123 True 123 -RuntimeError 256 -RuntimeError 256 -RuntimeError 257 -RuntimeError 257 -RuntimeError 258 -RuntimeError 258 +RuntimeError name too long 256 +RuntimeError name too long 256 +RuntimeError name too long 257 +RuntimeError name too long 257 +RuntimeError name too long 258 +RuntimeError name too long 258 254 255 -RuntimeError 256 -RuntimeError 257 -RuntimeError 258 -254 -255 -RuntimeError 256 -RuntimeError 257 -RuntimeError 258 +RuntimeError name too long 256 +RuntimeError name too long 257 +RuntimeError name too long 258 ok 100 ok 101 -RuntimeError 256 -RuntimeError 257 -RuntimeError 258 +RuntimeError name too long 256 +RuntimeError name too long 257 +RuntimeError name too long 258 ok 100 ok 101 ok 102 -RuntimeError 128 -RuntimeError 129 +RuntimeError name too long 128 +RuntimeError 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..90b9f4364ec --- /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", er, 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/NUCLEO_WB55.py b/tests/target_wiring/NUCLEO_WB55.py new file mode 100644 index 00000000000..ad7c120d377 --- /dev/null +++ b/tests/target_wiring/NUCLEO_WB55.py @@ -0,0 +1,8 @@ +# Target wiring for NUCLEO_WB55. +# +# Connect: +# - PA2 to PA3 + +# LPUART(1) is on PA2/PA3. +uart_loopback_args = ("LP1",) +uart_loopback_kwargs = {} diff --git a/tests/target_wiring/PYBx.py b/tests/target_wiring/PYBx.py new file mode 100644 index 00000000000..10ce520ef0a --- /dev/null +++ b/tests/target_wiring/PYBx.py @@ -0,0 +1,8 @@ +# 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 = {} diff --git a/tests/target_wiring/ZEPHYR_NUCLEO_WB55RG.py b/tests/target_wiring/ZEPHYR_NUCLEO_WB55RG.py new file mode 100644 index 00000000000..c7ca2ac26f7 --- /dev/null +++ b/tests/target_wiring/ZEPHYR_NUCLEO_WB55RG.py @@ -0,0 +1,7 @@ +# Target wiring for zephyr nucleo_wb55rg. +# +# Connect: +# - TX=PC0 to RX=PC1 + +uart_loopback_args = ("lpuart1",) +uart_loopback_kwargs = {} diff --git a/tests/target_wiring/alif.py b/tests/target_wiring/alif.py new file mode 100644 index 00000000000..18f3cbe7e5e --- /dev/null +++ b/tests/target_wiring/alif.py @@ -0,0 +1,7 @@ +# Target wiring for general alif board. +# +# Connect: +# - UART1 TX and RX, usually P0_5 and P0_4 + +uart_loopback_args = (1,) +uart_loopback_kwargs = {} diff --git a/tests/target_wiring/esp32.py b/tests/target_wiring/esp32.py new file mode 100644 index 00000000000..2767cd5acb2 --- /dev/null +++ b/tests/target_wiring/esp32.py @@ -0,0 +1,12 @@ +# Target wiring for general esp32 board. +# +# Connect: +# - GPIO4 to GPIO5 +# - GPIO12 to GPIO13 + +uart_loopback_args = (1,) +uart_loopback_kwargs = {"tx": 4, "rx": 5} + +encoder_loopback_id = 0 +encoder_loopback_out_pins = (4, 12) +encoder_loopback_in_pins = (5, 13) diff --git a/tests/target_wiring/mimxrt.py b/tests/target_wiring/mimxrt.py new file mode 100644 index 00000000000..669e9095990 --- /dev/null +++ b/tests/target_wiring/mimxrt.py @@ -0,0 +1,7 @@ +# Target wiring for general mimxrt board. +# +# Connect: +# - UART1 TX and RX, usually D0 and D1 + +uart_loopback_args = (1,) +uart_loopback_kwargs = {} diff --git a/tests/target_wiring/nrf.py b/tests/target_wiring/nrf.py new file mode 100644 index 00000000000..6979dd28ee5 --- /dev/null +++ b/tests/target_wiring/nrf.py @@ -0,0 +1,7 @@ +# Target wiring for general nrf board. +# +# Connect: +# - UART0 TX and RX + +uart_loopback_args = (0,) +uart_loopback_kwargs = {} diff --git a/tests/target_wiring/rp2.py b/tests/target_wiring/rp2.py new file mode 100644 index 00000000000..cb0fa0d6263 --- /dev/null +++ b/tests/target_wiring/rp2.py @@ -0,0 +1,7 @@ +# Target wiring for general rp2 board. +# +# Connect: +# - GPIO0 to GPIO1 + +uart_loopback_args = (0,) +uart_loopback_kwargs = {"tx": "GPIO0", "rx": "GPIO1"} diff --git a/tests/target_wiring/samd.py b/tests/target_wiring/samd.py new file mode 100644 index 00000000000..887c43a242f --- /dev/null +++ b/tests/target_wiring/samd.py @@ -0,0 +1,7 @@ +# Target wiring for general samd board. +# +# Connect: +# - D0 to D1 + +uart_loopback_args = () +uart_loopback_kwargs = {"tx": "D1", "rx": "D0"} diff --git a/tests/thread/disable_irq.py b/tests/thread/disable_irq.py index 3f1ac74f308..596e3e477b9 100644 --- a/tests/thread/disable_irq.py +++ b/tests/thread/disable_irq.py @@ -1,8 +1,14 @@ # Ensure that disabling IRQs creates mutual exclusion between threads # (also tests nesting of disable_irq across threads) -import machine -import time -import _thread + +# CIRCUITPY-CHANGE: no machine +try: + import machine + import time + import _thread +except ImportError: + print("SKIP") + raise SystemExit if not hasattr(machine, "disable_irq"): print("SKIP") diff --git a/tests/thread/mutate_bytearray.py b/tests/thread/mutate_bytearray.py index b4664781a15..7116d291cfe 100644 --- a/tests/thread/mutate_bytearray.py +++ b/tests/thread/mutate_bytearray.py @@ -2,6 +2,7 @@ # # MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd +import time import _thread # the shared bytearray @@ -36,7 +37,7 @@ def th(n, lo, hi): # busy wait for threads to finish while n_finished < n_thread: - pass + time.sleep(0) # check bytearray has correct contents print(len(ba)) diff --git a/tests/thread/mutate_dict.py b/tests/thread/mutate_dict.py index 3777af66248..dd5f69e6c5d 100644 --- a/tests/thread/mutate_dict.py +++ b/tests/thread/mutate_dict.py @@ -2,6 +2,7 @@ # # MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd +import time import _thread # the shared dict @@ -38,7 +39,7 @@ def th(n, lo, hi): # busy wait for threads to finish while n_finished < n_thread: - pass + time.sleep(0) # check dict has correct contents print(sorted(di.items())) diff --git a/tests/thread/mutate_instance.py b/tests/thread/mutate_instance.py index 306ad91c95c..63f7fb1e23d 100644 --- a/tests/thread/mutate_instance.py +++ b/tests/thread/mutate_instance.py @@ -2,6 +2,7 @@ # # MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd +import time import _thread @@ -40,7 +41,7 @@ def th(n, lo, hi): # busy wait for threads to finish while n_finished < n_thread: - pass + time.sleep(0) # check user instance has correct contents print(user.a, user.b, user.c) diff --git a/tests/thread/mutate_list.py b/tests/thread/mutate_list.py index 6f1e8812541..d7398a2f1e0 100644 --- a/tests/thread/mutate_list.py +++ b/tests/thread/mutate_list.py @@ -2,6 +2,7 @@ # # MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd +import time import _thread # the shared list @@ -39,7 +40,7 @@ def th(n, lo, hi): # busy wait for threads to finish while n_finished < n_thread: - pass + time.sleep(0) # check list has correct contents li.sort() diff --git a/tests/thread/mutate_set.py b/tests/thread/mutate_set.py index 2d9a3e0ce9e..7dcefa1d113 100644 --- a/tests/thread/mutate_set.py +++ b/tests/thread/mutate_set.py @@ -2,6 +2,7 @@ # # MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd +import time import _thread # the shared set @@ -33,7 +34,7 @@ def th(n, lo, hi): # busy wait for threads to finish while n_finished < n_thread: - pass + time.sleep(0) # check set has correct contents print(sorted(se)) diff --git a/tests/thread/stress_aes.py b/tests/thread/stress_aes.py index d8d0acd568a..ca25f8ad2fd 100644 --- a/tests/thread/stress_aes.py +++ b/tests/thread/stress_aes.py @@ -277,7 +277,7 @@ def thread_entry(n_loop): n_thread = 2 n_loop = 2 else: - n_thread = 20 + n_thread = 10 n_loop = 5 for i in range(n_thread): _thread.start_new_thread(thread_entry, (n_loop,)) diff --git a/tests/thread/stress_recurse.py b/tests/thread/stress_recurse.py index 73b3a40f33d..ec8b43fe8fc 100644 --- a/tests/thread/stress_recurse.py +++ b/tests/thread/stress_recurse.py @@ -2,6 +2,7 @@ # # MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd +import time import _thread @@ -24,5 +25,5 @@ def thread_entry(): # busy wait for thread to finish while not finished: - pass + time.sleep(0) print("done") diff --git a/tests/thread/stress_schedule.py b/tests/thread/stress_schedule.py index 97876f0f77c..362d71aa12e 100644 --- a/tests/thread/stress_schedule.py +++ b/tests/thread/stress_schedule.py @@ -27,6 +27,8 @@ def task(x): n += 1 +# This function must always use the bytecode emitter so it bounces the GIL when running. +@micropython.bytecode def thread(): while thread_run: try: @@ -46,7 +48,7 @@ def thread(): # Wait up to 10 seconds for 10000 tasks to be scheduled. t = time.ticks_ms() while n < _NUM_TASKS and time.ticks_diff(time.ticks_ms(), t) < _TIMEOUT_MS: - pass + time.sleep(0) # Stop all threads. thread_run = False diff --git a/tests/thread/thread_coop.py b/tests/thread/thread_coop.py index aefc4af074d..85cda789c93 100644 --- a/tests/thread/thread_coop.py +++ b/tests/thread/thread_coop.py @@ -7,6 +7,7 @@ import _thread import sys from time import ticks_ms, ticks_diff, sleep_ms +import micropython done = False @@ -21,6 +22,8 @@ MAX_DELTA = 100 +# This function must always use the bytecode emitter so the VM can bounce the GIL when running. +@micropython.bytecode def busy_thread(): while not done: pass diff --git a/tests/thread/thread_exc1.py b/tests/thread/thread_exc1.py index cd877409291..cd6599983c1 100644 --- a/tests/thread/thread_exc1.py +++ b/tests/thread/thread_exc1.py @@ -2,6 +2,7 @@ # # MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd +import time import _thread @@ -34,5 +35,5 @@ def thread_entry(): # busy wait for threads to finish while n_finished < n_thread: - pass + time.sleep(0) print("done") diff --git a/tests/thread/thread_exc2.py.native.exp b/tests/thread/thread_exc2.py.native.exp new file mode 100644 index 00000000000..9b2e715ef8d --- /dev/null +++ b/tests/thread/thread_exc2.py.native.exp @@ -0,0 +1,3 @@ +Unhandled exception in thread started by +ValueError: +done diff --git a/tests/thread/thread_gc1.py b/tests/thread/thread_gc1.py index b36ea9d4c84..45c17cc17be 100644 --- a/tests/thread/thread_gc1.py +++ b/tests/thread/thread_gc1.py @@ -2,6 +2,7 @@ # # MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd +import time import gc import _thread @@ -44,6 +45,6 @@ def thread_entry(n): # busy wait for threads to finish while n_finished < n_thread: - pass + time.sleep(0) print(n_correct == n_finished) diff --git a/tests/thread/thread_ident1.py b/tests/thread/thread_ident1.py index 2a3732eff53..08cfd3eb36e 100644 --- a/tests/thread/thread_ident1.py +++ b/tests/thread/thread_ident1.py @@ -2,6 +2,7 @@ # # MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd +import time import _thread @@ -27,6 +28,6 @@ def thread_entry(): new_tid = _thread.start_new_thread(thread_entry, ()) while not finished: - pass + time.sleep(0) print("done", type(new_tid) == int, new_tid == tid) diff --git a/tests/thread/thread_lock3.py b/tests/thread/thread_lock3.py index a927dc6829e..c5acfa21b7d 100644 --- a/tests/thread/thread_lock3.py +++ b/tests/thread/thread_lock3.py @@ -2,6 +2,7 @@ # # MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd +import time import _thread lock = _thread.allocate_lock() @@ -26,4 +27,4 @@ def thread_entry(idx): # busy wait for threads to finish while n_finished < n_thread: - pass + time.sleep(0) diff --git a/tests/thread/thread_lock4.py b/tests/thread/thread_lock4_intbig.py similarity index 100% rename from tests/thread/thread_lock4.py rename to tests/thread/thread_lock4_intbig.py diff --git a/tests/thread/thread_shared1.py b/tests/thread/thread_shared1.py index 251e26fae6c..c2e33abcec7 100644 --- a/tests/thread/thread_shared1.py +++ b/tests/thread/thread_shared1.py @@ -2,6 +2,7 @@ # # MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd +import time import _thread @@ -40,5 +41,5 @@ def thread_entry(n, tup): # busy wait for threads to finish while n_finished < n_thread: - pass + time.sleep(0) print(tup) diff --git a/tests/thread/thread_shared2.py b/tests/thread/thread_shared2.py index a1223c2b94f..4ce9057ca01 100644 --- a/tests/thread/thread_shared2.py +++ b/tests/thread/thread_shared2.py @@ -3,6 +3,7 @@ # # MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd +import time import _thread @@ -31,5 +32,5 @@ def thread_entry(n, lst, idx): # busy wait for threads to finish while n_finished < n_thread: - pass + time.sleep(0) print(lst) diff --git a/tests/thread/thread_stacksize1.py b/tests/thread/thread_stacksize1.py index 140d165cb34..75e1da9642f 100644 --- a/tests/thread/thread_stacksize1.py +++ b/tests/thread/thread_stacksize1.py @@ -3,6 +3,7 @@ # MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd import sys +import time import _thread # different implementations have different minimum sizes @@ -51,5 +52,5 @@ def thread_entry(): # busy wait for threads to finish while n_finished < n_thread: - pass + time.sleep(0) print("done") diff --git a/tests/thread/thread_stdin.py b/tests/thread/thread_stdin.py index a469933f19b..498b0a3a270 100644 --- a/tests/thread/thread_stdin.py +++ b/tests/thread/thread_stdin.py @@ -5,6 +5,7 @@ # This is a regression test for https://github.com/micropython/micropython/issues/15230 # on rp2, but doubles as a general property to test across all ports. import sys +import time import _thread try: @@ -38,7 +39,7 @@ def is_done(self): # have run yet. The actual delay is <20ms but spinning here instead of # sleep(0.1) means the test can run on MP builds without float support. while not thread_waiter.is_done(): - pass + time.sleep(0) # The background thread should have completed its wait by now. print(thread_waiter.is_done()) diff --git a/tests/unix/extra_coverage.py b/tests/unix/extra_coverage.py index 0ea8f7886bf..ec10a44ff39 100644 --- a/tests/unix/extra_coverage.py +++ b/tests/unix/extra_coverage.py @@ -6,6 +6,16 @@ import errno import io +import uctypes + +# create an int-like variable used for coverage of `mp_obj_get_ll` +buf = bytearray(b"\xde\xad\xbe\xef") +struct = uctypes.struct( + uctypes.addressof(buf), + {"f32": uctypes.UINT32 | 0}, + uctypes.BIG_ENDIAN, +) +deadbeef = struct.f32 data = extra_coverage() @@ -23,6 +33,7 @@ print(stream.read(1)) # read 1 byte encounters non-blocking error print(stream.readline()) # readline encounters non-blocking error print(stream.readinto(bytearray(10))) # readinto encounters non-blocking error +print(stream.readinto1(bytearray(10))) # readinto1 encounters non-blocking error print(stream.write(b"1")) # write encounters non-blocking error print(stream.write1(b"1")) # write1 encounters non-blocking error stream.set_buf(b"123") @@ -38,6 +49,28 @@ stream.set_error(0) print(stream.ioctl(0, bytearray(10))) # successful ioctl call +print("# stream.readinto") + +# stream.readinto will read 3 bytes then try to read more to fill the buffer, +# but on the second attempt will encounter EIO and should raise that error. +stream.set_error(errno.EIO) +stream.set_buf(b"123") +buf = bytearray(4) +try: + stream.readinto(buf) +except OSError as er: + print("OSError", er.errno == errno.EIO) +print(buf) + +# stream.readinto1 will read 3 bytes then should return them immediately, and +# not encounter the EIO. +stream.set_error(errno.EIO) +stream.set_buf(b"123") +buf = bytearray(4) +print(stream.readinto1(buf), buf) + +print("# stream textio") + stream2 = data[3] # is textio print(stream2.read(1)) # read 1 byte encounters non-blocking error with textio stream @@ -92,7 +125,7 @@ print(returns_NULL()) -# test for freeze_mpy +# test for freeze_mpy (importing prints several lines) import frozentest print(frozentest.__file__) diff --git a/tests/unix/extra_coverage.py.exp b/tests/unix/extra_coverage.py.exp index 4cd8b8666d2..cdb11455694 100644 --- a/tests/unix/extra_coverage.py.exp +++ b/tests/unix/extra_coverage.py.exp @@ -2,25 +2,41 @@ -123 +123 123 -0123 123 -123 -1ABCDEF +123f +123F +7fffffffffffffff +7FFFFFFFFFFFFFFF +18446744073709551615 +789f +789F ab abc ' abc' ' True' 'Tru' false true (null) -2147483648 2147483648 -80000000 -80000000 +8000000f +8000000F abc % +.a . +<%> + + +<43690> +<43690> +<43690> + +<1000.000000> + +<9223372036854775807> # GC -0x0 -0x0 +0 +0 # GC part 2 pass # tracked allocation -m_tracked_head = 0x0 +m_tracked_head = 0 0 1 1 1 2 1 @@ -37,7 +53,7 @@ m_tracked_head = 0x0 5 1 6 1 7 1 -m_tracked_head = 0x0 +m_tracked_head = 0 # vstr tests sts @@ -91,6 +107,16 @@ data 12345 6 -1 +0 +1 +0 +0.000000 +deadbeef +c0ffee777c0ffee +deadbeef +0deadbeef +c0ffee +000c0ffee # runtime utils TypeError: unsupported type for __abs__: 'str' TypeError: unsupported types for __divmod__: 'str', 'str' @@ -99,12 +125,10 @@ TypeError: unsupported types for __divmod__: 'str', 'str' 2 OverflowError: overflow converting long int to machine word OverflowError: overflow converting long int to machine word +TypeError: can't convert NoneType to int +TypeError: can't convert NoneType to int ValueError: Warning: test -# format float -? -+1e+00 -+1e+00 # binary 123 456 @@ -124,6 +148,13 @@ unlocked KeyboardInterrupt: KeyboardInterrupt: 10 +loop +scheduled function +loop +scheduled function +loop +scheduled function +scheduled function # ringbuf 99 0 98 1 @@ -185,11 +216,17 @@ None None None None +None b'123' b'123' b'123' OSError 0 +# stream.readinto +OSError True +bytearray(b'123\x00') +3 bytearray(b'123\x00') +# stream textio None None cpp None @@ -215,7 +252,7 @@ b'\x00\xff' frzmpy4 1 frzmpy4 2 NULL -uPy +interned a long string that is not interned a string that has unicode αβγ chars b'bytes 1234\x01' diff --git a/tests/unix/ffi_float2.py b/tests/unix/ffi_float2.py index bbed6966627..eac6cd106cf 100644 --- a/tests/unix/ffi_float2.py +++ b/tests/unix/ffi_float2.py @@ -29,4 +29,5 @@ def ffi_open(names): for fun in (tgammaf,): for val in (0.5, 1, 1.0, 1.5, 4, 4.0): - print("%.6f" % fun(val)) + # limit to 5 decimals in order to pass with REPR_C with FORMAT_IMPL_BASIC + print("%.5f" % fun(val)) diff --git a/tests/unix/ffi_float2.py.exp b/tests/unix/ffi_float2.py.exp index 58fc6a01acb..4c750e223a3 100644 --- a/tests/unix/ffi_float2.py.exp +++ b/tests/unix/ffi_float2.py.exp @@ -1,6 +1,6 @@ -1.772454 -1.000000 -1.000000 -0.886227 -6.000000 -6.000000 +1.77245 +1.00000 +1.00000 +0.88623 +6.00000 +6.00000 diff --git a/tests/unix/mod_os.py b/tests/unix/mod_os.py index f69fa45b2b2..468f6badd1e 100644 --- a/tests/unix/mod_os.py +++ b/tests/unix/mod_os.py @@ -1,6 +1,9 @@ # This module is not entirely compatible with CPython import os +if not hasattr(os, "getenv"): + print("SKIP") + raise SystemExit os.putenv("TEST_VARIABLE", "TEST_VALUE") diff --git a/tests/unix/time_mktime_localtime.py b/tests/unix/time_mktime_localtime.py index d1c03c103d7..df5d6cda690 100644 --- a/tests/unix/time_mktime_localtime.py +++ b/tests/unix/time_mktime_localtime.py @@ -1,4 +1,8 @@ -import time +try: + import time +except ImportError: + print("SKIP") + raise SystemExit DAYS_PER_MONTH = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] diff --git a/tools/analyze_heap_dump.py b/tools/analyze_heap_dump.py index ac1bb0c8ce5..a7be95db7d9 100755 --- a/tools/analyze_heap_dump.py +++ b/tools/analyze_heap_dump.py @@ -82,7 +82,7 @@ help="Draw the ownership graph of blocks on the heap", ) @click.option("--analyze-snapshots", default="last", type=click.Choice(["all", "last"])) -def do_all_the_things( # noqa: C901: too complex +def do_all_the_things( # noqa: C901 too complex ram_filename, bin_filename, map_filename, diff --git a/tools/board_stubs/circuitpython_setboard/__init__.py b/tools/board_stubs/circuitpython_setboard/__init__.py index 3a73beb3119..69a405405b8 100644 --- a/tools/board_stubs/circuitpython_setboard/__init__.py +++ b/tools/board_stubs/circuitpython_setboard/__init__.py @@ -12,7 +12,12 @@ import shutil from collections import defaultdict from importlib import resources -from importlib.abc import Traversable + +try: + from importlib.resources.abc import Traversable +except ModuleNotFoundError: + # 3.10 and earlier. + from importlib.abc import Traversable def get_definitions_or_exit(board: str) -> Traversable: diff --git a/tools/boardgen.py b/tools/boardgen.py index 39bedf71cd0..3723e7ce31b 100644 --- a/tools/boardgen.py +++ b/tools/boardgen.py @@ -108,6 +108,10 @@ def add_board_pin_name(self, board_pin_name, hidden=False): ) ) + # Iterate over board pin names in consistent sorted order. + def board_pin_names(self): + return sorted(self._board_pin_names, key=lambda x: x[0]) + # Override this to handle an af specified in af.csv. def add_af(self, af_idx, af_name, af): raise NotImplementedError @@ -295,7 +299,7 @@ def print_board_locals_dict(self, out_source): file=out_source, ) for pin in self.available_pins(): - for board_pin_name, board_hidden in pin._board_pin_names: + for board_pin_name, board_hidden in pin.board_pin_names(): if board_hidden: # Don't include hidden pins in Pins.board. continue @@ -389,7 +393,7 @@ def print_defines(self, out_header, cpu=True, board=True): # #define pin_BOARDNAME (pin_CPUNAME) if board: - for board_pin_name, _board_hidden in pin._board_pin_names: + for board_pin_name, _board_hidden in pin.board_pin_names(): # Note: Hidden board pins are still available to C via the macro. # Note: The RHS isn't wrapped in (), which is necessary to make the # STATIC_AF_ macro work on STM32. diff --git a/tools/cc1 b/tools/cc1 index 827d5886a04..aa2534f01e7 100755 --- a/tools/cc1 +++ b/tools/cc1 @@ -23,8 +23,8 @@ import re # TODO somehow make them externally configurable # this is the path to the true C compiler -cc1_path = '/usr/lib/gcc/x86_64-unknown-linux-gnu/5.3.0/cc1' -#cc1_path = '/usr/lib/gcc/arm-none-eabi/5.3.0/cc1' +cc1_path = "/usr/lib/gcc/x86_64-unknown-linux-gnu/5.3.0/cc1" +# cc1_path = '/usr/lib/gcc/arm-none-eabi/5.3.0/cc1' # this must be the same as MICROPY_QSTR_BYTES_IN_HASH bytes_in_qstr_hash = 2 @@ -41,11 +41,16 @@ print_debug = False ################################################################################ # precompile regexs -re_preproc_line = re.compile(r'# [0-9]+ ') -re_map_entry = re.compile(r'\{.+?\(MP_QSTR_([A-Za-z0-9_]+)\).+\},') -re_mp_obj_dict_t = re.compile(r'(?P(static )?const mp_obj_dict_t (?P[a-z0-9_]+) = \{ \.base = \{&mp_type_dict\}, \.map = \{ \.all_keys_are_qstrs = 1, \.is_fixed = 1, \.is_ordered = )1(?P, \.used = .+ };)$') -re_mp_map_t = re.compile(r'(?P(static )?const mp_map_t (?P[a-z0-9_]+) = \{ \.all_keys_are_qstrs = 1, \.is_fixed = 1, \.is_ordered = )1(?P, \.used = .+ };)$') -re_mp_rom_map_elem_t = re.compile(r'static const mp_rom_map_elem_t [a-z_0-9]+\[\] = {$') +re_preproc_line = re.compile(r"# [0-9]+ ") +re_map_entry = re.compile(r"\{.+?\(MP_QSTR_([A-Za-z0-9_]+)\).+\},") +re_mp_obj_dict_t = re.compile( + r"(?P(static )?const mp_obj_dict_t (?P[a-z0-9_]+) = \{ \.base = \{&mp_type_dict\}, \.map = \{ \.all_keys_are_qstrs = 1, \.is_fixed = 1, \.is_ordered = )1(?P, \.used = .+ };)$" +) +re_mp_map_t = re.compile( + r"(?P(static )?const mp_map_t (?P[a-z0-9_]+) = \{ \.all_keys_are_qstrs = 1, \.is_fixed = 1, \.is_ordered = )1(?P, \.used = .+ };)$" +) +re_mp_rom_map_elem_t = re.compile(r"static const mp_rom_map_elem_t [a-z_0-9]+\[\] = {$") + # this must match the equivalent function in qstr.c def compute_hash(qstr): @@ -55,18 +60,19 @@ def compute_hash(qstr): # Make sure that valid hash is never zero, zero means "hash not computed" return (hash & ((1 << (8 * bytes_in_qstr_hash)) - 1)) or 1 + # this algo must match the equivalent in map.c def hash_insert(map, key, value): hash = compute_hash(key) pos = hash % len(map) start_pos = pos if print_debug: - print(' insert %s: start at %u/%u -- ' % (key, pos, len(map)), end='') + print(" insert %s: start at %u/%u -- " % (key, pos, len(map)), end="") while True: if map[pos] is None: # found empty slot, so key is not in table if print_debug: - print('put at %u' % pos) + print("put at %u" % pos) map[pos] = (key, value) return else: @@ -76,6 +82,7 @@ def hash_insert(map, key, value): pos = (pos + 1) % len(map) assert pos != start_pos + def hash_find(map, key): hash = compute_hash(key) pos = hash % len(map) @@ -92,6 +99,7 @@ def hash_find(map, key): if pos == start_pos: return attempts, None + def process_map_table(file, line, output): output.append(line) @@ -101,7 +109,7 @@ def process_map_table(file, line, output): while True: line = file.readline() if len(line) == 0: - print('unexpected end of input') + print("unexpected end of input") sys.exit(1) line = line.strip() if len(line) == 0: @@ -110,38 +118,38 @@ def process_map_table(file, line, output): if re_preproc_line.match(line): # preprocessor line number comment continue - if line == '};': + if line == "};": # end of table (we assume it appears on a single line) break table_contents.append(line) # make combined string of entries - entries_str = ''.join(table_contents) + entries_str = "".join(table_contents) # split into individual entries entries = [] while entries_str: # look for single entry, by matching nested braces match = None - if entries_str[0] == '{': + if entries_str[0] == "{": nested_braces = 0 for i in range(len(entries_str)): - if entries_str[i] == '{': + if entries_str[i] == "{": nested_braces += 1 - elif entries_str[i] == '}': + elif entries_str[i] == "}": nested_braces -= 1 if nested_braces == 0: - match = re_map_entry.match(entries_str[:i + 2]) + match = re_map_entry.match(entries_str[: i + 2]) break if not match: - print('unknown line in table:', entries_str) + print("unknown line in table:", entries_str) sys.exit(1) # extract single entry line = match.group(0) qstr = match.group(1) - entries_str = entries_str[len(line):].lstrip() + entries_str = entries_str[len(line) :].lstrip() # add the qstr and the whole line to list of all entries entries.append((qstr, line)) @@ -164,28 +172,28 @@ def process_map_table(file, line, output): attempts, line = hash_find(map, qstr) assert line is not None if print_debug: - print(' %s lookup took %u attempts' % (qstr, attempts)) + print(" %s lookup took %u attempts" % (qstr, attempts)) total_attempts += attempts - if len(entries): + if entries: stats = len(map), len(entries) / len(map), total_attempts / len(entries) else: stats = 0, 0, 0 if print_debug: - print(' table stats: size=%d, load=%.2f, avg_lookups=%.1f' % stats) + print(" table stats: size=%d, load=%.2f, avg_lookups=%.1f" % stats) # output hash table for row in map: if row is None: - output.append('{ 0, 0 },\n') + output.append("{ 0, 0 },\n") else: - output.append(row[1] + '\n') - output.append('};\n') + output.append(row[1] + "\n") + output.append("};\n") # skip to next non-blank line while True: line = file.readline() if len(line) == 0: - print('unexpected end of input') + print("unexpected end of input") sys.exit(1) line = line.strip() if len(line) == 0: @@ -197,19 +205,20 @@ def process_map_table(file, line, output): if match is None: match = re_mp_map_t.match(line) if match is None: - print('expecting mp_obj_dict_t or mp_map_t definition') + print("expecting mp_obj_dict_t or mp_map_t definition") print(output[0]) print(line) sys.exit(1) - line = match.group('head') + '0' + match.group('tail') + '\n' + line = match.group("head") + "0" + match.group("tail") + "\n" output.append(line) - return (match.group('id'),) + stats + return (match.group("id"),) + stats + def process_file(filename): output = [] file_changed = False - with open(filename, 'rt') as f: + with open(filename, "rt") as f: while True: line = f.readline() if not line: @@ -218,39 +227,41 @@ def process_file(filename): file_changed = True stats = process_map_table(f, line, output) if print_stats: - print(' [%s: size=%d, load=%.2f, avg_lookups=%.1f]' % stats) + print(" [%s: size=%d, load=%.2f, avg_lookups=%.1f]" % stats) else: output.append(line) if file_changed: if print_debug: - print(' modifying static maps in', output[0].strip()) - with open(filename, 'wt') as f: + print(" modifying static maps in", output[0].strip()) + with open(filename, "wt") as f: for line in output: f.write(line) + def main(): # run actual C compiler # need to quote args that have special characters in them def quote(s): - if s.find('<') != -1 or s.find('>') != -1: + if s.find("<") != -1 or s.find(">") != -1: return "'" + s + "'" else: return s - ret = os.system(cc1_path + ' ' + ' '.join(quote(s) for s in sys.argv[1:])) + + ret = os.system(cc1_path + " " + " ".join(quote(s) for s in sys.argv[1:])) if ret != 0: - ret = (ret & 0x7f) or 127 # make it in range 0-127, but non-zero + ret = (ret & 0x7F) or 127 # make it in range 0-127, but non-zero sys.exit(ret) - if sys.argv[1] == '-E': + if sys.argv[1] == "-E": # CPP has been run, now do our processing stage for i, arg in enumerate(sys.argv): - if arg == '-o': + if arg == "-o": return process_file(sys.argv[i + 1]) print('%s: could not find "-o" option' % (sys.argv[0],)) sys.exit(1) - elif sys.argv[1] == '-fpreprocessed': + elif sys.argv[1] == "-fpreprocessed": # compiler has been run, nothing more to do return else: @@ -258,5 +269,6 @@ def main(): print('%s: unknown first option "%s"' % (sys.argv[0], sys.argv[1])) sys.exit(1) -if __name__ == '__main__': + +if __name__ == "__main__": main() diff --git a/tools/chart_code_size.py b/tools/chart_code_size.py index cd62074fd0d..f3d9c5bdc40 100644 --- a/tools/chart_code_size.py +++ b/tools/chart_code_size.py @@ -24,7 +24,7 @@ def parse_hex(h): @click.command() @click.argument("elf_filename") -def do_all_the_things(elf_filename): # noqa: C901: too complex +def do_all_the_things(elf_filename): # noqa: C901 too complex symbol = None last_address = 0 all_symbols = {} diff --git a/tools/ci.sh b/tools/ci.sh index cfc9754837f..132fbd8f81c 100755 --- a/tools/ci.sh +++ b/tools/ci.sh @@ -9,15 +9,20 @@ fi # Ensure known OPEN_MAX (NO_FILES) limit. ulimit -n 1024 +# Fail on some things which are warnings otherwise +export MICROPY_MAINTAINER_BUILD=1 + ######################################################################################## # general helper functions function ci_gcc_arm_setup { + sudo apt-get update sudo apt-get install gcc-arm-none-eabi libnewlib-arm-none-eabi arm-none-eabi-gcc --version } function ci_gcc_riscv_setup { + sudo apt-get update sudo apt-get install gcc-riscv64-unknown-elf picolibc-riscv64-unknown-elf riscv64-unknown-elf-gcc --version } @@ -35,6 +40,7 @@ function ci_picotool_setup { # c code formatting function ci_c_code_formatting_setup { + sudo apt-get update sudo apt-get install uncrustify uncrustify --version } @@ -74,42 +80,69 @@ function ci_code_size_setup { ci_picotool_setup } +function _ci_is_git_merge { + [[ $(git log -1 --format=%P "$1" | wc -w) > 1 ]] +} + function ci_code_size_build { # check the following ports for the change in their code size - PORTS_TO_CHECK=bmusxpdv + # Override the list by setting PORTS_TO_CHECK in the environment before invoking ci. + : ${PORTS_TO_CHECK:=bmusxpdv} + SUBMODULES="lib/asf4 lib/berkeley-db-1.xx lib/btstack lib/cyw43-driver lib/lwip lib/mbedtls lib/micropython-lib lib/nxp_driver lib/pico-sdk lib/stm32lib lib/tinyusb" # Default GitHub pull request sets HEAD to a generated merge commit # between PR branch (HEAD^2) and base branch (i.e. master) (HEAD^1). # # We want to compare this generated commit with the base branch, to see what - # the code size impact would be if we merged this PR. - REFERENCE=$(git rev-parse --short HEAD^1) - COMPARISON=$(git rev-parse --short HEAD) + # the code size impact would be if we merged this PR. During CI we are at a merge commit, + # so this tests the merged PR against its merge base. + # Override the refs by setting REFERENCE and/or COMPARISON in the environment before invoking ci. + : ${COMPARISON:=$(git rev-parse --short HEAD)} + : ${REFERENCE:=$(git rev-parse --short ${COMPARISON}^1)} echo "Comparing sizes of reference ${REFERENCE} to ${COMPARISON}..." git log --oneline $REFERENCE..$COMPARISON - function code_size_build_step { - COMMIT=$1 - OUTFILE=$2 - IGNORE_ERRORS=$3 - - echo "Building ${COMMIT}..." - git checkout --detach $COMMIT - git submodule update --init $SUBMODULES - git show -s - tools/metrics.py clean $PORTS_TO_CHECK - tools/metrics.py build $PORTS_TO_CHECK | tee $OUTFILE || $IGNORE_ERRORS - } - - # build reference, save to size0 - # ignore any errors with this build, in case master is failing - code_size_build_step $REFERENCE ~/size0 true - # build PR/branch, save to size1 - code_size_build_step $COMPARISON ~/size1 false - - unset -f code_size_build_step + OLD_BRANCH="$(git rev-parse --abbrev-ref HEAD)" + + ( # Execute in a subshell so the trap & code_size_build_step doesn't leak + function code_size_build_step { + if [ ! -z "$OLD_BRANCH" ]; then + trap 'git checkout "$OLD_BRANCH"' RETURN EXIT ERR + fi + + COMMIT=$1 + OUTFILE=$2 + IGNORE_ERRORS=$3 + + git checkout --detach $COMMIT + git submodule update --init $SUBMODULES + git show -s + tools/metrics.py clean "$PORTS_TO_CHECK" + # Allow errors from tools/metrics.py to propagate out of the pipe below. + set -o pipefail + tools/metrics.py build "$PORTS_TO_CHECK" | tee -a $OUTFILE || $IGNORE_ERRORS + return $? + } + + # build reference, save to size0 + # ignore any errors with this build, in case master is failing + echo "BUILDING $(git log --format='%s [%h]' -1 ${REFERENCE})" > ~/size0 + code_size_build_step $REFERENCE ~/size0 true + # build PR/branch, save to size1 + if _ci_is_git_merge "$COMPARISON"; then + echo "BUILDING $(git log --oneline -1 --format='%s [merge of %h]' ${COMPARISON}^2)" + else + echo "BUILDING $(git log --oneline -1 --formta='%s [%h]' ${COMPARISON})" + fi > ~/size1 + code_size_build_step $COMPARISON ~/size1 false + ) +} + +function ci_code_size_report { + # Allow errors from tools/metrics.py to propagate out of the pipe above. + (set -o pipefail; tools/metrics.py diff ~/size0 ~/size1 | tee diff) } ######################################################################################## @@ -117,15 +150,12 @@ function ci_code_size_build { function ci_mpy_format_setup { sudo apt-get update - sudo apt-get install python2.7 sudo pip3 install pyelftools - python2.7 --version python3 --version } function ci_mpy_format_test { # Test mpy-tool.py dump feature on bytecode - python2.7 ./tools/mpy-tool.py -xd tests/frozen/frozentest.mpy python3 ./tools/mpy-tool.py -xd tests/frozen/frozentest.mpy # Build MicroPython @@ -143,6 +173,15 @@ function ci_mpy_format_test { $micropython ./tools/mpy-tool.py -x -d examples/natmod/features1/features1.mpy } +function ci_mpy_cross_debug_emitter { + make ${MAKEOPTS} -C mpy-cross + mpy_cross=./mpy-cross/build/mpy-cross + + # Make sure the debug emitter does not crash or fail for simple files + $mpy_cross -X emit=native -march=debug ./tests/basics/0prelim.py | \ + grep -E "ENTRY|EXIT" | wc -l | grep "^2$" +} + ######################################################################################## # ports/cc3200 @@ -158,14 +197,17 @@ function ci_cc3200_build { ######################################################################################## # ports/esp32 -# GitHub tag of ESP-IDF to use for CI (note: must be a tag or a branch) -IDF_VER=v5.2.2 +# GitHub tag of ESP-IDF to use for CI, extracted from the esp32 dependency lockfile +# This should end up as a tag name like vX.Y.Z +# (note: This hacky parsing can be replaced with 'yq' once Ubuntu >=24.04 is in use) +IDF_VER=v$(grep -A10 "idf:" ports/esp32/lockfiles/dependencies.lock.esp32 | grep "version:" | head -n1 | sed -E 's/ +version: //') PYTHON=$(command -v python3 2> /dev/null) PYTHON_VER=$(${PYTHON:-python} --version | cut -d' ' -f2) export IDF_CCACHE_ENABLE=1 function ci_esp32_idf_setup { + echo "Using ESP-IDF version $IDF_VER" git clone --depth 1 --branch $IDF_VER https://github.com/espressif/esp-idf.git # doing a treeless clone isn't quite as good as --shallow-submodules, but it # is smaller than full clones and works when the submodule commit isn't a head. @@ -204,13 +246,28 @@ function ci_esp32_build_s3_c3 { make ${MAKEOPTS} -C ports/esp32 BOARD=ESP32_GENERIC_C3 } +function ci_esp32_build_c2_c5_c6 { + ci_esp32_build_common + + make ${MAKEOPTS} -C ports/esp32 BOARD=ESP32_GENERIC_C2 + make ${MAKEOPTS} -C ports/esp32 BOARD=ESP32_GENERIC_C5 + make ${MAKEOPTS} -C ports/esp32 BOARD=ESP32_GENERIC_C6 +} + +function ci_esp32_build_p4 { + ci_esp32_build_common + + make ${MAKEOPTS} -C ports/esp32 BOARD=ESP32_GENERIC_P4 + make ${MAKEOPTS} -C ports/esp32 BOARD=ESP32_GENERIC_P4 BOARD_VARIANT=C6_WIFI +} + ######################################################################################## # ports/esp8266 function ci_esp8266_setup { sudo pip3 install pyserial esptool==3.3.1 pyelftools ar - wget https://github.com/jepler/esp-open-sdk/releases/download/2018-06-10/xtensa-lx106-elf-standalone.tar.gz - zcat xtensa-lx106-elf-standalone.tar.gz | tar x + wget https://micropython.org/resources/xtensa-lx106-elf-standalone.tar.gz + (set -o pipefail; zcat xtensa-lx106-elf-standalone.tar.gz | tar x) # Remove this esptool.py so pip version is used instead rm xtensa-lx106-elf/bin/esptool.py } @@ -317,17 +374,52 @@ function ci_qemu_setup_rv32 { qemu-system-riscv32 --version } -function ci_qemu_build_arm { +function ci_qemu_setup_rv64 { + ci_gcc_riscv_setup + sudo apt-get update + sudo apt-get install qemu-system + qemu-system-riscv64 --version +} + +function ci_qemu_build_arm_prepare { make ${MAKEOPTS} -C mpy-cross make ${MAKEOPTS} -C ports/qemu submodules +} + +function ci_qemu_build_arm_bigendian { + ci_qemu_build_arm_prepare make ${MAKEOPTS} -C ports/qemu CFLAGS_EXTRA=-DMP_ENDIANNESS_BIG=1 - make ${MAKEOPTS} -C ports/qemu clean - make ${MAKEOPTS} -C ports/qemu test_full +} + +function ci_qemu_build_arm_sabrelite { + ci_qemu_build_arm_prepare make ${MAKEOPTS} -C ports/qemu BOARD=SABRELITE test_full +} - # Test building and running native .mpy with armv7m architecture. +function ci_qemu_build_arm_thumb_softfp { + ci_qemu_build_arm_prepare + make BOARD=MPS2_AN385 ${MAKEOPTS} -C ports/qemu test_full + + # Test building native .mpy with ARM-M softfp architectures. + ci_native_mpy_modules_build armv6m ci_native_mpy_modules_build armv7m - make ${MAKEOPTS} -C ports/qemu test_natmod + + # Test running native .mpy with all ARM-M architectures. + make BOARD=MPS2_AN385 ${MAKEOPTS} -C ports/qemu test_natmod RUN_TESTS_EXTRA="--arch armv6m" + make BOARD=MPS2_AN385 ${MAKEOPTS} -C ports/qemu test_natmod RUN_TESTS_EXTRA="--arch armv7m" +} + +function ci_qemu_build_arm_thumb_hardfp { + ci_qemu_build_arm_prepare + make BOARD=MPS2_AN500 ${MAKEOPTS} -C ports/qemu test_full + + # Test building native .mpy with all ARM-M hardfp architectures. + ci_native_mpy_modules_build armv7emsp + ci_native_mpy_modules_build armv7emdp + + # Test running native .mpy with all ARM-M hardfp architectures. + make BOARD=MPS2_AN500 ${MAKEOPTS} -C ports/qemu test_natmod RUN_TESTS_EXTRA="--arch armv7emsp" + make BOARD=MPS2_AN500 ${MAKEOPTS} -C ports/qemu test_natmod RUN_TESTS_EXTRA="--arch armv7emdp" } function ci_qemu_build_rv32 { @@ -340,6 +432,12 @@ function ci_qemu_build_rv32 { make ${MAKEOPTS} -C ports/qemu BOARD=VIRT_RV32 test_natmod } +function ci_qemu_build_rv64 { + make ${MAKEOPTS} -C mpy-cross + make ${MAKEOPTS} -C ports/qemu BOARD=VIRT_RV64 submodules + make ${MAKEOPTS} -C ports/qemu BOARD=VIRT_RV64 test +} + ######################################################################################## # ports/renesas-ra @@ -403,13 +501,22 @@ function ci_samd_build { # ports/stm32 function ci_stm32_setup { - ci_gcc_arm_setup + # Use a recent version of the ARM toolchain, to work with Cortex-M55. + wget https://developer.arm.com/-/media/Files/downloads/gnu/14.3.rel1/binrel/arm-gnu-toolchain-14.3.rel1-x86_64-arm-none-eabi.tar.xz + xzcat arm-gnu-toolchain-14.3.rel1-x86_64-arm-none-eabi.tar.xz | tar x + pip3 install pyelftools pip3 install ar pip3 install pyhy } +function ci_stm32_path { + echo $(pwd)/arm-gnu-toolchain-14.3.rel1-x86_64-arm-none-eabi/bin +} + function ci_stm32_pyb_build { + # This function builds the following MCU families: F4, F7. + make ${MAKEOPTS} -C mpy-cross make ${MAKEOPTS} -C ports/stm32 MICROPY_PY_NETWORK_WIZNET5K=5200 submodules make ${MAKEOPTS} -C ports/stm32 BOARD=PYBD_SF2 submodules @@ -421,20 +528,18 @@ function ci_stm32_pyb_build { make ${MAKEOPTS} -C ports/stm32/mboot BOARD=PYBV10 CFLAGS_EXTRA='-DMBOOT_FSLOAD=1 -DMBOOT_VFS_LFS2=1' make ${MAKEOPTS} -C ports/stm32/mboot BOARD=PYBD_SF6 make ${MAKEOPTS} -C ports/stm32/mboot BOARD=STM32F769DISC CFLAGS_EXTRA='-DMBOOT_ADDRESS_SPACE_64BIT=1 -DMBOOT_SDCARD_ADDR=0x100000000ULL -DMBOOT_SDCARD_BYTE_SIZE=0x400000000ULL -DMBOOT_FSLOAD=1 -DMBOOT_VFS_FAT=1' - - # Test building native .mpy with armv7emsp architecture. - git submodule update --init lib/berkeley-db-1.xx - ci_native_mpy_modules_build armv7emsp } function ci_stm32_nucleo_build { + # This function builds the following MCU families: F0, H5, H7, L0, L4, WB. + make ${MAKEOPTS} -C mpy-cross make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_H743ZI submodules git submodule update --init lib/mynewt-nimble # Test building various MCU families, some with additional options. make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_F091RC - make ${MAKEOPTS} -C ports/stm32 BOARD=STM32H573I_DK + make ${MAKEOPTS} -C ports/stm32 BOARD=STM32H573I_DK CFLAGS_EXTRA='-DMICROPY_HW_TINYUSB_STACK=1' make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_H743ZI COPT=-O2 CFLAGS_EXTRA='-DMICROPY_PY_THREAD=1' make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_L073RZ make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_L476RG DEBUG=1 @@ -454,21 +559,22 @@ function ci_stm32_nucleo_build { } function ci_stm32_misc_build { + # This function builds the following MCU families: G0, G4, H7, L1, N6, U5, WL. + make ${MAKEOPTS} -C mpy-cross make ${MAKEOPTS} -C ports/stm32 BOARD=ARDUINO_GIGA submodules make ${MAKEOPTS} -C ports/stm32 BOARD=ARDUINO_GIGA + make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_G0B1RE + make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_G474RE + make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_L152RE + make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_N657X0 + make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_U5A5ZJ_Q + make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_WL55 } ######################################################################################## # ports/unix -CI_UNIX_OPTS_SYS_SETTRACE=( - MICROPY_PY_BTREE=0 - MICROPY_PY_FFI=0 - MICROPY_PY_SSL=0 - CFLAGS_EXTRA="-DMICROPY_PY_SYS_SETTRACE=1" -) - CI_UNIX_OPTS_SYS_SETTRACE_STACKLESS=( MICROPY_PY_BTREE=0 MICROPY_PY_FFI=0 @@ -494,6 +600,26 @@ CI_UNIX_OPTS_QEMU_RISCV64=( MICROPY_STANDALONE=1 ) +CI_UNIX_OPTS_SANITIZE_ADDRESS=( + # Macro MP_ASAN allows detecting ASan on gcc<=13 + CFLAGS_EXTRA="-fsanitize=address --param asan-use-after-return=0 -DMP_ASAN=1" + LDFLAGS_EXTRA="-fsanitize=address --param asan-use-after-return=0" +) + +CI_UNIX_OPTS_SANITIZE_UNDEFINED=( + # Macro MP_UBSAN allows detecting UBSan on gcc<=13 + CFLAGS_EXTRA="-fsanitize=undefined -fno-sanitize=nonnull-attribute -DMP_UBSAN=1" + LDFLAGS_EXTRA="-fsanitize=undefined -fno-sanitize=nonnull-attribute" +) + +CI_UNIX_OPTS_REPR_B=( + VARIANT=standard + CFLAGS_EXTRA="-DMICROPY_OBJ_REPR=MICROPY_OBJ_REPR_B -DMICROPY_PY_UCTYPES=0 -Dmp_int_t=int32_t -Dmp_uint_t=uint32_t" + MICROPY_FORCE_32BIT=1 + RUN_TESTS_MPY_CROSS_FLAGS="--mpy-cross-flags=\"-march=x86 -msmall-int-bits=30\"" + +) + function ci_unix_build_helper { make ${MAKEOPTS} -C mpy-cross make ${MAKEOPTS} -C ports/unix "$@" submodules @@ -509,13 +635,26 @@ function ci_unix_run_tests_helper { make -C ports/unix "$@" test } +function ci_unix_run_tests_full_extra { + micropython=$1 + (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=$micropython ./run-multitests.py multi_net/*.py) + (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=$micropython ./run-perfbench.py --average 1 1000 1000) +} + +function ci_unix_run_tests_full_no_native_helper { + variant=$1 + shift + micropython=../ports/unix/build-$variant/micropython + make -C ports/unix VARIANT=$variant "$@" test_full_no_native + ci_unix_run_tests_full_extra $micropython +} + function ci_unix_run_tests_full_helper { variant=$1 shift micropython=../ports/unix/build-$variant/micropython make -C ports/unix VARIANT=$variant "$@" test_full - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=$micropython ./run-multitests.py multi_net/*.py) - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=$micropython ./run-perfbench.py 1000 1000) + ci_unix_run_tests_full_extra $micropython } function ci_native_mpy_modules_build { @@ -524,40 +663,19 @@ function ci_native_mpy_modules_build { else arch=$1 fi - for natmod in features1 features3 features4 heapq re + for natmod in btree deflate features1 features3 features4 framebuf heapq random re do - make -C examples/natmod/$natmod clean + make -C examples/natmod/$natmod ARCH=$arch clean make -C examples/natmod/$natmod ARCH=$arch done - # deflate, framebuf, and random currently cannot build on xtensa due to - # some symbols that have been removed from the compiler's runtime, in - # favour of being provided from ROM. - if [ $arch != "xtensa" ]; then - for natmod in deflate framebuf random - do - make -C examples/natmod/$natmod clean - make -C examples/natmod/$natmod ARCH=$arch - done - fi - - # features2 requires soft-float on armv7m, rv32imc, and xtensa. On armv6m - # the compiler generates absolute relocations in the object file - # referencing soft-float functions, which is not supported at the moment. - make -C examples/natmod/features2 clean - if [ $arch = "rv32imc" ] || [ $arch = "armv7m" ] || [ $arch = "xtensa" ]; then + # features2 requires soft-float on rv32imc and xtensa. + make -C examples/natmod/features2 ARCH=$arch clean + if [ $arch = "rv32imc" ] || [ $arch = "xtensa" ]; then make -C examples/natmod/features2 ARCH=$arch MICROPY_FLOAT_IMPL=float - elif [ $arch != "armv6m" ]; then + else make -C examples/natmod/features2 ARCH=$arch fi - - # btree requires thread local storage support on rv32imc, whilst on xtensa - # it relies on symbols that are provided from ROM but not exposed to - # natmods at the moment. - if [ $arch != "rv32imc" ] && [ $arch != "xtensa" ]; then - make -C examples/natmod/btree clean - make -C examples/natmod/btree ARCH=$arch - fi } function ci_native_mpy_modules_32bit_build { @@ -569,7 +687,7 @@ function ci_unix_minimal_build { } function ci_unix_minimal_run_tests { - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/build-minimal/micropython ./run-tests.py -e exception_chain -e self_type_check -e subclass_native_init -d basics) + make -C ports/unix VARIANT=minimal test } function ci_unix_standard_build { @@ -591,9 +709,9 @@ function ci_unix_standard_v2_run_tests { } function ci_unix_coverage_setup { - sudo pip3 install setuptools - sudo pip3 install pyelftools - sudo pip3 install ar + pip3 install setuptools + pip3 install pyelftools + pip3 install ar gcc --version python3 --version } @@ -604,7 +722,7 @@ function ci_unix_coverage_build { } function ci_unix_coverage_run_tests { - ci_unix_run_tests_full_helper coverage + MICROPY_TEST_TIMEOUT=60 ci_unix_run_tests_full_helper coverage } function ci_unix_coverage_run_mpy_merge_tests { @@ -639,12 +757,11 @@ function ci_unix_coverage_run_native_mpy_tests { function ci_unix_32bit_setup { sudo dpkg --add-architecture i386 sudo apt-get update - sudo apt-get install gcc-multilib g++-multilib libffi-dev:i386 python2.7 + sudo apt-get install gcc-multilib g++-multilib libffi-dev:i386 sudo pip3 install setuptools sudo pip3 install pyelftools sudo pip3 install ar gcc --version - python2.7 --version python3 --version } @@ -662,13 +779,20 @@ function ci_unix_coverage_32bit_run_native_mpy_tests { } function ci_unix_nanbox_build { - # Use Python 2 to check that it can run the build scripts - ci_unix_build_helper PYTHON=python2.7 VARIANT=nanbox CFLAGS_EXTRA="-DMICROPY_PY_MATH_CONSTANTS=1" + ci_unix_build_helper VARIANT=nanbox CFLAGS_EXTRA="-DMICROPY_PY_MATH_CONSTANTS=1" ci_unix_build_ffi_lib_helper gcc -m32 } function ci_unix_nanbox_run_tests { - ci_unix_run_tests_full_helper nanbox PYTHON=python2.7 + ci_unix_run_tests_full_no_native_helper nanbox +} + +function ci_unix_longlong_build { + ci_unix_build_helper VARIANT=longlong "${CI_UNIX_OPTS_SANITIZE_UNDEFINED[@]}" +} + +function ci_unix_longlong_run_tests { + ci_unix_run_tests_full_helper longlong } function ci_unix_float_build { @@ -681,7 +805,17 @@ function ci_unix_float_run_tests { ci_unix_run_tests_helper CFLAGS_EXTRA="-DMICROPY_FLOAT_IMPL=MICROPY_FLOAT_IMPL_FLOAT" } +function ci_unix_gil_enabled_build { + ci_unix_build_helper VARIANT=standard MICROPY_PY_THREAD_GIL=1 + ci_unix_build_ffi_lib_helper gcc +} + +function ci_unix_gil_enabled_run_tests { + ci_unix_run_tests_full_helper standard MICROPY_PY_THREAD_GIL=1 +} + function ci_unix_clang_setup { + sudo apt-get update sudo apt-get install clang clang --version } @@ -693,7 +827,8 @@ function ci_unix_stackless_clang_build { } function ci_unix_stackless_clang_run_tests { - ci_unix_run_tests_helper CC=clang + # Timeout needs to be increased for thread/stress_aes.py test. + MICROPY_TEST_TIMEOUT=90 ci_unix_run_tests_helper CC=clang } function ci_unix_float_clang_build { @@ -706,24 +841,36 @@ function ci_unix_float_clang_run_tests { ci_unix_run_tests_helper CC=clang } -function ci_unix_settrace_build { +function ci_unix_settrace_stackless_build { + make ${MAKEOPTS} -C mpy-cross + make ${MAKEOPTS} -C ports/unix submodules + make ${MAKEOPTS} -C ports/unix "${CI_UNIX_OPTS_SYS_SETTRACE_STACKLESS[@]}" +} + +function ci_unix_settrace_stackless_run_tests { + ci_unix_run_tests_full_helper standard "${CI_UNIX_OPTS_SYS_SETTRACE_STACKLESS[@]}" +} + +function ci_unix_sanitize_undefined_build { make ${MAKEOPTS} -C mpy-cross make ${MAKEOPTS} -C ports/unix submodules - make ${MAKEOPTS} -C ports/unix "${CI_UNIX_OPTS_SYS_SETTRACE[@]}" + make ${MAKEOPTS} -C ports/unix VARIANT=coverage "${CI_UNIX_OPTS_SANITIZE_UNDEFINED[@]}" + ci_unix_build_ffi_lib_helper gcc } -function ci_unix_settrace_run_tests { - ci_unix_run_tests_full_helper standard "${CI_UNIX_OPTS_SYS_SETTRACE[@]}" +function ci_unix_sanitize_undefined_run_tests { + MICROPY_TEST_TIMEOUT=60 ci_unix_run_tests_full_helper coverage VARIANT=coverage "${CI_UNIX_OPTS_SANITIZE_UNDEFINED[@]}" } -function ci_unix_settrace_stackless_build { +function ci_unix_sanitize_address_build { make ${MAKEOPTS} -C mpy-cross make ${MAKEOPTS} -C ports/unix submodules - make ${MAKEOPTS} -C ports/unix "${CI_UNIX_OPTS_SYS_SETTRACE_STACKLESS[@]}" + make ${MAKEOPTS} -C ports/unix VARIANT=coverage "${CI_UNIX_OPTS_SANITIZE_ADDRESS[@]}" + ci_unix_build_ffi_lib_helper gcc } -function ci_unix_settrace_stackless_run_tests { - ci_unix_run_tests_full_helper standard "${CI_UNIX_OPTS_SYS_SETTRACE_STACKLESS[@]}" +function ci_unix_sanitize_address_run_tests { + MICROPY_TEST_TIMEOUT=60 ci_unix_run_tests_full_helper coverage VARIANT=coverage "${CI_UNIX_OPTS_SANITIZE_ADDRESS[@]}" } function ci_unix_macos_build { @@ -740,7 +887,9 @@ function ci_unix_macos_run_tests { # Issues with macOS tests: # - float_parse and float_parse_doubleprec parse/print floats out by a few mantissa bits # - ffi_callback crashes for an unknown reason - (cd tests && MICROPY_MICROPYTHON=../ports/unix/build-standard/micropython ./run-tests.py --exclude '(float_parse|float_parse_doubleprec|ffi_callback).py') + # - thread/stress_heap.py is flaky + # - thread/thread_gc1.py is flaky + (cd tests && MICROPY_MICROPYTHON=../ports/unix/build-standard/micropython ./run-tests.py --exclude '(float_parse|float_parse_doubleprec|ffi_callback|thread/stress_heap|thread/thread_gc1).py') } function ci_unix_qemu_mips_setup { @@ -758,8 +907,12 @@ function ci_unix_qemu_mips_build { } function ci_unix_qemu_mips_run_tests { + # Issues with MIPS tests: + # - thread/stress_aes.py takes around 50 seconds + # - thread/stress_recurse.py is flaky + # - thread/thread_gc1.py is flaky file ./ports/unix/build-coverage/micropython - (cd tests && MICROPY_MICROPYTHON=../ports/unix/build-coverage/micropython ./run-tests.py) + (cd tests && MICROPY_MICROPYTHON=../ports/unix/build-coverage/micropython MICROPY_TEST_TIMEOUT=90 ./run-tests.py --exclude 'thread/stress_recurse.py|thread/thread_gc1.py') } function ci_unix_qemu_arm_setup { @@ -779,8 +932,11 @@ function ci_unix_qemu_arm_build { function ci_unix_qemu_arm_run_tests { # Issues with ARM tests: # - (i)listdir does not work, it always returns the empty list (it's an issue with the underlying C call) + # - thread/stress_aes.py takes around 70 seconds + # - thread/stress_recurse.py is flaky + # - thread/thread_gc1.py is flaky file ./ports/unix/build-coverage/micropython - (cd tests && MICROPY_MICROPYTHON=../ports/unix/build-coverage/micropython ./run-tests.py --exclude 'vfs_posix.*\.py') + (cd tests && MICROPY_MICROPYTHON=../ports/unix/build-coverage/micropython MICROPY_TEST_TIMEOUT=90 ./run-tests.py --exclude 'vfs_posix.*\.py|thread/stress_recurse.py|thread/thread_gc1.py') } function ci_unix_qemu_riscv64_setup { @@ -798,14 +954,30 @@ function ci_unix_qemu_riscv64_build { } function ci_unix_qemu_riscv64_run_tests { + # Issues with RISCV-64 tests: + # - thread/stress_aes.py takes around 140 seconds + # - thread/stress_recurse.py is flaky + # - thread/thread_gc1.py is flaky file ./ports/unix/build-coverage/micropython - (cd tests && MICROPY_MICROPYTHON=../ports/unix/build-coverage/micropython ./run-tests.py) + (cd tests && MICROPY_MICROPYTHON=../ports/unix/build-coverage/micropython MICROPY_TEST_TIMEOUT=180 ./run-tests.py --exclude 'thread/stress_recurse.py|thread/thread_gc1.py') +} + +function ci_unix_repr_b_build { + ci_unix_build_helper "${CI_UNIX_OPTS_REPR_B[@]}" + ci_unix_build_ffi_lib_helper gcc -m32 +} + +function ci_unix_repr_b_run_tests { + # ci_unix_run_tests_full_no_native_helper is not used due to + # https://github.com/micropython/micropython/issues/18105 + ci_unix_run_tests_helper "${CI_UNIX_OPTS_REPR_B[@]}" } ######################################################################################## # ports/windows function ci_windows_setup { + sudo apt-get update sudo apt-get install gcc-mingw-w64 } @@ -813,14 +985,15 @@ function ci_windows_build { make ${MAKEOPTS} -C mpy-cross make ${MAKEOPTS} -C ports/windows submodules make ${MAKEOPTS} -C ports/windows CROSS_COMPILE=i686-w64-mingw32- + make ${MAKEOPTS} -C ports/windows CROSS_COMPILE=x86_64-w64-mingw32- BUILD=build-standard-w64 } ######################################################################################## # ports/zephyr -ZEPHYR_DOCKER_VERSION=v0.26.13 -ZEPHYR_SDK_VERSION=0.16.8 -ZEPHYR_VERSION=v3.7.0 +ZEPHYR_DOCKER_VERSION=v0.28.1 +ZEPHYR_SDK_VERSION=0.17.2 +ZEPHYR_VERSION=v4.2.0 function ci_zephyr_setup { IMAGE=ghcr.io/zephyrproject-rtos/ci:${ZEPHYR_DOCKER_VERSION} @@ -859,6 +1032,7 @@ function ci_zephyr_install { } function ci_zephyr_build { + git submodule update --init lib/micropython-lib docker exec zephyr-ci west build -p auto -b qemu_x86 -- -DCONF_FILE=prj_minimal.conf docker exec zephyr-ci west build -p auto -b frdm_k64f docker exec zephyr-ci west build -p auto -b mimxrt1050_evk @@ -867,9 +1041,7 @@ function ci_zephyr_build { function ci_zephyr_run_tests { docker exec zephyr-ci west build -p auto -b qemu_cortex_m3 -- -DCONF_FILE=prj_minimal.conf - # Issues with zephyr tests: - # - inf_nan_arith fails pow(-1, nan) test - (cd tests && ./run-tests.py -t execpty:"qemu-system-arm -cpu cortex-m3 -machine lm3s6965evb -nographic -monitor null -serial pty -kernel ../ports/zephyr/build/zephyr/zephyr.elf" -d basics float --exclude inf_nan_arith) + (cd tests && ./run-tests.py -t execpty:"qemu-system-arm -cpu cortex-m3 -machine lm3s6965evb -nographic -monitor null -serial pty -kernel ../ports/zephyr/build/zephyr/zephyr.elf") } ######################################################################################## @@ -886,3 +1058,86 @@ function ci_alif_ae3_build { make ${MAKEOPTS} -C ports/alif BOARD=OPENMV_AE3 MCU_CORE=M55_DUAL make ${MAKEOPTS} -C ports/alif BOARD=ALIF_ENSEMBLE MCU_CORE=M55_DUAL } + +function _ci_help { + # Note: these lines must be indented with tab characters (required by bash <<-EOF) + cat <<-EOF + ci.sh: Script fragments used during CI + + When invoked as a script, runs a sequence of ci steps, + stopping after the first error. + + Usage: + ${BASH_SOURCE} step1 step2... + + Steps: + EOF + if type -path column > /dev/null 2>&1; then + grep '^function ci_' $0 | awk '{print $2}' | sed 's/^ci_//' | column + else + grep '^function ci_' $0 | awk '{print $2}' | sed 's/^ci_//' + fi + exit +} + +function _ci_bash_completion { + echo "alias ci=\"$(readlink -f "$0")\"; complete -W '$(grep '^function ci_' $0 | awk '{print $2}' | sed 's/^ci_//')' ci" +} + +function _ci_zsh_completion { + echo "alias ci=\"$(readlink -f "$0"\"); _complete_mpy_ci_zsh() { compadd $(grep '^function ci_' $0 | awk '{sub(/^ci_/,"",$2); print $2}' | tr '\n' ' ') }; autoload -Uz compinit; compinit; compdef _complete_mpy_ci_zsh $(readlink -f "$0")" +} + +function _ci_fish_completion { + echo "alias ci=\"$(readlink -f "$0"\"); complete -c ci -p $(readlink -f "$0") -f -a '$(grep '^function ci_' $(readlink -f "$0") | awk '{sub(/^ci_/,"",$2); print $2}' | tr '\n' ' ')'" +} + +function _ci_main { + case "$1" in + (-h|-?|--help) + _ci_help + ;; + (--bash-completion) + _ci_bash_completion + ;; + (--zsh-completion) + _ci_zsh_completion + ;; + (--fish-completion) + _ci_fish_completion + ;; + (-*) + echo "Unknown option: $1" 1>&2 + exit 1 + ;; + (*) + set -e + cd $(dirname "$0")/.. + while [ $# -ne 0 ]; do + ci_$1 + shift + done + ;; + esac +} + +# https://stackoverflow.com/questions/2683279/how-to-detect-if-a-script-is-being-sourced +sourced=0 +if [ -n "$ZSH_VERSION" ]; then + case $ZSH_EVAL_CONTEXT in *:file) sourced=1;; esac +elif [ -n "$KSH_VERSION" ]; then + [ "$(cd -- "$(dirname -- "$0")" && pwd -P)/$(basename -- "$0")" != "$(cd -- "$(dirname -- "${.sh.file}")" && pwd -P)/$(basename -- "${.sh.file}")" ] && sourced=1 +elif [ -n "$BASH_VERSION" ]; then + (return 0 2>/dev/null) && sourced=1 +else # All other shells: examine $0 for known shell binary filenames. + # Detects `sh` and `dash`; add additional shell filenames as needed. + case ${0##*/} in sh|-sh|dash|-dash) sourced=1;; esac +fi + +if [ $sourced -eq 0 ]; then + # invoked as a command + if [ "$#" -eq 0 ]; then + set -- --help + fi + _ci_main "$@" +fi diff --git a/tools/ci_check_duplicate_usb_vid_pid.py b/tools/ci_check_duplicate_usb_vid_pid.py index 5361914af19..38cce0f28be 100644 --- a/tools/ci_check_duplicate_usb_vid_pid.py +++ b/tools/ci_check_duplicate_usb_vid_pid.py @@ -104,7 +104,7 @@ def check_vid_pid(files, clusterlist): """ usb_pattern = re.compile( - r"^CIRCUITPY_USB_DEVICE\s*=\s*0$|^IDF_TARGET = (esp32|esp32c2|esp32c3|esp32c6|esp32h2|esp32p4)$|^MCU_SERIES = MG24$", + r"^CIRCUITPY_USB_DEVICE\s*=\s*0$|^IDF_TARGET = (esp32|esp32c2|esp32c3|esp32c5|esp32c6|esp32c61|esp32h2|esp32p4)$|^MCU_SERIES = MG24$", flags=re.M, ) diff --git a/tools/ci_fetch_deps.py b/tools/ci_fetch_deps.py index be190ad6606..05559ac2d12 100644 --- a/tools/ci_fetch_deps.py +++ b/tools/ci_fetch_deps.py @@ -59,6 +59,7 @@ def _all_submodules(): "espressif": [ "extmod/ulab/", "lib/certificates/", + "lib/mp3/", "lib/protomatter/", "lib/quirc/", "lib/tlsf", @@ -68,6 +69,7 @@ def _all_submodules(): "mimxrt10xx": ["extmod/ulab/", "lib/tinyusb/", "lib/tlsf", "data/nvm.toml/"], "nordic": [ "extmod/ulab/", + "lib/mbedtls/", "lib/mp3/", "lib/protomatter/", "lib/tinyusb/", diff --git a/tools/ci_set_idf_constraint.py b/tools/ci_set_idf_constraint.py new file mode 100644 index 00000000000..49c187f4587 --- /dev/null +++ b/tools/ci_set_idf_constraint.py @@ -0,0 +1,47 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026 Adafruit Industries LLC +# +# SPDX-License-Identifier: MIT + +"""Set IDF_CONSTRAINT_FILE for CI. + +CI installs requirements-dev.txt for all ports, but on Espressif builds we must +also apply the matching ESP-IDF constraints file so pip does not upgrade shared +packages (for example click) beyond what ESP-IDF allows. This script derives the +active ESP-IDF major.minor version from version.cmake and exports the exact +constraints file path into GITHUB_ENV for later install steps. +""" + +import os +import pathlib +import re + +TOP = pathlib.Path(__file__).resolve().parent.parent + + +def main() -> None: + version_cmake = TOP / "ports" / "espressif" / "esp-idf" / "tools" / "cmake" / "version.cmake" + data = version_cmake.read_text(encoding="utf-8") + + major = re.search(r"IDF_VERSION_MAJOR\s+(\d+)", data) + minor = re.search(r"IDF_VERSION_MINOR\s+(\d+)", data) + if major is None or minor is None: + raise RuntimeError(f"Unable to parse IDF version from {version_cmake}") + + idf_tools_path = os.environ.get("IDF_TOOLS_PATH") + if not idf_tools_path: + raise RuntimeError("IDF_TOOLS_PATH is not set") + + constraint = ( + pathlib.Path(idf_tools_path) / f"espidf.constraints.v{major.group(1)}.{minor.group(1)}.txt" + ) + + github_env = os.environ.get("GITHUB_ENV") + if github_env: + with open(github_env, "a", encoding="utf-8") as f: + f.write(f"IDF_CONSTRAINT_FILE={constraint}\n") + + print(f"Set IDF_CONSTRAINT_FILE={constraint}") + + +if __name__ == "__main__": + main() diff --git a/tools/codeformat.py b/tools/codeformat.py index a648d401ec3..cf91049a731 100644 --- a/tools/codeformat.py +++ b/tools/codeformat.py @@ -231,7 +231,7 @@ def batch(cmd, files, N=200, check=False): command = ["python3", "tools/ruff_bindings.py"] batch(command, bindings_files(), check=True) - # Format Python files with black. + # Format Python files with "ruff format" (using config in pyproject.toml). if format_py: command = ["ruff", "format"] if args.v: diff --git a/tools/file2h.py b/tools/file2h.py index df9cc02fdab..2707d4a16e5 100644 --- a/tools/file2h.py +++ b/tools/file2h.py @@ -9,8 +9,6 @@ # ; # This script simply prints the escaped string straight to stdout -from __future__ import print_function - import sys # Can either be set explicitly, or left blank to auto-detect diff --git a/tools/gen_display_resources.py b/tools/gen_display_resources.py index 7b6de6d95d4..9ed829f7d37 100644 --- a/tools/gen_display_resources.py +++ b/tools/gen_display_resources.py @@ -8,8 +8,8 @@ import struct import sys -sys.path.insert(0, "bitmap_font") -sys.path.insert(0, "../../tools/bitmap_font") +sys.path.insert(0, "tools/bitmap_font") # For running from root +sys.path.insert(0, "../../tools/bitmap_font") # For running from a port directory from adafruit_bitmap_font import bitmap_font diff --git a/tools/insert-usb-ids.py b/tools/insert-usb-ids.py index 4691d5a710c..1b043e1fef0 100644 --- a/tools/insert-usb-ids.py +++ b/tools/insert-usb-ids.py @@ -6,8 +6,6 @@ # inserts those values into the template file specified by sys.argv[2], # printing the result to stdout -from __future__ import print_function - import sys import re import string diff --git a/tools/makemanifest.py b/tools/makemanifest.py index e076a03e0be..860935397af 100644 --- a/tools/makemanifest.py +++ b/tools/makemanifest.py @@ -24,7 +24,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -from __future__ import print_function import sys import os import subprocess diff --git a/tools/manifestfile.py b/tools/manifestfile.py index beaa36d0f5f..9c7a6e140f9 100644 --- a/tools/manifestfile.py +++ b/tools/manifestfile.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 contextlib import os import sys diff --git a/tools/metrics.py b/tools/metrics.py index f6189e65abb..8bb96ba119a 100755 --- a/tools/metrics.py +++ b/tools/metrics.py @@ -43,20 +43,23 @@ """ -import collections, sys, re, subprocess +import collections, os, sys, re, shlex, subprocess, multiprocessing -MAKE_FLAGS = ["-j3", "CFLAGS_EXTRA=-DNDEBUG"] +MAKE_FLAGS = ["-j{}".format(multiprocessing.cpu_count()), "CFLAGS_EXTRA=-DNDEBUG"] class PortData: - def __init__(self, name, dir, output, make_flags=None): + def __init__(self, name, dir, output, make_flags=None, pre_cmd=None): self.name = name self.dir = dir self.output = output self.make_flags = make_flags self.needs_mpy_cross = dir not in ("bare-arm", "minimal") + self.pre_cmd = pre_cmd +mpy_cross_output = "mpy-cross/build/mpy-cross" + port_data = { "b": PortData("bare-arm", "bare-arm", "build/firmware.elf"), "m": PortData("minimal x86", "minimal", "build/firmware.elf"), @@ -65,7 +68,12 @@ def __init__(self, name, dir, output, make_flags=None): "s": PortData("stm32", "stm32", "build-PYBV10/firmware.elf", "BOARD=PYBV10"), "c": PortData("cc3200", "cc3200", "build/WIPY/release/application.axf", "BTARGET=application"), "8": PortData("esp8266", "esp8266", "build-ESP8266_GENERIC/firmware.elf"), - "3": PortData("esp32", "esp32", "build-ESP32_GENERIC/micropython.elf"), + "3": PortData( + "esp32", + "esp32", + "build-ESP32_GENERIC/micropython.elf", + pre_cmd=". esp-idf/export.sh", + ), "x": PortData("mimxrt", "mimxrt", "build-TEENSY40/firmware.elf"), "e": PortData("renesas-ra", "renesas-ra", "build-EK_RA6M2/firmware.elf"), "r": PortData("nrf", "nrf", "build-PCA10040/firmware.elf"), @@ -74,8 +82,15 @@ def __init__(self, name, dir, output, make_flags=None): "v": PortData("qemu rv32", "qemu", "build-VIRT_RV32/firmware.elf", "BOARD=VIRT_RV32"), } +for port_letter, port in port_data.items(): + port.pre_cmd = os.environ.get(f"PRE_CMD_{port_letter}", port.pre_cmd) + + +def quoted(args): + return " ".join(shlex.quote(word) for word in args) -def syscmd(*args): + +def syscmd(*args, pre_cmd=None): sys.stdout.flush() a2 = [] for a in args: @@ -83,6 +98,10 @@ def syscmd(*args): a2.append(a) elif a: a2.extend(a) + if pre_cmd is not None: + a2_quoted = quoted(a2) + a2 = ["bash", "-c", "{} && {}".format(pre_cmd, a2_quoted)] + print(a2) subprocess.check_call(a2) @@ -108,6 +127,8 @@ def read_build_log(filename): with open(filename) as f: for line in f: line = line.strip() + if line.startswith("BUILDING ") and "_ref" not in data: + data["_ref"] = line.removeprefix("BUILDING ") if line.strip() == "COMPUTING SIZES": found_sizes = True elif found_sizes: @@ -139,9 +160,15 @@ def do_diff(args): data1 = read_build_log(args[0]) data2 = read_build_log(args[1]) + ref1 = data1.pop("_ref", "(unknown ref)") + ref2 = data2.pop("_ref", "(unknown ref)") + print(f"Reference: {ref1}") + print(f"Comparison: {ref2}") max_delta = None for key, value1 in data1.items(): value2 = data2[key] + if key == mpy_cross_output: + name = "mpy-cross" for port in port_data.values(): if key == "ports/{}/{}".format(port.dir, port.output): name = port.name @@ -181,8 +208,19 @@ def do_clean(args): ports = parse_port_list(args) print("CLEANING") + + if any(port.needs_mpy_cross for port in ports): + syscmd("make", "-C", "mpy-cross", "clean") + for port in ports: - syscmd("make", "-C", "ports/{}".format(port.dir), port.make_flags, "clean") + syscmd( + "make", + "-C", + "ports/{}".format(port.dir), + port.make_flags, + "clean", + pre_cmd=port.pre_cmd, + ) def do_build(args): @@ -196,7 +234,14 @@ def do_build(args): print("BUILDING PORTS") for port in ports: - syscmd("make", "-C", "ports/{}".format(port.dir), MAKE_FLAGS, port.make_flags) + syscmd( + "make", + "-C", + "ports/{}".format(port.dir), + MAKE_FLAGS, + port.make_flags, + pre_cmd=port.pre_cmd, + ) do_sizes(args) @@ -207,6 +252,10 @@ def do_sizes(args): ports = parse_port_list(args) print("COMPUTING SIZES") + + if any(port.needs_mpy_cross for port in ports): + syscmd("size", mpy_cross_output) + for port in ports: syscmd("size", "ports/{}/{}".format(port.dir, port.output)) diff --git a/tools/mpy-tool.py b/tools/mpy-tool.py index 8849f2f1e59..bf0b89018e4 100755 --- a/tools/mpy-tool.py +++ b/tools/mpy-tool.py @@ -24,40 +24,21 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -# Python 2/3/MicroPython compatibility code -from __future__ import print_function +import io +import struct import sys +from binascii import hexlify -if sys.version_info[0] == 2: - from binascii import hexlify as hexlify_py2 - - str_cons = lambda val, enc=None: str(val) - bytes_cons = lambda val, enc=None: bytearray(val) - is_str_type = lambda o: isinstance(o, str) - is_bytes_type = lambda o: type(o) is bytearray - is_int_type = lambda o: isinstance(o, int) or isinstance(o, long) # noqa: F821 - - def hexlify_to_str(b): - x = hexlify_py2(b) - return ":".join(x[i : i + 2] for i in range(0, len(x), 2)) - -elif sys.version_info[0] == 3: # Also handles MicroPython - from binascii import hexlify - - str_cons = str - bytes_cons = bytes - is_str_type = lambda o: isinstance(o, str) - is_bytes_type = lambda o: isinstance(o, bytes) - is_int_type = lambda o: isinstance(o, int) - - def hexlify_to_str(b): - return str(hexlify(b, ":"), "ascii") +str_cons = str +bytes_cons = bytes +is_str_type = lambda o: isinstance(o, str) +is_bytes_type = lambda o: isinstance(o, bytes) +is_int_type = lambda o: isinstance(o, int) -# end compatibility code +def hexlify_to_str(b): + return str(hexlify(b, ":"), "ascii") -import sys -import struct sys.path.append(sys.path[0] + "/../py") import makeqstrdata as qstrutil @@ -114,6 +95,23 @@ class Config: MP_NATIVE_ARCH_XTENSA = 9 MP_NATIVE_ARCH_XTENSAWIN = 10 MP_NATIVE_ARCH_RV32IMC = 11 +MP_NATIVE_ARCH_RV64IMC = 12 + +MP_NATIVE_ARCH_NAMES = [ + "NONE", + "X86", + "X64", + "ARMV6", + "ARMV6M", + "ARMV7M", + "ARMV7EM", + "ARMV7EMSP", + "ARMV7EMDP", + "XTENSA", + "XTENSAWIN", + "RV32IMC", + "RV64IMC", +] MP_PERSISTENT_OBJ_FUN_TABLE = 0 MP_PERSISTENT_OBJ_NONE = 1 @@ -142,6 +140,8 @@ class Config: MP_BC_FORMAT_VAR_UINT = 2 MP_BC_FORMAT_OFFSET = 3 +MP_NATIVE_ARCH_FLAGS_PRESENT = 0x40 + mp_unary_op_method_name = ( "__pos__", "__neg__", @@ -306,6 +306,25 @@ class Opcode: MP_BC_POP_JUMP_IF_TRUE, MP_BC_POP_JUMP_IF_FALSE, ) + ALL_OFFSET = ( + MP_BC_UNWIND_JUMP, + MP_BC_JUMP, + MP_BC_POP_JUMP_IF_TRUE, + MP_BC_POP_JUMP_IF_FALSE, + MP_BC_JUMP_IF_TRUE_OR_POP, + MP_BC_JUMP_IF_FALSE_OR_POP, + MP_BC_SETUP_WITH, + MP_BC_SETUP_EXCEPT, + MP_BC_SETUP_FINALLY, + MP_BC_POP_EXCEPT_JUMP, + MP_BC_FOR_ITER, + ) + ALL_WITH_CHILD = ( + MP_BC_MAKE_FUNCTION, + MP_BC_MAKE_FUNCTION_DEFARGS, + MP_BC_MAKE_CLOSURE, + MP_BC_MAKE_CLOSURE_DEFARGS, + ) # Create a dict mapping opcode value to opcode name. mapping = ["unknown" for _ in range(256)] @@ -562,6 +581,7 @@ def __init__( mpy_source_file, mpy_segments, header, + arch_flags, qstr_table, obj_table, raw_code, @@ -574,6 +594,7 @@ def __init__( self.mpy_segments = mpy_segments self.source_file = qstr_table[0] self.header = header + self.arch_flags = arch_flags self.qstr_table = qstr_table self.obj_table = obj_table self.raw_code = raw_code @@ -651,6 +672,14 @@ def disassemble(self): print("mpy_source_file:", self.mpy_source_file) print("source_file:", self.source_file.str) print("header:", hexlify_to_str(self.header)) + arch_index = (self.header[2] >> 2) & 0x2F + if arch_index >= len(MP_NATIVE_ARCH_NAMES): + arch_name = "UNKNOWN" + else: + arch_name = MP_NATIVE_ARCH_NAMES[arch_index] + print("arch:", arch_name) + if self.header[2] & MP_NATIVE_ARCH_FLAGS_PRESENT != 0: + print("arch_flags:", hex(self.arch_flags)) print("qstr_table[%u]:" % len(self.qstr_table)) for q in self.qstr_table: print(" %s" % q.str) @@ -888,7 +917,7 @@ def __init__(self, parent_name, qstr_table, fun_data, prelude_offset, code_kind) self.escaped_name = unique_escaped_name def disassemble_children(self): - print(" children:", [rc.simple_name.str for rc in self.children]) + self.print_children_annotated() for rc in self.children: rc.disassemble() @@ -980,6 +1009,75 @@ def freeze_raw_code(self, prelude_ptr=None, type_sig=0): raw_code_count += 1 raw_code_content += 4 * 4 + @staticmethod + def decode_lineinfo(line_info: memoryview) -> "tuple[int, int, memoryview]": + c = line_info[0] + if (c & 0x80) == 0: + # 0b0LLBBBBB encoding + return (c & 0x1F), (c >> 5), line_info[1:] + else: + # 0b1LLLBBBB 0bLLLLLLLL encoding (l's LSB in second byte) + return (c & 0xF), (((c << 4) & 0x700) | line_info[1]), line_info[2:] + + def get_source_annotation(self, ip: int, file=None) -> dict: + bc_offset = ip - self.offset_opcodes + try: + line_info = memoryview(self.fun_data)[self.offset_line_info : self.offset_opcodes] + except AttributeError: + return {"file": file, "line": None} + + source_line = 1 + while line_info: + bc_increment, line_increment, line_info = self.decode_lineinfo(line_info) + if bc_offset >= bc_increment: + bc_offset -= bc_increment + source_line += line_increment + else: + break + + return {"file": file, "line": source_line} + + def get_label(self, ip: "int | None" = None, child_num: "int | None" = None) -> str: + if ip is not None: + assert child_num is None + return "%s.%d" % (self.escaped_name, ip) + elif child_num is not None: + return "%s.child%d" % (self.escaped_name, child_num) + else: + return "%s" % self.escaped_name + + def print_children_annotated(self) -> None: + """ + Equivalent to `print(" children:", [child.simple_name.str for child in self.children])`, + but also includes json markers for the start and end of each one's name in that line. + """ + + labels = ["%s.children" % self.escaped_name] + annotation_labels = [] + output = io.StringIO() + output.write(" children: [") + sep = ", " + for i, child in enumerate(self.children): + if i != 0: + output.write(sep) + start_col = output.tell() + 1 + output.write(child.simple_name.str) + end_col = output.tell() + 1 + labels.append(self.get_label(child_num=i)) + annotation_labels.append( + { + "name": self.get_label(child_num=i), + "target": child.get_label(), + "range": { + "startCol": start_col, + "endCol": end_col, + }, + }, + ) + output.write("]") + + print(output.getvalue(), annotations={"labels": annotation_labels}, labels=labels) + class RawCodeBytecode(RawCode): def __init__(self, parent_name, qstr_table, obj_table, fun_data): @@ -988,9 +1086,58 @@ def __init__(self, parent_name, qstr_table, obj_table, fun_data): parent_name, qstr_table, fun_data, 0, MP_CODE_BYTECODE ) + def get_opcode_annotations_labels( + self, opcode: int, ip: int, arg: int, sz: int, arg_pos: int, arg_len: int + ) -> "tuple[dict, list[str]]": + annotations = { + "source": self.get_source_annotation(ip), + "disassembly": Opcode.mapping[opcode], + } + labels = [self.get_label(ip)] + + if opcode in Opcode.ALL_OFFSET: + annotations["link"] = { + "offset": arg_pos, + "length": arg_len, + "to": ip + arg + sz, + } + annotations["labels"] = [ + { + "name": self.get_label(ip), + "target": self.get_label(ip + arg + sz), + "range": { + "startCol": arg_pos + 1, + "endCol": arg_pos + arg_len + 1, + }, + }, + ] + + elif opcode in Opcode.ALL_WITH_CHILD: + try: + child = self.children[arg] + except IndexError: + # link out-of-range child to the child array itself + target = "%s.children" % self.escaped_name + else: + # link resolvable child to the actual child + target = child.get_label() + + annotations["labels"] = [ + { + "name": self.get_label(ip), + "target": target, + "range": { + "startCol": arg_pos + 1, + "endCol": arg_pos + arg_len + 1, + }, + }, + ] + + return annotations, labels + def disassemble(self): bc = self.fun_data - print("simple_name:", self.simple_name.str) + print("simple_name:", self.simple_name.str, labels=[self.get_label()]) print(" raw bytecode:", len(bc), hexlify_to_str(bc)) print(" prelude:", self.prelude_signature) print(" args:", [self.qstr_table[i].str for i in self.names[1:]]) @@ -1006,9 +1153,22 @@ def disassemble(self): pass else: arg = "" - print( - " %-11s %s %s" % (hexlify_to_str(bc[ip : ip + sz]), Opcode.mapping[bc[ip]], arg) + + pre_arg_part = " %-11s %s" % ( + hexlify_to_str(bc[ip : ip + sz]), + Opcode.mapping[bc[ip]], + ) + arg_part = "%s" % arg + annotations, labels = self.get_opcode_annotations_labels( + opcode=bc[ip], + ip=ip, + arg=arg, + sz=sz, + arg_pos=len(pre_arg_part) + 1, + arg_len=len(arg_part), ) + + print(pre_arg_part, arg_part, annotations=annotations, labels=labels) ip += sz self.disassemble_children() @@ -1085,6 +1245,7 @@ def __init__( MP_NATIVE_ARCH_XTENSA, MP_NATIVE_ARCH_XTENSAWIN, MP_NATIVE_ARCH_RV32IMC, + MP_NATIVE_ARCH_RV64IMC, ): self.fun_data_attributes = '__attribute__((section(".text,\\"ax\\",@progbits # ")))' else: @@ -1102,13 +1263,13 @@ def __init__( self.fun_data_attributes += " __attribute__ ((aligned (4)))" elif ( MP_NATIVE_ARCH_ARMV6M <= config.native_arch <= MP_NATIVE_ARCH_ARMV7EMDP - ) or config.native_arch == MP_NATIVE_ARCH_RV32IMC: - # ARMVxxM or RV32IMC -- two byte align. + ) or MP_NATIVE_ARCH_RV32IMC <= config.native_arch <= MP_NATIVE_ARCH_RV64IMC: + # ARMVxxM or RV{32,64}IMC -- two byte align. self.fun_data_attributes += " __attribute__ ((aligned (2)))" def disassemble(self): fun_data = self.fun_data - print("simple_name:", self.simple_name.str) + print("simple_name:", self.simple_name.str, labels=[self.get_label()]) print( " raw data:", len(fun_data), @@ -1362,7 +1523,7 @@ def read_mpy(filename): if header[1] != config.MPY_VERSION: raise MPYReadError(filename, "incompatible .mpy version") feature_byte = header[2] - mpy_native_arch = feature_byte >> 2 + mpy_native_arch = (feature_byte >> 2) & 0x2F if mpy_native_arch != MP_NATIVE_ARCH_NONE: mpy_sub_version = feature_byte & 3 if mpy_sub_version != config.MPY_SUB_VERSION: @@ -1373,6 +1534,11 @@ def read_mpy(filename): raise MPYReadError(filename, "native architecture mismatch") config.mp_small_int_bits = header[3] + arch_flags = 0 + # Read the architecture-specific flag bits if present. + if (feature_byte & MP_NATIVE_ARCH_FLAGS_PRESENT) != 0: + arch_flags = reader.read_uint() + # Read number of qstrs, and number of objects. n_qstr = reader.read_uint() n_obj = reader.read_uint() @@ -1401,6 +1567,7 @@ def read_mpy(filename): filename, segments, header, + arch_flags, qstr_table, obj_table, raw_code, @@ -1696,26 +1863,40 @@ def merge_mpy(compiled_modules, output_file): merged_mpy.extend(f.read()) else: main_cm_idx = None + arch_flags = 0 for idx, cm in enumerate(compiled_modules): feature_byte = cm.header[2] - mpy_native_arch = feature_byte >> 2 + mpy_native_arch = (feature_byte >> 2) & 0x2F if mpy_native_arch: # Must use qstr_table and obj_table from this raw_code if main_cm_idx is not None: raise Exception("can't merge files when more than one contains native code") main_cm_idx = idx + arch_flags = cm.arch_flags if main_cm_idx is not None: # Shift main_cm to front of list. compiled_modules.insert(0, compiled_modules.pop(main_cm_idx)) + if config.arch_flags is not None: + arch_flags = config.arch_flags + header = bytearray(4) ## CIRCUITPY-CHANGE: "C" is used for CircuitPython header[0] = ord("C") header[1] = config.MPY_VERSION - header[2] = config.native_arch << 2 | config.MPY_SUB_VERSION if config.native_arch else 0 + header[2] = ( + (MP_NATIVE_ARCH_FLAGS_PRESENT if arch_flags != 0 else 0) + | config.native_arch << 2 + | config.MPY_SUB_VERSION + if config.native_arch + else 0 + ) header[3] = config.mp_small_int_bits merged_mpy.extend(header) + if arch_flags != 0: + merged_mpy.extend(mp_encode_uint(arch_flags)) + n_qstr = 0 n_obj = 0 for cm in compiled_modules: @@ -1771,6 +1952,138 @@ def copy_section(file, offset, offset2): f.write(merged_mpy) +def extract_segments(compiled_modules, basename, kinds_arg): + import re + + kind_str = ("META", "QSTR", "OBJ", "CODE") + kinds = set() + if kinds_arg is not None: + for kind in kinds_arg.upper().split(","): + if kind in kind_str: + kinds.add(kind) + else: + raise Exception('unknown segment kind "%s"' % (kind,)) + segments = [] + for module in compiled_modules: + for segment in module.mpy_segments: + if not kinds or kind_str[segment.kind] in kinds: + segments.append((module.mpy_source_file, module.source_file.str, segment)) + count_len = len(str(len(segments))) + sanitiser = re.compile("[^a-zA-Z0-9_.-]") + for counter, entry in enumerate(segments): + file_name, source_file, segment = entry + output_name = ( + basename + + "_" + + str(counter).rjust(count_len, "0") + + "_" + + sanitiser.sub("_", source_file) + + "_" + + kind_str[segment.kind] + + "_" + + sanitiser.sub("_", str(segment.name)) + + ".bin" + ) + with open(file_name, "rb") as source: + with open(output_name, "wb") as output: + source.seek(segment.start) + output.write(source.read(segment.end - segment.start)) + + +class PrintShim: + """Base class for interposing extra functionality onto the global `print` method.""" + + def __init__(self): + self.wrapped_print = None + + def __enter__(self): + global print + + if self.wrapped_print is not None: + raise RecursionError + + self.wrapped_print = print + print = self + + return self + + def __exit__(self, exc_type, exc_value, traceback): + global print + + if self.wrapped_print is None: + return + + print = self.wrapped_print + self.wrapped_print = None + + self.on_exit() + + def on_exit(self): + pass + + def __call__(self, *a, **k): + return self.wrapped_print(*a, **k) + + +class PrintIgnoreExtraArgs(PrintShim): + """Just strip the `annotations` and `labels` kwargs and pass down to the underlying print.""" + + def __call__(self, *a, annotations: dict = {}, labels: "list[str]" = (), **k): + return super().__call__(*a, **k) + + +class PrintJson(PrintShim): + """Output lines as godbolt-compatible JSON with extra annotation info from `annotations` and `labels`, rather than plain text.""" + + def __init__(self, fp=sys.stdout, language_id: str = "mpy"): + super().__init__() + self.fp = fp + self.asm = { + "asm": [], + "labelDefinitions": {}, + "languageId": language_id, + } + self.line_number: int = 0 + self.buf: "io.StringIO | None" = None + + def on_exit(self): + import json + + if self.buf is not None: + # flush last partial line + self.__call__() + + json.dump(self.asm, self.fp) + + def __call__(self, *a, annotations: dict = {}, labels: "list[str]" = (), **k): + # ignore prints directed to an explicit output + if "file" in k: + return super().__call__(*a, **k) + + if self.buf is None: + self.buf = io.StringIO() + + super().__call__(*a, file=sys.stderr, **k) + + if "end" in k: + # buffer partial-line prints to collect into a single AsmResultLine + return super().__call__(*a, file=self.buf, **k) + else: + retval = super().__call__(*a, file=self.buf, end="", **k) + output = self.buf.getvalue() + self.buf = None + + asm_line = {"text": output} + asm_line.update(annotations) + self.asm["asm"].append(asm_line) + + self.line_number += 1 + for label in labels: + self.asm["labelDefinitions"][label] = self.line_number + + return retval + + def main(args=None): global global_qstrs @@ -1784,9 +2097,23 @@ def main(args=None): "-d", "--disassemble", action="store_true", help="output disassembled contents of files" ) cmd_parser.add_argument("-f", "--freeze", action="store_true", help="freeze files") + cmd_parser.add_argument( + "-j", + "--json", + action="store_true", + help="output hexdump, disassembly, and frozen code as JSON with extra metadata", + ) cmd_parser.add_argument( "--merge", action="store_true", help="merge multiple .mpy files into one" ) + cmd_parser.add_argument( + "-e", "--extract", metavar="BASE", type=str, help="write segments into separate files" + ) + cmd_parser.add_argument( + "--extract-only", + metavar="KIND[,...]", + help="extract only segments of the given type (meta, qstr, obj, code)", + ) cmd_parser.add_argument("-q", "--qstr-header", help="qstr header file to freeze against") cmd_parser.add_argument( "-mlongint-impl", @@ -1801,6 +2128,12 @@ def main(args=None): default=16, help="mpz digit size used by target (default 16)", ) + cmd_parser.add_argument( + "-march-flags", + metavar="F", + type=int, + help="architecture flags value to set in the output file (strips existing flags if not present)", + ) cmd_parser.add_argument("-o", "--output", default=None, help="output file") cmd_parser.add_argument("files", nargs="+", help="input .mpy files") args = cmd_parser.parse_args(args) @@ -1813,6 +2146,7 @@ def main(args=None): }[args.mlongint_impl] config.MPZ_DIG_SIZE = args.mmpz_dig_size config.native_arch = MP_NATIVE_ARCH_NONE + config.arch_flags = args.march_flags # set config values for qstrs, and get the existing base set of qstrs # already in the firmware @@ -1836,24 +2170,40 @@ def main(args=None): print(er, file=sys.stderr) sys.exit(1) - if args.hexdump: - hexdump_mpy(compiled_modules) + if args.json: + if args.freeze: + print_shim = PrintJson(sys.stdout, language_id="c") + elif args.hexdump: + print_shim = PrintJson(sys.stdout, language_id="stderr") + elif args.disassemble: + print_shim = PrintJson(sys.stdout, language_id="mpy") + else: + print_shim = PrintJson(sys.stdout) + else: + print_shim = PrintIgnoreExtraArgs() - if args.disassemble: + with print_shim: if args.hexdump: - print() - disassemble_mpy(compiled_modules) + hexdump_mpy(compiled_modules) - if args.freeze: - try: - freeze_mpy(firmware_qstr_idents, compiled_modules) - except FreezeError as er: - print(er, file=sys.stderr) - sys.exit(1) + if args.disassemble: + if args.hexdump: + print() + disassemble_mpy(compiled_modules) + + if args.freeze: + try: + freeze_mpy(firmware_qstr_idents, compiled_modules) + except FreezeError as er: + print(er, file=sys.stderr) + sys.exit(1) if args.merge: merge_mpy(compiled_modules, args.output) + if args.extract: + extract_segments(compiled_modules, args.extract, args.extract_only) + if __name__ == "__main__": main() diff --git a/tools/mpy_ld.py b/tools/mpy_ld.py index 219cd1a7468..26db0726163 100755 --- a/tools/mpy_ld.py +++ b/tools/mpy_ld.py @@ -402,6 +402,7 @@ def __init__(self, arch): self.known_syms = {} # dict of symbols that are defined self.unresolved_syms = [] # list of unresolved symbols self.mpy_relocs = [] # list of relocations needed in the output .mpy file + self.externs = {} # dict of externally-defined symbols def check_arch(self, arch_name): if arch_name != self.arch.name: @@ -491,10 +492,14 @@ def populate_got(env): sym = got_entry.sym if hasattr(sym, "resolved"): sym = sym.resolved - sec = sym.section - addr = sym["st_value"] - got_entry.sec_name = sec.name - got_entry.link_addr += sec.addr + addr + if sym.name in env.externs: + got_entry.sec_name = ".external.fixed_addr" + got_entry.link_addr = env.externs[sym.name] + else: + sec = sym.section + addr = sym["st_value"] + got_entry.sec_name = sec.name + got_entry.link_addr += sec.addr + addr # Get sorted GOT, sorted by external, text, rodata, bss so relocations can be combined got_list = sorted( @@ -520,6 +525,9 @@ def populate_got(env): dest = int(got_entry.name.split("+")[1], 16) // env.arch.word_size elif got_entry.sec_name == ".external.mp_fun_table": dest = got_entry.sym.mp_fun_table_offset + elif got_entry.sec_name == ".external.fixed_addr": + # Fixed-address symbols should not be relocated. + continue elif got_entry.sec_name.startswith(".text"): dest = ".text" elif got_entry.sec_name.startswith(".rodata"): @@ -703,8 +711,9 @@ def do_relocation_text(env, text_addr, r): (addr, value) = process_riscv32_relocation(env, text_addr, r) elif env.arch.name == "EM_ARM" and r_info_type == R_ARM_ABS32: - # happens for soft-float on armv6m - raise ValueError("Absolute relocations not supported on ARM") + # Absolute relocation, handled as a data relocation. + do_relocation_data(env, text_addr, r) + return else: # Unknown/unsupported relocation @@ -773,9 +782,9 @@ def do_relocation_data(env, text_addr, r): ): # Relocation in data.rel.ro to internal/external symbol if env.arch.word_size == 4: - struct_type = "/). + + symbols = {} + + LINE_REGEX = re.compile( + r"^(?PPROVIDE\()?" # optional weak marker start + r"(?P[a-zA-Z_]\w*)" # symbol name + r"=0x(?P
[\da-fA-F]{1,8})*" # symbol address + r"(?(weak)\));$", # optional weak marker end and line terminator + re.ASCII, + ) + + inside_comment = False + for line in (line.strip() for line in source.readlines()): + if line.startswith("/*") and not inside_comment: + if not line.endswith("*/"): + inside_comment = True + continue + if inside_comment: + if line.endswith("*/"): + inside_comment = False + continue + if line.startswith("//"): + continue + match = LINE_REGEX.match("".join(line.split())) + if not match: + continue + tokens = match.groupdict() + symbol = tokens["symbol"] + address = int(tokens["address"], 16) + if symbol in symbols: + raise ValueError(f"Symbol {symbol} already defined") + symbols[symbol] = address + return symbols + + def main(): import argparse @@ -1501,6 +1569,13 @@ def main(): cmd_parser.add_argument( "--output", "-o", default=None, help="output .mpy file (default to input with .o->.mpy)" ) + cmd_parser.add_argument( + "--externs", + "-e", + type=argparse.FileType("rt"), + default=None, + help="linkerscript providing fixed-address symbols to augment symbol resolution", + ) cmd_parser.add_argument("files", nargs="+", help="input files") args = cmd_parser.parse_args() diff --git a/tools/pyboard.py b/tools/pyboard.py index 20310ba7081..c9f65d5d873 100755 --- a/tools/pyboard.py +++ b/tools/pyboard.py @@ -248,14 +248,22 @@ def inWaiting(self): class Pyboard: def __init__( - self, device, baudrate=115200, user="micro", password="python", wait=0, exclusive=True + self, + device, + baudrate=115200, + user="micro", + password="python", + wait=0, + exclusive=True, + timeout=None, + write_timeout=5, ): self.in_raw_repl = False self.use_raw_paste = True if device.startswith("exec:"): self.serial = ProcessToSerial(device[len("exec:") :]) elif device.startswith("execpty:"): - self.serial = ProcessPtyToTerminal(device[len("qemupty:") :]) + self.serial = ProcessPtyToTerminal(device[len("execpty:") :]) elif device and device[0].isdigit() and device[-1].isdigit() and device.count(".") == 3: # device looks like an IP address self.serial = TelnetToSerial(device, user, password, read_timeout=10) @@ -264,7 +272,12 @@ def __init__( import serial.tools.list_ports # Set options, and exclusive if pyserial supports it - serial_kwargs = {"baudrate": baudrate, "interCharTimeout": 1} + serial_kwargs = { + "baudrate": baudrate, + "timeout": timeout, + "write_timeout": write_timeout, + "interCharTimeout": 1, + } if serial.__version__ >= "3.3": serial_kwargs["exclusive"] = exclusive @@ -304,14 +317,25 @@ def __init__( def close(self): self.serial.close() - def read_until(self, min_num_bytes, ending, timeout=10, data_consumer=None): - # if data_consumer is used then data is not accumulated and the ending must be 1 byte long + def read_until( + self, min_num_bytes, ending, timeout=10, data_consumer=None, timeout_overall=None + ): + """ + min_num_bytes: Obsolete. + ending: Return if 'ending' matches. + timeout [s]: Return if timeout between characters. None: Infinite timeout. + timeout_overall [s]: Return not later than timeout_overall. None: Infinite timeout. + data_consumer: Use callback for incoming characters. + If data_consumer is used then data is not accumulated and the ending must be 1 byte long + + It is not visible to the caller why the function returned. It could be ending or timeout. + """ assert data_consumer is None or len(ending) == 1 + assert isinstance(timeout, (type(None), int, float)) + assert isinstance(timeout_overall, (type(None), int, float)) - data = self.serial.read(min_num_bytes) - if data_consumer: - data_consumer(data) - timeout_count = 0 + data = b"" + begin_overall_s = begin_char_s = time.monotonic() while True: if data.endswith(ending): break @@ -322,15 +346,25 @@ def read_until(self, min_num_bytes, ending, timeout=10, data_consumer=None): data = new_data else: data = data + new_data - timeout_count = 0 + begin_char_s = time.monotonic() else: - timeout_count += 1 - if timeout is not None and timeout_count >= 100 * timeout: + if timeout is not None and time.monotonic() >= begin_char_s + timeout: + break + if ( + timeout_overall is not None + and time.monotonic() >= begin_overall_s + timeout_overall + ): break time.sleep(0.01) return data - def enter_raw_repl(self, soft_reset=True): + def enter_raw_repl(self, soft_reset=True, timeout_overall=10): + try: + self._enter_raw_repl_unprotected(soft_reset, timeout_overall) + except OSError as er: + raise PyboardError("could not enter raw repl: {}".format(er)) + + def _enter_raw_repl_unprotected(self, soft_reset, timeout_overall): self.serial.write(b"\r\x03") # ctrl-C: interrupt any running program # flush input (without relying on serial.flushInput()) @@ -342,7 +376,9 @@ def enter_raw_repl(self, soft_reset=True): self.serial.write(b"\r\x01") # ctrl-A: enter raw REPL if soft_reset: - data = self.read_until(1, b"raw REPL; CTRL-B to exit\r\n>") + data = self.read_until( + 1, b"raw REPL; CTRL-B to exit\r\n>", timeout_overall=timeout_overall + ) if not data.endswith(b"raw REPL; CTRL-B to exit\r\n>"): print(data) raise PyboardError("could not enter raw repl") @@ -352,12 +388,12 @@ def enter_raw_repl(self, soft_reset=True): # Waiting for "soft reboot" independently to "raw REPL" (done below) # allows boot.py to print, which will show up after "soft reboot" # and before "raw REPL". - data = self.read_until(1, b"soft reboot\r\n") + data = self.read_until(1, b"soft reboot\r\n", timeout_overall=timeout_overall) if not data.endswith(b"soft reboot\r\n"): print(data) raise PyboardError("could not enter raw repl") - data = self.read_until(1, b"raw REPL; CTRL-B to exit\r\n") + data = self.read_until(1, b"raw REPL; CTRL-B to exit\r\n", timeout_overall=timeout_overall) if not data.endswith(b"raw REPL; CTRL-B to exit\r\n"): print(data) raise PyboardError("could not enter raw repl") @@ -475,8 +511,8 @@ def eval(self, expression, parse=False): return ret # In Python3, call as pyboard.exec(), see the setattr call below. - def exec_(self, command, data_consumer=None): - ret, ret_err = self.exec_raw(command, data_consumer=data_consumer) + def exec_(self, command, timeout=10, data_consumer=None): + ret, ret_err = self.exec_raw(command, timeout, data_consumer) if ret_err: raise PyboardError("exception", ret, ret_err) return ret diff --git a/tools/pydfu.py b/tools/pydfu.py index cd7354818cd..376c697cbd5 100755 --- a/tools/pydfu.py +++ b/tools/pydfu.py @@ -11,8 +11,6 @@ See document UM0391 for a description of the DFuse file. """ -from __future__ import print_function - import argparse import collections import inspect @@ -75,11 +73,7 @@ # USB DFU interface __DFU_INTERFACE = 0 -# Python 3 deprecated getargspec in favour of getfullargspec, but -# Python 2 doesn't have the latter, so detect which one to use -getargspec = getattr(inspect, "getfullargspec", getattr(inspect, "getargspec", None)) - -if "length" in getargspec(usb.util.get_string).args: +if "length" in inspect.getfullargspec(usb.util.get_string).args: # PyUSB 1.0.0.b1 has the length argument def get_string(dev, index): return usb.util.get_string(dev, 255, index) diff --git a/tools/verifygitlog.py b/tools/verifygitlog.py index 67215d5c5d0..dba6ebd6de5 100755 --- a/tools/verifygitlog.py +++ b/tools/verifygitlog.py @@ -96,20 +96,47 @@ def verify_message_body(raw_body, err): if len(subject_line) >= 73: err.error("Subject line must be 72 or fewer characters: " + subject_line) + # Do additional checks on the prefix of the subject line. + verify_subject_line_prefix(subject_line.split(": ")[0], err) + # Second one divides subject and body. if len(raw_body) > 1 and raw_body[1]: err.error("Second message line must be empty: " + raw_body[1]) # Message body lines. for line in raw_body[2:]: - # Long lines with URLs are exempt from the line length rule. - if len(line) >= 76 and "://" not in line: + # Long lines with URLs or human names are exempt from the line length rule. + if len(line) >= 76 and not ( + "://" in line + or line.startswith("Co-authored-by: ") + or line.startswith("Signed-off-by: ") + ): err.error("Message lines should be 75 or less characters: " + line) if not raw_body[-1].startswith("Signed-off-by: ") or "@" not in raw_body[-1]: err.error('Message must be signed-off. Use "git commit -s".') +def verify_subject_line_prefix(prefix, err): + ext = (".c", ".h", ".cpp", ".js", ".rst", ".md") + + if prefix.startswith((".", "/")): + err.error('Subject prefix cannot begin with "." or "/".') + + if prefix.endswith("/"): + err.error('Subject prefix cannot end with "/".') + + if prefix.startswith("ports/"): + err.error( + 'Subject prefix cannot begin with "ports/", start with the name of the port instead.' + ) + + if prefix.endswith(ext): + err.error( + "Subject prefix cannot end with a file extension, use the main part of the filename without the extension." + ) + + def run(args): verbose("run", *args)