diff --git a/.devcontainer/99-platformio-udev.rules b/.devcontainer/99-platformio-udev.rules new file mode 100644 index 000000000..83c7b8731 --- /dev/null +++ b/.devcontainer/99-platformio-udev.rules @@ -0,0 +1,183 @@ +# Copyright (c) 2014-present PlatformIO +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +##################################################################################### +# +# INSTALLATION +# +# Please visit > https://docs.platformio.org/en/latest/core/installation/udev-rules.html +# +##################################################################################### + +# +# Boards +# + +# CP210X USB UART +ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea[67][013]", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" +ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="80a9", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# FT231XS USB UART +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6015", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# Prolific Technology, Inc. PL2303 Serial Port +ATTRS{idVendor}=="067b", ATTRS{idProduct}=="2303", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# QinHeng Electronics HL-340 USB-Serial adapter +ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" +# QinHeng Electronics CH343 USB-Serial adapter +ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="55d3", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" +# QinHeng Electronics CH9102 USB-Serial adapter +ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="55d4", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# Arduino boards +ATTRS{idVendor}=="2341", ATTRS{idProduct}=="[08][023]*", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" +ATTRS{idVendor}=="2a03", ATTRS{idProduct}=="[08][02]*", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# Arduino SAM-BA +ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="6124", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{MTP_NO_PROBE}="1" + +# Digistump boards +ATTRS{idVendor}=="16d0", ATTRS{idProduct}=="0753", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# Maple with DFU +ATTRS{idVendor}=="1eaf", ATTRS{idProduct}=="000[34]", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# USBtiny +ATTRS{idProduct}=="0c9f", ATTRS{idVendor}=="1781", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# USBasp V2.0 +ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="05dc", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# Teensy boards +ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="04[789B]?", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" +ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="04[789A]?", ENV{MTP_NO_PROBE}="1" +SUBSYSTEMS=="usb", ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="04[789ABCD]?", MODE:="0666" +KERNEL=="ttyACM*", ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="04[789B]?", MODE:="0666" + +# TI Stellaris Launchpad +ATTRS{idVendor}=="1cbe", ATTRS{idProduct}=="00fd", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# TI MSP430 Launchpad +ATTRS{idVendor}=="0451", ATTRS{idProduct}=="f432", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# GD32V DFU Bootloader +ATTRS{idVendor}=="28e9", ATTRS{idProduct}=="0189", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# FireBeetle-ESP32 +ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7522", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# Wio Terminal +ATTRS{idVendor}=="2886", ATTRS{idProduct}=="[08]02d", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# Raspberry Pi Pico +ATTRS{idVendor}=="2e8a", ATTRS{idProduct}=="[01]*", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# AIR32F103 +ATTRS{idVendor}=="0d28", ATTRS{idProduct}=="0204", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# STM32 virtual COM port +ATTRS{idVendor}=="0483", ATTRS{idProduct}=="5740", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# +# Debuggers +# + +# Black Magic Probe +SUBSYSTEM=="tty", ATTRS{interface}=="Black Magic GDB Server", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" +SUBSYSTEM=="tty", ATTRS{interface}=="Black Magic UART Port", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# opendous and estick +ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="204f", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# Original FT232/FT245/FT2232/FT232H/FT4232 +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="60[01][104]", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# DISTORTEC JTAG-lock-pick Tiny 2 +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="8220", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# TUMPA, TUMPA Lite +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="8a9[89]", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# XDS100v2 +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="a6d0", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# Xverve Signalyzer Tool (DT-USB-ST), Signalyzer LITE (DT-USB-SLITE) +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bca[01]", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# TI/Luminary Stellaris Evaluation Board FTDI (several) +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bcd[9a]", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# egnite Turtelizer 2 +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bdc8", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# Section5 ICEbear +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="c14[01]", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# Amontec JTAGkey and JTAGkey-tiny +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="cff8", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# TI ICDI +ATTRS{idVendor}=="0451", ATTRS{idProduct}=="c32a", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# STLink probes +ATTRS{idVendor}=="0483", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# Hilscher NXHX Boards +ATTRS{idVendor}=="0640", ATTRS{idProduct}=="0028", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# Hitex probes +ATTRS{idVendor}=="0640", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# Altera USB Blaster +ATTRS{idVendor}=="09fb", ATTRS{idProduct}=="6001", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# Amontec JTAGkey-HiSpeed +ATTRS{idVendor}=="0fbb", ATTRS{idProduct}=="1000", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# SEGGER J-Link +ATTRS{idVendor}=="1366", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# Raisonance RLink +ATTRS{idVendor}=="138e", ATTRS{idProduct}=="9000", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# Debug Board for Neo1973 +ATTRS{idVendor}=="1457", ATTRS{idProduct}=="5118", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# Olimex probes +ATTRS{idVendor}=="15ba", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# USBprog with OpenOCD firmware +ATTRS{idVendor}=="1781", ATTRS{idProduct}=="0c63", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# TI/Luminary Stellaris In-Circuit Debug Interface (ICDI) Board +ATTRS{idVendor}=="1cbe", ATTRS{idProduct}=="00fd", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# Marvell Sheevaplug +ATTRS{idVendor}=="9e88", ATTRS{idProduct}=="9e8f", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# Keil Software, Inc. ULink +ATTRS{idVendor}=="c251", ATTRS{idProduct}=="2710", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# CMSIS-DAP compatible adapters +ATTRS{product}=="*CMSIS-DAP*", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# Atmel AVR Dragon +ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="2107", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# Espressif USB JTAG/serial debug unit +ATTRS{idVendor}=="303a", ATTRS{idProduct}=="1001", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# Zephyr framework USB CDC-ACM +ATTRS{idVendor}=="2fe3", ATTRS{idProduct}=="0100", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" \ No newline at end of file diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index c21564491..62f0b7ead 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,6 +1,9 @@ FROM mcr.microsoft.com/devcontainers/cpp:1-debian-12 -# [Optional] Uncomment this section to install additional packages. +USER root + +# trunk-ignore(terrascan/AC_DOCKER_0002): Known terrascan issue +# trunk-ignore(hadolint/DL3008): Use latest version of packages RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ && apt-get -y install --no-install-recommends \ ca-certificates \ @@ -20,6 +23,16 @@ RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ python3-wheel \ wget \ zip \ + usbutils \ + hwdata \ + gpg \ + gnupg2 \ && apt-get clean && rm -rf /var/lib/apt/lists/* -RUN pipx install platformio==6.1.15 \ No newline at end of file +RUN pipx install platformio==6.1.15 + +COPY 99-platformio-udev.rules /etc/udev/rules.d/99-platformio-udev.rules + +USER vscode + +HEALTHCHECK NONE \ No newline at end of file diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index d83d052b0..bf1c50982 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -13,13 +13,24 @@ }, "customizations": { "vscode": { - "extensions": ["ms-vscode.cpptools", "platformio.platformio-ide"] + "extensions": [ + "ms-vscode.cpptools", + "platformio.platformio-ide", + "Trunk.io" + ], + "unwantedRecommendations": ["ms-azuretools.vscode-docker"], + "settings": { + "extensions.ignoreRecommendations": true + } } }, // Use 'forwardPorts' to make a list of ports inside the container available locally. "forwardPorts": [4403], + // Use "--device=" to make a local device available inside the container. + // "runArgs": ["--device=/dev/ttyACM0"], + // Run commands to prepare the container for use "postCreateCommand": ".devcontainer/setup.sh" } diff --git a/.env.example b/.env.example new file mode 100644 index 000000000..72d95970a --- /dev/null +++ b/.env.example @@ -0,0 +1,4 @@ +# Absolute path to the local meshtastic config.yaml file +CONFIG_PATH=/path/to/meshtastic/config.yaml +# USB device to passthrough (`lsusb -t`: look for `ch341`) +USB_DEVICE=/dev/bus/usb/001/037 diff --git a/.github/workflows/build_docker.yml b/.github/workflows/build_docker.yml new file mode 100644 index 000000000..13817a8cf --- /dev/null +++ b/.github/workflows/build_docker.yml @@ -0,0 +1,51 @@ +name: Build Docker + +on: workflow_call + +permissions: + contents: write + packages: write + +jobs: + build-native: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + submodules: recursive + ref: ${{github.event.pull_request.head.ref}} + repository: ${{github.event.pull_request.head.repo.full_name}} + + - name: Get release version string + run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT + id: version + + - name: Docker login + if: ${{ github.event_name != 'pull_request_target' && github.event_name != 'pull_request' }} + uses: docker/login-action@v3 + with: + username: meshtastic + password: ${{ secrets.DOCKER_FIRMWARE_TOKEN }} + + - name: Docker setup + if: ${{ github.event_name != 'pull_request_target' && github.event_name != 'pull_request' }} + uses: docker/setup-buildx-action@v3 + + - name: Docker build and push tagged versions + if: ${{ github.event_name == 'workflow_dispatch' }} + uses: docker/build-push-action@v6 + with: + context: . + file: ./Dockerfile + push: true + tags: meshtastic/meshtasticd:${{ steps.version.outputs.version }} + + - name: Docker build and push + if: ${{ github.ref == 'refs/heads/master' && github.event_name != 'pull_request_target' && github.event_name != 'pull_request' }} + uses: docker/build-push-action@v6 + with: + context: . + file: ./Dockerfile + push: true + tags: meshtastic/meshtasticd:latest diff --git a/.github/workflows/build_native.yml b/.github/workflows/build_native.yml index 1fb44a717..74bc074aa 100644 --- a/.github/workflows/build_native.yml +++ b/.github/workflows/build_native.yml @@ -14,7 +14,7 @@ jobs: shell: bash run: | sudo apt-get update --fix-missing - sudo apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev + sudo apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev libusb-1.0-0-dev libi2c-dev - name: Checkout code uses: actions/checkout@v4 @@ -50,36 +50,3 @@ jobs: path: | release/meshtasticd_linux_x86_64 bin/config-dist.yaml - - - name: Docker login - if: ${{ github.event_name != 'pull_request_target' && github.event_name != 'pull_request' }} - uses: docker/login-action@v3 - continue-on-error: true # FIXME: Failing docker login auth - with: - username: meshtastic - password: ${{ secrets.DOCKER_FIRMWARE_TOKEN }} - - - name: Docker setup - if: ${{ github.event_name != 'pull_request_target' && github.event_name != 'pull_request' }} - continue-on-error: true # FIXME: Failing docker login auth - uses: docker/setup-buildx-action@v3 - - - name: Docker build and push tagged versions - if: ${{ github.event_name == 'workflow_dispatch' }} - continue-on-error: true # FIXME: Failing docker login auth - uses: docker/build-push-action@v6 - with: - context: . - file: ./Dockerfile - push: true - tags: meshtastic/device-simulator:${{ steps.version.outputs.version }} - - - name: Docker build and push - if: ${{ github.ref == 'refs/heads/master' && github.event_name != 'pull_request_target' && github.event_name != 'pull_request' }} - continue-on-error: true # FIXME: Failing docker login auth - uses: docker/build-push-action@v6 - with: - context: . - file: ./Dockerfile - push: true - tags: meshtastic/device-simulator:latest diff --git a/.github/workflows/build_raspbian.yml b/.github/workflows/build_raspbian.yml index e857ae635..ac63dfea4 100644 --- a/.github/workflows/build_raspbian.yml +++ b/.github/workflows/build_raspbian.yml @@ -14,7 +14,7 @@ jobs: shell: bash run: | sudo apt-get update -y --fix-missing - sudo apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev + sudo apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev libusb-1.0-0-dev libi2c-dev - name: Checkout code uses: actions/checkout@v4 diff --git a/.github/workflows/build_raspbian_armv7l.yml b/.github/workflows/build_raspbian_armv7l.yml index f7fddd038..565d9a0dc 100644 --- a/.github/workflows/build_raspbian_armv7l.yml +++ b/.github/workflows/build_raspbian_armv7l.yml @@ -14,7 +14,7 @@ jobs: shell: bash run: | sudo apt-get update -y --fix-missing - sudo apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev + sudo apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev libusb-1.0-0-dev libi2c-dev - name: Checkout code uses: actions/checkout@v4 diff --git a/.github/workflows/main_matrix.yml b/.github/workflows/main_matrix.yml index 37164b758..0109bef1a 100644 --- a/.github/workflows/main_matrix.yml +++ b/.github/workflows/main_matrix.yml @@ -37,7 +37,7 @@ jobs: else TARGETS=$(./bin/generate_ci_matrix.py ${{matrix.arch}} quick) fi - echo "Name: ${{ github.ref_name }} Base: ${{ github.base_ref }} Head: ${{ github.head_ref }} Ref: ${{ github.ref }} Targets: $TARGETS" + echo "Name: ${{ github.ref_name }} Base: ${{ github.base_ref }} } Ref: ${{ github.ref }} Targets: $TARGETS" echo "${{matrix.arch}}=$(jq -cn --argjson environments "$TARGETS" '{board: $environments}')" >> $GITHUB_OUTPUT outputs: esp32: ${{ steps.jsonStep.outputs.esp32 }} @@ -137,6 +137,11 @@ jobs: package-native: uses: ./.github/workflows/package_amd64.yml + build-docker: + if: ${{ github.event_name == 'workflow_dispatch' }} + uses: ./.github/workflows/build_docker.yml + secrets: inherit + after-checks: runs-on: ubuntu-latest if: ${{ github.event_name != 'workflow_dispatch' }} diff --git a/.github/workflows/package_amd64.yml b/.github/workflows/package_amd64.yml index 4f6636712..c6e82e1be 100644 --- a/.github/workflows/package_amd64.yml +++ b/.github/workflows/package_amd64.yml @@ -47,25 +47,30 @@ jobs: - name: build .debpkg run: | mkdir -p .debpkg/DEBIAN - mkdir -p .debpkg/usr/share/doc/meshtasticd/web + mkdir -p .debpkg/usr/share/meshtasticd/web mkdir -p .debpkg/usr/sbin mkdir -p .debpkg/etc/meshtasticd mkdir -p .debpkg/etc/meshtasticd/config.d mkdir -p .debpkg/etc/meshtasticd/available.d mkdir -p .debpkg/usr/lib/systemd/system/ - tar -xf build.tar -C .debpkg/usr/share/doc/meshtasticd/web + tar -xf build.tar -C .debpkg/usr/share/meshtasticd/web shopt -s dotglob nullglob - if [ -d .debpkg/usr/share/doc/meshtasticd/web/build ]; then mv .debpkg/usr/share/doc/meshtasticd/web/build/* .debpkg/usr/share/doc/meshtasticd/web/; fi - if [ -d .debpkg/usr/share/doc/meshtasticd/web/build ]; then rmdir .debpkg/usr/share/doc/meshtasticd/web/build; fi - if [ -d .debpkg/usr/share/doc/meshtasticd/web/.DS_Store]; then rm -f .debpkg/usr/share/doc/meshtasticd/web/.DS_Store; fi - gunzip .debpkg/usr/share/doc/meshtasticd/web/*.gz + if [ -d .debpkg/usr/share/meshtasticd/web/build ]; then mv .debpkg/usr/share/meshtasticd/web/build/* .debpkg/usr/share/meshtasticd/web/; fi + if [ -d .debpkg/usr/share/meshtasticd/web/build ]; then rmdir .debpkg/usr/share/meshtasticd/web/build; fi + if [ -d .debpkg/usr/share/meshtasticd/web/.DS_Store ]; then rm -f .debpkg/usr/share/meshtasticd/web/.DS_Store; fi + gunzip .debpkg/usr/share/meshtasticd/web/ -r cp release/meshtasticd_linux_x86_64 .debpkg/usr/sbin/meshtasticd cp bin/config-dist.yaml .debpkg/etc/meshtasticd/config.yaml - cp bin/config.d/* .debpkg/etc/meshtasticd/available.d/ + cp bin/config.d/* .debpkg/etc/meshtasticd/available.d/ -r chmod +x .debpkg/usr/sbin/meshtasticd cp bin/meshtasticd.service .debpkg/usr/lib/systemd/system/meshtasticd.service echo "/etc/meshtasticd/config.yaml" > .debpkg/DEBIAN/conffiles chmod +x .debpkg/DEBIAN/conffiles + # Transition /usr/share/doc/meshtasticd to /usr/share/meshtasticd + echo "rm -rf /usr/share/doc/meshtasticd" > .debpkg/DEBIAN/preinst + chmod +x .debpkg/DEBIAN/preinst + echo "ln -sf /usr/share/meshtasticd /usr/share/doc/meshtasticd" > .debpkg/DEBIAN/postinst + chmod +x .debpkg/DEBIAN/postinst - uses: jiro4989/build-deb-action@v3 with: @@ -74,7 +79,7 @@ jobs: maintainer: Jonathan Bennett version: ${{ steps.version.outputs.version }} # refs/tags/v*.*.* arch: amd64 - depends: libyaml-cpp0.7, openssl, libulfius2.7 + depends: libyaml-cpp0.7, openssl, libulfius2.7, libi2c0 desc: Native Linux Meshtastic binary. - uses: actions/upload-artifact@v4 diff --git a/.github/workflows/package_raspbian.yml b/.github/workflows/package_raspbian.yml index d9b12d6da..a4cd49573 100644 --- a/.github/workflows/package_raspbian.yml +++ b/.github/workflows/package_raspbian.yml @@ -47,25 +47,30 @@ jobs: - name: build .debpkg run: | mkdir -p .debpkg/DEBIAN - mkdir -p .debpkg/usr/share/doc/meshtasticd/web + mkdir -p .debpkg/usr/share/meshtasticd/web mkdir -p .debpkg/usr/sbin mkdir -p .debpkg/etc/meshtasticd mkdir -p .debpkg/etc/meshtasticd/config.d mkdir -p .debpkg/etc/meshtasticd/available.d mkdir -p .debpkg/usr/lib/systemd/system/ - tar -xf build.tar -C .debpkg/usr/share/doc/meshtasticd/web + tar -xf build.tar -C .debpkg/usr/share/meshtasticd/web shopt -s dotglob nullglob - if [ -d .debpkg/usr/share/doc/meshtasticd/web/build ]; then mv .debpkg/usr/share/doc/meshtasticd/web/build/* .debpkg/usr/share/doc/meshtasticd/web/; fi - if [ -d .debpkg/usr/share/doc/meshtasticd/web/build ]; then rmdir .debpkg/usr/share/doc/meshtasticd/web/build; fi - if [ -d .debpkg/usr/share/doc/meshtasticd/web/.DS_Store]; then rm -f .debpkg/usr/share/doc/meshtasticd/web/.DS_Store; fi - gunzip .debpkg/usr/share/doc/meshtasticd/web/*.gz + if [ -d .debpkg/usr/share/meshtasticd/web/build ]; then mv .debpkg/usr/share/meshtasticd/web/build/* .debpkg/usr/share/meshtasticd/web/; fi + if [ -d .debpkg/usr/share/meshtasticd/web/build ]; then rmdir .debpkg/usr/share/meshtasticd/web/build; fi + if [ -d .debpkg/usr/share/meshtasticd/web/.DS_Store ]; then rm -f .debpkg/usr/share/meshtasticd/web/.DS_Store; fi + gunzip .debpkg/usr/share/meshtasticd/web/ -r cp release/meshtasticd_linux_aarch64 .debpkg/usr/sbin/meshtasticd cp bin/config-dist.yaml .debpkg/etc/meshtasticd/config.yaml - cp bin/config.d/* .debpkg/etc/meshtasticd/available.d/ + cp bin/config.d/* .debpkg/etc/meshtasticd/available.d/ -r chmod +x .debpkg/usr/sbin/meshtasticd cp bin/meshtasticd.service .debpkg/usr/lib/systemd/system/meshtasticd.service echo "/etc/meshtasticd/config.yaml" > .debpkg/DEBIAN/conffiles chmod +x .debpkg/DEBIAN/conffiles + # Transition /usr/share/doc/meshtasticd to /usr/share/meshtasticd + echo "rm -rf /usr/share/doc/meshtasticd" > .debpkg/DEBIAN/preinst + chmod +x .debpkg/DEBIAN/preinst + echo "ln -sf /usr/share/meshtasticd /usr/share/doc/meshtasticd" > .debpkg/DEBIAN/postinst + chmod +x .debpkg/DEBIAN/postinst - uses: jiro4989/build-deb-action@v3 with: @@ -74,7 +79,7 @@ jobs: maintainer: Jonathan Bennett version: ${{ steps.version.outputs.version }} # refs/tags/v*.*.* arch: arm64 - depends: libyaml-cpp0.7, openssl, libulfius2.7 + depends: libyaml-cpp0.7, openssl, libulfius2.7, libi2c0 desc: Native Linux Meshtastic binary. - uses: actions/upload-artifact@v4 diff --git a/.github/workflows/package_raspbian_armv7l.yml b/.github/workflows/package_raspbian_armv7l.yml index e19df9d17..c4cc5c673 100644 --- a/.github/workflows/package_raspbian_armv7l.yml +++ b/.github/workflows/package_raspbian_armv7l.yml @@ -47,25 +47,30 @@ jobs: - name: build .debpkg run: | mkdir -p .debpkg/DEBIAN - mkdir -p .debpkg/usr/share/doc/meshtasticd/web + mkdir -p .debpkg/usr/share/meshtasticd/web mkdir -p .debpkg/usr/sbin mkdir -p .debpkg/etc/meshtasticd mkdir -p .debpkg/etc/meshtasticd/config.d mkdir -p .debpkg/etc/meshtasticd/available.d mkdir -p .debpkg/usr/lib/systemd/system/ - tar -xf build.tar -C .debpkg/usr/share/doc/meshtasticd/web + tar -xf build.tar -C .debpkg/usr/share/meshtasticd/web shopt -s dotglob nullglob - if [ -d .debpkg/usr/share/doc/meshtasticd/web/build ]; then mv .debpkg/usr/share/doc/meshtasticd/web/build/* .debpkg/usr/share/doc/meshtasticd/web/; fi - if [ -d .debpkg/usr/share/doc/meshtasticd/web/build ]; then rmdir .debpkg/usr/share/doc/meshtasticd/web/build; fi - if [ -d .debpkg/usr/share/doc/meshtasticd/web/.DS_Store]; then rm -f .debpkg/usr/share/doc/meshtasticd/web/.DS_Store; fi - gunzip .debpkg/usr/share/doc/meshtasticd/web/*.gz + if [ -d .debpkg/usr/share/meshtasticd/web/build ]; then mv .debpkg/usr/share/meshtasticd/web/build/* .debpkg/usr/share/meshtasticd/web/; fi + if [ -d .debpkg/usr/share/meshtasticd/web/build ]; then rmdir .debpkg/usr/share/meshtasticd/web/build; fi + if [ -d .debpkg/usr/share/meshtasticd/web/.DS_Store ]; then rm -f .debpkg/usr/share/meshtasticd/web/.DS_Store; fi + gunzip .debpkg/usr/share/meshtasticd/web/ -r cp release/meshtasticd_linux_armv7l .debpkg/usr/sbin/meshtasticd cp bin/config-dist.yaml .debpkg/etc/meshtasticd/config.yaml - cp bin/config.d/* .debpkg/etc/meshtasticd/available.d/ + cp bin/config.d/* .debpkg/etc/meshtasticd/available.d/ -r chmod +x .debpkg/usr/sbin/meshtasticd cp bin/meshtasticd.service .debpkg/usr/lib/systemd/system/meshtasticd.service echo "/etc/meshtasticd/config.yaml" > .debpkg/DEBIAN/conffiles chmod +x .debpkg/DEBIAN/conffiles + # Transition /usr/share/doc/meshtasticd to /usr/share/meshtasticd + echo "rm -rf /usr/share/doc/meshtasticd" > .debpkg/DEBIAN/preinst + chmod +x .debpkg/DEBIAN/preinst + echo "ln -sf /usr/share/meshtasticd /usr/share/doc/meshtasticd" > .debpkg/DEBIAN/postinst + chmod +x .debpkg/DEBIAN/postinst - uses: jiro4989/build-deb-action@v3 with: @@ -74,7 +79,7 @@ jobs: maintainer: Jonathan Bennett version: ${{ steps.version.outputs.version }} # refs/tags/v*.*.* arch: armhf - depends: libyaml-cpp0.7, openssl, libulfius2.7 + depends: libyaml-cpp0.7, openssl, libulfius2.7, libi2c0 desc: Native Linux Meshtastic binary. - uses: actions/upload-artifact@v4 diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 241598fd0..ae9f82543 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -8,12 +8,15 @@ on: jobs: test-simulator: runs-on: ubuntu-latest + env: + LCOV_CAPTURE_FLAGS: --quiet --capture --include "${PWD}/src/*" --exclude '*/src/mesh/generated/*' --directory .pio/build/coverage/src --base-directory "${PWD}" steps: - - name: Install libbluetooth + - name: Install libs needed for native build shell: bash run: | sudo apt-get update --fix-missing - sudo apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev + sudo apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev libusb-1.0-0-dev libi2c-dev + sudo apt-get install -y lcov - name: Checkout code uses: actions/checkout@v4 @@ -24,7 +27,7 @@ jobs: shell: bash run: | python -m pip install --upgrade pip - pip install -U platformio adafruit-nrfutil + pip install -U platformio adafruit-nrfutil dotmap pip install -U meshtastic --pre - name: Upgrade platformio @@ -36,17 +39,25 @@ jobs: run: bin/build-native.sh # We now run integration test before other build steps (to quickly see runtime failures) - - name: Build for native - run: platformio run -e native + - name: Build for native/coverage + run: | + platformio run -e coverage + lcov ${{ env.LCOV_CAPTURE_FLAGS }} --initial --output-file coverage_base.info - name: Integration test run: | - .pio/build/native/program & sleep 10 # 5 seconds was not enough + .pio/build/coverage/program & + PID=$! + timeout 20 bash -c "until ls -al /proc/$PID/fd | grep socket; do sleep 1; done" echo "Simulator started, launching python test..." python3 -c 'from meshtastic.test import testSimulator; testSimulator()' + wait + lcov ${{ env.LCOV_CAPTURE_FLAGS }} --test-name integration --output-file coverage_integration.info - name: PlatformIO Tests - run: platformio test -e native --junit-output-path testreport.xml + run: | + platformio test -e coverage --junit-output-path testreport.xml + lcov ${{ env.LCOV_CAPTURE_FLAGS }} --test-name tests --output-file coverage_tests.info - name: Test Report uses: dorny/test-reporter@v1.9.1 @@ -56,6 +67,19 @@ jobs: path: testreport.xml reporter: java-junit + - name: Generate Code Coverage Report + run: | + lcov --quiet --add-tracefile coverage_base.info --add-tracefile coverage_integration.info --add-tracefile coverage_tests.info --output-file coverage_src.info + mkdir code-coverage-report + genhtml --quiet --legend --prefix "${PWD}" coverage_src.info --output-directory code-coverage-report + mv coverage_*.info code-coverage-report + + - name: Save Code Coverage Report + uses: actions/upload-artifact@v4 + with: + name: code-coverage-report + path: code-coverage-report + hardware-tests: runs-on: test-runner steps: diff --git a/.github/workflows/update_protobufs.yml b/.github/workflows/update_protobufs.yml index f1c92b860..2732ab760 100644 --- a/.github/workflows/update_protobufs.yml +++ b/.github/workflows/update_protobufs.yml @@ -17,9 +17,9 @@ jobs: - name: Download nanopb run: | - wget https://jpa.kapsi.fi/nanopb/download/nanopb-0.4.9-linux-x86.tar.gz - tar xvzf nanopb-0.4.9-linux-x86.tar.gz - mv nanopb-0.4.9-linux-x86 nanopb-0.4.9 + wget https://jpa.kapsi.fi/nanopb/download/nanopb-0.4.9.1-linux-x86.tar.gz + tar xvzf nanopb-0.4.9.1-linux-x86.tar.gz + mv nanopb-0.4.9.1-linux-x86 nanopb-0.4.9 - name: Re-generate protocol buffers run: | diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml index 040712e1d..f2393592c 100644 --- a/.trunk/trunk.yaml +++ b/.trunk/trunk.yaml @@ -4,33 +4,34 @@ cli: plugins: sources: - id: trunk - ref: v1.6.4 + ref: v1.6.6 uri: https://github.com/trunk-io/plugins lint: enabled: - - trufflehog@3.83.6 + - prettier@3.4.2 + - trufflehog@3.86.1 - yamllint@1.35.1 - - bandit@1.7.10 - - checkov@3.2.287 + - bandit@1.8.0 + - checkov@3.2.334 - terrascan@1.19.9 - - trivy@0.56.2 + - trivy@0.58.0 #- trufflehog@3.63.2-rc0 - taplo@0.9.3 - - ruff@0.7.3 + - ruff@0.8.3 - isort@5.13.2 - - markdownlint@0.42.0 - - oxipng@9.1.2 + - markdownlint@0.43.0 + - oxipng@9.1.3 - svgo@3.3.2 - actionlint@1.7.4 - flake8@7.1.1 - - hadolint@2.12.0 + - hadolint@2.12.1-beta - shfmt@3.6.0 - shellcheck@0.10.0 - black@24.10.0 - git-diff-check - - gitleaks@8.21.1 + - gitleaks@8.21.2 - clang-format@16.0.3 - - prettier@3.3.3 + #- prettier@3.3.3 ignore: - linters: [ALL] paths: @@ -39,7 +40,7 @@ runtimes: enabled: - python@3.10.8 - go@1.21.0 - - node@18.12.1 + - node@18.20.5 actions: disabled: - trunk-announce diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 1e23cdf4d..6843fc85d 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,4 +1,4 @@ # Contributor Covenant Code of Conduct -The Meshtastic Firmware project is subject to the code of conduct for the parent project, which can be found here: +The Meshtastic Firmware project is subject to the code of conduct for the parent project, which can be found here: https://meshtastic.org/docs/legal/conduct/ diff --git a/Dockerfile b/Dockerfile index fc34fbd4c..f3b294a5b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,32 +1,29 @@ -FROM debian:bookworm-slim AS builder +# trunk-ignore-all(terrascan/AC_DOCKER_0002): Known terrascan issue +# trunk-ignore-all(hadolint/DL3008): Use latest version of apt packages for buildchain +# trunk-ignore-all(trivy/DS002): We must run as root for this container +# trunk-ignore-all(checkov/CKV_DOCKER_8): We must run as root for this container +# trunk-ignore-all(hadolint/DL3002): We must run as root for this container +FROM python:3.12-bookworm AS builder ENV DEBIAN_FRONTEND=noninteractive ENV TZ=Etc/UTC -# http://bugs.python.org/issue19846 -# > At the moment, setting "LANG=C" on a Linux system *fundamentally breaks Python 3*, and that's not OK. -ENV LANG C.UTF-8 - -# Install build deps -USER root - -# trunk-ignore(terrascan/AC_DOCKER_0002): Known terrascan issue -# trunk-ignore(hadolint/DL3008): Use latest version of packages for buildchain -RUN apt-get update && apt-get install --no-install-recommends -y wget python3 python3-pip python3-wheel python3-venv g++ zip git \ - ca-certificates libgpiod-dev libyaml-cpp-dev libbluetooth-dev \ - libulfius-dev liborcania-dev libssl-dev pkg-config && \ - apt-get clean && rm -rf /var/lib/apt/lists/* && mkdir /tmp/firmware - -RUN groupadd -g 1000 mesh && useradd -ml -u 1000 -g 1000 mesh && chown mesh:mesh /tmp/firmware -USER mesh +# Install Dependencies +ENV PIP_ROOT_USER_ACTION=ignore +RUN apt-get update && apt-get install --no-install-recommends -y wget g++ zip git ca-certificates \ + libgpiod-dev libyaml-cpp-dev libbluetooth-dev libi2c-dev \ + libusb-1.0-0-dev libulfius-dev liborcania-dev libssl-dev pkg-config && \ + apt-get clean && rm -rf /var/lib/apt/lists/* && \ + pip install --no-cache-dir -U platformio==6.1.16 && \ + mkdir /tmp/firmware +# Copy source code WORKDIR /tmp/firmware -RUN python3 -m venv /tmp/firmware -RUN bash -o pipefail -c "source bin/activate; pip3 install --no-cache-dir -U platformio==6.1.15" -# trunk-ignore(terrascan/AC_DOCKER_00024): We would actually like these files to be owned by mesh tyvm -COPY --chown=mesh:mesh . /tmp/firmware -RUN bash -o pipefail -c "source ./bin/activate && bash ./bin/build-native.sh" -RUN cp "/tmp/firmware/release/meshtasticd_linux_$(uname -m)" "/tmp/firmware/release/meshtasticd" +COPY . /tmp/firmware + +# Build +RUN bash ./bin/build-native.sh && \ + cp "/tmp/firmware/release/meshtasticd_linux_$(uname -m)" "/tmp/firmware/release/meshtasticd" ##### PRODUCTION BUILD ############# @@ -35,20 +32,25 @@ FROM debian:bookworm-slim ENV DEBIAN_FRONTEND=noninteractive ENV TZ=Etc/UTC -# trunk-ignore(terrascan/AC_DOCKER_0002): Known terrascan issue -# trunk-ignore(hadolint/DL3008): Use latest version of packages for buildchain -RUN apt-get update && apt-get --no-install-recommends -y install libc-bin libc6 libgpiod2 libyaml-cpp0.7 libulfius2.7 liborcania2.3 libssl3 && \ - apt-get clean && rm -rf /var/lib/apt/lists/* +# nosemgrep: dockerfile.security.last-user-is-root.last-user-is-root +USER root -RUN groupadd -g 1000 mesh && useradd -ml -u 1000 -g 1000 mesh -USER mesh +RUN apt-get update && apt-get --no-install-recommends -y install libc-bin libc6 libgpiod2 libyaml-cpp0.7 libi2c0 libulfius2.7 libusb-1.0-0-dev liborcania2.3 libssl3 && \ + apt-get clean && rm -rf /var/lib/apt/lists/* \ + && mkdir -p /var/lib/meshtasticd \ + && mkdir -p /etc/meshtasticd/config.d -WORKDIR /home/mesh -COPY --from=builder /tmp/firmware/release/meshtasticd /home/mesh/ +# Fetch compiled binary from the builder +COPY --from=builder /tmp/firmware/release/meshtasticd /usr/sbin/ +# Copy config templates +COPY ./bin/config.d /etc/meshtasticd/available.d -RUN mkdir data -VOLUME /home/mesh/data +WORKDIR /var/lib/meshtasticd +VOLUME /var/lib/meshtasticd -CMD [ "sh", "-cx", "./meshtasticd -d /home/mesh/data --hwid=${HWID:-$RANDOM}" ] +# Expose Meshtastic TCP API port from the host +EXPOSE 4403 -HEALTHCHECK NONE +CMD [ "sh", "-cx", "meshtasticd -d /var/lib/meshtasticd" ] + +HEALTHCHECK NONE \ No newline at end of file diff --git a/alpine.Dockerfile b/alpine.Dockerfile new file mode 100644 index 000000000..115602b3b --- /dev/null +++ b/alpine.Dockerfile @@ -0,0 +1,42 @@ +# trunk-ignore-all(trivy/DS002): We must run as root for this container +# trunk-ignore-all(checkov/CKV_DOCKER_8): We must run as root for this container +# trunk-ignore-all(hadolint/DL3002): We must run as root for this container + +FROM python:3.12-alpine3.21 AS builder + +ENV PIP_ROOT_USER_ACTION=ignore +RUN apk add bash g++ libstdc++-dev linux-headers zip git ca-certificates libgpiod-dev yaml-cpp-dev bluez-dev \ + libusb-dev i2c-tools-dev openssl-dev pkgconf argp-standalone && \ + pip install --no-cache-dir -U platformio==6.1.16 && \ + mkdir /tmp/firmware + +WORKDIR /tmp/firmware +COPY . /tmp/firmware + +# Create small package (no debugging symbols) +# Add `argp` for musl +ENV PLATFORMIO_BUILD_FLAGS="-Os -ffunction-sections -fdata-sections -Wl,--gc-sections -largp" + +RUN bash ./bin/build-native.sh && \ + cp "/tmp/firmware/release/meshtasticd_linux_$(uname -m)" "/tmp/firmware/release/meshtasticd" + +# ##### PRODUCTION BUILD ############# + +FROM alpine:3.21 + +# nosemgrep: dockerfile.security.last-user-is-root.last-user-is-root +USER root + +RUN apk add libstdc++ libgpiod yaml-cpp libusb i2c-tools \ + && mkdir -p /var/lib/meshtasticd \ + && mkdir -p /etc/meshtasticd/config.d +COPY --from=builder /tmp/firmware/release/meshtasticd /usr/sbin/ + +WORKDIR /var/lib/meshtasticd +VOLUME /var/lib/meshtasticd + +EXPOSE 4403 + +CMD [ "sh", "-cx", "meshtasticd --fsdir=/var/lib/meshtasticd" ] + +HEALTHCHECK NONE \ No newline at end of file diff --git a/arch/nrf52/nrf52.ini b/arch/nrf52/nrf52.ini index d75f86306..57b276978 100644 --- a/arch/nrf52/nrf52.ini +++ b/arch/nrf52/nrf52.ini @@ -1,10 +1,11 @@ [nrf52_base] ; Instead of the standard nordicnrf52 platform, we use our fork which has our added variant files -platform = platformio/nordicnrf52@^10.5.0 +platform = platformio/nordicnrf52@^10.7.0 extends = arduino_base platform_packages = ; our custom Git version until they merge our PR framework-arduinoadafruitnrf52 @ https://github.com/geeksville/Adafruit_nRF52_Arduino.git + toolchain-gccarmnoneeabi@~1.90301.0 build_type = debug build_flags = @@ -28,4 +29,4 @@ lib_deps= lib_ignore = BluetoothOTA - lvgl + lvgl \ No newline at end of file diff --git a/arch/portduino/portduino.ini b/arch/portduino/portduino.ini index 04fd6db09..aa1150e9a 100644 --- a/arch/portduino/portduino.ini +++ b/arch/portduino/portduino.ini @@ -1,6 +1,6 @@ -; The Portduino based sim environment on top of any host OS, all hardware will be simulated +; The Portduino based 'native' environment. Currently supported on Linux targets with real LoRa hardware (or simulated). [portduino_base] -platform = https://github.com/meshtastic/platform-native.git#bcd02436cfca91f7d28ad0f7dab977c6aaa781af +platform = https://github.com/meshtastic/platform-native.git#562d189828f09fbf4c4093b3c0104bae9d8e9ff9 framework = arduino build_src_filter = @@ -26,6 +26,7 @@ lib_deps = ${radiolib_base.lib_deps} rweather/Crypto@^0.4.0 https://github.com/lovyan03/LovyanGFX.git#1401c28a47646fe00538d487adcb2eb3c72de805 + https://github.com/pine64/libch341-spi-userspace#a9b17e3452f7fb747000d9b4ad4409155b39f6ef build_flags = ${arduino_base.build_flags} @@ -33,7 +34,10 @@ build_flags = -Isrc/platform/portduino -DRADIOLIB_EEPROM_UNSUPPORTED -DPORTDUINO_LINUX_HARDWARE + -lpthread -lstdc++fs -lbluetooth -lgpiod -lyaml-cpp + -li2c + -std=c++17 \ No newline at end of file diff --git a/arch/rp2xx0/rp2040.ini b/arch/rp2xx0/rp2040.ini index 85efa583c..5cfa678d5 100644 --- a/arch/rp2xx0/rp2040.ini +++ b/arch/rp2xx0/rp2040.ini @@ -1,8 +1,8 @@ ; Common settings for rp2040 Processor based targets [rp2040_base] -platform = https://github.com/maxgerhardt/platform-raspberrypi.git#19e30129fb1428b823be585c787dcb4ac0d9014c ; For arduino-pico 4.2.1 +platform = https://github.com/maxgerhardt/platform-raspberrypi.git#19e30129fb1428b823be585c787dcb4ac0d9014c ; For arduino-pico >=4.2.1 extends = arduino_base -platform_packages = framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#996c3bfab9758f12c07aa20cc6d352e630c16987 ; 4.2.1 with fix for sporadic hangs +platform_packages = framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#6024e9a7e82a72e38dd90f42029ba3748835eb2e ; 4.3.0 with fix MDNS board_build.core = earlephilhower board_build.filesystem_size = 0.5m diff --git a/arch/rp2xx0/rp2350.ini b/arch/rp2xx0/rp2350.ini index 6daf59bdf..c5849ff2a 100644 --- a/arch/rp2xx0/rp2350.ini +++ b/arch/rp2xx0/rp2350.ini @@ -1,8 +1,8 @@ ; Common settings for rp2040 Processor based targets [rp2350_base] -platform = https://github.com/maxgerhardt/platform-raspberrypi.git#19e30129fb1428b823be585c787dcb4ac0d9014c ; For arduino-pico 4.2.1 +platform = https://github.com/maxgerhardt/platform-raspberrypi.git#19e30129fb1428b823be585c787dcb4ac0d9014c ; For arduino-pico >=4.2.1 extends = arduino_base -platform_packages = framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#96c3bfab9758f12c07aa20cc6d352e630c16987 ; 4.2.1 with fix for sporadic hangs +platform_packages = framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#6024e9a7e82a72e38dd90f42029ba3748835eb2e ; 4.3.0 with fix MDNS board_build.core = earlephilhower board_build.filesystem_size = 0.5m diff --git a/bin/build-userprefs-json.py b/bin/build-userprefs-json.py index 58f460bcf..d155bae01 100644 --- a/bin/build-userprefs-json.py +++ b/bin/build-userprefs-json.py @@ -24,7 +24,7 @@ def write_macros_to_json(macros, output_file): def main(): header_file = 'userPrefs.h' - output_file = 'userPrefs.json' + output_file = 'userPrefs.jsonc' # Uncomment all macros in the header file with open(header_file, 'r') as file: lines = file.readlines() diff --git a/bin/config-dist.yaml b/bin/config-dist.yaml index 77680cc63..49de1675b 100644 --- a/bin/config-dist.yaml +++ b/bin/config-dist.yaml @@ -12,13 +12,6 @@ Lora: # IRQ: 17 # Reset: 22 -# Module: sx1262 # pinedio -# CS: 0 -# IRQ: 10 -# Busy: 11 -# DIO2_AS_RF_SWITCH: true -# spidev: spidev0.1 - # Module: RF95 # Adafruit RFM9x # Reset: 25 # CS: 7 @@ -50,8 +43,6 @@ Lora: # TXen: x # TX and RX enable pins # RXen: x -# ch341_quirk: true # Uncomment this to use the chunked SPI transfer that seems to fix the ch341 - # spiSpeed: 2000000 ### Set gpio chip to use in /dev/. Defaults to 0. @@ -155,9 +146,11 @@ Logging: Webserver: # Port: 443 # Port for Webserver & Webservices -# RootPath: /usr/share/doc/meshtasticd/web # Root Dir of WebServer +# RootPath: /usr/share/meshtasticd/web # Root Dir of WebServer General: MaxNodes: 200 MaxMessageQueue: 100 - ConfigDirectory: /etc/meshtasticd/config.d/ \ No newline at end of file + ConfigDirectory: /etc/meshtasticd/config.d/ +# MACAddress: AA:BB:CC:DD:EE:FF +# MACAddressSource: eth0 \ No newline at end of file diff --git a/bin/config.d/OpenWRT-One-mikroBUS-LR-IOT-CLICK.yaml b/bin/config.d/OpenWRT-One-mikroBUS-LR-IOT-CLICK.yaml new file mode 100644 index 000000000..ca5b27ebc --- /dev/null +++ b/bin/config.d/OpenWRT-One-mikroBUS-LR-IOT-CLICK.yaml @@ -0,0 +1,9 @@ +## https://www.mikroe.com/lr-iot-click +Lora: + Module: lr1110 # OpenWRT ONE mikroBUS with LR-IOT-CLICK +# CS: 25 + IRQ: 10 + Busy: 12 +# Reset: 2 + spidev: spidev2.0 + DIO3_TCXO_VOLTAGE: 1.6 diff --git a/bin/config.d/OpenWRT_One_mikroBUS_sx1262.yaml b/bin/config.d/OpenWRT_One_mikroBUS_sx1262.yaml new file mode 100644 index 000000000..6dc1e870d --- /dev/null +++ b/bin/config.d/OpenWRT_One_mikroBUS_sx1262.yaml @@ -0,0 +1,8 @@ +Lora: + Module: sx1262 + IRQ: 10 + Busy: 12 +# Reset: 2 + spidev: spidev2.0 + DIO2_AS_RF_SWITCH: true + DIO3_TCXO_VOLTAGE: true diff --git a/bin/config.d/femtofox/femtofox_LR1121_TCXO.yaml b/bin/config.d/femtofox/femtofox_LR1121_TCXO.yaml new file mode 100644 index 000000000..7aa860f61 --- /dev/null +++ b/bin/config.d/femtofox/femtofox_LR1121_TCXO.yaml @@ -0,0 +1,20 @@ +--- +Lora: +## Ebyte E80-900M22S +## This is a bit experimental +## +## + Module: lr1121 + gpiochip: 1 # subtract 32 from the gpio numbers + DIO3_TCXO_VOLTAGE: 1.8 + CS: 16 #pin6 / GPIO48 1C0 + IRQ: 23 #pin17 / GPIO55 1C7 + Busy: 22 #pin16 / GPIO54 1C6 + Reset: 25 #pin13 / GPIO57 1D1 + + + spidev: spidev0.0 #pins are (CS=16, CLK=17, MOSI=18, MISO=19) + spiSpeed: 2000000 + +General: + MACAddressSource: eth0 diff --git a/bin/config.d/femtofox/femtofox_SX1262_TCXO.yaml b/bin/config.d/femtofox/femtofox_SX1262_TCXO.yaml new file mode 100644 index 000000000..a4dec870a --- /dev/null +++ b/bin/config.d/femtofox/femtofox_SX1262_TCXO.yaml @@ -0,0 +1,21 @@ +--- +Lora: +## Ebyte E22-900M30S, E22-900M22S with or without external RF switching setup +## HT-RA62 (Has internal switching, but whatever) +## Seeed WIO SX1262 (already has TXEN-DIO2 link, but needs RXEN) +## Will work with any module with or without RF switching, and with TCXO + Module: sx1262 + gpiochip: 1 # subtract 32 from the gpio numbers + DIO2_AS_RF_SWITCH: true + DIO3_TCXO_VOLTAGE: true + CS: 16 #pin6 / GPIO48 1C0 + IRQ: 23 #pin17 / GPIO55 1C7 + Busy: 22 #pin16 / GPIO54 1C6 + Reset: 25 #pin13 / GPIO57 1D1 + RXen: 24 #pin12 / GPIO56 1D0 # Not strictly needed for auto-switching, but why complicate things? +# TXen: bridge to DIO2 on E22 module + spidev: spidev0.0 #pins are (CS=16, CLK=17, MOSI=18, MISO=19) + spiSpeed: 2000000 + +General: + MACAddressSource: eth0 diff --git a/bin/config.d/femtofox/femtofox_SX1262_XTAL.yaml b/bin/config.d/femtofox/femtofox_SX1262_XTAL.yaml new file mode 100644 index 000000000..6b956f3e3 --- /dev/null +++ b/bin/config.d/femtofox/femtofox_SX1262_XTAL.yaml @@ -0,0 +1,21 @@ +--- +Lora: +## Ebyte E22-900MM22S with no external RF switching setup +## Waveshare SX126X XXXM, AI Thinker RA-01SH +## Will work with any module with or without RF switching and no TCXO + + Module: sx1262 + gpiochip: 1 # subtract 32 from the gpio numbers + DIO2_AS_RF_SWITCH: true + DIO3_TCXO_VOLTAGE: false + CS: 16 #pin6 / GPIO48 1C0 + IRQ: 23 #pin17 / GPIO55 1C7 + Busy: 22 #pin16 / GPIO54 1C6 + Reset: 25 #pin13 / GPIO57 1D1 + RXen: 24 #pin12 / GPIO56 1D0 # Not strictly needed for auto-switching, but why complicate things? +# TXen: bridge to DIO2 on E22 module + spidev: spidev0.0 #pins are (CS=16, CLK=17, MOSI=18, MISO=19) + spiSpeed: 2000000 + +General: + MACAddressSource: eth0 diff --git a/bin/config.d/lora-meshstick-1262.yaml b/bin/config.d/lora-meshstick-1262.yaml new file mode 100644 index 000000000..3f8d6c617 --- /dev/null +++ b/bin/config.d/lora-meshstick-1262.yaml @@ -0,0 +1,11 @@ +Lora: + Module: sx1262 + CS: 0 + IRQ: 6 + Reset: 2 + Busy: 4 + spidev: ch341 + DIO3_TCXO_VOLTAGE: true +# USB_Serialnum: 12345678 + USB_PID: 0x5512 + USB_VID: 0x1A86 diff --git a/bin/config.d/lora-pinedio-usb-sx1262.yaml b/bin/config.d/lora-pinedio-usb-sx1262.yaml new file mode 100644 index 000000000..6b8a9fc95 --- /dev/null +++ b/bin/config.d/lora-pinedio-usb-sx1262.yaml @@ -0,0 +1,5 @@ +Lora: + Module: sx1262 + CS: 0 + IRQ: 10 + spidev: ch341 \ No newline at end of file diff --git a/bin/platformio-custom.py b/bin/platformio-custom.py index 701f6b5d8..acfeae10c 100644 --- a/bin/platformio-custom.py +++ b/bin/platformio-custom.py @@ -3,6 +3,8 @@ # trunk-ignore-all(flake8/F821): For SConstruct imports import sys from os.path import join +import json +import re from readprops import readProps @@ -90,11 +92,37 @@ prefsLoc = projenv["PROJECT_DIR"] + "/version.properties" verObj = readProps(prefsLoc) print("Using meshtastic platformio-custom.py, firmware version " + verObj["long"] + " on " + env.get("PIOENV")) +jsonLoc = env["PROJECT_DIR"] + "/userPrefs.jsonc" +with open(jsonLoc) as f: + jsonStr = re.sub("//.*","", f.read(), flags=re.MULTILINE) + userPrefs = json.loads(jsonStr) + +pref_flags = [] +# Pre-process the userPrefs +for pref in userPrefs: + if userPrefs[pref].startswith("{"): + pref_flags.append("-D" + pref + "=" + userPrefs[pref]) + elif userPrefs[pref].replace(".", "").isdigit(): + pref_flags.append("-D" + pref + "=" + userPrefs[pref]) + elif userPrefs[pref] == "true" or userPrefs[pref] == "false": + pref_flags.append("-D" + pref + "=" + userPrefs[pref]) + elif userPrefs[pref].startswith("meshtastic_"): + pref_flags.append("-D" + pref + "=" + userPrefs[pref]) + # If the value is a string, we need to wrap it in quotes + else: + pref_flags.append("-D" + pref + "=" + env.StringifyMacro(userPrefs[pref]) + "") + # General options that are passed to the C and C++ compilers -projenv.Append( - CCFLAGS=[ +flags = [ "-DAPP_VERSION=" + verObj["long"], "-DAPP_VERSION_SHORT=" + verObj["short"], "-DAPP_ENV=" + env.get("PIOENV"), - ] -) + ] + pref_flags + +print ("Using flags:") +for flag in flags: + print(flag) + +projenv.Append( + CCFLAGS=flags, +) \ No newline at end of file diff --git a/boards/esp32-s3-zero.json b/boards/esp32-s3-zero.json new file mode 100644 index 000000000..76cb34fa0 --- /dev/null +++ b/boards/esp32-s3-zero.json @@ -0,0 +1,41 @@ +{ + "build": { + "arduino": { + "partitions": "default.csv", + "memory_type": "qio_qspi" + }, + "core": "esp32", + "extra_flags": [ + "-DARDUINO_ESP32S3_DEV", + "-DARDUINO_RUNNING_CORE=1", + "-DARDUINO_EVENT_RUNNING_CORE=1", + "-DARDUINO_USB_CDC_ON_BOOT=1", + "-DBOARD_HAS_PSRAM" + ], + "f_cpu": "240000000L", + "f_flash": "80000000L", + "flash_mode": "qio", + "psram_type": "qio", + "hwids": [["0x303A", "0x1001"]], + "mcu": "esp32s3", + "variant": "esp32s3" + }, + "connectivity": ["wifi", "bluetooth"], + "debug": { + "default_tool": "esp-builtin", + "onboard_tools": ["esp-builtin"], + "openocd_target": "esp32s3.cfg" + }, + "frameworks": ["arduino", "espidf"], + "platforms": ["espressif32"], + "name": "Espressif ESP32-S3-FH4R2 (4 MB QD, 2MB PSRAM)", + "upload": { + "flash_size": "4MB", + "maximum_ram_size": 327680, + "maximum_size": 4194304, + "require_upload_port": true, + "speed": 921600 + }, + "url": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/hw-reference/esp32s3/user-guide-devkitc-1.html", + "vendor": "Espressif" +} diff --git a/boards/mesh-tab.json b/boards/mesh-tab.json new file mode 100644 index 000000000..52c65bf77 --- /dev/null +++ b/boards/mesh-tab.json @@ -0,0 +1,42 @@ +{ + "build": { + "arduino": { + "ldscript": "esp32s3_out.ld", + "partitions": "default_16MB.csv", + "memory_type": "qio_qspi" + }, + "core": "esp32", + "extra_flags": [ + "-DBOARD_HAS_PSRAM", + "-DARDUINO_USB_CDC_ON_BOOT=1", + "-DARDUINO_USB_MODE=0", + "-DARDUINO_RUNNING_CORE=1", + "-DARDUINO_EVENT_RUNNING_CORE=1" + ], + "f_cpu": "240000000L", + "f_flash": "80000000L", + "flash_mode": "qio", + "hwids": [["0x303A", "0x80D6"]], + "mcu": "esp32s3", + "variant": "mesh-tab" + }, + "connectivity": ["wifi", "bluetooth", "lora"], + "debug": { + "default_tool": "esp-builtin", + "onboard_tools": ["esp-builtin"], + "openocd_target": "esp32s3.cfg" + }, + "frameworks": ["arduino", "espidf"], + "name": "ESP32-S3 WROOM-1 N16R2 (16 MB FLASH, 2 MB PSRAM)", + "upload": { + "flash_size": "16MB", + "maximum_ram_size": 327680, + "maximum_size": 16777216, + "use_1200bps_touch": true, + "wait_for_upload_port": true, + "require_upload_port": true, + "speed": 460800 + }, + "url": "https://github.com/valzzu/Mesh-Tab", + "vendor": "Espressif" +} diff --git a/boards/seeed-sensecap-indicator.json b/boards/seeed-sensecap-indicator.json index 3fc57126f..0a02fc882 100644 --- a/boards/seeed-sensecap-indicator.json +++ b/boards/seeed-sensecap-indicator.json @@ -15,10 +15,12 @@ ], "f_cpu": "240000000L", "f_flash": "80000000L", + "f_boot": "120000000L", + "boot": "qio", "flash_mode": "qio", "hwids": [["0x1A86", "0x7523"]], "mcu": "esp32s3", - "variant": "esp32s3r8" + "variant": "esp32s3" }, "connectivity": ["wifi", "bluetooth", "lora"], "debug": { @@ -32,9 +34,9 @@ "flash_size": "8MB", "maximum_ram_size": 327680, "maximum_size": 8388608, - "require_upload_port": true, + "require_upload_port": false, "use_1200bps_touch": true, - "wait_for_upload_port": true, + "wait_for_upload_port": false, "speed": 921600 }, "url": "https://www.seeedstudio.com/Indicator-for-Meshtastic.html", diff --git a/boards/t-deck.json b/boards/t-deck.json index d62ec48e6..b112921b9 100644 --- a/boards/t-deck.json +++ b/boards/t-deck.json @@ -10,7 +10,7 @@ "-DARDUINO_USB_CDC_ON_BOOT=1", "-DARDUINO_USB_MODE=0", "-DARDUINO_RUNNING_CORE=1", - "-DARDUINO_EVENT_RUNNING_CORE=0" + "-DARDUINO_EVENT_RUNNING_CORE=1" ], "f_cpu": "240000000L", "f_flash": "80000000L", diff --git a/boards/t-echo.json b/boards/t-echo.json index fcfc8c50b..f891da94f 100644 --- a/boards/t-echo.json +++ b/boards/t-echo.json @@ -48,6 +48,6 @@ "require_upload_port": true, "wait_for_upload_port": true }, - "url": "FIXME", - "vendor": "TTGO" + "url": "https://lilygo.cc/products/t-echo-lilygo", + "vendor": "LILYGO" } diff --git a/docker-compose.yml b/docker-compose.yml index 82f2647e8..4aac318c5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,13 +1,26 @@ -version: "3.7" +# USB-Based Meshtastic container-node! + +# Copy .env.example to .env and set the USB_DEVICE and CONFIG_PATH variables services: meshtastic-node: build: . - deploy: - mode: replicated - replicas: 4 - networks: - - mesh + container_name: meshtasticd -networks: - mesh: + # Pass USB device through to the container + devices: + - "${USB_DEVICE}" + + # Mount local config file and named volume for data persistence + volumes: + - "${CONFIG_PATH}:/etc/meshtasticd/config.yaml:ro" + - meshtastic_data:/var/lib/meshtasticd + + # Forward the container’s port 4403 to the host + ports: + - 4403:4403 + + restart: unless-stopped + +volumes: + meshtastic_data: diff --git a/platformio.ini b/platformio.ini index f9770f79c..d8d682aa1 100644 --- a/platformio.ini +++ b/platformio.ini @@ -16,6 +16,7 @@ default_envs = tbeam ;default_envs = tlora-v2 ;default_envs = tlora-v2-1-1_6 ;default_envs = tlora-v2-1-1_6-tcxo +;default_envs = tlora-v3-3-0-tcxo ;default_envs = tlora-t3s3-v1 ;default_envs = t-echo ;default_envs = canaryone @@ -34,7 +35,6 @@ default_envs = tbeam ;default_envs = radiomaster_900_bandit_nano ;default_envs = radiomaster_900_bandit_micro ;default_envs = radiomaster_900_bandit -;default_envs = heltec_capsule_sensor_v3 ;default_envs = heltec_vision_master_t190 ;default_envs = heltec_vision_master_e213 ;default_envs = heltec_vision_master_e290 @@ -81,7 +81,8 @@ build_flags = -Wno-missing-field-initializers -DRADIOLIB_EXCLUDE_LORAWAN=1 -DMESHTASTIC_EXCLUDE_DROPZONE=1 -DMESHTASTIC_EXCLUDE_REMOTEHARDWARE=1 - -DMESHTASTIC_EXCLUDE_POWERSTRESS=1 ; exclude power stress test module from main firmware + -DMESHTASTIC_EXCLUDE_HEALTH_TELEMETRY=1 + -DMESHTASTIC_EXCLUDE_POWERSTRESS=1 ; exclude power stress test module from main firmware #-DBUILD_EPOCH=$UNIX_TIME ;-D OLED_PL @@ -111,7 +112,6 @@ framework = arduino lib_deps = ${env.lib_deps} end2endzone/NonBlockingRTTTL@1.3.0 - https://github.com/meshtastic/SparkFun_ATECCX08a_Arduino_Library.git#5cf62b36c6f30bc72a07bdb2c11fc9a22d1e31da build_flags = ${env.build_flags} -Os build_src_filter = ${env.build_src_filter} - @@ -155,7 +155,6 @@ lib_deps = sparkfun/SparkFun 9DoF IMU Breakout - ICM 20948 - Arduino Library@1.2.13 ClosedCube OPT3001@1.1.2 emotibit/EmotiBit MLX90632@1.0.8 - sparkfun/SparkFun MAX3010x Pulse and Proximity Sensor Library@1.1.2 adafruit/Adafruit MLX90614 Library@2.1.5 https://github.com/boschsensortec/Bosch-BSEC2-Library#v1.7.2502 boschsensortec/BME68x Sensor Library@1.1.40407 @@ -163,3 +162,7 @@ lib_deps = mprograms/QMC5883LCompass@1.2.3 dfrobot/DFRobot_RTU@1.0.3 https://github.com/meshtastic/DFRobot_LarkWeatherStation#4de3a9cadef0f6a5220a8a906cf9775b02b0040d + robtillaart/INA226@0.6.0 + + ; Health Sensor Libraries + sparkfun/SparkFun MAX3010x Pulse and Proximity Sensor Library@1.1.2 \ No newline at end of file diff --git a/protobufs b/protobufs index c952f8a4c..c55f120a9 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit c952f8a4c1c30f724743ee322dd3ec3ec2f934c4 +Subproject commit c55f120a9c1ce90c85e4826907a0b9bcb2d5f5a2 diff --git a/src/ButtonThread.cpp b/src/ButtonThread.cpp index 238359952..3f64b3b3e 100644 --- a/src/ButtonThread.cpp +++ b/src/ButtonThread.cpp @@ -1,5 +1,5 @@ #include "ButtonThread.h" -#include "../userPrefs.h" + #include "configuration.h" #if !MESHTASTIC_EXCLUDE_GPS #include "GPS.h" diff --git a/src/DebugConfiguration.h b/src/DebugConfiguration.h index 55453ea1e..7987e7fa1 100644 --- a/src/DebugConfiguration.h +++ b/src/DebugConfiguration.h @@ -45,7 +45,7 @@ #define LOG_CRIT(...) SEGGER_RTT_printf(0, __VA_ARGS__) #define LOG_TRACE(...) SEGGER_RTT_printf(0, __VA_ARGS__) #else -#if defined(DEBUG_PORT) && !defined(DEBUG_MUTE) && !defined(PIO_UNIT_TESTING) +#if defined(DEBUG_PORT) && !defined(DEBUG_MUTE) #define LOG_DEBUG(...) DEBUG_PORT.log(MESHTASTIC_LOG_LEVEL_DEBUG, __VA_ARGS__) #define LOG_INFO(...) DEBUG_PORT.log(MESHTASTIC_LOG_LEVEL_INFO, __VA_ARGS__) #define LOG_WARN(...) DEBUG_PORT.log(MESHTASTIC_LOG_LEVEL_WARN, __VA_ARGS__) diff --git a/src/FSCommon.cpp b/src/FSCommon.cpp index 6cd17dac8..df46c1941 100644 --- a/src/FSCommon.cpp +++ b/src/FSCommon.cpp @@ -55,6 +55,15 @@ extern "C" void lfs_assert(const char *reason) { LOG_ERROR("LFS assert: %s", reason); lfs_assert_failed = true; + +#ifndef ARCH_PORTDUINO +#ifdef FSCom + // CORRUPTED FILESYSTEM. This causes bootloop so + // might as well try formatting now. + LOG_ERROR("Trying FSCom.format()"); + FSCom.format(); +#endif +#endif } /** diff --git a/src/Power.cpp b/src/Power.cpp index a354b74e2..ae0908ec6 100644 --- a/src/Power.cpp +++ b/src/Power.cpp @@ -72,8 +72,9 @@ static const uint8_t ext_chrg_detect_value = EXT_CHRG_DETECT_VALUE; #endif #if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && !defined(ARCH_PORTDUINO) -INA260Sensor ina260Sensor; INA219Sensor ina219Sensor; +INA226Sensor ina226Sensor; +INA260Sensor ina260Sensor; INA3221Sensor ina3221Sensor; #endif @@ -413,7 +414,20 @@ class AnalogBatteryLevel : public HasBatteryLevel #ifdef EXT_CHRG_DETECT return digitalRead(EXT_CHRG_DETECT) == ext_chrg_detect_value; #else +#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) && \ + !defined(DISABLE_INA_CHARGING_DETECTION) + if (hasINA()) { + // get current flow from INA sensor - negative value means power flowing into the battery + // default assuming BATTERY+ <--> INA_VIN+ <--> SHUNT RESISTOR <--> INA_VIN- <--> LOAD + LOG_DEBUG("Using INA on I2C addr 0x%x for charging detection", config.power.device_battery_ina_address); +#if defined(INA_CHARGING_DETECTION_INVERT) + return getINACurrent() > 0; +#else + return getINACurrent() < 0; +#endif + } return isBatteryConnect() && isVbusIn(); +#endif #endif } @@ -450,6 +464,9 @@ class AnalogBatteryLevel : public HasBatteryLevel { if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA219].first == config.power.device_battery_ina_address) { return ina219Sensor.getBusVoltageMv(); + } else if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA226].first == + config.power.device_battery_ina_address) { + return ina226Sensor.getBusVoltageMv(); } else if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA260].first == config.power.device_battery_ina_address) { return ina260Sensor.getBusVoltageMv(); @@ -460,6 +477,20 @@ class AnalogBatteryLevel : public HasBatteryLevel return 0; } + int16_t getINACurrent() + { + if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA219].first == config.power.device_battery_ina_address) { + return ina219Sensor.getCurrentMa(); + } else if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA226].first == + config.power.device_battery_ina_address) { + return ina226Sensor.getCurrentMa(); + } else if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA3221].first == + config.power.device_battery_ina_address) { + return ina3221Sensor.getCurrentMa(); + } + return 0; + } + bool hasINA() { if (!config.power.device_battery_ina_address) { @@ -469,6 +500,10 @@ class AnalogBatteryLevel : public HasBatteryLevel if (!ina219Sensor.isInitialized()) return ina219Sensor.runOnce() > 0; return ina219Sensor.isRunning(); + } else if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA226].first == + config.power.device_battery_ina_address) { + if (!ina226Sensor.isInitialized()) + return ina226Sensor.runOnce() > 0; } else if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA260].first == config.power.device_battery_ina_address) { if (!ina260Sensor.isInitialized()) @@ -1154,4 +1189,4 @@ bool Power::lipoInit() { return false; } -#endif \ No newline at end of file +#endif diff --git a/src/PowerFSM.cpp b/src/PowerFSM.cpp index 00dd6c942..4c4d203c2 100644 --- a/src/PowerFSM.cpp +++ b/src/PowerFSM.cpp @@ -19,6 +19,10 @@ #include "sleep.h" #include "target_specific.h" +#if HAS_WIFI && !defined(ARCH_PORTDUINO) +#include "mesh/wifi/WiFiAPClient.h" +#endif + #ifndef SLEEP_TIME #define SLEEP_TIME 30 #endif @@ -377,9 +381,9 @@ void PowerFSM_setup() // We never enter light-sleep or NB states on NRF52 (because the CPU uses so little power normally) #ifdef ARCH_ESP32 // See: https://github.com/meshtastic/firmware/issues/1071 - // Don't add power saving transitions if we are a power saving tracker or sensor. Sleep will be initiated through the - // modules - if ((isRouter || config.power.is_power_saving) && !isTrackerOrSensor) { + // Don't add power saving transitions if we are a power saving tracker or sensor or have Wifi enabled. Sleep will be initiated + // through the modules + if ((isRouter || config.power.is_power_saving) && !isWifiAvailable() && !isTrackerOrSensor) { powerFSM.add_timed_transition(&stateNB, &stateLS, Default::getConfiguredOrDefaultMs(config.power.min_wake_secs, default_min_wake_secs), NULL, "Min wake timeout"); diff --git a/src/configuration.h b/src/configuration.h index 01ec64bea..8bb53d4eb 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -172,7 +172,6 @@ along with this program. If not, see . // ----------------------------------------------------------------------------- // Security // ----------------------------------------------------------------------------- -#define ATECC608B_ADDR 0x35 // ----------------------------------------------------------------------------- // IO Expander @@ -252,6 +251,9 @@ along with this program. If not, see . #ifndef HAS_SCREEN #define HAS_SCREEN 0 #endif +#ifndef HAS_TFT +#define HAS_TFT 0 +#endif #ifndef HAS_WIRE #define HAS_WIRE 0 #endif @@ -314,6 +316,7 @@ along with this program. If not, see . #define MESHTASTIC_EXCLUDE_AUDIO 1 #define MESHTASTIC_EXCLUDE_DETECTIONSENSOR 1 #define MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR 1 +#define MESHTASTIC_EXCLUDE_HEALTH_TELEMETRY 1 #define MESHTASTIC_EXCLUDE_EXTERNALNOTIFICATION 1 #define MESHTASTIC_EXCLUDE_PAXCOUNTER 1 #define MESHTASTIC_EXCLUDE_POWER_TELEMETRY 1 diff --git a/src/detect/ScanI2C.h b/src/detect/ScanI2C.h index 525ebeaa2..22d5d1a3e 100644 --- a/src/detect/ScanI2C.h +++ b/src/detect/ScanI2C.h @@ -12,7 +12,6 @@ class ScanI2C SCREEN_SH1106, SCREEN_UNKNOWN, // has the same address as the two above but does not respond to the same commands SCREEN_ST7567, - ATECC608B, RTC_RV3028, RTC_PCF8563, CARDKB, @@ -65,7 +64,9 @@ class ScanI2C MAX30102, TPS65233, MPR121KB, - CGRADSENS + CGRADSENS, + INA226, + NXP_SE050, } DeviceType; // typedef uint8_t DeviceAddress; @@ -129,4 +130,4 @@ class ScanI2C private: bool shouldSuppressScreen = false; -}; \ No newline at end of file +}; diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index 604b2d2f3..3730736a7 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -7,7 +7,6 @@ #include "linux/LinuxHardwareI2C.h" #endif #if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) -#include "main.h" // atecc #include "meshUtils.h" // vformat #endif @@ -72,10 +71,10 @@ ScanI2C::DeviceType ScanI2CTwoWire::probeOLED(ScanI2C::DeviceAddress addr) const r &= 0x0f; if (r == 0x08 || r == 0x00) { - LOG_INFO("sh1106 display found"); + logFoundDevice("SH1106", (uint8_t)addr.address); o_probe = SCREEN_SH1106; // SH1106 } else if (r == 0x03 || r == 0x04 || r == 0x06 || r == 0x07) { - LOG_INFO("ssd1306 display found"); + logFoundDevice("SSD1306", (uint8_t)addr.address); o_probe = SCREEN_SSD1306; // SSD1306 } c++; @@ -84,40 +83,6 @@ ScanI2C::DeviceType ScanI2CTwoWire::probeOLED(ScanI2C::DeviceAddress addr) const return o_probe; } -void ScanI2CTwoWire::printATECCInfo() const -{ -#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) - atecc.readConfigZone(false); - - std::string atecc_numbers = "ATECC608B Serial Number: "; - for (int i = 0; i < 9; i++) { - atecc_numbers += vformat("%02x", atecc.serialNumber[i]); - } - - atecc_numbers += ", Rev Number: "; - for (int i = 0; i < 4; i++) { - atecc_numbers += vformat("%02x", atecc.revisionNumber[i]); - } - LOG_DEBUG(atecc_numbers.c_str()); - - LOG_DEBUG("ATECC608B Config %s, Data %s, Slot 0 %s", atecc.configLockStatus ? "Locked" : "Unlocked", - atecc.dataOTPLockStatus ? "Locked" : "Unlocked", atecc.slot0LockStatus ? "Locked" : "Unlocked"); - - std::string atecc_publickey = ""; - if (atecc.configLockStatus && atecc.dataOTPLockStatus && atecc.slot0LockStatus) { - if (atecc.generatePublicKey() == false) { - atecc_publickey += "ATECC608B Error generating public key"; - } else { - atecc_publickey += "ATECC608B Public Key: "; - for (int i = 0; i < 64; i++) { - atecc_publickey += vformat("%02x", atecc.publicKey64Bytes[i]); - } - } - LOG_DEBUG(atecc_publickey.c_str()); - } -#endif -} - uint16_t ScanI2CTwoWire::getRegisterValue(const ScanI2CTwoWire::RegisterLocation ®isterLocation, ScanI2CTwoWire::ResponseWidth responseWidth) const { @@ -129,7 +94,6 @@ uint16_t ScanI2CTwoWire::getRegisterValue(const ScanI2CTwoWire::RegisterLocation i2cBus->endTransmission(); delay(20); i2cBus->requestFrom(registerLocation.i2cAddress.address, responseWidth); - LOG_DEBUG("Wire.available() = %d", i2cBus->available()); if (i2cBus->available() == 2) { // Read MSB, then LSB value = (uint16_t)i2cBus->read() << 8; @@ -142,7 +106,7 @@ uint16_t ScanI2CTwoWire::getRegisterValue(const ScanI2CTwoWire::RegisterLocation #define SCAN_SIMPLE_CASE(ADDR, T, ...) \ case ADDR: \ - LOG_INFO(__VA_ARGS__); \ + logFoundDevice(__VA_ARGS__); \ type = T; \ break; @@ -184,50 +148,36 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) for (addr.address = 8; addr.address < 120; addr.address++) { if (asize != 0) { - if (!in_array(address, asize, addr.address)) + if (!in_array(address, asize, (uint8_t)addr.address)) continue; - LOG_DEBUG("Scan address 0x%x", addr.address); + LOG_DEBUG("Scan address 0x%x", (uint8_t)addr.address); } i2cBus->beginTransmission(addr.address); #ifdef ARCH_PORTDUINO - if (i2cBus->read() != -1) - err = 0; - else + err = 2; + if ((addr.address >= 0x30 && addr.address <= 0x37) || (addr.address >= 0x50 && addr.address <= 0x5F)) { + if (i2cBus->read() != -1) + err = 0; + } else { + err = i2cBus->writeQuick((uint8_t)0); + } + if (err != 0) err = 2; #else err = i2cBus->endTransmission(); #endif type = NONE; if (err == 0) { - LOG_DEBUG("I2C device found at address 0x%x", addr.address); - switch (addr.address) { case SSD1306_ADDRESS: type = probeOLED(addr); break; -#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) - case ATECC608B_ADDR: -#ifdef RP2040_SLOW_CLOCK - if (atecc.begin(addr.address, Wire, Serial2) == true) -#else - if (atecc.begin(addr.address) == true) -#endif - - { - LOG_INFO("ATECC608B initialized"); - } else { - LOG_WARN("ATECC608B initialization failed"); - } - printATECCInfo(); - break; -#endif - #ifdef RV3028_RTC case RV3028_RTC: // foundDevices[addr] = RTC_RV3028; type = RTC_RV3028; - LOG_INFO("RV3028 RTC found"); + logFoundDevice("RV3028", (uint8_t)addr.address); rtc.initI2C(*i2cBus); rtc.writeToRegister(0x35, 0x07); // no Clkout rtc.writeToRegister(0x37, 0xB4); @@ -235,7 +185,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) #endif #ifdef PCF8563_RTC - SCAN_SIMPLE_CASE(PCF8563_RTC, RTC_PCF8563, "PCF8563 RTC found") + SCAN_SIMPLE_CASE(PCF8563_RTC, RTC_PCF8563, "PCF8563", (uint8_t)addr.address) #endif case CARDKB_ADDR: @@ -243,53 +193,53 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x04), 1); if (registerValue == 0x02) { // KEYPAD_VERSION - LOG_INFO("RAK14004 found"); + logFoundDevice("RAK14004", (uint8_t)addr.address); type = RAK14004; } else { - LOG_INFO("m5 cardKB found"); + logFoundDevice("M5 cardKB", (uint8_t)addr.address); type = CARDKB; } break; - SCAN_SIMPLE_CASE(TDECK_KB_ADDR, TDECKKB, "T-Deck keyboard found"); - SCAN_SIMPLE_CASE(BBQ10_KB_ADDR, BBQ10KB, "BB Q10 keyboard found"); + SCAN_SIMPLE_CASE(TDECK_KB_ADDR, TDECKKB, "T-Deck keyboard", (uint8_t)addr.address); + SCAN_SIMPLE_CASE(BBQ10_KB_ADDR, BBQ10KB, "BB Q10", (uint8_t)addr.address); - SCAN_SIMPLE_CASE(ST7567_ADDRESS, SCREEN_ST7567, "st7567 display found"); + SCAN_SIMPLE_CASE(ST7567_ADDRESS, SCREEN_ST7567, "ST7567", (uint8_t)addr.address); #ifndef HAS_TCA9535 - SCAN_SIMPLE_CASE(PCF8574A_ADDRESS, PCF8574A, "PCF8574A based keyboard found"); + SCAN_SIMPLE_CASE(PCF8574A_ADDRESS, PCF8574A, "PCF8574A", (uint8_t)addr.address); #endif #ifdef HAS_NCP5623 - SCAN_SIMPLE_CASE(NCP5623_ADDR, NCP5623, "NCP5623 RGB LED found"); + SCAN_SIMPLE_CASE(NCP5623_ADDR, NCP5623, "NCP5623", (uint8_t)addr.address); #endif #ifdef HAS_PMU - SCAN_SIMPLE_CASE(XPOWERS_AXP192_AXP2101_ADDRESS, PMU_AXP192_AXP2101, "axp192/axp2101 PMU found") + SCAN_SIMPLE_CASE(XPOWERS_AXP192_AXP2101_ADDRESS, PMU_AXP192_AXP2101, "AXP192/AXP2101", (uint8_t)addr.address) #endif case BME_ADDR: case BME_ADDR_ALTERNATE: registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xD0), 1); // GET_ID switch (registerValue) { case 0x61: - LOG_INFO("BME-680 sensor found at address 0x%x", (uint8_t)addr.address); + logFoundDevice("BME680", (uint8_t)addr.address); type = BME_680; break; case 0x60: - LOG_INFO("BME-280 sensor found at address 0x%x", (uint8_t)addr.address); + logFoundDevice("BME280", (uint8_t)addr.address); type = BME_280; break; case 0x55: - LOG_INFO("BMP-085 or BMP-180 sensor found at address 0x%x", (uint8_t)addr.address); + logFoundDevice("BMP085/BMP180", (uint8_t)addr.address); type = BMP_085; break; default: registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x00), 1); // GET_ID switch (registerValue) { case 0x50: // BMP-388 should be 0x50 - LOG_INFO("BMP-388 sensor found at address 0x%x", (uint8_t)addr.address); + logFoundDevice("BMP-388", (uint8_t)addr.address); type = BMP_3XX; break; case 0x58: // BMP-280 should be 0x58 default: - LOG_INFO("BMP-280 sensor found at address 0x%x", (uint8_t)addr.address); + logFoundDevice("BMP-280", (uint8_t)addr.address); type = BMP_280; break; } @@ -298,7 +248,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) break; #ifndef HAS_NCP5623 case AHT10_ADDR: - LOG_INFO("AHT10 sensor found at address 0x%x", (uint8_t)addr.address); + logFoundDevice("AHT10", (uint8_t)addr.address); type = AHT10; break; #endif @@ -308,10 +258,18 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xFE), 2); LOG_DEBUG("Register MFG_UID: 0x%x", registerValue); if (registerValue == 0x5449) { - LOG_INFO("INA260 sensor found at address 0x%x", (uint8_t)addr.address); - type = INA260; + registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xFF), 2); + LOG_DEBUG("Register DIE_UID: 0x%x", registerValue); + + if (registerValue == 0x2260) { + logFoundDevice("INA226", (uint8_t)addr.address); + type = INA226; + } else { + logFoundDevice("INA260", (uint8_t)addr.address); + type = INA260; + } } else { // Assume INA219 if INA260 ID is not found - LOG_INFO("INA219 sensor found at address 0x%x", (uint8_t)addr.address); + logFoundDevice("INA219", (uint8_t)addr.address); type = INA219; } break; @@ -319,7 +277,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xFE), 2); LOG_DEBUG("Register MFG_UID FE: 0x%x", registerValue); if (registerValue == 0x5449) { - LOG_INFO("INA3221 sensor found at address 0x%x", (uint8_t)addr.address); + logFoundDevice("INA3221", (uint8_t)addr.address); type = INA3221; } else { /* check the first 2 bytes of the 6 byte response register @@ -334,7 +292,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x05), 2); LOG_DEBUG("Register MFG_UID 05: 0x%x", registerValue); if (registerValue == 0x5305) { - LOG_INFO("DFRobot Lark weather station found at address 0x%x", (uint8_t)addr.address); + logFoundDevice("DFRobot Lark", (uint8_t)addr.address); type = DFROBOT_LARK; } // else: probably a RAK12500/UBLOX GPS on I2C @@ -349,7 +307,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x00), 2); if (registerValue == 0x8700) { type = STK8BAXX; - LOG_INFO("STK8BAXX accelerometer found"); + logFoundDevice("STK8BAXX", (uint8_t)addr.address); break; } #endif @@ -358,7 +316,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x07), 2); if (registerValue == 0x0400) { type = MCP9808; - LOG_INFO("MCP9808 sensor found"); + logFoundDevice("MCP9808", (uint8_t)addr.address); break; } @@ -366,7 +324,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x0F), 2); if (registerValue == 0x3300 || registerValue == 0x3333) { // RAK4631 WisBlock has LIS3DH register at 0x3333 type = LIS3DH; - LOG_INFO("LIS3DH accelerometer found"); + logFoundDevice("LIS3DH", (uint8_t)addr.address); } break; } @@ -374,95 +332,91 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x89), 2); if (registerValue == 0x11a2 || registerValue == 0x11da || registerValue == 0xe9c) { type = SHT4X; - LOG_INFO("SHT4X sensor found"); + logFoundDevice("SHT4X", (uint8_t)addr.address); } else if (getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x7E), 2) == 0x5449) { type = OPT3001; - LOG_INFO("OPT3001 light sensor found"); + logFoundDevice("OPT3001", (uint8_t)addr.address); } else { type = SHT31; - LOG_INFO("SHT31 sensor found"); + logFoundDevice("SHT31", (uint8_t)addr.address); } break; - SCAN_SIMPLE_CASE(SHTC3_ADDR, SHTC3, "SHTC3 sensor found") + SCAN_SIMPLE_CASE(SHTC3_ADDR, SHTC3, "SHTC3", (uint8_t)addr.address) case RCWL9620_ADDR: // get MAX30102 PARTID registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xFF), 1); if (registerValue == 0x15) { type = MAX30102; - LOG_INFO("MAX30102 Health sensor found"); + logFoundDevice("MAX30102", (uint8_t)addr.address); break; } else { type = RCWL9620; - LOG_INFO("RCWL9620 sensor found"); + logFoundDevice("RCWL9620", (uint8_t)addr.address); } break; case LPS22HB_ADDR_ALT: - SCAN_SIMPLE_CASE(LPS22HB_ADDR, LPS22HB, "LPS22HB sensor found") - - SCAN_SIMPLE_CASE(QMC6310_ADDR, QMC6310, "QMC6310 Highrate 3-Axis magnetic sensor found") + SCAN_SIMPLE_CASE(LPS22HB_ADDR, LPS22HB, "LPS22HB", (uint8_t)addr.address) + SCAN_SIMPLE_CASE(QMC6310_ADDR, QMC6310, "QMC6310", (uint8_t)addr.address) case QMI8658_ADDR: registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x0A), 1); // get ID if (registerValue == 0xC0) { type = BQ24295; - LOG_INFO("BQ24295 PMU found"); + logFoundDevice("BQ24295", (uint8_t)addr.address); break; } registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x0F), 1); // get ID if (registerValue == 0x6A) { type = LSM6DS3; - LOG_INFO("LSM6DS3 accelerometer found at address 0x%x", (uint8_t)addr.address); + logFoundDevice("LSM6DS3", (uint8_t)addr.address); } else { type = QMI8658; - LOG_INFO("QMI8658 Highrate 6-Axis inertial measurement sensor found"); + logFoundDevice("QMI8658", (uint8_t)addr.address); } break; - SCAN_SIMPLE_CASE(QMC5883L_ADDR, QMC5883L, "QMC5883L Highrate 3-Axis magnetic sensor found") - SCAN_SIMPLE_CASE(HMC5883L_ADDR, HMC5883L, "HMC5883L 3-Axis digital compass found") + SCAN_SIMPLE_CASE(QMC5883L_ADDR, QMC5883L, "QMC5883L", (uint8_t)addr.address) + SCAN_SIMPLE_CASE(HMC5883L_ADDR, HMC5883L, "HMC5883L", (uint8_t)addr.address) #ifdef HAS_QMA6100P - SCAN_SIMPLE_CASE(QMA6100P_ADDR, QMA6100P, "QMA6100P accelerometer found") + SCAN_SIMPLE_CASE(QMA6100P_ADDR, QMA6100P, "QMA6100P", (uint8_t)addr.address) #else - SCAN_SIMPLE_CASE(PMSA0031_ADDR, PMSA0031, "PMSA0031 air quality sensor found") + SCAN_SIMPLE_CASE(PMSA0031_ADDR, PMSA0031, "PMSA0031", (uint8_t)addr.address) #endif case BMA423_ADDR: // this can also be LIS3DH_ADDR_ALT registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x0F), 2); if (registerValue == 0x3300 || registerValue == 0x3333) { // RAK4631 WisBlock has LIS3DH register at 0x3333 type = LIS3DH; - LOG_INFO("LIS3DH accelerometer found"); + logFoundDevice("LIS3DH", (uint8_t)addr.address); } else { type = BMA423; - LOG_INFO("BMA423 accelerometer found"); + logFoundDevice("BMA423", (uint8_t)addr.address); } break; - SCAN_SIMPLE_CASE(LSM6DS3_ADDR, LSM6DS3, "LSM6DS3 accelerometer found at address 0x%x", (uint8_t)addr.address); -#ifdef HAS_TCA9535 - SCAN_SIMPLE_CASE(TCA9535_ADDR, TCA9535, "TCA9535 I2C expander found"); -#endif - SCAN_SIMPLE_CASE(TCA9555_ADDR, TCA9555, "TCA9555 I2C expander found"); - SCAN_SIMPLE_CASE(VEML7700_ADDR, VEML7700, "VEML7700 light sensor found"); - SCAN_SIMPLE_CASE(TSL25911_ADDR, TSL2591, "TSL2591 light sensor found"); - SCAN_SIMPLE_CASE(OPT3001_ADDR, OPT3001, "OPT3001 light sensor found"); - SCAN_SIMPLE_CASE(MLX90632_ADDR, MLX90632, "MLX90632 IR temp sensor found"); - SCAN_SIMPLE_CASE(NAU7802_ADDR, NAU7802, "NAU7802 based scale found"); - SCAN_SIMPLE_CASE(FT6336U_ADDR, FT6336U, "FT6336U touchscreen found"); - SCAN_SIMPLE_CASE(MAX1704X_ADDR, MAX17048, "MAX17048 lipo fuel gauge found"); + SCAN_SIMPLE_CASE(LSM6DS3_ADDR, LSM6DS3, "LSM6DS3", (uint8_t)addr.address); + SCAN_SIMPLE_CASE(TCA9535_ADDR, TCA9535, "TCA9535", (uint8_t)addr.address); + SCAN_SIMPLE_CASE(TCA9555_ADDR, TCA9555, "TCA9555", (uint8_t)addr.address); + SCAN_SIMPLE_CASE(VEML7700_ADDR, VEML7700, "VEML7700", (uint8_t)addr.address); + SCAN_SIMPLE_CASE(TSL25911_ADDR, TSL2591, "TSL2591", (uint8_t)addr.address); + SCAN_SIMPLE_CASE(OPT3001_ADDR, OPT3001, "OPT3001", (uint8_t)addr.address); + SCAN_SIMPLE_CASE(MLX90632_ADDR, MLX90632, "MLX90632", (uint8_t)addr.address); + SCAN_SIMPLE_CASE(NAU7802_ADDR, NAU7802, "NAU7802", (uint8_t)addr.address); + SCAN_SIMPLE_CASE(MAX1704X_ADDR, MAX17048, "MAX17048", (uint8_t)addr.address); #ifdef HAS_TPS65233 - SCAN_SIMPLE_CASE(TPS65233_ADDR, TPS65233, "TPS65233 BIAS-T found"); + SCAN_SIMPLE_CASE(TPS65233_ADDR, TPS65233, "TPS65233", (uint8_t)addr.address); #endif case MLX90614_ADDR_DEF: registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x0e), 1); if (registerValue == 0x5a) { type = MLX90614; - LOG_INFO("MLX90614 IR temp sensor found"); + logFoundDevice("MLX90614", (uint8_t)addr.address); } else { type = MPR121KB; - LOG_INFO("MPR121KB keyboard found"); + logFoundDevice("MPR121KB", (uint8_t)addr.address); } break; @@ -471,34 +425,57 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x00), 1); if (registerValue == 0xEA) { type = ICM20948; - LOG_INFO("ICM20948 9-dof motion processor found"); + logFoundDevice("ICM20948", (uint8_t)addr.address); break; } else if (addr.address == BMX160_ADDR) { type = BMX160; - LOG_INFO("BMX160 accelerometer found"); + logFoundDevice("BMX160", (uint8_t)addr.address); break; } else { type = MPU6050; - LOG_INFO("MPU6050 accelerometer found"); + logFoundDevice("MPU6050", (uint8_t)addr.address); break; } break; case CGRADSENS_ADDR: // Register 0x00 of the RadSens sensor contains is product identifier 0x7D + // Undocumented, but some devices return a product identifier of 0x7A registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x00), 1); - if (registerValue == 0x7D) { + if (registerValue == 0x7D || registerValue == 0x7A) { type = CGRADSENS; - LOG_INFO("ClimateGuard RadSens Geiger-Muller Sensor found"); + logFoundDevice("ClimateGuard RadSens", (uint8_t)addr.address); break; + } else { + LOG_DEBUG("Unexpected Device ID for RadSense: addr=0x%x id=0x%x", CGRADSENS_ADDR, registerValue); } break; + case 0x48: { + i2cBus->beginTransmission(addr.address); + uint8_t getInfo[] = {0x5A, 0xC0, 0x00, 0xFF, 0xFC}; + uint8_t expectedInfo[] = {0xa5, 0xE0, 0x00, 0x3F, 0x19}; + uint8_t info[5]; + size_t len = 0; + i2cBus->write(getInfo, 5); + i2cBus->endTransmission(); + len = i2cBus->readBytes(info, 5); + if (len == 5 && memcmp(expectedInfo, info, len) == 0) { + LOG_INFO("NXP SE050 crypto chip found"); + type = NXP_SE050; + + } else { + LOG_INFO("FT6336U touchscreen found"); + type = FT6336U; + } + break; + } + default: - LOG_INFO("Device found at address 0x%x was not able to be enumerated", addr.address); + LOG_INFO("Device found at address 0x%x was not able to be enumerated", (uint8_t)addr.address); } } else if (err == 4) { - LOG_ERROR("Unknown error at address 0x%x", addr.address); + LOG_ERROR("Unknown error at address 0x%x", (uint8_t)addr.address); } // Check if a type was found for the enumerated device - save, if so @@ -531,4 +508,9 @@ size_t ScanI2CTwoWire::countDevices() const { return foundDevices.size(); } -#endif \ No newline at end of file + +void ScanI2CTwoWire::logFoundDevice(const char *device, uint8_t address) +{ + LOG_INFO("%s found at address 0x%x", device, address); +} +#endif diff --git a/src/detect/ScanI2CTwoWire.h b/src/detect/ScanI2CTwoWire.h index c8dd96469..d0af7cde6 100644 --- a/src/detect/ScanI2CTwoWire.h +++ b/src/detect/ScanI2CTwoWire.h @@ -53,10 +53,10 @@ class ScanI2CTwoWire : public ScanI2C concurrency::Lock lock; - void printATECCInfo() const; - uint16_t getRegisterValue(const RegisterLocation &, ResponseWidth) const; DeviceType probeOLED(ScanI2C::DeviceAddress) const; + + static void logFoundDevice(const char *device, uint8_t address); }; #endif \ No newline at end of file diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index a6db85950..dcece305a 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -28,29 +28,43 @@ #define GPS_RESET_MODE HIGH #endif +// Not all platforms have std::size(). +template std::size_t array_count(const T (&)[N]) +{ + return N; +} + #if defined(NRF52840_XXAA) || defined(NRF52833_XXAA) || defined(ARCH_ESP32) || defined(ARCH_PORTDUINO) HardwareSerial *GPS::_serial_gps = &Serial1; #elif defined(ARCH_RP2040) SerialUART *GPS::_serial_gps = &Serial1; #else -HardwareSerial *GPS::_serial_gps = NULL; +HardwareSerial *GPS::_serial_gps = nullptr; #endif GPS *gps = nullptr; -GPSUpdateScheduling scheduling; +static const char *ACK_SUCCESS_MESSAGE = "Get ack success!"; + +static GPSUpdateScheduling scheduling; /// Multiple GPS instances might use the same serial port (in sequence), but we can /// only init that port once. static bool didSerialInit; -struct uBloxGnssModelInfo info; -uint8_t uBloxProtocolVersion; +static struct uBloxGnssModelInfo { + char swVersion[30]; + char hwVersion[10]; + uint8_t extensionNo; + char extension[10][30]; + uint8_t protocol_version; +} ublox_info; + #define GPS_SOL_EXPIRY_MS 5000 // in millis. give 1 second time to combine different sentences. NMEA Frequency isn't higher anyway #define NMEA_MSG_GXGSA "GNGSA" // GSA message (GPGSA, GNGSA etc) // For logging -const char *getGPSPowerStateString(GPSPowerState state) +static const char *getGPSPowerStateString(GPSPowerState state) { switch (state) { case GPS_ACTIVE: @@ -69,7 +83,7 @@ const char *getGPSPowerStateString(GPSPowerState state) } } -void GPS::UBXChecksum(uint8_t *message, size_t length) +static void UBXChecksum(uint8_t *message, size_t length) { uint8_t CK_A = 0, CK_B = 0; @@ -85,7 +99,7 @@ void GPS::UBXChecksum(uint8_t *message, size_t length) } // Calculate the checksum for a CAS packet -void GPS::CASChecksum(uint8_t *message, size_t length) +static void CASChecksum(uint8_t *message, size_t length) { uint32_t cksum = ((uint32_t)message[5] << 24); // Message ID cksum += ((uint32_t)message[4]) << 16; // Class @@ -410,6 +424,15 @@ int GPS::getACK(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t return 0; } +#if GPS_BAUDRATE_FIXED +// if GPS_BAUDRATE is specified in variant, only try that. +static const int serialSpeeds[1] = {GPS_BAUDRATE}; +static const int rareSerialSpeeds[1] = {GPS_BAUDRATE}; +#else +static const int serialSpeeds[3] = {9600, 115200, 38400}; +static const int rareSerialSpeeds[3] = {4800, 57600, GPS_BAUDRATE}; +#endif + /** * @brief Setup the GPS based on the model detected. * We detect the GPS by cycling through a set of baud rates, first common then rare. @@ -419,7 +442,6 @@ int GPS::getACK(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t */ bool GPS::setup() { - if (!didSerialInit) { int msglen = 0; if (tx_gpio && gnssModel == GNSS_MODEL_UNKNOWN) { @@ -427,7 +449,7 @@ bool GPS::setup() LOG_DEBUG("Probe for GPS at %d", serialSpeeds[speedSelect]); gnssModel = probe(serialSpeeds[speedSelect]); if (gnssModel == GNSS_MODEL_UNKNOWN) { - if (++speedSelect == sizeof(serialSpeeds) / sizeof(int)) { + if (++speedSelect == array_count(serialSpeeds)) { speedSelect = 0; ++probeTries; } @@ -438,7 +460,7 @@ bool GPS::setup() LOG_DEBUG("Probe for GPS at %d", rareSerialSpeeds[speedSelect]); gnssModel = probe(rareSerialSpeeds[speedSelect]); if (gnssModel == GNSS_MODEL_UNKNOWN) { - if (++speedSelect == sizeof(rareSerialSpeeds) / sizeof(int)) { + if (++speedSelect == array_count(rareSerialSpeeds)) { LOG_WARN("Give up on GPS probe and set to %d", GPS_BAUDRATE); return true; } @@ -634,7 +656,7 @@ bool GPS::setup() SEND_UBX_PACKET(0x06, 0x01, _message_RMC, "enable NMEA RMC", 500); SEND_UBX_PACKET(0x06, 0x01, _message_GGA, "enable NMEA GGA", 500); - if (uBloxProtocolVersion >= 18) { + if (ublox_info.protocol_version >= 18) { clearBuffer(); SEND_UBX_PACKET(0x06, 0x86, _message_PMS, "enable powersave for GPS", 500); SEND_UBX_PACKET(0x06, 0x3B, _message_CFG_PM2, "enable powersave details for GPS", 500); @@ -718,6 +740,7 @@ GPS::~GPS() // we really should unregister our sleep observer notifyDeepSleepObserver.unobserve(¬ifyDeepSleep); } + // Put the GPS hardware into a specified state void GPS::setPowerState(GPSPowerState newState, uint32_t sleepTime) { @@ -882,17 +905,17 @@ void GPS::setPowerUBLOX(bool on, uint32_t sleepMs) if (gnssModel != GNSS_MODEL_UBLOX10) { // Encode the sleep time in millis into the packet for (int i = 0; i < 4; i++) - gps->_message_PMREQ[0 + i] = sleepMs >> (i * 8); + _message_PMREQ[0 + i] = sleepMs >> (i * 8); // Record the message length - msglen = gps->makeUBXPacket(0x02, 0x41, sizeof(_message_PMREQ), gps->_message_PMREQ); + msglen = gps->makeUBXPacket(0x02, 0x41, sizeof(_message_PMREQ), _message_PMREQ); } else { // Encode the sleep time in millis into the packet for (int i = 0; i < 4; i++) - gps->_message_PMREQ_10[4 + i] = sleepMs >> (i * 8); + _message_PMREQ_10[4 + i] = sleepMs >> (i * 8); // Record the message length - msglen = gps->makeUBXPacket(0x02, 0x41, sizeof(_message_PMREQ_10), gps->_message_PMREQ_10); + msglen = gps->makeUBXPacket(0x02, 0x41, sizeof(_message_PMREQ_10), _message_PMREQ_10); } // Send the UBX packet @@ -1099,17 +1122,19 @@ int GPS::prepareDeepSleep(void *unused) return 0; } -const char *PROBE_MESSAGE = "Trying %s (%s)..."; -const char *DETECTED_MESSAGE = "%s detected, using %s Module"; +static const char *PROBE_MESSAGE = "Trying %s (%s)..."; +static const char *DETECTED_MESSAGE = "%s detected, using %s Module"; #define PROBE_SIMPLE(CHIP, TOWRITE, RESPONSE, DRIVER, TIMEOUT, ...) \ - LOG_DEBUG(PROBE_MESSAGE, TOWRITE, CHIP); \ - clearBuffer(); \ - _serial_gps->write(TOWRITE "\r\n"); \ - if (getACK(RESPONSE, TIMEOUT) == GNSS_RESPONSE_OK) { \ - LOG_INFO(DETECTED_MESSAGE, CHIP, #DRIVER); \ - return DRIVER; \ - } + do { \ + LOG_DEBUG(PROBE_MESSAGE, TOWRITE, CHIP); \ + clearBuffer(); \ + _serial_gps->write(TOWRITE "\r\n"); \ + if (getACK(RESPONSE, TIMEOUT) == GNSS_RESPONSE_OK) { \ + LOG_INFO(DETECTED_MESSAGE, CHIP, #DRIVER); \ + return DRIVER; \ + } \ + } while (0) GnssModel_t GPS::probe(int serialSpeed) { @@ -1127,7 +1152,7 @@ GnssModel_t GPS::probe(int serialSpeed) } #endif - memset(&info, 0, sizeof(struct uBloxGnssModelInfo)); + memset(&ublox_info, 0, sizeof(ublox_info)); uint8_t buffer[768] = {0}; delay(100); @@ -1194,64 +1219,64 @@ GnssModel_t GPS::probe(int serialSpeed) if (len) { uint16_t position = 0; for (int i = 0; i < 30; i++) { - info.swVersion[i] = buffer[position]; + ublox_info.swVersion[i] = buffer[position]; position++; } for (int i = 0; i < 10; i++) { - info.hwVersion[i] = buffer[position]; + ublox_info.hwVersion[i] = buffer[position]; position++; } while (len >= position + 30) { for (int i = 0; i < 30; i++) { - info.extension[info.extensionNo][i] = buffer[position]; + ublox_info.extension[ublox_info.extensionNo][i] = buffer[position]; position++; } - info.extensionNo++; - if (info.extensionNo > 9) + ublox_info.extensionNo++; + if (ublox_info.extensionNo > 9) break; } LOG_DEBUG("Module Info : "); - LOG_DEBUG("Soft version: %s", info.swVersion); - LOG_DEBUG("Hard version: %s", info.hwVersion); - LOG_DEBUG("Extensions:%d", info.extensionNo); - for (int i = 0; i < info.extensionNo; i++) { - LOG_DEBUG(" %s", info.extension[i]); + LOG_DEBUG("Soft version: %s", ublox_info.swVersion); + LOG_DEBUG("Hard version: %s", ublox_info.hwVersion); + LOG_DEBUG("Extensions:%d", ublox_info.extensionNo); + for (int i = 0; i < ublox_info.extensionNo; i++) { + LOG_DEBUG(" %s", ublox_info.extension[i]); } memset(buffer, 0, sizeof(buffer)); // tips: extensionNo field is 0 on some 6M GNSS modules - for (int i = 0; i < info.extensionNo; ++i) { - if (!strncmp(info.extension[i], "MOD=", 4)) { - strncpy((char *)buffer, &(info.extension[i][4]), sizeof(buffer)); - } else if (!strncmp(info.extension[i], "PROTVER", 7)) { + for (int i = 0; i < ublox_info.extensionNo; ++i) { + if (!strncmp(ublox_info.extension[i], "MOD=", 4)) { + strncpy((char *)buffer, &(ublox_info.extension[i][4]), sizeof(buffer)); + } else if (!strncmp(ublox_info.extension[i], "PROTVER", 7)) { char *ptr = nullptr; memset(buffer, 0, sizeof(buffer)); - strncpy((char *)buffer, &(info.extension[i][8]), sizeof(buffer)); + strncpy((char *)buffer, &(ublox_info.extension[i][8]), sizeof(buffer)); LOG_DEBUG("Protocol Version:%s", (char *)buffer); if (strlen((char *)buffer)) { - uBloxProtocolVersion = strtoul((char *)buffer, &ptr, 10); - LOG_DEBUG("ProtVer=%d", uBloxProtocolVersion); + ublox_info.protocol_version = strtoul((char *)buffer, &ptr, 10); + LOG_DEBUG("ProtVer=%d", ublox_info.protocol_version); } else { - uBloxProtocolVersion = 0; + ublox_info.protocol_version = 0; } } } - if (strncmp(info.hwVersion, "00040007", 8) == 0) { + if (strncmp(ublox_info.hwVersion, "00040007", 8) == 0) { LOG_INFO(DETECTED_MESSAGE, "U-blox 6", "6"); return GNSS_MODEL_UBLOX6; - } else if (strncmp(info.hwVersion, "00070000", 8) == 0) { + } else if (strncmp(ublox_info.hwVersion, "00070000", 8) == 0) { LOG_INFO(DETECTED_MESSAGE, "U-blox 7", "7"); return GNSS_MODEL_UBLOX7; - } else if (strncmp(info.hwVersion, "00080000", 8) == 0) { + } else if (strncmp(ublox_info.hwVersion, "00080000", 8) == 0) { LOG_INFO(DETECTED_MESSAGE, "U-blox 8", "8"); return GNSS_MODEL_UBLOX8; - } else if (strncmp(info.hwVersion, "00190000", 8) == 0) { + } else if (strncmp(ublox_info.hwVersion, "00190000", 8) == 0) { LOG_INFO(DETECTED_MESSAGE, "U-blox 9", "9"); return GNSS_MODEL_UBLOX9; - } else if (strncmp(info.hwVersion, "000A0000", 8) == 0) { + } else if (strncmp(ublox_info.hwVersion, "000A0000", 8) == 0) { LOG_INFO(DETECTED_MESSAGE, "U-blox 10", "10"); return GNSS_MODEL_UBLOX10; } @@ -1725,4 +1750,4 @@ void GPS::toggleGpsMode() enable(); } } -#endif // Exclude GPS +#endif // Exclude GPS \ No newline at end of file diff --git a/src/gps/GPS.h b/src/gps/GPS.h index cb970f7db..15fc50fe7 100644 --- a/src/gps/GPS.h +++ b/src/gps/GPS.h @@ -16,13 +16,6 @@ #define GPS_EN_ACTIVE 1 #endif -struct uBloxGnssModelInfo { - char swVersion[30]; - char hwVersion[10]; - uint8_t extensionNo; - char extension[10][30]; -}; - typedef enum { GNSS_MODEL_ATGM336H, GNSS_MODEL_MTK, @@ -54,9 +47,6 @@ enum GPSPowerState : uint8_t { GPS_OFF // Powered off indefinitely }; -// Generate a string representation of DOP -const char *getDOPString(uint32_t dop); - /** * A gps class that only reads from the GPS periodically and keeps the gps powered down except when reading * @@ -122,7 +112,9 @@ class GPS : private concurrency::OSThread // Let the GPS hardware save power between updates void down(); - protected: + private: + GPS() : concurrency::OSThread("GPS") {} + /// Record that we have a GPS void setConnected(); @@ -150,9 +142,6 @@ class GPS : private concurrency::OSThread GnssModel_t gnssModel = GNSS_MODEL_UNKNOWN; - private: - GPS() : concurrency::OSThread("GPS") {} - TinyGPSPlus reader; uint8_t fixQual = 0; // fix quality from GPGGA uint32_t lastChecksumFailCount = 0; @@ -164,21 +153,13 @@ class GPS : private concurrency::OSThread TinyGPSCustom gsapdop; // custom extract PDOP from GPGSA uint8_t fixType = 0; // fix type from GPGSA #endif -#if GPS_BAUDRATE_FIXED - // if GPS_BAUDRATE is specified in variant, only try that. - const int serialSpeeds[1] = {GPS_BAUDRATE}; - const int rareSerialSpeeds[1] = {GPS_BAUDRATE}; -#else - const int serialSpeeds[3] = {9600, 115200, 38400}; - const int rareSerialSpeeds[3] = {4800, 57600, GPS_BAUDRATE}; -#endif uint32_t lastWakeStartMsec = 0, lastSleepStartMsec = 0, lastFixStartMsec = 0; uint32_t rx_gpio = 0; uint32_t tx_gpio = 0; - int speedSelect = 0; - int probeTries = 0; + uint8_t speedSelect = 0; + uint8_t probeTries = 0; /** * hasValidLocation - indicates that the position variables contain a complete @@ -207,52 +188,6 @@ class GPS : private concurrency::OSThread #else static HardwareSerial *_serial_gps; #endif - static uint8_t _message_PMREQ[]; - static uint8_t _message_PMREQ_10[]; - static const uint8_t _message_CFG_RXM_PSM[]; - static const uint8_t _message_CFG_RXM_ECO[]; - static const uint8_t _message_CFG_PM2[]; - static const uint8_t _message_GNSS_7[]; - static const uint8_t _message_GNSS_8[]; - static const uint8_t _message_JAM_6_7[]; - static const uint8_t _message_JAM_8[]; - static const uint8_t _message_NAVX5[]; - static const uint8_t _message_NAVX5_8[]; - static const uint8_t _message_NMEA[]; - static const uint8_t _message_DISABLE_TXT_INFO[]; - static const uint8_t _message_1HZ[]; - static const uint8_t _message_GLL[]; - static const uint8_t _message_GSA[]; - static const uint8_t _message_GSV[]; - static const uint8_t _message_VTG[]; - static const uint8_t _message_RMC[]; - static const uint8_t _message_AID[]; - static const uint8_t _message_GGA[]; - static const uint8_t _message_PMS[]; - static const uint8_t _message_SAVE[]; - static const uint8_t _message_SAVE_10[]; - - // VALSET Commands for M10 - static const uint8_t _message_VALSET_PM[]; - static const uint8_t _message_VALSET_PM_RAM[]; - static const uint8_t _message_VALSET_PM_BBR[]; - static const uint8_t _message_VALSET_ITFM_RAM[]; - static const uint8_t _message_VALSET_ITFM_BBR[]; - static const uint8_t _message_VALSET_DISABLE_NMEA_RAM[]; - static const uint8_t _message_VALSET_DISABLE_NMEA_BBR[]; - static const uint8_t _message_VALSET_DISABLE_TXT_INFO_RAM[]; - static const uint8_t _message_VALSET_DISABLE_TXT_INFO_BBR[]; - static const uint8_t _message_VALSET_ENABLE_NMEA_RAM[]; - static const uint8_t _message_VALSET_ENABLE_NMEA_BBR[]; - static const uint8_t _message_VALSET_DISABLE_SBAS_RAM[]; - static const uint8_t _message_VALSET_DISABLE_SBAS_BBR[]; - - // CASIC commands for ATGM336H - static const uint8_t _message_CAS_CFG_RST_FACTORY[]; - static const uint8_t _message_CAS_CFG_NAVX_CONF[]; - static const uint8_t _message_CAS_CFG_RATE_1HZ[]; - - const char *ACK_SUCCESS_MESSAGE = "Get ack success!"; // Create a ublox packet for editing in memory uint8_t makeUBXPacket(uint8_t class_id, uint8_t msg_id, uint8_t payload_size, const uint8_t *msg); @@ -273,10 +208,6 @@ class GPS : private concurrency::OSThread /// always returns 0 to indicate okay to sleep int prepareDeepSleep(void *unused); - // Calculate checksum - void UBXChecksum(uint8_t *message, size_t length); - void CASChecksum(uint8_t *message, size_t length); - /** Set power with EN pin, if relevant */ void writePinEN(bool on); @@ -305,9 +236,7 @@ class GPS : private concurrency::OSThread // delay counter to allow more sats before fixed position stops GPS thread uint8_t fixeddelayCtr = 0; - - const char *powerStateToString(); }; extern GPS *gps; -#endif // Exclude GPS +#endif // Exclude GPS \ No newline at end of file diff --git a/src/gps/GeoCoord.cpp b/src/gps/GeoCoord.cpp index 5abb25a06..6d1f2da6d 100644 --- a/src/gps/GeoCoord.cpp +++ b/src/gps/GeoCoord.cpp @@ -574,3 +574,23 @@ const char *GeoCoord::degreesToBearing(unsigned int degrees) else return "N"; } + +double GeoCoord::pow_neg(double base, double exponent) +{ + if (exponent == 0) { + return 1; + } else if (exponent > 0) { + return pow(base, exponent); + } + return 1 / pow(base, -exponent); +} + +double GeoCoord::toRadians(double deg) +{ + return deg * PI / 180; +} + +double GeoCoord::toDegrees(double r) +{ + return r * 180 / PI; +} \ No newline at end of file diff --git a/src/gps/GeoCoord.h b/src/gps/GeoCoord.h index ecdaf0ec7..658c177b3 100644 --- a/src/gps/GeoCoord.h +++ b/src/gps/GeoCoord.h @@ -13,28 +13,6 @@ #define OLC_CODE_LEN 11 #define DEG_CONVERT (180 / PI) -// Helper functions -// Raises a number to an exponent, handling negative exponents. -static inline double pow_neg(double base, double exponent) -{ - if (exponent == 0) { - return 1; - } else if (exponent > 0) { - return pow(base, exponent); - } - return 1 / pow(base, -exponent); -} - -static inline double toRadians(double deg) -{ - return deg * PI / 180; -} - -static inline double toDegrees(double r) -{ - return r * 180 / PI; -} - // GeoCoord structs/classes // A struct to hold the data for a DMS coordinate. struct DMS { @@ -120,6 +98,11 @@ class GeoCoord static unsigned int bearingToDegrees(const char *bearing); static const char *degreesToBearing(unsigned int degrees); + // Raises a number to an exponent, handling negative exponents. + static double pow_neg(double base, double exponent); + static double toRadians(double deg); + static double toDegrees(double r); + // Point to point conversions int32_t distanceTo(const GeoCoord &pointB); int32_t bearingTo(const GeoCoord &pointB); @@ -162,4 +145,4 @@ class GeoCoord // OLC getter void getOLCCode(char *code) { strncpy(code, _olc.code, OLC_CODE_LEN + 1); } // +1 for null termination -}; +}; \ No newline at end of file diff --git a/src/gps/cas.h b/src/gps/cas.h index 53d75cda9..725fd07b3 100644 --- a/src/gps/cas.h +++ b/src/gps/cas.h @@ -21,7 +21,7 @@ // CFG-RST (0x06, 0x02) // Factory reset -const uint8_t GPS::_message_CAS_CFG_RST_FACTORY[] = { +static const uint8_t _message_CAS_CFG_RST_FACTORY[] = { 0xFF, 0x03, // Fields to clear 0x01, // Reset Mode: Controlled Software reset 0x03 // Startup Mode: Factory @@ -30,7 +30,7 @@ const uint8_t GPS::_message_CAS_CFG_RST_FACTORY[] = { // CFG_RATE (0x06, 0x01) // 1HZ update rate, this should always be the case after // factory reset but update it regardless -const uint8_t GPS::_message_CAS_CFG_RATE_1HZ[] = { +static const uint8_t _message_CAS_CFG_RATE_1HZ[] = { 0xE8, 0x03, // Update Rate: 0x03E8 = 1000ms 0x00, 0x00 // Reserved }; @@ -39,7 +39,7 @@ const uint8_t GPS::_message_CAS_CFG_RATE_1HZ[] = { // Initial ATGM33H-5N configuration, Updates for Dynamic Mode, Fix Mode, and SV system // Qwirk: The ATGM33H-5N-31 should only support GPS+BDS, however it will happily enable // and use GPS+BDS+GLONASS iff the correct CFG_NAVX command is used. -const uint8_t GPS::_message_CAS_CFG_NAVX_CONF[] = { +static const uint8_t _message_CAS_CFG_NAVX_CONF[] = { 0x03, 0x01, 0x00, 0x00, // Update Mask: Dynamic Mode, Fix Mode, Nav Settings 0x03, // Dynamic Mode: Automotive 0x03, // Fix Mode: Auto 2D/3D @@ -60,4 +60,4 @@ const uint8_t GPS::_message_CAS_CFG_NAVX_CONF[] = { 0x00, 0x00, 0x00, 0x00, // Position Accuracy Max 0x00, 0x00, 0x00, 0x00, // Time Accuracy Max 0x00, 0x00, 0x00, 0x00 // Static Hold Threshold -}; \ No newline at end of file +}; diff --git a/src/gps/ubx.h b/src/gps/ubx.h index 551921384..d674bed51 100644 --- a/src/gps/ubx.h +++ b/src/gps/ubx.h @@ -1,20 +1,22 @@ -const char *failMessage = "Unable to %s"; +static const char *failMessage = "Unable to %s"; #define SEND_UBX_PACKET(TYPE, ID, DATA, ERRMSG, TIMEOUT) \ - msglen = makeUBXPacket(TYPE, ID, sizeof(DATA), DATA); \ - _serial_gps->write(UBXscratch, msglen); \ - if (getACK(TYPE, ID, TIMEOUT) != GNSS_RESPONSE_OK) { \ - LOG_WARN(failMessage, #ERRMSG); \ - } + do { \ + msglen = makeUBXPacket(TYPE, ID, sizeof(DATA), DATA); \ + _serial_gps->write(UBXscratch, msglen); \ + if (getACK(TYPE, ID, TIMEOUT) != GNSS_RESPONSE_OK) { \ + LOG_WARN(failMessage, #ERRMSG); \ + } \ + } while (0) // Power Management -uint8_t GPS::_message_PMREQ[] PROGMEM = { +static uint8_t _message_PMREQ[] PROGMEM = { 0x00, 0x00, 0x00, 0x00, // 4 bytes duration of request task (milliseconds) 0x02, 0x00, 0x00, 0x00 // Bitfield, set backup = 1 }; -uint8_t GPS::_message_PMREQ_10[] PROGMEM = { +static uint8_t _message_PMREQ_10[] PROGMEM = { 0x00, // version (0 for this version) 0x00, 0x00, 0x00, // Reserved 1 0x00, 0x00, 0x00, 0x00, // 4 bytes duration of request task (milliseconds) @@ -22,18 +24,18 @@ uint8_t GPS::_message_PMREQ_10[] PROGMEM = { 0x08, 0x00, 0x00, 0x00 // wakeupSources Wake on uartrx }; -const uint8_t GPS::_message_CFG_RXM_PSM[] PROGMEM = { +static const uint8_t _message_CFG_RXM_PSM[] PROGMEM = { 0x08, // Reserved 0x01 // Power save mode }; // only for Neo-6 -const uint8_t GPS::_message_CFG_RXM_ECO[] PROGMEM = { +static const uint8_t _message_CFG_RXM_ECO[] PROGMEM = { 0x08, // Reserved 0x04 // eco mode }; -const uint8_t GPS::_message_CFG_PM2[] PROGMEM = { +static const uint8_t _message_CFG_PM2[] PROGMEM = { 0x01, // version 0x00, // Reserved 1, set to 0x06 by u-Center 0x00, // Reserved 2 @@ -58,7 +60,7 @@ const uint8_t GPS::_message_CFG_PM2[] PROGMEM = { // Constallation setup, none required for Neo-6 // For Neo-7 GPS & SBAS -const uint8_t GPS::_message_GNSS_7[] = { +static const uint8_t _message_GNSS_7[] = { 0x00, // msgVer (0 for this version) 0x00, // numTrkChHw (max number of hardware channels, read only, so it's always 0) 0xff, // numTrkChUse (max number of channels to use, 0xff = max available) @@ -76,7 +78,7 @@ const uint8_t GPS::_message_GNSS_7[] = { // There is also a possibility that the module may be GPS-only. // For M8 GPS, GLONASS, Galileo, SBAS, QZSS -const uint8_t GPS::_message_GNSS_8[] = { +static const uint8_t _message_GNSS_8[] = { 0x00, // msgVer (0 for this version) 0x00, // numTrkChHw (max number of hardware channels, read only, so it's always 0) 0xff, // numTrkChUse (max number of channels to use, 0xff = max available) @@ -90,7 +92,7 @@ const uint8_t GPS::_message_GNSS_8[] = { }; /* // For M8 GPS, GLONASS, BeiDou, SBAS, QZSS -const uint8_t GPS::_message_GNSS_8_B[] = { +static const uint8_t _message_GNSS_8_B[] = { 0x00, // msgVer (0 for this version) 0x00, // numTrkChHw (max number of hardware channels, read only, so it's always 0) 0xff, // numTrkChUse (max number of channels to use, 0xff = max available) read only for protocol >23 @@ -105,7 +107,7 @@ const uint8_t GPS::_message_GNSS_8_B[] = { */ // For M8 we want to enable NMEA version 4.10 messages to allow for Galileo and or BeiDou -const uint8_t GPS::_message_NMEA[]{ +static const uint8_t _message_NMEA[]{ 0x00, // filter flags 0x41, // NMEA Version 0x00, // Max number of SVs to report per TaklerId @@ -121,13 +123,13 @@ const uint8_t GPS::_message_NMEA[]{ // Enable jamming/interference monitor // For Neo-6, Max-7 and Neo-7 -const uint8_t GPS::_message_JAM_6_7[] = { +static const uint8_t _message_JAM_6_7[] = { 0xf3, 0xac, 0x62, 0xad, // config1 bbThreshold = 3, cwThreshold = 15, enable = 1, reserved bits 0x16B156 0x1e, 0x03, 0x00, 0x00 // config2 antennaSetting Unknown = 0, reserved 3, = 0x00,0x00, reserved 2 = 0x31E }; // For M8 -const uint8_t GPS::_message_JAM_8[] = { +static const uint8_t _message_JAM_8[] = { 0xf3, 0xac, 0x62, 0xad, // config1 bbThreshold = 3, cwThreshold = 15, enable1 = 1, reserved bits 0x16B156 0x1e, 0x43, 0x00, 0x00 // config2 antennaSetting Unknown = 0, enable2 = 1, generalBits = 0x31E }; @@ -137,7 +139,7 @@ const uint8_t GPS::_message_JAM_8[] = { // ToDo: check UBX-MON-VER for module type and protocol version // For the Neo-6 -const uint8_t GPS::_message_NAVX5[] = { +static const uint8_t _message_NAVX5[] = { 0x00, 0x00, // msgVer (0 for this version) 0x4c, 0x66, // mask1 0x00, 0x00, 0x00, 0x00, // Reserved 0 @@ -166,7 +168,7 @@ const uint8_t GPS::_message_NAVX5[] = { 0x00, 0x00, 0x00, 0x00 // Reserved 4 }; // For the M8 -const uint8_t GPS::_message_NAVX5_8[] = { +static const uint8_t _message_NAVX5_8[] = { 0x02, 0x00, // msgVer (2 for this version) 0x4c, 0x66, // mask1 0x00, 0x00, 0x00, 0x00, // mask2 @@ -197,7 +199,7 @@ const uint8_t GPS::_message_NAVX5_8[] = { // Additionally, for some new modules like the M9/M10, an update rate lower than 5Hz // is recommended to avoid a known issue with satellites disappearing. // The module defaults for M8, M9, M10 are the same as we use here so no update is necessary -const uint8_t GPS::_message_1HZ[] = { +static const uint8_t _message_1HZ[] = { 0xE8, 0x03, // Measurement Rate (1000ms for 1Hz) 0x01, 0x00, // Navigation rate, always 1 in GPS mode 0x01, 0x00 // Time reference @@ -205,7 +207,7 @@ const uint8_t GPS::_message_1HZ[] = { // Disable GLL. GLL - Geographic position (latitude and longitude), which provides the current geographical // coordinates. -const uint8_t GPS::_message_GLL[] = { +static const uint8_t _message_GLL[] = { 0xF0, 0x01, // NMEA ID for GLL 0x00, // Rate for DDC 0x00, // Rate for UART1 @@ -217,7 +219,7 @@ const uint8_t GPS::_message_GLL[] = { // Disable GSA. GSA - GPS DOP and active satellites, used for detailing the satellites used in the positioning and // the DOP (Dilution of Precision) -const uint8_t GPS::_message_GSA[] = { +static const uint8_t _message_GSA[] = { 0xF0, 0x02, // NMEA ID for GSA 0x00, // Rate for DDC 0x00, // Rate for UART1 @@ -228,7 +230,7 @@ const uint8_t GPS::_message_GSA[] = { }; // Disable GSV. GSV - Satellites in view, details the number and location of satellites in view. -const uint8_t GPS::_message_GSV[] = { +static const uint8_t _message_GSV[] = { 0xF0, 0x03, // NMEA ID for GSV 0x00, // Rate for DDC 0x00, // Rate for UART1 @@ -240,7 +242,7 @@ const uint8_t GPS::_message_GSV[] = { // Disable VTG. VTG - Track made good and ground speed, which provides course and speed information relative to // the ground. -const uint8_t GPS::_message_VTG[] = { +static const uint8_t _message_VTG[] = { 0xF0, 0x05, // NMEA ID for VTG 0x00, // Rate for DDC 0x00, // Rate for UART1 @@ -251,7 +253,7 @@ const uint8_t GPS::_message_VTG[] = { }; // Enable RMC. RMC - Recommended Minimum data, the essential gps pvt (position, velocity, time) data. -const uint8_t GPS::_message_RMC[] = { +static const uint8_t _message_RMC[] = { 0xF0, 0x04, // NMEA ID for RMC 0x00, // Rate for DDC 0x01, // Rate for UART1 @@ -262,7 +264,7 @@ const uint8_t GPS::_message_RMC[] = { }; // Enable GGA. GGA - Global Positioning System Fix Data, which provides 3D location and accuracy data. -const uint8_t GPS::_message_GGA[] = { +static const uint8_t _message_GGA[] = { 0xF0, 0x00, // NMEA ID for GGA 0x00, // Rate for DDC 0x01, // Rate for UART1 @@ -274,7 +276,7 @@ const uint8_t GPS::_message_GGA[] = { // Disable UBX-AID-ALPSRV as it may confuse TinyGPS. The Neo-6 seems to send this message // whether the AID Autonomous is enabled or not -const uint8_t GPS::_message_AID[] = { +static const uint8_t _message_AID[] = { 0x0B, 0x32, // NMEA ID for UBX-AID-ALPSRV 0x00, // Rate for DDC 0x00, // Rate for UART1 @@ -287,7 +289,7 @@ const uint8_t GPS::_message_AID[] = { // Turn off TEXT INFO Messages for all but M10 series // B5 62 06 02 0A 00 01 00 00 00 03 03 00 03 03 00 1F 20 -const uint8_t GPS::_message_DISABLE_TXT_INFO[] = { +static const uint8_t _message_DISABLE_TXT_INFO[] = { 0x01, // Protocol ID for NMEA 0x00, 0x00, 0x00, // Reserved 0x03, // I2C @@ -310,7 +312,7 @@ const uint8_t GPS::_message_DISABLE_TXT_INFO[] = { // and must be smaller than the period. It is only valid when the powerSetupValue is set to Interval; otherwise, // it must be set to '0'. // This command applies to M8 products -const uint8_t GPS::_message_PMS[] = { +static const uint8_t _message_PMS[] = { 0x00, // Version (0) 0x03, // Power setup value 3 = Agresssive 1Hz 0x00, 0x00, // period: not applicable, set to 0 @@ -318,14 +320,14 @@ const uint8_t GPS::_message_PMS[] = { 0x00, 0x00 // reserved, generated by u-center }; -const uint8_t GPS::_message_SAVE[] = { +static const uint8_t _message_SAVE[] = { 0x00, 0x00, 0x00, 0x00, // clearMask: no sections cleared 0xFF, 0xFF, 0x00, 0x00, // saveMask: save all sections 0x00, 0x00, 0x00, 0x00, // loadMask: no sections loaded 0x17 // deviceMask: BBR, Flash, EEPROM, and SPI Flash }; -const uint8_t GPS::_message_SAVE_10[] = { +static const uint8_t _message_SAVE_10[] = { 0x00, 0x00, 0x00, 0x00, // clearMask: no sections cleared 0xFF, 0xFF, 0x00, 0x00, // saveMask: save all sections 0x00, 0x00, 0x00, 0x00, // loadMask: no sections loaded @@ -375,12 +377,12 @@ LIMITPEAKCURRENT L 1 // b5 62 06 8a 26 00 00 02 00 00 01 00 d0 20 02 02 00 d0 40 05 00 00 00 05 00 d0 30 01 00 08 00 d0 10 01 09 00 d0 10 01 10 00 d0 // 10 01 8c 03 */ -const uint8_t GPS::_message_VALSET_PM_RAM[] = {0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0xd0, 0x20, 0x02, 0x02, 0x00, 0xd0, 0x40, - 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0xd0, 0x30, 0x01, 0x00, 0x08, 0x00, 0xd0, - 0x10, 0x01, 0x09, 0x00, 0xd0, 0x10, 0x01, 0x10, 0x00, 0xd0, 0x10, 0x01}; -const uint8_t GPS::_message_VALSET_PM_BBR[] = {0x00, 0x02, 0x00, 0x00, 0x01, 0x00, 0xd0, 0x20, 0x02, 0x02, 0x00, 0xd0, 0x40, - 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0xd0, 0x30, 0x01, 0x00, 0x08, 0x00, 0xd0, - 0x10, 0x01, 0x09, 0x00, 0xd0, 0x10, 0x01, 0x10, 0x00, 0xd0, 0x10, 0x01}; +static const uint8_t _message_VALSET_PM_RAM[] = {0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0xd0, 0x20, 0x02, 0x02, 0x00, 0xd0, 0x40, + 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0xd0, 0x30, 0x01, 0x00, 0x08, 0x00, 0xd0, + 0x10, 0x01, 0x09, 0x00, 0xd0, 0x10, 0x01, 0x10, 0x00, 0xd0, 0x10, 0x01}; +static const uint8_t _message_VALSET_PM_BBR[] = {0x00, 0x02, 0x00, 0x00, 0x01, 0x00, 0xd0, 0x20, 0x02, 0x02, 0x00, 0xd0, 0x40, + 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0xd0, 0x30, 0x01, 0x00, 0x08, 0x00, 0xd0, + 0x10, 0x01, 0x09, 0x00, 0xd0, 0x10, 0x01, 0x10, 0x00, 0xd0, 0x10, 0x01}; /* CFG-ITFM replaced by 5 valset messages which can be combined into one for RAM and one for BBR @@ -394,10 +396,10 @@ CFG-ITFM replaced by 5 valset messages which can be combined into one for RAM an b5 62 06 8a 0e 00 00 01 00 00 0d 00 41 10 01 13 00 41 10 01 63 c6 */ -const uint8_t GPS::_message_VALSET_ITFM_RAM[] = {0x00, 0x01, 0x00, 0x00, 0x0d, 0x00, 0x41, - 0x10, 0x01, 0x13, 0x00, 0x41, 0x10, 0x01}; -const uint8_t GPS::_message_VALSET_ITFM_BBR[] = {0x00, 0x02, 0x00, 0x00, 0x0d, 0x00, 0x41, - 0x10, 0x01, 0x13, 0x00, 0x41, 0x10, 0x01}; +static const uint8_t _message_VALSET_ITFM_RAM[] = {0x00, 0x01, 0x00, 0x00, 0x0d, 0x00, 0x41, + 0x10, 0x01, 0x13, 0x00, 0x41, 0x10, 0x01}; +static const uint8_t _message_VALSET_ITFM_BBR[] = {0x00, 0x02, 0x00, 0x00, 0x0d, 0x00, 0x41, + 0x10, 0x01, 0x13, 0x00, 0x41, 0x10, 0x01}; // Turn off all NMEA messages: // Ram layer config message: @@ -407,13 +409,13 @@ const uint8_t GPS::_message_VALSET_ITFM_BBR[] = {0x00, 0x02, 0x00, 0x00, 0x0d, 0 // BBR layer config message: // b5 62 06 8a 13 00 00 02 00 00 ca 00 91 20 00 c5 00 91 20 00 b1 00 91 20 00 f8 4e -const uint8_t GPS::_message_VALSET_DISABLE_NMEA_RAM[] = { +static const uint8_t _message_VALSET_DISABLE_NMEA_RAM[] = { /*0x00, 0x01, 0x00, 0x00, 0xca, 0x00, 0x91, 0x20, 0x00, 0xc5, 0x00, 0x91, 0x20, 0x00, 0xb1, 0x00, 0x91, 0x20, 0x00 */ 0x00, 0x01, 0x00, 0x00, 0xc0, 0x00, 0x91, 0x20, 0x00, 0xca, 0x00, 0x91, 0x20, 0x00, 0xc5, 0x00, 0x91, 0x20, 0x00, 0xac, 0x00, 0x91, 0x20, 0x00, 0xb1, 0x00, 0x91, 0x20, 0x00, 0xbb, 0x00, 0x91, 0x20, 0x00}; -const uint8_t GPS::_message_VALSET_DISABLE_NMEA_BBR[] = {0x00, 0x02, 0x00, 0x00, 0xca, 0x00, 0x91, 0x20, 0x00, 0xc5, - 0x00, 0x91, 0x20, 0x00, 0xb1, 0x00, 0x91, 0x20, 0x00}; +static const uint8_t _message_VALSET_DISABLE_NMEA_BBR[] = {0x00, 0x02, 0x00, 0x00, 0xca, 0x00, 0x91, 0x20, 0x00, 0xc5, + 0x00, 0x91, 0x20, 0x00, 0xb1, 0x00, 0x91, 0x20, 0x00}; // Turn off text info messages: // Ram layer config message: @@ -432,17 +434,17 @@ const uint8_t GPS::_message_VALSET_DISABLE_NMEA_BBR[] = {0x00, 0x02, 0x00, 0x00, // b5 62 06 8a 0e 00 00 04 00 00 bb 00 91 20 01 ac 00 91 20 01 6d b6 // Doing this for the FLASH layer isn't really required since we save the config to flash later -const uint8_t GPS::_message_VALSET_DISABLE_TXT_INFO_RAM[] = {0x00, 0x01, 0x00, 0x00, 0x07, 0x00, 0x92, 0x20, 0x03}; -const uint8_t GPS::_message_VALSET_DISABLE_TXT_INFO_BBR[] = {0x00, 0x02, 0x00, 0x00, 0x07, 0x00, 0x92, 0x20, 0x03}; +static const uint8_t _message_VALSET_DISABLE_TXT_INFO_RAM[] = {0x00, 0x01, 0x00, 0x00, 0x07, 0x00, 0x92, 0x20, 0x03}; +static const uint8_t _message_VALSET_DISABLE_TXT_INFO_BBR[] = {0x00, 0x02, 0x00, 0x00, 0x07, 0x00, 0x92, 0x20, 0x03}; -const uint8_t GPS::_message_VALSET_ENABLE_NMEA_RAM[] = {0x00, 0x01, 0x00, 0x00, 0xbb, 0x00, 0x91, - 0x20, 0x01, 0xac, 0x00, 0x91, 0x20, 0x01}; -const uint8_t GPS::_message_VALSET_ENABLE_NMEA_BBR[] = {0x00, 0x02, 0x00, 0x00, 0xbb, 0x00, 0x91, - 0x20, 0x01, 0xac, 0x00, 0x91, 0x20, 0x01}; -const uint8_t GPS::_message_VALSET_DISABLE_SBAS_RAM[] = {0x00, 0x01, 0x00, 0x00, 0x20, 0x00, 0x31, - 0x10, 0x00, 0x05, 0x00, 0x31, 0x10, 0x00}; -const uint8_t GPS::_message_VALSET_DISABLE_SBAS_BBR[] = {0x00, 0x02, 0x00, 0x00, 0x20, 0x00, 0x31, - 0x10, 0x00, 0x05, 0x00, 0x31, 0x10, 0x00}; +static const uint8_t _message_VALSET_ENABLE_NMEA_RAM[] = {0x00, 0x01, 0x00, 0x00, 0xbb, 0x00, 0x91, + 0x20, 0x01, 0xac, 0x00, 0x91, 0x20, 0x01}; +static const uint8_t _message_VALSET_ENABLE_NMEA_BBR[] = {0x00, 0x02, 0x00, 0x00, 0xbb, 0x00, 0x91, + 0x20, 0x01, 0xac, 0x00, 0x91, 0x20, 0x01}; +static const uint8_t _message_VALSET_DISABLE_SBAS_RAM[] = {0x00, 0x01, 0x00, 0x00, 0x20, 0x00, 0x31, + 0x10, 0x00, 0x05, 0x00, 0x31, 0x10, 0x00}; +static const uint8_t _message_VALSET_DISABLE_SBAS_BBR[] = {0x00, 0x02, 0x00, 0x00, 0x20, 0x00, 0x31, + 0x10, 0x00, 0x05, 0x00, 0x31, 0x10, 0x00}; /* Operational issues with the M10: @@ -475,4 +477,4 @@ b5 62 06 8a 0e 00 00 01 00 00 20 00 31 10 00 05 00 31 10 00 46 87 BBR layer config message: b5 62 06 8a 0e 00 00 02 00 00 20 00 31 10 00 05 00 31 10 00 47 94 -*/ \ No newline at end of file +*/ diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index a875c11d6..31647c92d 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -20,7 +20,6 @@ along with this program. If not, see . */ #include "Screen.h" -#include "../userPrefs.h" #include "PowerMon.h" #include "Throttle.h" #include "configuration.h" @@ -127,7 +126,7 @@ static bool heartbeat = false; /// Check if the display can render a string (detect special chars; emoji) static bool haveGlyphs(const char *str) { -#if defined(OLED_PL) || defined(OLED_UA) || defined(OLED_RU) +#if defined(OLED_PL) || defined(OLED_UA) || defined(OLED_RU) || defined(OLED_CS) // Don't want to make any assumptions about custom language support return true; #endif @@ -1016,7 +1015,7 @@ static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - devil_height) / 2 + 2 + 5, devil_width, devil_height, devil); } else if (strcmp(msg, "♥️") == 0 || strcmp(msg, "\U0001F9E1") == 0 || strcmp(msg, "\U00002763") == 0 || strcmp(msg, "\U00002764") == 0 || strcmp(msg, "\U0001F495") == 0 || strcmp(msg, "\U0001F496") == 0 || - strcmp(msg, "\U0001F497") == 0 || strcmp(msg, "\U0001F496") == 0) { + strcmp(msg, "\U0001F497") == 0 || strcmp(msg, "\U0001F498") == 0) { display->drawXbm(x + (SCREEN_WIDTH - heart_width) / 2, y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - heart_height) / 2 + 2 + 5, heart_width, heart_height, heart); } else { @@ -1420,7 +1419,7 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_ } bool hasNodeHeading = false; - if (ourNode && (hasValidPosition(ourNode) || screen->hasHeading())) { + if (ourNode && (nodeDB->hasValidPosition(ourNode) || screen->hasHeading())) { const meshtastic_PositionLite &op = ourNode->position; float myHeading; if (screen->hasHeading()) @@ -1429,7 +1428,7 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_ myHeading = screen->estimatedHeading(DegD(op.latitude_i), DegD(op.longitude_i)); screen->drawCompassNorth(display, compassX, compassY, myHeading); - if (hasValidPosition(node)) { + if (nodeDB->hasValidPosition(node)) { // display direction toward node hasNodeHeading = true; const meshtastic_PositionLite &p = node->position; @@ -1719,7 +1718,7 @@ void Screen::setup() #endif serialSinceMsec = millis(); -#if ARCH_PORTDUINO +#if ARCH_PORTDUINO && !HAS_TFT if (settingsMap[touchscreenModule]) { touchScreenImpl1 = new TouchScreenImpl1(dispdev->getWidth(), dispdev->getHeight(), static_cast(dispdev)->getTouch); @@ -2757,4 +2756,4 @@ int Screen::handleAdminMessage(const meshtastic_AdminMessage *arg) } // namespace graphics #else graphics::Screen::Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY) {} -#endif // HAS_SCREEN +#endif // HAS_SCREEN \ No newline at end of file diff --git a/src/graphics/Screen.h b/src/graphics/Screen.h index 2a77ca575..3cb39e8ec 100644 --- a/src/graphics/Screen.h +++ b/src/graphics/Screen.h @@ -427,6 +427,86 @@ class Screen : public concurrency::OSThread if (ch == 0xC2 || ch == 0xC3 || ch == 0x82 || ch == 0xD0 || ch == 0xD1) return (uint8_t)0; +#endif + +#if defined(OLED_CS) + + switch (last) { + case 0xC2: { + SKIPREST = false; + return (uint8_t)ch; + } + + case 0xC3: { + SKIPREST = false; + return (uint8_t)(ch | 0xC0); + } + + case 0xC4: { + SKIPREST = false; + if (ch == 140) + return (uint8_t)(129); // Č + if (ch == 141) + return (uint8_t)(138); // č + if (ch == 142) + return (uint8_t)(130); // Ď + if (ch == 143) + return (uint8_t)(139); // ď + if (ch == 154) + return (uint8_t)(131); // Ě + if (ch == 155) + return (uint8_t)(140); // ě + // Slovak specific glyphs + if (ch == 185) + return (uint8_t)(147); // Ĺ + if (ch == 186) + return (uint8_t)(148); // ĺ + if (ch == 189) + return (uint8_t)(149); // Ľ + if (ch == 190) + return (uint8_t)(150); // ľ + break; + } + + case 0xC5: { + SKIPREST = false; + if (ch == 135) + return (uint8_t)(132); // Ň + if (ch == 136) + return (uint8_t)(141); // ň + if (ch == 152) + return (uint8_t)(133); // Ř + if (ch == 153) + return (uint8_t)(142); // ř + if (ch == 160) + return (uint8_t)(134); // Š + if (ch == 161) + return (uint8_t)(143); // š + if (ch == 164) + return (uint8_t)(135); // Ť + if (ch == 165) + return (uint8_t)(144); // ť + if (ch == 174) + return (uint8_t)(136); // Ů + if (ch == 175) + return (uint8_t)(145); // ů + if (ch == 189) + return (uint8_t)(137); // Ž + if (ch == 190) + return (uint8_t)(146); // ž + // Slovak specific glyphs + if (ch == 148) + return (uint8_t)(151); // Ŕ + if (ch == 149) + return (uint8_t)(152); // ŕ + break; + } + } + + // We want to strip out prefix chars for two-byte char formats + if (ch == 0xC2 || ch == 0xC3 || ch == 0xC4 || ch == 0xC5) + return (uint8_t)0; + #endif // If we already returned an unconvertable-character symbol for this unconvertable-character sequence, return NULs for the @@ -605,4 +685,4 @@ class Screen : public concurrency::OSThread } // namespace graphics -#endif +#endif \ No newline at end of file diff --git a/src/graphics/ScreenFonts.h b/src/graphics/ScreenFonts.h index c9ce961fa..81eb717cd 100644 --- a/src/graphics/ScreenFonts.h +++ b/src/graphics/ScreenFonts.h @@ -12,6 +12,10 @@ #include "graphics/fonts/OLEDDisplayFontsUA.h" #endif +#ifdef OLED_CS +#include "graphics/fonts/OLEDDisplayFontsCS.h" +#endif + #if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \ defined(ST7789_CS) || defined(USE_ST7789) || defined(HX8357_CS)) && \ !defined(DISPLAY_FORCE_SMALL_FONTS) @@ -27,14 +31,34 @@ #define FONT_SMALL ArialMT_Plain_10_RU #else #ifdef OLED_UA -#define FONT_SMALL ArialMT_Plain_10_UA +#define FONT_SMALL ArialMT_Plain_10_UA // Height: 13 +#else +#ifdef OLED_CS +#define FONT_SMALL ArialMT_Plain_10_CS #else #define FONT_SMALL ArialMT_Plain_10 // Height: 13 #endif #endif #endif +#endif +#ifdef OLED_UA +#define FONT_MEDIUM ArialMT_Plain_16_UA // Height: 19 +#else +#ifdef OLED_CS +#define FONT_MEDIUM ArialMT_Plain_16_CS +#else #define FONT_MEDIUM ArialMT_Plain_16 // Height: 19 -#define FONT_LARGE ArialMT_Plain_24 // Height: 28 +#endif +#endif +#ifdef OLED_UA +#define FONT_LARGE ArialMT_Plain_24_UA // Height: 28 +#else +#ifdef OLED_CS +#define FONT_LARGE ArialMT_Plain_24_CS // Height: 28 +#else +#define FONT_LARGE ArialMT_Plain_24 // Height: 28 +#endif +#endif #endif #define _fontHeight(font) ((font)[1] + 1) // height is position 1 diff --git a/src/graphics/TFTDisplay.cpp b/src/graphics/TFTDisplay.cpp index 87c3f7de9..4f2af670b 100644 --- a/src/graphics/TFTDisplay.cpp +++ b/src/graphics/TFTDisplay.cpp @@ -347,7 +347,7 @@ static LGFX *tft = nullptr; #include // Graphics and font library for ILI9342 driver chip static TFT_eSPI *tft = nullptr; // Invoke library, pins defined in User_Setup.h -#elif ARCH_PORTDUINO && HAS_SCREEN != 0 +#elif ARCH_PORTDUINO && HAS_SCREEN != 0 && !HAS_TFT #include // Graphics and font library for ST7735 driver chip class LGFX : public lgfx::LGFX_Device diff --git a/src/graphics/fonts/OLEDDisplayFontsCS.cpp b/src/graphics/fonts/OLEDDisplayFontsCS.cpp new file mode 100644 index 000000000..5c17e9177 --- /dev/null +++ b/src/graphics/fonts/OLEDDisplayFontsCS.cpp @@ -0,0 +1,1863 @@ +#include "OLEDDisplayFontsCS.h" + +// Font generated or edited with the glyphEditor +const uint8_t ArialMT_Plain_10_CS[] PROGMEM = { + 0x0A, // Width: 10 + 0x0D, // Height: 13 + 0x20, // First char: 32 + 0xE0, // Number of chars: 224 + // Jump Table: + 0xFF, 0xFF, 0x00, 0x0A, // 32 + 0x00, 0x00, 0x04, 0x03, // 33 + 0x00, 0x04, 0x05, 0x04, // 34 + 0x00, 0x09, 0x09, 0x06, // 35 + 0x00, 0x12, 0x0A, 0x06, // 36 + 0x00, 0x1C, 0x10, 0x09, // 37 + 0x00, 0x2C, 0x0E, 0x08, // 38 + 0x00, 0x3A, 0x01, 0x02, // 39 + 0x00, 0x3B, 0x06, 0x04, // 40 + 0x00, 0x41, 0x06, 0x04, // 41 + 0x00, 0x47, 0x05, 0x04, // 42 + 0x00, 0x4C, 0x09, 0x06, // 43 + 0x00, 0x55, 0x04, 0x03, // 44 + 0x00, 0x59, 0x03, 0x03, // 45 + 0x00, 0x5C, 0x04, 0x03, // 46 + 0x00, 0x60, 0x05, 0x04, // 47 + 0x00, 0x65, 0x0A, 0x06, // 48 + 0x00, 0x6F, 0x08, 0x05, // 49 + 0x00, 0x77, 0x0A, 0x06, // 50 + 0x00, 0x81, 0x0A, 0x06, // 51 + 0x00, 0x8B, 0x0B, 0x07, // 52 + 0x00, 0x96, 0x0A, 0x06, // 53 + 0x00, 0xA0, 0x0A, 0x06, // 54 + 0x00, 0xAA, 0x09, 0x06, // 55 + 0x00, 0xB3, 0x0A, 0x06, // 56 + 0x00, 0xBD, 0x0A, 0x06, // 57 + 0x00, 0xC7, 0x04, 0x03, // 58 + 0x00, 0xCB, 0x04, 0x03, // 59 + 0x00, 0xCF, 0x0A, 0x06, // 60 + 0x00, 0xD9, 0x09, 0x06, // 61 + 0x00, 0xE2, 0x09, 0x06, // 62 + 0x00, 0xEB, 0x0B, 0x07, // 63 + 0x00, 0xF6, 0x14, 0x0B, // 64 + 0x01, 0x0A, 0x0E, 0x08, // 65 + 0x01, 0x18, 0x0C, 0x07, // 66 + 0x01, 0x24, 0x0C, 0x07, // 67 + 0x01, 0x30, 0x0B, 0x07, // 68 + 0x01, 0x3B, 0x0C, 0x07, // 69 + 0x01, 0x47, 0x09, 0x06, // 70 + 0x01, 0x50, 0x0D, 0x08, // 71 + 0x01, 0x5D, 0x0C, 0x07, // 72 + 0x01, 0x69, 0x04, 0x03, // 73 + 0x01, 0x6D, 0x08, 0x05, // 74 + 0x01, 0x75, 0x0E, 0x08, // 75 + 0x01, 0x83, 0x0C, 0x07, // 76 + 0x01, 0x8F, 0x10, 0x09, // 77 + 0x01, 0x9F, 0x0C, 0x07, // 78 + 0x01, 0xAB, 0x0E, 0x08, // 79 + 0x01, 0xB9, 0x0B, 0x07, // 80 + 0x01, 0xC4, 0x0E, 0x08, // 81 + 0x01, 0xD2, 0x0C, 0x07, // 82 + 0x01, 0xDE, 0x0C, 0x07, // 83 + 0x01, 0xEA, 0x0B, 0x07, // 84 + 0x01, 0xF5, 0x0C, 0x07, // 85 + 0x02, 0x01, 0x0D, 0x08, // 86 + 0x02, 0x0E, 0x11, 0x0A, // 87 + 0x02, 0x1F, 0x0E, 0x08, // 88 + 0x02, 0x2D, 0x0D, 0x08, // 89 + 0x02, 0x3A, 0x0C, 0x07, // 90 + 0x02, 0x46, 0x06, 0x04, // 91 + 0x02, 0x4C, 0x06, 0x04, // 92 + 0x02, 0x52, 0x04, 0x03, // 93 + 0x02, 0x56, 0x09, 0x06, // 94 + 0x02, 0x5F, 0x0C, 0x07, // 95 + 0x02, 0x6B, 0x03, 0x03, // 96 + 0x02, 0x6E, 0x0A, 0x06, // 97 + 0x02, 0x78, 0x0A, 0x06, // 98 + 0x02, 0x82, 0x0A, 0x06, // 99 + 0x02, 0x8C, 0x0A, 0x06, // 100 + 0x02, 0x96, 0x0A, 0x06, // 101 + 0x02, 0xA0, 0x05, 0x04, // 102 + 0x02, 0xA5, 0x0A, 0x06, // 103 + 0x02, 0xAF, 0x0A, 0x06, // 104 + 0x02, 0xB9, 0x04, 0x03, // 105 + 0x02, 0xBD, 0x04, 0x03, // 106 + 0x02, 0xC1, 0x08, 0x05, // 107 + 0x02, 0xC9, 0x04, 0x03, // 108 + 0x02, 0xCD, 0x10, 0x09, // 109 + 0x02, 0xDD, 0x0A, 0x06, // 110 + 0x02, 0xE7, 0x0A, 0x06, // 111 + 0x02, 0xF1, 0x0A, 0x06, // 112 + 0x02, 0xFB, 0x0A, 0x06, // 113 + 0x03, 0x05, 0x05, 0x04, // 114 + 0x03, 0x0A, 0x08, 0x05, // 115 + 0x03, 0x12, 0x06, 0x04, // 116 + 0x03, 0x18, 0x0A, 0x06, // 117 + 0x03, 0x22, 0x09, 0x06, // 118 + 0x03, 0x2B, 0x0E, 0x08, // 119 + 0x03, 0x39, 0x0A, 0x06, // 120 + 0x03, 0x43, 0x09, 0x06, // 121 + 0x03, 0x4C, 0x0A, 0x06, // 122 + 0x03, 0x56, 0x06, 0x04, // 123 + 0x03, 0x5C, 0x04, 0x03, // 124 + 0x03, 0x60, 0x05, 0x04, // 125 + 0x03, 0x65, 0x09, 0x06, // 126 + 0xFF, 0xFF, 0x00, 0x0A, // 127 + 0xFF, 0xFF, 0x00, 0x0A, // 128 + 0x03, 0x6E, 0x0C, 0x07, // 129 + 0x03, 0x7A, 0x0B, 0x07, // 130 + 0x03, 0x85, 0x0C, 0x07, // 131 + 0x03, 0x91, 0x0C, 0x07, // 132 + 0x03, 0x9D, 0x0C, 0x07, // 133 + 0x03, 0xA9, 0x0C, 0x07, // 134 + 0x03, 0xB5, 0x0B, 0x07, // 135 + 0x03, 0xC0, 0x0C, 0x07, // 136 + 0x03, 0xCC, 0x0C, 0x07, // 137 + 0x03, 0xD8, 0x0A, 0x06, // 138 + 0x03, 0xE2, 0x0D, 0x08, // 139 + 0x03, 0xEF, 0x0A, 0x06, // 140 + 0x03, 0xF9, 0x0A, 0x06, // 141 + 0x04, 0x03, 0x07, 0x05, // 142 + 0x04, 0x0A, 0x08, 0x05, // 143 + 0x04, 0x12, 0x07, 0x05, // 144 + 0x04, 0x19, 0x0A, 0x06, // 145 + 0x04, 0x23, 0x0A, 0x06, // 146 + 0x04, 0x2D, 0x0C, 0x07, // 147 + 0x04, 0x39, 0x05, 0x04, // 148 + 0x04, 0x3E, 0x0C, 0x07, // 149 + 0x04, 0x4A, 0x07, 0x05, // 150 + 0x04, 0x51, 0x0C, 0x07, // 151 + 0x04, 0x5D, 0x07, 0x05, // 152 + 0xFF, 0xFF, 0x00, 0x0A, // 153 + 0xFF, 0xFF, 0x00, 0x0A, // 154 + 0xFF, 0xFF, 0x00, 0x0A, // 155 + 0xFF, 0xFF, 0x00, 0x0A, // 156 + 0xFF, 0xFF, 0x00, 0x0A, // 157 + 0xFF, 0xFF, 0x00, 0x0A, // 158 + 0xFF, 0xFF, 0x00, 0x0A, // 159 + 0xFF, 0xFF, 0x00, 0x0A, // 160 + 0x04, 0x64, 0x04, 0x03, // 161 + 0x04, 0x68, 0x0A, 0x06, // 162 + 0x04, 0x72, 0x0C, 0x07, // 163 + 0x04, 0x7E, 0x0A, 0x06, // 164 + 0x04, 0x88, 0x0A, 0x06, // 165 + 0x04, 0x92, 0x04, 0x03, // 166 + 0x04, 0x96, 0x0A, 0x06, // 167 + 0x04, 0xA0, 0x05, 0x04, // 168 + 0x04, 0xA5, 0x0D, 0x08, // 169 + 0x04, 0xB2, 0x07, 0x05, // 170 + 0x04, 0xB9, 0x0A, 0x06, // 171 + 0x04, 0xC3, 0x09, 0x06, // 172 + 0x04, 0xCC, 0x03, 0x03, // 173 + 0x04, 0xCF, 0x0D, 0x08, // 174 + 0x04, 0xDC, 0x0B, 0x07, // 175 + 0x04, 0xE7, 0x07, 0x05, // 176 + 0x04, 0xEE, 0x0A, 0x06, // 177 + 0x04, 0xF8, 0x05, 0x04, // 178 + 0x04, 0xFD, 0x05, 0x04, // 179 + 0x05, 0x02, 0x05, 0x04, // 180 + 0x05, 0x07, 0x0A, 0x06, // 181 + 0x05, 0x11, 0x09, 0x06, // 182 + 0x05, 0x1A, 0x03, 0x03, // 183 + 0x05, 0x1D, 0x06, 0x04, // 184 + 0x05, 0x23, 0x05, 0x04, // 185 + 0x05, 0x28, 0x07, 0x05, // 186 + 0x05, 0x2F, 0x0A, 0x06, // 187 + 0x05, 0x39, 0x10, 0x09, // 188 + 0x05, 0x49, 0x10, 0x09, // 189 + 0x05, 0x59, 0x10, 0x09, // 190 + 0x05, 0x69, 0x0A, 0x06, // 191 + 0x05, 0x73, 0x0E, 0x08, // 192 + 0x05, 0x81, 0x0E, 0x08, // 193 + 0x05, 0x8F, 0x0E, 0x08, // 194 + 0x05, 0x9D, 0x0E, 0x08, // 195 + 0x05, 0xAB, 0x0E, 0x08, // 196 + 0x05, 0xB9, 0x0E, 0x08, // 197 + 0x05, 0xC7, 0x12, 0x0A, // 198 + 0x05, 0xD9, 0x0C, 0x07, // 199 + 0x05, 0xE5, 0x0C, 0x07, // 200 + 0x05, 0xF1, 0x0C, 0x07, // 201 + 0x05, 0xFD, 0x0C, 0x07, // 202 + 0x06, 0x09, 0x0C, 0x07, // 203 + 0x06, 0x15, 0x05, 0x04, // 204 + 0x06, 0x1A, 0x04, 0x03, // 205 + 0x06, 0x1E, 0x04, 0x03, // 206 + 0x06, 0x22, 0x05, 0x04, // 207 + 0x06, 0x27, 0x0B, 0x07, // 208 + 0x06, 0x32, 0x0C, 0x07, // 209 + 0x06, 0x3E, 0x0E, 0x08, // 210 + 0x06, 0x4C, 0x0E, 0x08, // 211 + 0x06, 0x5A, 0x0E, 0x08, // 212 + 0x06, 0x68, 0x0E, 0x08, // 213 + 0x06, 0x76, 0x0E, 0x08, // 214 + 0x06, 0x84, 0x0A, 0x06, // 215 + 0x06, 0x8E, 0x0D, 0x08, // 216 + 0x06, 0x9B, 0x0C, 0x07, // 217 + 0x06, 0xA7, 0x0C, 0x07, // 218 + 0x06, 0xB3, 0x0C, 0x07, // 219 + 0x06, 0xBF, 0x0C, 0x07, // 220 + 0x06, 0xCB, 0x0D, 0x08, // 221 + 0x06, 0xD8, 0x0B, 0x07, // 222 + 0x06, 0xE3, 0x0C, 0x07, // 223 + 0x06, 0xEF, 0x0A, 0x06, // 224 + 0x06, 0xF9, 0x0A, 0x06, // 225 + 0x07, 0x03, 0x0A, 0x06, // 226 + 0x07, 0x0D, 0x0A, 0x06, // 227 + 0x07, 0x17, 0x0A, 0x06, // 228 + 0x07, 0x21, 0x0A, 0x06, // 229 + 0x07, 0x2B, 0x10, 0x09, // 230 + 0x07, 0x3B, 0x0A, 0x06, // 231 + 0x07, 0x45, 0x0A, 0x06, // 232 + 0x07, 0x4F, 0x0A, 0x06, // 233 + 0x07, 0x59, 0x0A, 0x06, // 234 + 0x07, 0x63, 0x0A, 0x06, // 235 + 0x07, 0x6D, 0x05, 0x04, // 236 + 0x07, 0x72, 0x04, 0x03, // 237 + 0x07, 0x76, 0x05, 0x04, // 238 + 0x07, 0x7B, 0x05, 0x04, // 239 + 0x07, 0x80, 0x0A, 0x06, // 240 + 0x07, 0x8A, 0x0A, 0x06, // 241 + 0x07, 0x94, 0x0A, 0x06, // 242 + 0x07, 0x9E, 0x0A, 0x06, // 243 + 0x07, 0xA8, 0x0A, 0x06, // 244 + 0x07, 0xB2, 0x0A, 0x06, // 245 + 0x07, 0xBC, 0x0A, 0x06, // 246 + 0x07, 0xC6, 0x09, 0x06, // 247 + 0x07, 0xCF, 0x0A, 0x06, // 248 + 0x07, 0xD9, 0x0A, 0x06, // 249 + 0x07, 0xE3, 0x0A, 0x06, // 250 + 0x07, 0xED, 0x0A, 0x06, // 251 + 0x07, 0xF7, 0x0A, 0x06, // 252 + 0x08, 0x01, 0x09, 0x06, // 253 + 0x08, 0x0A, 0x0A, 0x06, // 254 + 0x08, 0x14, 0x09, 0x06, // 255 + // Font Data: + 0x00, 0x00, 0xF8, 0x02, // 33 + 0x38, 0x00, 0x00, 0x00, 0x38, // 34 + 0xA0, 0x03, 0xE0, 0x00, 0xB8, 0x03, 0xE0, 0x00, 0xB8, // 35 + 0x30, 0x01, 0x28, 0x02, 0xF8, 0x07, 0x48, 0x02, 0x90, 0x01, // 36 + 0x00, 0x00, 0x30, 0x00, 0x48, 0x00, 0x30, 0x03, 0xC0, 0x00, 0xB0, 0x01, 0x48, 0x02, 0x80, 0x01, // 37 + 0x80, 0x01, 0x50, 0x02, 0x68, 0x02, 0xA8, 0x02, 0x18, 0x01, 0x80, 0x03, 0x80, 0x02, // 38 + 0x38, // 39 + 0xE0, 0x03, 0x10, 0x04, 0x08, 0x08, // 40 + 0x08, 0x08, 0x10, 0x04, 0xE0, 0x03, // 41 + 0x28, 0x00, 0x18, 0x00, 0x28, // 42 + 0x40, 0x00, 0x40, 0x00, 0xF0, 0x01, 0x40, 0x00, 0x40, // 43 + 0x00, 0x00, 0x00, 0x06, // 44 + 0x80, 0x00, 0x80, // 45 + 0x00, 0x00, 0x00, 0x02, // 46 + 0x00, 0x03, 0xE0, 0x00, 0x18, // 47 + 0xF0, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x02, 0xF0, 0x01, // 48 + 0x00, 0x00, 0x20, 0x00, 0x10, 0x00, 0xF8, 0x03, // 49 + 0x10, 0x02, 0x08, 0x03, 0x88, 0x02, 0x48, 0x02, 0x30, 0x02, // 50 + 0x10, 0x01, 0x08, 0x02, 0x48, 0x02, 0x48, 0x02, 0xB0, 0x01, // 51 + 0xC0, 0x00, 0xA0, 0x00, 0x90, 0x00, 0x88, 0x00, 0xF8, 0x03, 0x80, // 52 + 0x60, 0x01, 0x38, 0x02, 0x28, 0x02, 0x28, 0x02, 0xC8, 0x01, // 53 + 0xF0, 0x01, 0x28, 0x02, 0x28, 0x02, 0x28, 0x02, 0xD0, 0x01, // 54 + 0x08, 0x00, 0x08, 0x03, 0xC8, 0x00, 0x38, 0x00, 0x08, // 55 + 0xB0, 0x01, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0xB0, 0x01, // 56 + 0x70, 0x01, 0x88, 0x02, 0x88, 0x02, 0x88, 0x02, 0xF0, 0x01, // 57 + 0x00, 0x00, 0x20, 0x02, // 58 + 0x00, 0x00, 0x20, 0x06, // 59 + 0x00, 0x00, 0x40, 0x00, 0xA0, 0x00, 0xA0, 0x00, 0x10, 0x01, // 60 + 0xA0, 0x00, 0xA0, 0x00, 0xA0, 0x00, 0xA0, 0x00, 0xA0, // 61 + 0x00, 0x00, 0x10, 0x01, 0xA0, 0x00, 0xA0, 0x00, 0x40, // 62 + 0x10, 0x00, 0x08, 0x00, 0x08, 0x00, 0xC8, 0x02, 0x48, 0x00, 0x30, // 63 + 0x00, 0x00, 0xC0, 0x03, 0x30, 0x04, 0xD0, 0x09, 0x28, 0x0A, 0x28, 0x0A, 0xC8, 0x0B, 0x68, 0x0A, 0x10, 0x05, 0xE0, 0x04, // 64 + 0x00, 0x02, 0xC0, 0x01, 0xB0, 0x00, 0x88, 0x00, 0xB0, 0x00, 0xC0, 0x01, 0x00, 0x02, // 65 + 0x00, 0x00, 0xF8, 0x03, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0xF0, 0x01, // 66 + 0x00, 0x00, 0xF0, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x02, 0x10, 0x01, // 67 + 0x00, 0x00, 0xF8, 0x03, 0x08, 0x02, 0x08, 0x02, 0x10, 0x01, 0xE0, // 68 + 0x00, 0x00, 0xF8, 0x03, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, // 69 + 0x00, 0x00, 0xF8, 0x03, 0x48, 0x00, 0x48, 0x00, 0x08, // 70 + 0x00, 0x00, 0xE0, 0x00, 0x10, 0x01, 0x08, 0x02, 0x48, 0x02, 0x50, 0x01, 0xC0, // 71 + 0x00, 0x00, 0xF8, 0x03, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0xF8, 0x03, // 72 + 0x00, 0x00, 0xF8, 0x03, // 73 + 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0xF8, 0x01, // 74 + 0x00, 0x00, 0xF8, 0x03, 0x80, 0x00, 0x60, 0x00, 0x90, 0x00, 0x08, 0x01, 0x00, 0x02, // 75 + 0x00, 0x00, 0xF8, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, // 76 + 0x00, 0x00, 0xF8, 0x03, 0x30, 0x00, 0xC0, 0x01, 0x00, 0x02, 0xC0, 0x01, 0x30, 0x00, 0xF8, 0x03, // 77 + 0x00, 0x00, 0xF8, 0x03, 0x30, 0x00, 0x40, 0x00, 0x80, 0x01, 0xF8, 0x03, // 78 + 0x00, 0x00, 0xF0, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x02, 0x08, 0x02, 0xF0, 0x01, // 79 + 0x00, 0x00, 0xF8, 0x03, 0x48, 0x00, 0x48, 0x00, 0x48, 0x00, 0x30, // 80 + 0x00, 0x00, 0xF0, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x03, 0x08, 0x03, 0xF0, 0x02, // 81 + 0x00, 0x00, 0xF8, 0x03, 0x48, 0x00, 0x48, 0x00, 0xC8, 0x00, 0x30, 0x03, // 82 + 0x00, 0x00, 0x30, 0x01, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0x90, 0x01, // 83 + 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0xF8, 0x03, 0x08, 0x00, 0x08, // 84 + 0x00, 0x00, 0xF8, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0xF8, 0x01, // 85 + 0x08, 0x00, 0x70, 0x00, 0x80, 0x01, 0x00, 0x02, 0x80, 0x01, 0x70, 0x00, 0x08, // 86 + 0x18, 0x00, 0xE0, 0x01, 0x00, 0x02, 0xF0, 0x01, 0x08, 0x00, 0xF0, 0x01, 0x00, 0x02, 0xE0, 0x01, 0x18, // 87 + 0x00, 0x02, 0x08, 0x01, 0x90, 0x00, 0x60, 0x00, 0x90, 0x00, 0x08, 0x01, 0x00, 0x02, // 88 + 0x08, 0x00, 0x10, 0x00, 0x20, 0x00, 0xC0, 0x03, 0x20, 0x00, 0x10, 0x00, 0x08, // 89 + 0x08, 0x03, 0x88, 0x02, 0xC8, 0x02, 0x68, 0x02, 0x38, 0x02, 0x18, 0x02, // 90 + 0x00, 0x00, 0xF8, 0x0F, 0x08, 0x08, // 91 + 0x18, 0x00, 0xE0, 0x00, 0x00, 0x03, // 92 + 0x08, 0x08, 0xF8, 0x0F, // 93 + 0x40, 0x00, 0x30, 0x00, 0x08, 0x00, 0x30, 0x00, 0x40, // 94 + 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, // 95 + 0x08, 0x00, 0x10, // 96 + 0x00, 0x00, 0x00, 0x03, 0xA0, 0x02, 0xA0, 0x02, 0xE0, 0x03, // 97 + 0x00, 0x00, 0xF8, 0x03, 0x20, 0x02, 0x20, 0x02, 0xC0, 0x01, // 98 + 0x00, 0x00, 0xC0, 0x01, 0x20, 0x02, 0x20, 0x02, 0x40, 0x01, // 99 + 0x00, 0x00, 0xC0, 0x01, 0x20, 0x02, 0x20, 0x02, 0xF8, 0x03, // 100 + 0x00, 0x00, 0xC0, 0x01, 0xA0, 0x02, 0xA0, 0x02, 0xC0, 0x02, // 101 + 0x20, 0x00, 0xF0, 0x03, 0x28, // 102 + 0x00, 0x00, 0xC0, 0x05, 0x20, 0x0A, 0x20, 0x0A, 0xE0, 0x07, // 103 + 0x00, 0x00, 0xF8, 0x03, 0x20, 0x00, 0x20, 0x00, 0xC0, 0x03, // 104 + 0x00, 0x00, 0xE8, 0x03, // 105 + 0x00, 0x08, 0xE8, 0x07, // 106 + 0xF8, 0x03, 0x80, 0x00, 0xC0, 0x01, 0x20, 0x02, // 107 + 0x00, 0x00, 0xF8, 0x03, // 108 + 0x00, 0x00, 0xE0, 0x03, 0x20, 0x00, 0x20, 0x00, 0xE0, 0x03, 0x20, 0x00, 0x20, 0x00, 0xC0, 0x03, // 109 + 0x00, 0x00, 0xE0, 0x03, 0x20, 0x00, 0x20, 0x00, 0xC0, 0x03, // 110 + 0x00, 0x00, 0xC0, 0x01, 0x20, 0x02, 0x20, 0x02, 0xC0, 0x01, // 111 + 0x00, 0x00, 0xE0, 0x0F, 0x20, 0x02, 0x20, 0x02, 0xC0, 0x01, // 112 + 0x00, 0x00, 0xC0, 0x01, 0x20, 0x02, 0x20, 0x02, 0xE0, 0x0F, // 113 + 0x00, 0x00, 0xE0, 0x03, 0x20, // 114 + 0x40, 0x02, 0xA0, 0x02, 0xA0, 0x02, 0x20, 0x01, // 115 + 0x20, 0x00, 0xF8, 0x03, 0x20, 0x02, // 116 + 0x00, 0x00, 0xE0, 0x01, 0x00, 0x02, 0x00, 0x02, 0xE0, 0x03, // 117 + 0x20, 0x00, 0xC0, 0x01, 0x00, 0x02, 0xC0, 0x01, 0x20, // 118 + 0xE0, 0x01, 0x00, 0x02, 0xC0, 0x01, 0x20, 0x00, 0xC0, 0x01, 0x00, 0x02, 0xE0, 0x01, // 119 + 0x20, 0x02, 0x40, 0x01, 0x80, 0x00, 0x40, 0x01, 0x20, 0x02, // 120 + 0x20, 0x00, 0xC0, 0x09, 0x00, 0x06, 0xC0, 0x01, 0x20, // 121 + 0x20, 0x02, 0x20, 0x03, 0xA0, 0x02, 0x60, 0x02, 0x20, 0x02, // 122 + 0x80, 0x00, 0x78, 0x0F, 0x08, 0x08, // 123 + 0x00, 0x00, 0xF8, 0x0F, // 124 + 0x08, 0x08, 0x78, 0x0F, 0x80, // 125 + 0xC0, 0x00, 0x40, 0x00, 0xC0, 0x00, 0x80, 0x00, 0xC0, // 126 + 0x00, 0x00, 0xF0, 0x01, 0x09, 0x02, 0x0A, 0x02, 0x09, 0x02, 0x10, 0x01, // 129 + 0x00, 0x00, 0xF8, 0x03, 0x09, 0x02, 0x0A, 0x02, 0x11, 0x01, 0xE0, // 130 + 0x00, 0x00, 0xF8, 0x03, 0x49, 0x02, 0x4A, 0x02, 0x49, 0x02, 0x48, 0x02, // 131 + 0x00, 0x00, 0xF8, 0x03, 0x31, 0x00, 0x42, 0x00, 0x81, 0x01, 0xF8, 0x03, // 132 + 0x00, 0x00, 0xF8, 0x03, 0x49, 0x00, 0x4A, 0x00, 0xC9, 0x00, 0x30, 0x03, // 133 + 0x00, 0x00, 0x30, 0x01, 0x49, 0x02, 0x4A, 0x02, 0x49, 0x02, 0x90, 0x01, // 134 + 0x00, 0x00, 0x08, 0x00, 0x09, 0x00, 0xFA, 0x03, 0x09, 0x00, 0x08, // 135 + 0x00, 0x00, 0xF8, 0x01, 0x02, 0x02, 0x05, 0x02, 0x02, 0x02, 0xF8, 0x01, // 136 + 0x08, 0x03, 0x88, 0x02, 0xC9, 0x02, 0x6A, 0x02, 0x39, 0x02, 0x18, 0x02, // 137 + 0x00, 0x00, 0xC0, 0x01, 0x24, 0x02, 0x28, 0x02, 0x44, 0x01, // 138 + 0x00, 0x00, 0xC0, 0x01, 0x20, 0x02, 0x20, 0x02, 0xF8, 0x03, 0x00, 0x00, 0x18, // 139 + 0x00, 0x00, 0xC0, 0x01, 0xA4, 0x02, 0xA8, 0x02, 0xC4, 0x02, // 140 + 0x00, 0x00, 0xE0, 0x03, 0x24, 0x00, 0x28, 0x00, 0xC4, 0x03, // 141 + 0x00, 0x00, 0xE4, 0x03, 0x28, 0x00, 0x04, // 142 + 0x40, 0x02, 0xA4, 0x02, 0xA8, 0x02, 0x24, 0x01, // 143 + 0x20, 0x00, 0xF8, 0x03, 0x20, 0x02, 0x18, // 144 + 0x00, 0x00, 0xE0, 0x01, 0x08, 0x02, 0x14, 0x02, 0xE8, 0x03, // 145 + 0x20, 0x02, 0x24, 0x03, 0xA8, 0x02, 0x64, 0x02, 0x20, 0x02, // 146 + 0x00, 0x00, 0xFA, 0x03, 0x01, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, // 147 + 0x00, 0x00, 0xFA, 0x03, 0x01, // 148 + 0x00, 0x00, 0xF8, 0x03, 0x00, 0x02, 0x00, 0x02, 0x18, 0x02, 0x00, 0x02, // 149 + 0x00, 0x00, 0xF8, 0x03, 0x00, 0x00, 0x18, // 150 + 0x00, 0x00, 0xF8, 0x03, 0x48, 0x00, 0x4A, 0x00, 0xC9, 0x00, 0x30, 0x03, // 151 + 0x00, 0x00, 0xE0, 0x03, 0x28, 0x00, 0x04, // 152 + 0x00, 0x00, 0xA0, 0x0F, // 161 + 0x00, 0x00, 0xC0, 0x01, 0xA0, 0x0F, 0x78, 0x02, 0x40, 0x01, // 162 + 0x40, 0x02, 0x70, 0x03, 0xC8, 0x02, 0x48, 0x02, 0x08, 0x02, 0x10, 0x02, // 163 + 0x00, 0x00, 0xE0, 0x01, 0x20, 0x01, 0x20, 0x01, 0xE0, 0x01, // 164 + 0x48, 0x01, 0x70, 0x01, 0xC0, 0x03, 0x70, 0x01, 0x48, 0x01, // 165 + 0x00, 0x00, 0x38, 0x0F, // 166 + 0xD0, 0x04, 0x28, 0x09, 0x48, 0x09, 0x48, 0x0A, 0x90, 0x05, // 167 + 0x08, 0x00, 0x00, 0x00, 0x08, // 168 + 0xE0, 0x00, 0x10, 0x01, 0x48, 0x02, 0xA8, 0x02, 0xA8, 0x02, 0x10, 0x01, 0xE0, // 169 + 0x68, 0x00, 0x68, 0x00, 0x68, 0x00, 0x78, // 170 + 0x00, 0x00, 0x80, 0x01, 0x40, 0x02, 0x80, 0x01, 0x40, 0x02, // 171 + 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0xE0, // 172 + 0x80, 0x00, 0x80, // 173 + 0xE0, 0x00, 0x10, 0x01, 0xE8, 0x02, 0x68, 0x02, 0xC8, 0x02, 0x10, 0x01, 0xE0, // 174 + 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, // 175 + 0x00, 0x00, 0x38, 0x00, 0x28, 0x00, 0x38, // 176 + 0x40, 0x02, 0x40, 0x02, 0xF0, 0x03, 0x40, 0x02, 0x40, 0x02, // 177 + 0x48, 0x00, 0x68, 0x00, 0x58, // 178 + 0x48, 0x00, 0x58, 0x00, 0x68, // 179 + 0x00, 0x00, 0x10, 0x00, 0x08, // 180 + 0x00, 0x00, 0xE0, 0x0F, 0x00, 0x02, 0x00, 0x02, 0xE0, 0x03, // 181 + 0x70, 0x00, 0xF8, 0x0F, 0x08, 0x00, 0xF8, 0x0F, 0x08, // 182 + 0x00, 0x00, 0x40, // 183 + 0x00, 0x00, 0x00, 0x14, 0x00, 0x18, // 184 + 0x00, 0x00, 0x10, 0x00, 0x78, // 185 + 0x30, 0x00, 0x48, 0x00, 0x48, 0x00, 0x30, // 186 + 0x00, 0x00, 0x40, 0x02, 0x80, 0x01, 0x40, 0x02, 0x80, 0x01, // 187 + 0x00, 0x00, 0x10, 0x02, 0x78, 0x01, 0xC0, 0x00, 0x20, 0x01, 0x90, 0x01, 0xC8, 0x03, 0x00, 0x01, // 188 + 0x00, 0x00, 0x10, 0x02, 0x78, 0x01, 0x80, 0x00, 0x60, 0x00, 0x50, 0x02, 0x48, 0x03, 0xC0, 0x02, // 189 + 0x48, 0x00, 0x58, 0x00, 0x68, 0x03, 0x80, 0x00, 0x60, 0x01, 0x90, 0x01, 0xC8, 0x03, 0x00, 0x01, // 190 + 0x00, 0x00, 0x00, 0x06, 0x00, 0x09, 0xA0, 0x09, 0x00, 0x04, // 191 + 0x00, 0x02, 0xC0, 0x01, 0xB0, 0x00, 0x89, 0x00, 0xB2, 0x00, 0xC0, 0x01, 0x00, 0x02, // 192 + 0x00, 0x02, 0xC0, 0x01, 0xB0, 0x00, 0x8A, 0x00, 0xB1, 0x00, 0xC0, 0x01, 0x00, 0x02, // 193 + 0x00, 0x02, 0xC0, 0x01, 0xB2, 0x00, 0x89, 0x00, 0xB2, 0x00, 0xC0, 0x01, 0x00, 0x02, // 194 + 0x00, 0x02, 0xC2, 0x01, 0xB1, 0x00, 0x8A, 0x00, 0xB1, 0x00, 0xC0, 0x01, 0x00, 0x02, // 195 + 0x00, 0x02, 0xC0, 0x01, 0xB2, 0x00, 0x88, 0x00, 0xB2, 0x00, 0xC0, 0x01, 0x00, 0x02, // 196 + 0x00, 0x02, 0xC0, 0x01, 0xBE, 0x00, 0x8A, 0x00, 0xBE, 0x00, 0xC0, 0x01, 0x00, 0x02, // 197 + 0x00, 0x03, 0xC0, 0x00, 0xE0, 0x00, 0x98, 0x00, 0x88, 0x00, 0xF8, 0x03, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, // 198 + 0x00, 0x00, 0xF0, 0x01, 0x08, 0x02, 0x08, 0x16, 0x08, 0x1A, 0x10, 0x01, // 199 + 0x00, 0x00, 0xF8, 0x03, 0x49, 0x02, 0x4A, 0x02, 0x48, 0x02, 0x48, 0x02, // 200 + 0x00, 0x00, 0xF8, 0x03, 0x48, 0x02, 0x4A, 0x02, 0x49, 0x02, 0x48, 0x02, // 201 + 0x00, 0x00, 0xFA, 0x03, 0x49, 0x02, 0x4A, 0x02, 0x48, 0x02, 0x48, 0x02, // 202 + 0x00, 0x00, 0xF8, 0x03, 0x4A, 0x02, 0x48, 0x02, 0x4A, 0x02, 0x48, 0x02, // 203 + 0x00, 0x00, 0xF9, 0x03, 0x02, // 204 + 0x02, 0x00, 0xF9, 0x03, // 205 + 0x01, 0x00, 0xFA, 0x03, // 206 + 0x02, 0x00, 0xF8, 0x03, 0x02, // 207 + 0x40, 0x00, 0xF8, 0x03, 0x48, 0x02, 0x48, 0x02, 0x10, 0x01, 0xE0, // 208 + 0x00, 0x00, 0xFA, 0x03, 0x31, 0x00, 0x42, 0x00, 0x81, 0x01, 0xF8, 0x03, // 209 + 0x00, 0x00, 0xF0, 0x01, 0x08, 0x02, 0x09, 0x02, 0x0A, 0x02, 0x08, 0x02, 0xF0, 0x01, // 210 + 0x00, 0x00, 0xF0, 0x01, 0x08, 0x02, 0x0A, 0x02, 0x09, 0x02, 0x08, 0x02, 0xF0, 0x01, // 211 + 0x00, 0x00, 0xF0, 0x01, 0x08, 0x02, 0x0A, 0x02, 0x09, 0x02, 0x0A, 0x02, 0xF0, 0x01, // 212 + 0x00, 0x00, 0xF0, 0x01, 0x0A, 0x02, 0x09, 0x02, 0x0A, 0x02, 0x09, 0x02, 0xF0, 0x01, // 213 + 0x00, 0x00, 0xF0, 0x01, 0x0A, 0x02, 0x08, 0x02, 0x0A, 0x02, 0x08, 0x02, 0xF0, 0x01, // 214 + 0x10, 0x01, 0xA0, 0x00, 0xE0, 0x00, 0xA0, 0x00, 0x10, 0x01, // 215 + 0x00, 0x00, 0xF0, 0x02, 0x08, 0x03, 0xC8, 0x02, 0x28, 0x02, 0x18, 0x03, 0xE8, // 216 + 0x00, 0x00, 0xF8, 0x01, 0x01, 0x02, 0x02, 0x02, 0x00, 0x02, 0xF8, 0x01, // 217 + 0x00, 0x00, 0xF8, 0x01, 0x02, 0x02, 0x01, 0x02, 0x00, 0x02, 0xF8, 0x01, // 218 + 0x00, 0x00, 0xF8, 0x01, 0x02, 0x02, 0x01, 0x02, 0x02, 0x02, 0xF8, 0x01, // 219 + 0x00, 0x00, 0xF8, 0x01, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0xF8, 0x01, // 220 + 0x08, 0x00, 0x10, 0x00, 0x20, 0x00, 0xC2, 0x03, 0x21, 0x00, 0x10, 0x00, 0x08, // 221 + 0x00, 0x00, 0xF8, 0x03, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0xE0, // 222 + 0x00, 0x00, 0xF0, 0x03, 0x08, 0x01, 0x48, 0x02, 0xB0, 0x02, 0x80, 0x01, // 223 + 0x00, 0x00, 0x00, 0x03, 0xA4, 0x02, 0xA8, 0x02, 0xE0, 0x03, // 224 + 0x00, 0x00, 0x00, 0x03, 0xA8, 0x02, 0xA4, 0x02, 0xE0, 0x03, // 225 + 0x00, 0x00, 0x00, 0x03, 0xA8, 0x02, 0xA4, 0x02, 0xE8, 0x03, // 226 + 0x00, 0x00, 0x08, 0x03, 0xA4, 0x02, 0xA8, 0x02, 0xE4, 0x03, // 227 + 0x00, 0x00, 0x00, 0x03, 0xA8, 0x02, 0xA0, 0x02, 0xE8, 0x03, // 228 + 0x00, 0x00, 0x00, 0x03, 0xAE, 0x02, 0xAA, 0x02, 0xEE, 0x03, // 229 + 0x00, 0x00, 0x40, 0x03, 0xA0, 0x02, 0xA0, 0x02, 0xC0, 0x01, 0xA0, 0x02, 0xA0, 0x02, 0xC0, 0x02, // 230 + 0x00, 0x00, 0xC0, 0x01, 0x20, 0x16, 0x20, 0x1A, 0x40, 0x01, // 231 + 0x00, 0x00, 0xC0, 0x01, 0xA4, 0x02, 0xA8, 0x02, 0xC0, 0x02, // 232 + 0x00, 0x00, 0xC0, 0x01, 0xA8, 0x02, 0xA4, 0x02, 0xC0, 0x02, // 233 + 0x00, 0x00, 0xC0, 0x01, 0xA8, 0x02, 0xA4, 0x02, 0xC8, 0x02, // 234 + 0x00, 0x00, 0xC0, 0x01, 0xA8, 0x02, 0xA0, 0x02, 0xC8, 0x02, // 235 + 0x00, 0x00, 0xE4, 0x03, 0x08, // 236 + 0x08, 0x00, 0xE4, 0x03, // 237 + 0x08, 0x00, 0xE4, 0x03, 0x08, // 238 + 0x08, 0x00, 0xE0, 0x03, 0x08, // 239 + 0x00, 0x00, 0xC0, 0x01, 0x28, 0x02, 0x38, 0x02, 0xE0, 0x01, // 240 + 0x00, 0x00, 0xE8, 0x03, 0x24, 0x00, 0x28, 0x00, 0xC4, 0x03, // 241 + 0x00, 0x00, 0xC0, 0x01, 0x24, 0x02, 0x28, 0x02, 0xC0, 0x01, // 242 + 0x00, 0x00, 0xC0, 0x01, 0x28, 0x02, 0x24, 0x02, 0xC0, 0x01, // 243 + 0x00, 0x00, 0xC0, 0x01, 0x28, 0x02, 0x24, 0x02, 0xC8, 0x01, // 244 + 0x00, 0x00, 0xC8, 0x01, 0x24, 0x02, 0x28, 0x02, 0xC4, 0x01, // 245 + 0x00, 0x00, 0xC0, 0x01, 0x28, 0x02, 0x20, 0x02, 0xC8, 0x01, // 246 + 0x40, 0x00, 0x40, 0x00, 0x50, 0x01, 0x40, 0x00, 0x40, // 247 + 0x00, 0x00, 0xC0, 0x02, 0xA0, 0x03, 0x60, 0x02, 0xA0, 0x01, // 248 + 0x00, 0x00, 0xE0, 0x01, 0x04, 0x02, 0x08, 0x02, 0xE0, 0x03, // 249 + 0x00, 0x00, 0xE0, 0x01, 0x08, 0x02, 0x04, 0x02, 0xE0, 0x03, // 250 + 0x00, 0x00, 0xE8, 0x01, 0x04, 0x02, 0x08, 0x02, 0xE0, 0x03, // 251 + 0x00, 0x00, 0xE0, 0x01, 0x08, 0x02, 0x00, 0x02, 0xE8, 0x03, // 252 + 0x20, 0x00, 0xC0, 0x09, 0x08, 0x06, 0xC4, 0x01, 0x20, // 253 + 0x00, 0x00, 0xF8, 0x0F, 0x20, 0x02, 0x20, 0x02, 0xC0, 0x01, // 254 + 0x20, 0x00, 0xC8, 0x09, 0x00, 0x06, 0xC8, 0x01, 0x20, // 255 +}; + +const uint8_t ArialMT_Plain_16_CS[] PROGMEM = { + 0x10, // Width: 16 + 0x13, // Height: 19 + 0x20, // First char: 32 + 0xE0, // Number of chars: 224 + // Jump Table: + 0xFF, 0xFF, 0x00, 0x10, // 32 + 0x00, 0x00, 0x08, 0x04, // 33 + 0x00, 0x08, 0x0D, 0x06, // 34 + 0x00, 0x15, 0x1A, 0x0A, // 35 + 0x00, 0x2F, 0x17, 0x09, // 36 + 0x00, 0x46, 0x26, 0x0E, // 37 + 0x00, 0x6C, 0x1D, 0x0B, // 38 + 0x00, 0x89, 0x04, 0x03, // 39 + 0x00, 0x8D, 0x0C, 0x05, // 40 + 0x00, 0x99, 0x0B, 0x05, // 41 + 0x00, 0xA4, 0x0D, 0x06, // 42 + 0x00, 0xB1, 0x17, 0x09, // 43 + 0x00, 0xC8, 0x09, 0x04, // 44 + 0x00, 0xD1, 0x0B, 0x05, // 45 + 0x00, 0xDC, 0x08, 0x04, // 46 + 0x00, 0xE4, 0x0A, 0x05, // 47 + 0x00, 0xEE, 0x17, 0x09, // 48 + 0x01, 0x05, 0x11, 0x07, // 49 + 0x01, 0x16, 0x17, 0x09, // 50 + 0x01, 0x2D, 0x17, 0x09, // 51 + 0x01, 0x44, 0x17, 0x09, // 52 + 0x01, 0x5B, 0x17, 0x09, // 53 + 0x01, 0x72, 0x17, 0x09, // 54 + 0x01, 0x89, 0x16, 0x09, // 55 + 0x01, 0x9F, 0x17, 0x09, // 56 + 0x01, 0xB6, 0x17, 0x09, // 57 + 0x01, 0xCD, 0x05, 0x03, // 58 + 0x01, 0xD2, 0x06, 0x03, // 59 + 0x01, 0xD8, 0x17, 0x09, // 60 + 0x01, 0xEF, 0x17, 0x09, // 61 + 0x02, 0x06, 0x17, 0x09, // 62 + 0x02, 0x1D, 0x16, 0x09, // 63 + 0x02, 0x33, 0x2F, 0x11, // 64 + 0x02, 0x62, 0x1D, 0x0B, // 65 + 0x02, 0x7F, 0x1D, 0x0B, // 66 + 0x02, 0x9C, 0x20, 0x0C, // 67 + 0x02, 0xBC, 0x20, 0x0C, // 68 + 0x02, 0xDC, 0x1D, 0x0B, // 69 + 0x02, 0xF9, 0x19, 0x0A, // 70 + 0x03, 0x12, 0x20, 0x0C, // 71 + 0x03, 0x32, 0x1D, 0x0B, // 72 + 0x03, 0x4F, 0x05, 0x03, // 73 + 0x03, 0x54, 0x14, 0x08, // 74 + 0x03, 0x68, 0x1D, 0x0B, // 75 + 0x03, 0x85, 0x17, 0x09, // 76 + 0x03, 0x9C, 0x23, 0x0D, // 77 + 0x03, 0xBF, 0x1D, 0x0B, // 78 + 0x03, 0xDC, 0x20, 0x0C, // 79 + 0x03, 0xFC, 0x1C, 0x0B, // 80 + 0x04, 0x18, 0x20, 0x0C, // 81 + 0x04, 0x38, 0x1D, 0x0B, // 82 + 0x04, 0x55, 0x1D, 0x0B, // 83 + 0x04, 0x72, 0x19, 0x0A, // 84 + 0x04, 0x8B, 0x1D, 0x0B, // 85 + 0x04, 0xA8, 0x1C, 0x0B, // 86 + 0x04, 0xC4, 0x2B, 0x10, // 87 + 0x04, 0xEF, 0x20, 0x0C, // 88 + 0x05, 0x0F, 0x19, 0x0A, // 89 + 0x05, 0x28, 0x1A, 0x0A, // 90 + 0x05, 0x42, 0x0C, 0x05, // 91 + 0x05, 0x4E, 0x0B, 0x05, // 92 + 0x05, 0x59, 0x09, 0x04, // 93 + 0x05, 0x62, 0x14, 0x08, // 94 + 0x05, 0x76, 0x1B, 0x0A, // 95 + 0x05, 0x91, 0x07, 0x04, // 96 + 0x05, 0x98, 0x17, 0x09, // 97 + 0x05, 0xAF, 0x17, 0x09, // 98 + 0x05, 0xC6, 0x14, 0x08, // 99 + 0x05, 0xDA, 0x17, 0x09, // 100 + 0x05, 0xF1, 0x17, 0x09, // 101 + 0x06, 0x08, 0x0A, 0x05, // 102 + 0x06, 0x12, 0x17, 0x09, // 103 + 0x06, 0x29, 0x14, 0x08, // 104 + 0x06, 0x3D, 0x05, 0x03, // 105 + 0x06, 0x42, 0x06, 0x03, // 106 + 0x06, 0x48, 0x17, 0x09, // 107 + 0x06, 0x5F, 0x05, 0x03, // 108 + 0x06, 0x64, 0x23, 0x0D, // 109 + 0x06, 0x87, 0x14, 0x08, // 110 + 0x06, 0x9B, 0x17, 0x09, // 111 + 0x06, 0xB2, 0x17, 0x09, // 112 + 0x06, 0xC9, 0x18, 0x09, // 113 + 0x06, 0xE1, 0x0D, 0x06, // 114 + 0x06, 0xEE, 0x14, 0x08, // 115 + 0x07, 0x02, 0x0B, 0x05, // 116 + 0x07, 0x0D, 0x14, 0x08, // 117 + 0x07, 0x21, 0x13, 0x08, // 118 + 0x07, 0x34, 0x1F, 0x0C, // 119 + 0x07, 0x53, 0x14, 0x08, // 120 + 0x07, 0x67, 0x13, 0x08, // 121 + 0x07, 0x7A, 0x14, 0x08, // 122 + 0x07, 0x8E, 0x0F, 0x06, // 123 + 0x07, 0x9D, 0x06, 0x03, // 124 + 0x07, 0xA3, 0x0E, 0x06, // 125 + 0x07, 0xB1, 0x17, 0x09, // 126 + 0xFF, 0xFF, 0x00, 0x10, // 127 + 0xFF, 0xFF, 0x00, 0x10, // 128 + 0x07, 0xC8, 0x20, 0x0C, // 129 + 0x07, 0xE8, 0x20, 0x0C, // 130 + 0x08, 0x08, 0x1D, 0x0B, // 131 + 0x08, 0x25, 0x1D, 0x0B, // 132 + 0x08, 0x42, 0x1D, 0x0B, // 133 + 0x08, 0x5F, 0x1D, 0x0B, // 134 + 0x08, 0x7C, 0x19, 0x0A, // 135 + 0x08, 0x95, 0x1D, 0x0B, // 136 + 0x08, 0xB2, 0x1A, 0x0A, // 137 + 0x08, 0xCC, 0x14, 0x08, // 138 + 0x08, 0xE0, 0x1C, 0x0B, // 139 + 0x08, 0xFC, 0x17, 0x09, // 140 + 0x09, 0x13, 0x14, 0x08, // 141 + 0x09, 0x27, 0x0D, 0x06, // 142 + 0x09, 0x34, 0x14, 0x08, // 143 + 0x09, 0x48, 0x10, 0x07, // 144 + 0x09, 0x58, 0x14, 0x08, // 145 + 0x09, 0x6C, 0x14, 0x08, // 146 + 0x09, 0x80, 0x17, 0x09, // 147 + 0x09, 0x97, 0x07, 0x04, // 148 + 0x09, 0x9E, 0x17, 0x09, // 149 + 0x09, 0xB5, 0x0A, 0x05, // 150 + 0x09, 0xBF, 0x1D, 0x0B, // 151 + 0x09, 0xDC, 0x0D, 0x06, // 152 + 0xFF, 0xFF, 0x00, 0x10, // 153 + 0xFF, 0xFF, 0x00, 0x10, // 154 + 0xFF, 0xFF, 0x00, 0x10, // 155 + 0xFF, 0xFF, 0x00, 0x10, // 156 + 0xFF, 0xFF, 0x00, 0x10, // 157 + 0xFF, 0xFF, 0x00, 0x10, // 158 + 0xFF, 0xFF, 0x00, 0x10, // 159 + 0xFF, 0xFF, 0x00, 0x10, // 160 + 0x09, 0xE9, 0x09, 0x04, // 161 + 0x09, 0xF2, 0x17, 0x09, // 162 + 0x0A, 0x09, 0x17, 0x09, // 163 + 0x0A, 0x20, 0x14, 0x08, // 164 + 0x0A, 0x34, 0x1A, 0x0A, // 165 + 0x0A, 0x4E, 0x06, 0x03, // 166 + 0x0A, 0x54, 0x17, 0x09, // 167 + 0x0A, 0x6B, 0x07, 0x04, // 168 + 0x0A, 0x72, 0x23, 0x0D, // 169 + 0x0A, 0x95, 0x0E, 0x06, // 170 + 0x0A, 0xA3, 0x14, 0x08, // 171 + 0x0A, 0xB7, 0x17, 0x09, // 172 + 0x0A, 0xCE, 0x0B, 0x05, // 173 + 0x0A, 0xD9, 0x23, 0x0D, // 174 + 0x0A, 0xFC, 0x19, 0x0A, // 175 + 0x0B, 0x15, 0x0D, 0x06, // 176 + 0x0B, 0x22, 0x17, 0x09, // 177 + 0x0B, 0x39, 0x0E, 0x06, // 178 + 0x0B, 0x47, 0x0D, 0x06, // 179 + 0x0B, 0x54, 0x0A, 0x05, // 180 + 0x0B, 0x5E, 0x17, 0x09, // 181 + 0x0B, 0x75, 0x19, 0x0A, // 182 + 0x0B, 0x8E, 0x08, 0x04, // 183 + 0x0B, 0x96, 0x0C, 0x05, // 184 + 0x0B, 0xA2, 0x0B, 0x05, // 185 + 0x0B, 0xAD, 0x0D, 0x06, // 186 + 0x0B, 0xBA, 0x17, 0x09, // 187 + 0x0B, 0xD1, 0x26, 0x0E, // 188 + 0x0B, 0xF7, 0x26, 0x0E, // 189 + 0x0C, 0x1D, 0x26, 0x0E, // 190 + 0x0C, 0x43, 0x1A, 0x0A, // 191 + 0x0C, 0x5D, 0x1D, 0x0B, // 192 + 0x0C, 0x7A, 0x1D, 0x0B, // 193 + 0x0C, 0x97, 0x1D, 0x0B, // 194 + 0x0C, 0xB4, 0x1D, 0x0B, // 195 + 0x0C, 0xD1, 0x1D, 0x0B, // 196 + 0x0C, 0xEE, 0x1D, 0x0B, // 197 + 0x0D, 0x0B, 0x2C, 0x10, // 198 + 0x0D, 0x37, 0x20, 0x0C, // 199 + 0x0D, 0x57, 0x1D, 0x0B, // 200 + 0x0D, 0x74, 0x1D, 0x0B, // 201 + 0x0D, 0x91, 0x1D, 0x0B, // 202 + 0x0D, 0xAE, 0x1D, 0x0B, // 203 + 0x0D, 0xCB, 0x05, 0x03, // 204 + 0x0D, 0xD0, 0x07, 0x04, // 205 + 0x0D, 0xD7, 0x0A, 0x05, // 206 + 0x0D, 0xE1, 0x07, 0x04, // 207 + 0x0D, 0xE8, 0x20, 0x0C, // 208 + 0x0E, 0x08, 0x1D, 0x0B, // 209 + 0x0E, 0x25, 0x20, 0x0C, // 210 + 0x0E, 0x45, 0x20, 0x0C, // 211 + 0x0E, 0x65, 0x20, 0x0C, // 212 + 0x0E, 0x85, 0x20, 0x0C, // 213 + 0x0E, 0xA5, 0x20, 0x0C, // 214 + 0x0E, 0xC5, 0x17, 0x09, // 215 + 0x0E, 0xDC, 0x20, 0x0C, // 216 + 0x0E, 0xFC, 0x1D, 0x0B, // 217 + 0x0F, 0x19, 0x1D, 0x0B, // 218 + 0x0F, 0x36, 0x1D, 0x0B, // 219 + 0x0F, 0x53, 0x1D, 0x0B, // 220 + 0x0F, 0x70, 0x19, 0x0A, // 221 + 0x0F, 0x89, 0x1D, 0x0B, // 222 + 0x0F, 0xA6, 0x17, 0x09, // 223 + 0x0F, 0xBD, 0x17, 0x09, // 224 + 0x0F, 0xD4, 0x17, 0x09, // 225 + 0x0F, 0xEB, 0x17, 0x09, // 226 + 0x10, 0x02, 0x17, 0x09, // 227 + 0x10, 0x19, 0x17, 0x09, // 228 + 0x10, 0x30, 0x17, 0x09, // 229 + 0x10, 0x47, 0x29, 0x0F, // 230 + 0x10, 0x70, 0x14, 0x08, // 231 + 0x10, 0x84, 0x17, 0x09, // 232 + 0x10, 0x9B, 0x17, 0x09, // 233 + 0x10, 0xB2, 0x17, 0x09, // 234 + 0x10, 0xC9, 0x17, 0x09, // 235 + 0x10, 0xE0, 0x05, 0x03, // 236 + 0x10, 0xE5, 0x07, 0x04, // 237 + 0x10, 0xEC, 0x0A, 0x05, // 238 + 0x10, 0xF6, 0x07, 0x04, // 239 + 0x10, 0xFD, 0x17, 0x09, // 240 + 0x11, 0x14, 0x14, 0x08, // 241 + 0x11, 0x28, 0x17, 0x09, // 242 + 0x11, 0x3F, 0x17, 0x09, // 243 + 0x11, 0x56, 0x17, 0x09, // 244 + 0x11, 0x6D, 0x17, 0x09, // 245 + 0x11, 0x84, 0x17, 0x09, // 246 + 0x11, 0x9B, 0x17, 0x09, // 247 + 0x11, 0xB2, 0x17, 0x09, // 248 + 0x11, 0xC9, 0x14, 0x08, // 249 + 0x11, 0xDD, 0x14, 0x08, // 250 + 0x11, 0xF1, 0x14, 0x08, // 251 + 0x12, 0x05, 0x14, 0x08, // 252 + 0x12, 0x19, 0x13, 0x08, // 253 + 0x12, 0x2C, 0x17, 0x09, // 254 + 0x12, 0x43, 0x13, 0x08, // 255 + // Font Data: + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x5F, // 33 + 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, // 34 + 0x80, 0x08, 0x00, 0x80, 0x78, 0x00, 0xC0, 0x0F, 0x00, 0xB8, 0x08, 0x00, 0x80, 0x08, 0x00, 0x80, 0x78, 0x00, 0xC0, 0x0F, 0x00, + 0xB8, 0x08, 0x00, 0x80, 0x08, // 35 + 0x00, 0x00, 0x00, 0xE0, 0x10, 0x00, 0x10, 0x21, 0x00, 0x08, 0x41, 0x00, 0xFC, 0xFF, 0x00, 0x08, 0x42, 0x00, 0x10, 0x22, 0x00, + 0x20, 0x1C, // 36 + 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x08, 0x01, 0x00, 0x08, 0x01, 0x00, 0x08, 0x61, 0x00, 0xF0, 0x18, 0x00, 0x00, 0x06, 0x00, + 0xC0, 0x01, 0x00, 0x30, 0x3C, 0x00, 0x08, 0x42, 0x00, 0x00, 0x42, 0x00, 0x00, 0x42, 0x00, 0x00, 0x3C, // 37 + 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x70, 0x22, 0x00, 0x88, 0x41, 0x00, 0x08, 0x43, 0x00, 0x88, 0x44, 0x00, 0x70, 0x28, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x28, 0x00, 0x00, 0x44, // 38 + 0x00, 0x00, 0x00, 0x78, // 39 + 0x00, 0x00, 0x00, 0x80, 0x3F, 0x00, 0x70, 0xC0, 0x01, 0x08, 0x00, 0x02, // 40 + 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x70, 0xC0, 0x01, 0x80, 0x3F, // 41 + 0x10, 0x00, 0x00, 0xD0, 0x00, 0x00, 0x38, 0x00, 0x00, 0xD0, 0x00, 0x00, 0x10, // 42 + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0xC0, 0x1F, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x02, // 43 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, // 44 + 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, // 45 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, // 46 + 0x00, 0x60, 0x00, 0x00, 0x1E, 0x00, 0xE0, 0x01, 0x00, 0x18, // 47 + 0x00, 0x00, 0x00, 0xE0, 0x1F, 0x00, 0x10, 0x20, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x10, 0x20, 0x00, + 0xE0, 0x1F, // 48 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, 0x00, 0x00, 0xF8, 0x7F, // 49 + 0x00, 0x00, 0x00, 0x20, 0x40, 0x00, 0x10, 0x60, 0x00, 0x08, 0x50, 0x00, 0x08, 0x48, 0x00, 0x08, 0x44, 0x00, 0x10, 0x43, 0x00, + 0xE0, 0x40, // 50 + 0x00, 0x00, 0x00, 0x20, 0x10, 0x00, 0x10, 0x20, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x88, 0x41, 0x00, 0xF0, 0x22, 0x00, + 0x00, 0x1C, // 51 + 0x00, 0x0C, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x09, 0x00, 0xC0, 0x08, 0x00, 0x20, 0x08, 0x00, 0x10, 0x08, 0x00, 0xF8, 0x7F, 0x00, + 0x00, 0x08, // 52 + 0x00, 0x00, 0x00, 0xC0, 0x11, 0x00, 0xB8, 0x20, 0x00, 0x88, 0x40, 0x00, 0x88, 0x40, 0x00, 0x88, 0x40, 0x00, 0x08, 0x21, 0x00, + 0x08, 0x1E, // 53 + 0x00, 0x00, 0x00, 0xE0, 0x1F, 0x00, 0x10, 0x21, 0x00, 0x88, 0x40, 0x00, 0x88, 0x40, 0x00, 0x88, 0x40, 0x00, 0x10, 0x21, 0x00, + 0x20, 0x1E, // 54 + 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x78, 0x00, 0x08, 0x07, 0x00, 0xC8, 0x00, 0x00, 0x28, 0x00, 0x00, + 0x18, // 55 + 0x00, 0x00, 0x00, 0x60, 0x1C, 0x00, 0x90, 0x22, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x90, 0x22, 0x00, + 0x60, 0x1C, // 56 + 0x00, 0x00, 0x00, 0xE0, 0x11, 0x00, 0x10, 0x22, 0x00, 0x08, 0x44, 0x00, 0x08, 0x44, 0x00, 0x08, 0x44, 0x00, 0x10, 0x22, 0x00, + 0xE0, 0x1F, // 57 + 0x00, 0x00, 0x00, 0x40, 0x40, // 58 + 0x00, 0x00, 0x00, 0x40, 0xC0, 0x01, // 59 + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x05, 0x00, 0x80, 0x08, 0x00, 0x80, 0x08, 0x00, 0x80, 0x08, 0x00, + 0x40, 0x10, // 60 + 0x00, 0x00, 0x00, 0x80, 0x08, 0x00, 0x80, 0x08, 0x00, 0x80, 0x08, 0x00, 0x80, 0x08, 0x00, 0x80, 0x08, 0x00, 0x80, 0x08, 0x00, + 0x80, 0x08, // 61 + 0x00, 0x00, 0x00, 0x40, 0x10, 0x00, 0x80, 0x08, 0x00, 0x80, 0x08, 0x00, 0x80, 0x08, 0x00, 0x00, 0x05, 0x00, 0x00, 0x05, 0x00, + 0x00, 0x02, // 62 + 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x10, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x5C, 0x00, 0x08, 0x02, 0x00, 0x10, 0x01, 0x00, + 0xE0, // 63 + 0x00, 0x00, 0x00, 0x00, 0x3F, 0x00, 0xC0, 0x40, 0x00, 0x20, 0x80, 0x00, 0x10, 0x1E, 0x01, 0x10, 0x21, 0x01, 0x88, 0x40, 0x02, + 0x48, 0x40, 0x02, 0x48, 0x40, 0x02, 0x48, 0x20, 0x02, 0x88, 0x7C, 0x02, 0xC8, 0x43, 0x02, 0x10, 0x40, 0x02, 0x10, 0x20, 0x01, + 0x60, 0x10, 0x01, 0x80, 0x8F, // 64 + 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x1C, 0x00, 0x80, 0x07, 0x00, 0x70, 0x04, 0x00, 0x08, 0x04, 0x00, 0x70, 0x04, 0x00, + 0x80, 0x07, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x60, // 65 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, + 0x08, 0x41, 0x00, 0x90, 0x22, 0x00, 0x60, 0x1C, // 66 + 0x00, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x20, 0x10, 0x00, 0x10, 0x20, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, + 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x10, 0x20, 0x00, 0x20, 0x10, // 67 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, + 0x08, 0x40, 0x00, 0x10, 0x20, 0x00, 0x20, 0x10, 0x00, 0xC0, 0x0F, // 68 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, + 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x40, // 69 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x08, 0x02, 0x00, 0x08, 0x02, 0x00, 0x08, 0x02, 0x00, 0x08, 0x02, 0x00, 0x08, 0x02, 0x00, + 0x08, 0x02, 0x00, 0x08, // 70 + 0x00, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x20, 0x10, 0x00, 0x10, 0x20, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x08, 0x42, 0x00, + 0x08, 0x42, 0x00, 0x10, 0x22, 0x00, 0x20, 0x12, 0x00, 0x00, 0x0E, // 71 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0xF8, 0x7F, // 72 + 0x00, 0x00, 0x00, 0xF8, 0x7F, // 73 + 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0xF8, 0x3F, // 74 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x04, 0x00, 0x00, 0x02, 0x00, 0x00, 0x01, 0x00, 0x80, 0x03, 0x00, 0x40, 0x04, 0x00, + 0x20, 0x18, 0x00, 0x10, 0x20, 0x00, 0x08, 0x40, // 75 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, + 0x00, 0x40, // 76 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x30, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x60, 0x00, + 0x00, 0x1C, 0x00, 0x00, 0x03, 0x00, 0xC0, 0x00, 0x00, 0x30, 0x00, 0x00, 0xF8, 0x7F, // 77 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x10, 0x00, 0x00, 0x60, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x04, 0x00, + 0x00, 0x18, 0x00, 0x00, 0x20, 0x00, 0xF8, 0x7F, // 78 + 0x00, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x20, 0x10, 0x00, 0x10, 0x20, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, + 0x08, 0x40, 0x00, 0x10, 0x20, 0x00, 0x20, 0x10, 0x00, 0xC0, 0x0F, // 79 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x08, 0x02, 0x00, 0x08, 0x02, 0x00, 0x08, 0x02, 0x00, 0x08, 0x02, 0x00, 0x08, 0x02, 0x00, + 0x08, 0x02, 0x00, 0x10, 0x01, 0x00, 0xE0, // 80 + 0x00, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x20, 0x10, 0x00, 0x10, 0x20, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x08, 0x50, 0x00, + 0x08, 0x50, 0x00, 0x10, 0x20, 0x00, 0x20, 0x70, 0x00, 0xC0, 0x4F, // 81 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x08, 0x02, 0x00, 0x08, 0x02, 0x00, 0x08, 0x02, 0x00, 0x08, 0x02, 0x00, 0x08, 0x06, 0x00, + 0x08, 0x1A, 0x00, 0x10, 0x21, 0x00, 0xE0, 0x40, // 82 + 0x00, 0x00, 0x00, 0x60, 0x10, 0x00, 0x90, 0x20, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x42, 0x00, + 0x08, 0x42, 0x00, 0x10, 0x22, 0x00, 0x20, 0x1C, // 83 + 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x08, // 84 + 0x00, 0x00, 0x00, 0xF8, 0x1F, 0x00, 0x00, 0x20, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x20, 0x00, 0xF8, 0x1F, // 85 + 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x18, 0x00, 0x00, 0x60, 0x00, 0x00, 0x18, 0x00, + 0x00, 0x07, 0x00, 0xE0, 0x00, 0x00, 0x18, // 86 + 0x18, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x60, 0x00, 0x00, 0x1C, 0x00, 0x80, 0x03, 0x00, 0x70, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x70, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x60, 0x00, 0x00, 0x1E, 0x00, 0xE0, 0x01, 0x00, + 0x18, // 87 + 0x00, 0x40, 0x00, 0x08, 0x20, 0x00, 0x10, 0x10, 0x00, 0x60, 0x0C, 0x00, 0x80, 0x02, 0x00, 0x00, 0x01, 0x00, 0x80, 0x02, 0x00, + 0x60, 0x0C, 0x00, 0x10, 0x10, 0x00, 0x08, 0x20, 0x00, 0x00, 0x40, // 88 + 0x08, 0x00, 0x00, 0x30, 0x00, 0x00, 0x40, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x7E, 0x00, 0x80, 0x01, 0x00, 0x40, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x08, // 89 + 0x00, 0x40, 0x00, 0x08, 0x60, 0x00, 0x08, 0x58, 0x00, 0x08, 0x44, 0x00, 0x08, 0x43, 0x00, 0x88, 0x40, 0x00, 0x68, 0x40, 0x00, + 0x18, 0x40, 0x00, 0x08, 0x40, // 90 + 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x03, 0x08, 0x00, 0x02, 0x08, 0x00, 0x02, // 91 + 0x18, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x60, // 92 + 0x08, 0x00, 0x02, 0x08, 0x00, 0x02, 0xF8, 0xFF, 0x03, // 93 + 0x00, 0x01, 0x00, 0xC0, 0x00, 0x00, 0x30, 0x00, 0x00, 0x08, 0x00, 0x00, 0x30, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x01, // 94 + 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, // 95 + 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x10, // 96 + 0x00, 0x00, 0x00, 0x00, 0x39, 0x00, 0x80, 0x44, 0x00, 0x40, 0x44, 0x00, 0x40, 0x44, 0x00, 0x40, 0x42, 0x00, 0x40, 0x22, 0x00, + 0x80, 0x7F, // 97 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x80, 0x20, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x80, 0x20, 0x00, + 0x00, 0x1F, // 98 + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x80, 0x20, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x80, 0x20, // 99 + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x80, 0x20, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x80, 0x20, 0x00, + 0xF8, 0x7F, // 100 + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x80, 0x24, 0x00, 0x40, 0x44, 0x00, 0x40, 0x44, 0x00, 0x40, 0x44, 0x00, 0x80, 0x24, 0x00, + 0x00, 0x17, // 101 + 0x40, 0x00, 0x00, 0xF0, 0x7F, 0x00, 0x48, 0x00, 0x00, 0x48, // 102 + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x01, 0x80, 0x20, 0x02, 0x40, 0x40, 0x02, 0x40, 0x40, 0x02, 0x40, 0x40, 0x02, 0x80, 0x20, 0x01, + 0xC0, 0xFF, // 103 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x80, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x80, 0x7F, // 104 + 0x00, 0x00, 0x00, 0xC8, 0x7F, // 105 + 0x00, 0x00, 0x02, 0xC8, 0xFF, 0x01, // 106 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x04, 0x00, 0x00, 0x06, 0x00, 0x00, 0x19, 0x00, 0x80, 0x20, 0x00, + 0x40, 0x40, // 107 + 0x00, 0x00, 0x00, 0xF8, 0x7F, // 108 + 0x00, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x80, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x80, 0x7F, 0x00, + 0x80, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x80, 0x7F, // 109 + 0x00, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x80, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x80, 0x7F, // 110 + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x80, 0x20, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x80, 0x20, 0x00, + 0x00, 0x1F, // 111 + 0x00, 0x00, 0x00, 0xC0, 0xFF, 0x03, 0x80, 0x20, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x80, 0x20, 0x00, + 0x00, 0x1F, // 112 + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x80, 0x20, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x80, 0x20, 0x00, + 0xC0, 0xFF, 0x03, // 113 + 0x00, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x80, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, // 114 + 0x00, 0x00, 0x00, 0x80, 0x23, 0x00, 0x40, 0x44, 0x00, 0x40, 0x44, 0x00, 0x40, 0x44, 0x00, 0x40, 0x44, 0x00, 0x80, 0x38, // 115 + 0x40, 0x00, 0x00, 0xF0, 0x7F, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, // 116 + 0x00, 0x00, 0x00, 0xC0, 0x3F, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x20, 0x00, 0xC0, 0x7F, // 117 + 0xC0, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x60, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x03, 0x00, 0xC0, // 118 + 0xC0, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x60, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x03, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x03, 0x00, + 0x00, 0x1C, 0x00, 0x00, 0x60, 0x00, 0x00, 0x1F, 0x00, 0xC0, // 119 + 0x40, 0x40, 0x00, 0x80, 0x20, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x04, 0x00, 0x00, 0x1B, 0x00, 0x80, 0x20, 0x00, 0x40, 0x40, // 120 + 0xC0, 0x01, 0x00, 0x00, 0x06, 0x02, 0x00, 0x38, 0x02, 0x00, 0xE0, 0x01, 0x00, 0x38, 0x00, 0x00, 0x07, 0x00, 0xC0, // 121 + 0x40, 0x40, 0x00, 0x40, 0x60, 0x00, 0x40, 0x58, 0x00, 0x40, 0x44, 0x00, 0x40, 0x43, 0x00, 0xC0, 0x40, 0x00, 0x40, 0x40, // 122 + 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0xF0, 0xFB, 0x01, 0x08, 0x00, 0x02, 0x08, 0x00, 0x02, // 123 + 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x03, // 124 + 0x08, 0x00, 0x02, 0x08, 0x00, 0x02, 0xF0, 0xFB, 0x01, 0x00, 0x04, 0x00, 0x00, 0x04, // 125 + 0x00, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x01, // 126 + 0x00, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x20, 0x10, 0x00, 0x10, 0x20, 0x00, 0x09, 0x40, 0x00, 0x0A, 0x40, 0x00, 0x0A, 0x40, 0x00, + 0x09, 0x40, 0x00, 0x08, 0x40, 0x00, 0x10, 0x20, 0x00, 0x20, 0x10, // 129 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x09, 0x40, 0x00, 0x0A, 0x40, 0x00, 0x0A, 0x40, 0x00, + 0x09, 0x40, 0x00, 0x10, 0x20, 0x00, 0x20, 0x10, 0x00, 0xC0, 0x0F, // 130 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x09, 0x41, 0x00, 0x0A, 0x41, 0x00, 0x0A, 0x41, 0x00, + 0x09, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x40, // 131 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x10, 0x00, 0x00, 0x60, 0x00, 0x00, 0x81, 0x00, 0x00, 0x02, 0x03, 0x00, 0x02, 0x04, 0x00, + 0x01, 0x18, 0x00, 0x00, 0x20, 0x00, 0xF8, 0x7F, // 132 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x08, 0x02, 0x00, 0x08, 0x02, 0x00, 0x09, 0x02, 0x00, 0x0A, 0x02, 0x00, 0x0A, 0x06, 0x00, + 0x09, 0x1A, 0x00, 0x10, 0x21, 0x00, 0xE0, 0x40, // 133 + 0x00, 0x00, 0x00, 0x60, 0x10, 0x00, 0x90, 0x20, 0x00, 0x08, 0x41, 0x00, 0x09, 0x41, 0x00, 0x0A, 0x41, 0x00, 0x0A, 0x42, 0x00, + 0x09, 0x42, 0x00, 0x10, 0x22, 0x00, 0x20, 0x1C, // 134 + 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x09, 0x00, 0x00, 0xFA, 0x7F, 0x00, 0x0A, 0x00, 0x00, 0x09, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x08, // 135 + 0x00, 0x00, 0x00, 0xF8, 0x1F, 0x00, 0x00, 0x20, 0x00, 0x00, 0x40, 0x00, 0x06, 0x40, 0x00, 0x09, 0x40, 0x00, 0x09, 0x40, 0x00, + 0x06, 0x40, 0x00, 0x00, 0x20, 0x00, 0xF8, 0x1F, // 136 + 0x00, 0x40, 0x00, 0x08, 0x60, 0x00, 0x08, 0x58, 0x00, 0x09, 0x44, 0x00, 0x0A, 0x43, 0x00, 0x8A, 0x40, 0x00, 0x69, 0x40, 0x00, + 0x18, 0x40, 0x00, 0x08, 0x40, // 137 + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x80, 0x20, 0x00, 0x48, 0x40, 0x00, 0x50, 0x40, 0x00, 0x50, 0x40, 0x00, 0x88, 0x20, // 138 + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x80, 0x20, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x80, 0x20, 0x00, + 0xF8, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x38, // 139 + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x80, 0x24, 0x00, 0x48, 0x44, 0x00, 0x50, 0x44, 0x00, 0x50, 0x44, 0x00, 0x88, 0x24, 0x00, + 0x00, 0x17, // 140 + 0x00, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x88, 0x00, 0x00, 0x50, 0x00, 0x00, 0x50, 0x00, 0x00, 0x48, 0x00, 0x00, 0x80, 0x7F, // 141 + 0x00, 0x00, 0x00, 0xC8, 0x7F, 0x00, 0x90, 0x00, 0x00, 0x50, 0x00, 0x00, 0x48, // 142 + 0x00, 0x00, 0x00, 0x80, 0x23, 0x00, 0x48, 0x44, 0x00, 0x50, 0x44, 0x00, 0x50, 0x44, 0x00, 0x48, 0x44, 0x00, 0x80, 0x38, // 143 + 0x40, 0x00, 0x00, 0xF0, 0x7F, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x70, // 144 + 0x00, 0x00, 0x00, 0xC0, 0x3F, 0x00, 0x0C, 0x40, 0x00, 0x12, 0x40, 0x00, 0x12, 0x40, 0x00, 0x0C, 0x20, 0x00, 0xC0, 0x7F, // 145 + 0x40, 0x40, 0x00, 0x40, 0x60, 0x00, 0x48, 0x58, 0x00, 0x50, 0x44, 0x00, 0x50, 0x43, 0x00, 0xC8, 0x40, 0x00, 0x40, 0x40, // 146 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x02, 0x40, 0x00, 0x01, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, + 0x00, 0x40, // 147 + 0x00, 0x00, 0x00, 0xFA, 0x7F, 0x00, 0x01, // 148 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x38, 0x40, 0x00, + 0x00, 0x40, // 149 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x38, // 150 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x08, 0x02, 0x00, 0x08, 0x02, 0x00, 0x08, 0x02, 0x00, 0x0A, 0x02, 0x00, 0x09, 0x06, 0x00, + 0x08, 0x1A, 0x00, 0x10, 0x21, 0x00, 0xE0, 0x40, // 151 + 0x00, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x80, 0x00, 0x00, 0x50, 0x00, 0x00, 0x48, // 152 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xFF, 0x03, // 161 + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x80, 0x20, 0x03, 0x40, 0xF0, 0x00, 0x40, 0x4E, 0x00, 0xC0, 0x41, 0x00, 0xB8, 0x20, 0x00, + 0x00, 0x11, // 162 + 0x00, 0x41, 0x00, 0xE0, 0x31, 0x00, 0x10, 0x2F, 0x00, 0x08, 0x21, 0x00, 0x08, 0x21, 0x00, 0x08, 0x40, 0x00, 0x10, 0x40, 0x00, + 0x20, 0x20, // 163 + 0x00, 0x00, 0x00, 0x40, 0x0B, 0x00, 0x80, 0x04, 0x00, 0x40, 0x08, 0x00, 0x40, 0x08, 0x00, 0x80, 0x04, 0x00, 0x40, 0x0B, // 164 + 0x08, 0x0A, 0x00, 0x10, 0x0A, 0x00, 0x60, 0x0A, 0x00, 0x80, 0x0B, 0x00, 0x00, 0x7E, 0x00, 0x80, 0x0B, 0x00, 0x60, 0x0A, 0x00, + 0x10, 0x0A, 0x00, 0x08, 0x0A, // 165 + 0x00, 0x00, 0x00, 0xF8, 0xF1, 0x03, // 166 + 0x00, 0x86, 0x00, 0x70, 0x09, 0x01, 0xC8, 0x10, 0x02, 0x88, 0x10, 0x02, 0x08, 0x21, 0x02, 0x08, 0x61, 0x02, 0x30, 0xD2, 0x01, + 0x00, 0x0C, // 167 + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, // 168 + 0xC0, 0x0F, 0x00, 0x20, 0x10, 0x00, 0x10, 0x20, 0x00, 0xC8, 0x47, 0x00, 0x28, 0x48, 0x00, 0x28, 0x48, 0x00, 0x28, 0x48, 0x00, + 0x28, 0x48, 0x00, 0x48, 0x44, 0x00, 0x10, 0x20, 0x00, 0x20, 0x10, 0x00, 0xC0, 0x0F, // 169 + 0xD0, 0x00, 0x00, 0x48, 0x01, 0x00, 0x28, 0x01, 0x00, 0x28, 0x01, 0x00, 0xF0, 0x01, // 170 + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x1B, 0x00, 0x80, 0x20, 0x00, 0x00, 0x04, 0x00, 0x00, 0x1B, 0x00, 0x80, 0x20, // 171 + 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x80, 0x0F, // 172 + 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, // 173 + 0xC0, 0x0F, 0x00, 0x20, 0x10, 0x00, 0x10, 0x20, 0x00, 0xE8, 0x4F, 0x00, 0x28, 0x41, 0x00, 0x28, 0x41, 0x00, 0x28, 0x43, 0x00, + 0x28, 0x45, 0x00, 0xC8, 0x48, 0x00, 0x10, 0x20, 0x00, 0x20, 0x10, 0x00, 0xC0, 0x0F, // 174 + 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x04, // 175 + 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x48, 0x00, 0x00, 0x48, 0x00, 0x00, 0x30, // 176 + 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, 0xE0, 0x4F, 0x00, 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, + 0x00, 0x41, // 177 + 0x10, 0x01, 0x00, 0x88, 0x01, 0x00, 0x48, 0x01, 0x00, 0x48, 0x01, 0x00, 0x30, 0x01, // 178 + 0x90, 0x00, 0x00, 0x08, 0x01, 0x00, 0x08, 0x01, 0x00, 0x28, 0x01, 0x00, 0xD8, // 179 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x08, // 180 + 0x00, 0x00, 0x00, 0xC0, 0xFF, 0x03, 0x00, 0x20, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x20, 0x00, + 0xC0, 0x7F, // 181 + 0xF0, 0x00, 0x00, 0xF8, 0x00, 0x00, 0xF8, 0x01, 0x00, 0xF8, 0x01, 0x00, 0xF8, 0xFF, 0x03, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, + 0xF8, 0xFF, 0x03, 0x08, // 182 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, // 183 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x80, 0x02, 0x00, 0x00, 0x03, // 184 + 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x08, 0x00, 0x00, 0xF8, 0x01, // 185 + 0xF0, 0x00, 0x00, 0x08, 0x01, 0x00, 0x08, 0x01, 0x00, 0x08, 0x01, 0x00, 0xF0, // 186 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x20, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x04, 0x00, 0x80, 0x20, 0x00, 0x00, 0x1B, 0x00, + 0x00, 0x04, // 187 + 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x08, 0x40, 0x00, 0xF8, 0x21, 0x00, 0x00, 0x10, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x02, 0x00, + 0x80, 0x01, 0x00, 0x40, 0x30, 0x00, 0x30, 0x28, 0x00, 0x08, 0x24, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x20, // 188 + 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x08, 0x40, 0x00, 0xF8, 0x31, 0x00, 0x00, 0x08, 0x00, 0x00, 0x04, 0x00, 0x00, 0x03, 0x00, + 0x80, 0x00, 0x00, 0x60, 0x44, 0x00, 0x10, 0x62, 0x00, 0x08, 0x52, 0x00, 0x00, 0x52, 0x00, 0x00, 0x4C, // 189 + 0x90, 0x00, 0x00, 0x08, 0x01, 0x00, 0x08, 0x41, 0x00, 0x28, 0x21, 0x00, 0xD8, 0x18, 0x00, 0x00, 0x04, 0x00, 0x00, 0x03, 0x00, + 0x80, 0x00, 0x00, 0x40, 0x30, 0x00, 0x30, 0x28, 0x00, 0x08, 0x24, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x20, // 190 + 0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x10, 0x01, 0x00, 0x08, 0x02, 0x40, 0x07, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x01, 0x00, 0xC0, // 191 + 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x1C, 0x00, 0x80, 0x07, 0x00, 0x71, 0x04, 0x00, 0x0A, 0x04, 0x00, 0x70, 0x04, 0x00, + 0x80, 0x07, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x60, // 192 + 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x1C, 0x00, 0x80, 0x07, 0x00, 0x70, 0x04, 0x00, 0x0A, 0x04, 0x00, 0x71, 0x04, 0x00, + 0x80, 0x07, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x60, // 193 + 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x1C, 0x00, 0x80, 0x07, 0x00, 0x72, 0x04, 0x00, 0x09, 0x04, 0x00, 0x71, 0x04, 0x00, + 0x82, 0x07, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x60, // 194 + 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x1C, 0x00, 0x80, 0x07, 0x00, 0x72, 0x04, 0x00, 0x09, 0x04, 0x00, 0x72, 0x04, 0x00, + 0x81, 0x07, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x60, // 195 + 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x1C, 0x00, 0x80, 0x07, 0x00, 0x72, 0x04, 0x00, 0x08, 0x04, 0x00, 0x72, 0x04, 0x00, + 0x80, 0x07, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x60, // 196 + 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x1C, 0x00, 0x80, 0x07, 0x00, 0x7E, 0x04, 0x00, 0x0A, 0x04, 0x00, 0x7E, 0x04, 0x00, + 0x80, 0x07, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x60, // 197 + 0x00, 0x60, 0x00, 0x00, 0x18, 0x00, 0x00, 0x06, 0x00, 0x80, 0x05, 0x00, 0x60, 0x04, 0x00, 0x18, 0x04, 0x00, 0x08, 0x04, 0x00, + 0x08, 0x04, 0x00, 0xF8, 0x7F, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, + 0x08, 0x41, // 198 + 0x00, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x20, 0x10, 0x00, 0x10, 0x20, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x02, 0x08, 0xC0, 0x02, + 0x08, 0x40, 0x03, 0x08, 0x40, 0x00, 0x10, 0x20, 0x00, 0x20, 0x10, // 199 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x09, 0x41, 0x00, 0x0A, 0x41, 0x00, + 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x40, // 200 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x0A, 0x41, 0x00, 0x09, 0x41, 0x00, + 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x40, // 201 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x0A, 0x41, 0x00, 0x09, 0x41, 0x00, 0x09, 0x41, 0x00, + 0x0A, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x40, // 202 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x0A, 0x41, 0x00, 0x08, 0x41, 0x00, 0x0A, 0x41, 0x00, + 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x40, // 203 + 0x01, 0x00, 0x00, 0xFA, 0x7F, // 204 + 0x00, 0x00, 0x00, 0xFA, 0x7F, 0x00, 0x01, // 205 + 0x02, 0x00, 0x00, 0xF9, 0x7F, 0x00, 0x01, 0x00, 0x00, 0x02, // 206 + 0x02, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x02, // 207 + 0x00, 0x02, 0x00, 0xF8, 0x7F, 0x00, 0x08, 0x42, 0x00, 0x08, 0x42, 0x00, 0x08, 0x42, 0x00, 0x08, 0x42, 0x00, 0x08, 0x40, 0x00, + 0x08, 0x40, 0x00, 0x10, 0x20, 0x00, 0x20, 0x10, 0x00, 0xC0, 0x0F, // 208 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x10, 0x00, 0x00, 0x60, 0x00, 0x00, 0x82, 0x00, 0x00, 0x01, 0x03, 0x00, 0x02, 0x04, 0x00, + 0x01, 0x18, 0x00, 0x00, 0x20, 0x00, 0xF8, 0x7F, // 209 + 0x00, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x20, 0x10, 0x00, 0x10, 0x20, 0x00, 0x08, 0x40, 0x00, 0x09, 0x40, 0x00, 0x0A, 0x40, 0x00, + 0x08, 0x40, 0x00, 0x10, 0x20, 0x00, 0x20, 0x10, 0x00, 0xC0, 0x0F, // 210 + 0x00, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x20, 0x10, 0x00, 0x10, 0x20, 0x00, 0x08, 0x40, 0x00, 0x0A, 0x40, 0x00, 0x09, 0x40, 0x00, + 0x08, 0x40, 0x00, 0x10, 0x20, 0x00, 0x20, 0x10, 0x00, 0xC0, 0x0F, // 211 + 0x00, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x20, 0x10, 0x00, 0x10, 0x20, 0x00, 0x0A, 0x40, 0x00, 0x09, 0x40, 0x00, 0x09, 0x40, 0x00, + 0x0A, 0x40, 0x00, 0x10, 0x20, 0x00, 0x20, 0x10, 0x00, 0xC0, 0x0F, // 212 + 0x00, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x20, 0x10, 0x00, 0x10, 0x20, 0x00, 0x0A, 0x40, 0x00, 0x09, 0x40, 0x00, 0x0A, 0x40, 0x00, + 0x09, 0x40, 0x00, 0x10, 0x20, 0x00, 0x20, 0x10, 0x00, 0xC0, 0x0F, // 213 + 0x00, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x20, 0x10, 0x00, 0x10, 0x20, 0x00, 0x08, 0x40, 0x00, 0x0A, 0x40, 0x00, 0x08, 0x40, 0x00, + 0x0A, 0x40, 0x00, 0x10, 0x20, 0x00, 0x20, 0x10, 0x00, 0xC0, 0x0F, // 214 + 0x00, 0x00, 0x00, 0x40, 0x10, 0x00, 0x80, 0x08, 0x00, 0x00, 0x05, 0x00, 0x00, 0x07, 0x00, 0x00, 0x05, 0x00, 0x80, 0x08, 0x00, + 0x40, 0x10, // 215 + 0x00, 0x00, 0x00, 0xC0, 0x4F, 0x00, 0x20, 0x30, 0x00, 0x10, 0x30, 0x00, 0x08, 0x4C, 0x00, 0x08, 0x42, 0x00, 0x08, 0x41, 0x00, + 0xC8, 0x40, 0x00, 0x30, 0x20, 0x00, 0x30, 0x10, 0x00, 0xC8, 0x0F, // 216 + 0x00, 0x00, 0x00, 0xF8, 0x1F, 0x00, 0x00, 0x20, 0x00, 0x00, 0x40, 0x00, 0x01, 0x40, 0x00, 0x02, 0x40, 0x00, 0x00, 0x40, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x20, 0x00, 0xF8, 0x1F, // 217 + 0x00, 0x00, 0x00, 0xF8, 0x1F, 0x00, 0x00, 0x20, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x02, 0x40, 0x00, 0x01, 0x40, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x20, 0x00, 0xF8, 0x1F, // 218 + 0x00, 0x00, 0x00, 0xF8, 0x1F, 0x00, 0x00, 0x20, 0x00, 0x00, 0x40, 0x00, 0x02, 0x40, 0x00, 0x01, 0x40, 0x00, 0x01, 0x40, 0x00, + 0x02, 0x40, 0x00, 0x00, 0x20, 0x00, 0xF8, 0x1F, // 219 + 0x00, 0x00, 0x00, 0xF8, 0x1F, 0x00, 0x00, 0x20, 0x00, 0x00, 0x40, 0x00, 0x02, 0x40, 0x00, 0x00, 0x40, 0x00, 0x02, 0x40, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x20, 0x00, 0xF8, 0x1F, // 220 + 0x08, 0x00, 0x00, 0x30, 0x00, 0x00, 0x40, 0x00, 0x00, 0x80, 0x01, 0x00, 0x02, 0x7E, 0x00, 0x81, 0x01, 0x00, 0x40, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x08, // 221 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x20, 0x10, 0x00, 0x20, 0x10, 0x00, 0x20, 0x10, 0x00, 0x20, 0x10, 0x00, 0x20, 0x10, 0x00, + 0x20, 0x10, 0x00, 0x40, 0x08, 0x00, 0x80, 0x07, // 222 + 0x00, 0x00, 0x00, 0xE0, 0x7F, 0x00, 0x10, 0x00, 0x00, 0x08, 0x20, 0x00, 0x88, 0x43, 0x00, 0x70, 0x42, 0x00, 0x00, 0x44, 0x00, + 0x00, 0x38, // 223 + 0x00, 0x00, 0x00, 0x00, 0x39, 0x00, 0x80, 0x44, 0x00, 0x40, 0x44, 0x00, 0x48, 0x44, 0x00, 0x50, 0x42, 0x00, 0x40, 0x22, 0x00, + 0x80, 0x7F, // 224 + 0x00, 0x00, 0x00, 0x00, 0x39, 0x00, 0x80, 0x44, 0x00, 0x40, 0x44, 0x00, 0x50, 0x44, 0x00, 0x48, 0x42, 0x00, 0x40, 0x22, 0x00, + 0x80, 0x7F, // 225 + 0x00, 0x00, 0x00, 0x00, 0x39, 0x00, 0x80, 0x44, 0x00, 0x50, 0x44, 0x00, 0x48, 0x44, 0x00, 0x48, 0x42, 0x00, 0x50, 0x22, 0x00, + 0x80, 0x7F, // 226 + 0x00, 0x00, 0x00, 0x00, 0x39, 0x00, 0x80, 0x44, 0x00, 0x50, 0x44, 0x00, 0x48, 0x44, 0x00, 0x50, 0x42, 0x00, 0x48, 0x22, 0x00, + 0x80, 0x7F, // 227 + 0x00, 0x00, 0x00, 0x00, 0x39, 0x00, 0x80, 0x44, 0x00, 0x50, 0x44, 0x00, 0x40, 0x44, 0x00, 0x50, 0x42, 0x00, 0x40, 0x22, 0x00, + 0x80, 0x7F, // 228 + 0x00, 0x00, 0x00, 0x00, 0x39, 0x00, 0x80, 0x44, 0x00, 0x5C, 0x44, 0x00, 0x54, 0x44, 0x00, 0x5C, 0x42, 0x00, 0x40, 0x22, 0x00, + 0x80, 0x7F, // 229 + 0x00, 0x00, 0x00, 0x00, 0x39, 0x00, 0x80, 0x44, 0x00, 0x40, 0x44, 0x00, 0x40, 0x44, 0x00, 0x40, 0x42, 0x00, 0x40, 0x22, 0x00, + 0x80, 0x3F, 0x00, 0x80, 0x24, 0x00, 0x40, 0x44, 0x00, 0x40, 0x44, 0x00, 0x40, 0x44, 0x00, 0x80, 0x24, 0x00, 0x00, 0x17, // 230 + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x80, 0x20, 0x00, 0x40, 0x40, 0x02, 0x40, 0xC0, 0x02, 0x40, 0x40, 0x03, 0x80, 0x20, // 231 + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x80, 0x24, 0x00, 0x48, 0x44, 0x00, 0x50, 0x44, 0x00, 0x40, 0x44, 0x00, 0x80, 0x24, 0x00, + 0x00, 0x17, // 232 + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x80, 0x24, 0x00, 0x40, 0x44, 0x00, 0x50, 0x44, 0x00, 0x48, 0x44, 0x00, 0x80, 0x24, 0x00, + 0x00, 0x17, // 233 + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x80, 0x24, 0x00, 0x50, 0x44, 0x00, 0x48, 0x44, 0x00, 0x48, 0x44, 0x00, 0x90, 0x24, 0x00, + 0x00, 0x17, // 234 + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x80, 0x24, 0x00, 0x50, 0x44, 0x00, 0x40, 0x44, 0x00, 0x50, 0x44, 0x00, 0x80, 0x24, 0x00, + 0x00, 0x17, // 235 + 0x08, 0x00, 0x00, 0xD0, 0x7F, // 236 + 0x00, 0x00, 0x00, 0xD0, 0x7F, 0x00, 0x08, // 237 + 0x10, 0x00, 0x00, 0xC8, 0x7F, 0x00, 0x08, 0x00, 0x00, 0x10, // 238 + 0x10, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x10, // 239 + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0xA0, 0x20, 0x00, 0x68, 0x40, 0x00, 0x58, 0x40, 0x00, 0x70, 0x40, 0x00, 0xE8, 0x20, 0x00, + 0x00, 0x1F, // 240 + 0x00, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x90, 0x00, 0x00, 0x48, 0x00, 0x00, 0x50, 0x00, 0x00, 0x48, 0x00, 0x00, 0x80, 0x7F, // 241 + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x80, 0x20, 0x00, 0x48, 0x40, 0x00, 0x50, 0x40, 0x00, 0x40, 0x40, 0x00, 0x80, 0x20, 0x00, + 0x00, 0x1F, // 242 + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x80, 0x20, 0x00, 0x40, 0x40, 0x00, 0x50, 0x40, 0x00, 0x48, 0x40, 0x00, 0x80, 0x20, 0x00, + 0x00, 0x1F, // 243 + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x80, 0x20, 0x00, 0x50, 0x40, 0x00, 0x48, 0x40, 0x00, 0x48, 0x40, 0x00, 0x90, 0x20, 0x00, + 0x00, 0x1F, // 244 + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x80, 0x20, 0x00, 0x50, 0x40, 0x00, 0x48, 0x40, 0x00, 0x50, 0x40, 0x00, 0x88, 0x20, 0x00, + 0x00, 0x1F, // 245 + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x80, 0x20, 0x00, 0x50, 0x40, 0x00, 0x40, 0x40, 0x00, 0x50, 0x40, 0x00, 0x80, 0x20, 0x00, + 0x00, 0x1F, // 246 + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x80, 0x0A, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x02, // 247 + 0x00, 0x00, 0x00, 0x00, 0x5F, 0x00, 0x80, 0x30, 0x00, 0x40, 0x48, 0x00, 0x40, 0x44, 0x00, 0x40, 0x42, 0x00, 0x80, 0x21, 0x00, + 0x40, 0x1F, // 248 + 0x00, 0x00, 0x00, 0xC0, 0x3F, 0x00, 0x00, 0x40, 0x00, 0x08, 0x40, 0x00, 0x10, 0x40, 0x00, 0x00, 0x20, 0x00, 0xC0, 0x7F, // 249 + 0x00, 0x00, 0x00, 0xC0, 0x3F, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x10, 0x40, 0x00, 0x08, 0x20, 0x00, 0xC0, 0x7F, // 250 + 0x00, 0x00, 0x00, 0xC0, 0x3F, 0x00, 0x10, 0x40, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x10, 0x20, 0x00, 0xC0, 0x7F, // 251 + 0x00, 0x00, 0x00, 0xD0, 0x3F, 0x00, 0x00, 0x40, 0x00, 0x10, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x20, 0x00, 0xC0, 0x7F, // 252 + 0xC0, 0x01, 0x00, 0x00, 0x06, 0x02, 0x00, 0x38, 0x02, 0x10, 0xE0, 0x01, 0x08, 0x38, 0x00, 0x00, 0x07, 0x00, 0xC0, // 253 + 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x03, 0x80, 0x20, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x80, 0x20, 0x00, + 0x00, 0x1F, // 254 + 0xC0, 0x01, 0x00, 0x00, 0x06, 0x02, 0x10, 0x38, 0x02, 0x00, 0xE0, 0x01, 0x10, 0x38, 0x00, 0x00, 0x07, 0x00, 0xC0, // 255 +}; + +const uint8_t ArialMT_Plain_24_CS[] PROGMEM = { + 0x18, // Width: 24 + 0x1C, // Height: 28 + 0x20, // First char: 32 + 0xE0, // Number of chars: 224 + // Jump Table: + 0xFF, 0xFF, 0x00, 0x18, // 32 + 0x00, 0x00, 0x13, 0x06, // 33 + 0x00, 0x13, 0x1A, 0x08, // 34 + 0x00, 0x2D, 0x33, 0x0E, // 35 + 0x00, 0x60, 0x2F, 0x0D, // 36 + 0x00, 0x8F, 0x4F, 0x15, // 37 + 0x00, 0xDE, 0x3B, 0x10, // 38 + 0x01, 0x19, 0x0A, 0x04, // 39 + 0x01, 0x23, 0x1C, 0x08, // 40 + 0x01, 0x3F, 0x1B, 0x08, // 41 + 0x01, 0x5A, 0x21, 0x0A, // 42 + 0x01, 0x7B, 0x32, 0x0E, // 43 + 0x01, 0xAD, 0x10, 0x05, // 44 + 0x01, 0xBD, 0x1B, 0x08, // 45 + 0x01, 0xD8, 0x0F, 0x05, // 46 + 0x01, 0xE7, 0x19, 0x08, // 47 + 0x02, 0x00, 0x2F, 0x0D, // 48 + 0x02, 0x2F, 0x23, 0x0A, // 49 + 0x02, 0x52, 0x2F, 0x0D, // 50 + 0x02, 0x81, 0x2F, 0x0D, // 51 + 0x02, 0xB0, 0x2F, 0x0D, // 52 + 0x02, 0xDF, 0x2F, 0x0D, // 53 + 0x03, 0x0E, 0x2F, 0x0D, // 54 + 0x03, 0x3D, 0x2D, 0x0D, // 55 + 0x03, 0x6A, 0x2F, 0x0D, // 56 + 0x03, 0x99, 0x2F, 0x0D, // 57 + 0x03, 0xC8, 0x0F, 0x05, // 58 + 0x03, 0xD7, 0x10, 0x05, // 59 + 0x03, 0xE7, 0x2F, 0x0D, // 60 + 0x04, 0x16, 0x2F, 0x0D, // 61 + 0x04, 0x45, 0x2E, 0x0D, // 62 + 0x04, 0x73, 0x2E, 0x0D, // 63 + 0x04, 0xA1, 0x5B, 0x18, // 64 + 0x04, 0xFC, 0x3B, 0x10, // 65 + 0x05, 0x37, 0x3B, 0x10, // 66 + 0x05, 0x72, 0x3F, 0x11, // 67 + 0x05, 0xB1, 0x3F, 0x11, // 68 + 0x05, 0xF0, 0x3B, 0x10, // 69 + 0x06, 0x2B, 0x35, 0x0F, // 70 + 0x06, 0x60, 0x43, 0x12, // 71 + 0x06, 0xA3, 0x3B, 0x10, // 72 + 0x06, 0xDE, 0x0F, 0x05, // 73 + 0x06, 0xED, 0x27, 0x0B, // 74 + 0x07, 0x14, 0x3F, 0x11, // 75 + 0x07, 0x53, 0x2F, 0x0D, // 76 + 0x07, 0x82, 0x43, 0x12, // 77 + 0x07, 0xC5, 0x3B, 0x10, // 78 + 0x08, 0x00, 0x47, 0x13, // 79 + 0x08, 0x47, 0x3A, 0x10, // 80 + 0x08, 0x81, 0x47, 0x13, // 81 + 0x08, 0xC8, 0x3F, 0x11, // 82 + 0x09, 0x07, 0x3B, 0x10, // 83 + 0x09, 0x42, 0x35, 0x0F, // 84 + 0x09, 0x77, 0x3B, 0x10, // 85 + 0x09, 0xB2, 0x39, 0x10, // 86 + 0x09, 0xEB, 0x59, 0x18, // 87 + 0x0A, 0x44, 0x3B, 0x10, // 88 + 0x0A, 0x7F, 0x3D, 0x11, // 89 + 0x0A, 0xBC, 0x37, 0x0F, // 90 + 0x0A, 0xF3, 0x14, 0x06, // 91 + 0x0B, 0x07, 0x1B, 0x08, // 92 + 0x0B, 0x22, 0x18, 0x07, // 93 + 0x0B, 0x3A, 0x2A, 0x0C, // 94 + 0x0B, 0x64, 0x34, 0x0E, // 95 + 0x0B, 0x98, 0x11, 0x06, // 96 + 0x0B, 0xA9, 0x2F, 0x0D, // 97 + 0x0B, 0xD8, 0x33, 0x0E, // 98 + 0x0C, 0x0B, 0x2B, 0x0C, // 99 + 0x0C, 0x36, 0x2F, 0x0D, // 100 + 0x0C, 0x65, 0x2F, 0x0D, // 101 + 0x0C, 0x94, 0x1A, 0x08, // 102 + 0x0C, 0xAE, 0x2F, 0x0D, // 103 + 0x0C, 0xDD, 0x2F, 0x0D, // 104 + 0x0D, 0x0C, 0x0F, 0x05, // 105 + 0x0D, 0x1B, 0x10, 0x05, // 106 + 0x0D, 0x2B, 0x2F, 0x0D, // 107 + 0x0D, 0x5A, 0x0F, 0x05, // 108 + 0x0D, 0x69, 0x47, 0x13, // 109 + 0x0D, 0xB0, 0x2F, 0x0D, // 110 + 0x0D, 0xDF, 0x2F, 0x0D, // 111 + 0x0E, 0x0E, 0x33, 0x0E, // 112 + 0x0E, 0x41, 0x30, 0x0D, // 113 + 0x0E, 0x71, 0x1E, 0x09, // 114 + 0x0E, 0x8F, 0x2B, 0x0C, // 115 + 0x0E, 0xBA, 0x1B, 0x08, // 116 + 0x0E, 0xD5, 0x2F, 0x0D, // 117 + 0x0F, 0x04, 0x2A, 0x0C, // 118 + 0x0F, 0x2E, 0x42, 0x12, // 119 + 0x0F, 0x70, 0x2B, 0x0C, // 120 + 0x0F, 0x9B, 0x2A, 0x0C, // 121 + 0x0F, 0xC5, 0x2B, 0x0C, // 122 + 0x0F, 0xF0, 0x1C, 0x08, // 123 + 0x10, 0x0C, 0x10, 0x05, // 124 + 0x10, 0x1C, 0x1B, 0x08, // 125 + 0x10, 0x37, 0x32, 0x0E, // 126 + 0xFF, 0xFF, 0x00, 0x18, // 127 + 0xFF, 0xFF, 0x00, 0x18, // 128 + 0x10, 0x69, 0x3F, 0x11, // 129 + 0x10, 0xA8, 0x3F, 0x11, // 130 + 0x10, 0xE7, 0x3B, 0x10, // 131 + 0x11, 0x22, 0x3B, 0x10, // 132 + 0x11, 0x5D, 0x3F, 0x11, // 133 + 0x11, 0x9C, 0x3B, 0x10, // 134 + 0x11, 0xD7, 0x35, 0x0F, // 135 + 0x12, 0x0C, 0x3B, 0x10, // 136 + 0x12, 0x47, 0x37, 0x0F, // 137 + 0x12, 0x7E, 0x2B, 0x0C, // 138 + 0x12, 0xA9, 0x3A, 0x10, // 139 + 0x12, 0xE3, 0x2F, 0x0D, // 140 + 0x13, 0x12, 0x2F, 0x0D, // 141 + 0x13, 0x41, 0x1E, 0x09, // 142 + 0x13, 0x5F, 0x2B, 0x0C, // 143 + 0x13, 0x8A, 0x26, 0x0B, // 144 + 0x13, 0xB0, 0x2F, 0x0D, // 145 + 0x13, 0xDF, 0x2B, 0x0C, // 146 + 0x14, 0x0A, 0x2F, 0x0D, // 147 + 0x14, 0x39, 0x15, 0x07, // 148 + 0x14, 0x4E, 0x2F, 0x0D, // 149 + 0x14, 0x7D, 0x1A, 0x08, // 150 + 0x14, 0x97, 0x3F, 0x11, // 151 + 0x14, 0xD6, 0x1E, 0x09, // 152 + 0xFF, 0xFF, 0x00, 0x18, // 153 + 0xFF, 0xFF, 0x00, 0x18, // 154 + 0xFF, 0xFF, 0x00, 0x18, // 155 + 0xFF, 0xFF, 0x00, 0x18, // 156 + 0xFF, 0xFF, 0x00, 0x18, // 157 + 0xFF, 0xFF, 0x00, 0x18, // 158 + 0xFF, 0xFF, 0x00, 0x18, // 159 + 0xFF, 0xFF, 0x00, 0x18, // 160 + 0x14, 0xF4, 0x14, 0x06, // 161 + 0x15, 0x08, 0x2B, 0x0C, // 162 + 0x15, 0x33, 0x2F, 0x0D, // 163 + 0x15, 0x62, 0x33, 0x0E, // 164 + 0x15, 0x95, 0x31, 0x0E, // 165 + 0x15, 0xC6, 0x10, 0x05, // 166 + 0x15, 0xD6, 0x2F, 0x0D, // 167 + 0x16, 0x05, 0x19, 0x08, // 168 + 0x16, 0x1E, 0x46, 0x13, // 169 + 0x16, 0x64, 0x1A, 0x08, // 170 + 0x16, 0x7E, 0x27, 0x0B, // 171 + 0x16, 0xA5, 0x2F, 0x0D, // 172 + 0x16, 0xD4, 0x1B, 0x08, // 173 + 0x16, 0xEF, 0x46, 0x13, // 174 + 0x17, 0x35, 0x31, 0x0E, // 175 + 0x17, 0x66, 0x1E, 0x09, // 176 + 0x17, 0x84, 0x33, 0x0E, // 177 + 0x17, 0xB7, 0x1A, 0x08, // 178 + 0x17, 0xD1, 0x1A, 0x08, // 179 + 0x17, 0xEB, 0x19, 0x08, // 180 + 0x18, 0x04, 0x2F, 0x0D, // 181 + 0x18, 0x33, 0x31, 0x0E, // 182 + 0x18, 0x64, 0x12, 0x06, // 183 + 0x18, 0x76, 0x18, 0x07, // 184 + 0x18, 0x8E, 0x16, 0x07, // 185 + 0x18, 0xA4, 0x1E, 0x09, // 186 + 0x18, 0xC2, 0x2E, 0x0D, // 187 + 0x18, 0xF0, 0x4F, 0x15, // 188 + 0x19, 0x3F, 0x4B, 0x14, // 189 + 0x19, 0x8A, 0x4B, 0x14, // 190 + 0x19, 0xD5, 0x33, 0x0E, // 191 + 0x1A, 0x08, 0x3B, 0x10, // 192 + 0x1A, 0x43, 0x3B, 0x10, // 193 + 0x1A, 0x7E, 0x3B, 0x10, // 194 + 0x1A, 0xB9, 0x3B, 0x10, // 195 + 0x1A, 0xF4, 0x3B, 0x10, // 196 + 0x1B, 0x2F, 0x3B, 0x10, // 197 + 0x1B, 0x6A, 0x5B, 0x18, // 198 + 0x1B, 0xC5, 0x3F, 0x11, // 199 + 0x1C, 0x04, 0x3B, 0x10, // 200 + 0x1C, 0x3F, 0x3B, 0x10, // 201 + 0x1C, 0x7A, 0x3B, 0x10, // 202 + 0x1C, 0xB5, 0x3B, 0x10, // 203 + 0x1C, 0xF0, 0x11, 0x06, // 204 + 0x1D, 0x01, 0x11, 0x06, // 205 + 0x1D, 0x12, 0x15, 0x07, // 206 + 0x1D, 0x27, 0x15, 0x07, // 207 + 0x1D, 0x3C, 0x3F, 0x11, // 208 + 0x1D, 0x7B, 0x3B, 0x10, // 209 + 0x1D, 0xB6, 0x47, 0x13, // 210 + 0x1D, 0xFD, 0x47, 0x13, // 211 + 0x1E, 0x44, 0x47, 0x13, // 212 + 0x1E, 0x8B, 0x47, 0x13, // 213 + 0x1E, 0xD2, 0x47, 0x13, // 214 + 0x1F, 0x19, 0x2B, 0x0C, // 215 + 0x1F, 0x44, 0x47, 0x13, // 216 + 0x1F, 0x8B, 0x3B, 0x10, // 217 + 0x1F, 0xC6, 0x3B, 0x10, // 218 + 0x20, 0x01, 0x3B, 0x10, // 219 + 0x20, 0x3C, 0x3B, 0x10, // 220 + 0x20, 0x77, 0x3D, 0x11, // 221 + 0x20, 0xB4, 0x3A, 0x10, // 222 + 0x20, 0xEE, 0x37, 0x0F, // 223 + 0x21, 0x25, 0x2F, 0x0D, // 224 + 0x21, 0x54, 0x2F, 0x0D, // 225 + 0x21, 0x83, 0x2F, 0x0D, // 226 + 0x21, 0xB2, 0x2F, 0x0D, // 227 + 0x21, 0xE1, 0x2F, 0x0D, // 228 + 0x22, 0x10, 0x2F, 0x0D, // 229 + 0x22, 0x3F, 0x53, 0x16, // 230 + 0x22, 0x92, 0x2B, 0x0C, // 231 + 0x22, 0xBD, 0x2F, 0x0D, // 232 + 0x22, 0xEC, 0x2F, 0x0D, // 233 + 0x23, 0x1B, 0x2F, 0x0D, // 234 + 0x23, 0x4A, 0x2F, 0x0D, // 235 + 0x23, 0x79, 0x11, 0x06, // 236 + 0x23, 0x8A, 0x11, 0x06, // 237 + 0x23, 0x9B, 0x15, 0x07, // 238 + 0x23, 0xB0, 0x15, 0x07, // 239 + 0x23, 0xC5, 0x2F, 0x0D, // 240 + 0x23, 0xF4, 0x2F, 0x0D, // 241 + 0x24, 0x23, 0x2F, 0x0D, // 242 + 0x24, 0x52, 0x2F, 0x0D, // 243 + 0x24, 0x81, 0x2F, 0x0D, // 244 + 0x24, 0xB0, 0x2F, 0x0D, // 245 + 0x24, 0xDF, 0x2F, 0x0D, // 246 + 0x25, 0x0E, 0x32, 0x0E, // 247 + 0x25, 0x40, 0x33, 0x0E, // 248 + 0x25, 0x73, 0x2F, 0x0D, // 249 + 0x25, 0xA2, 0x2F, 0x0D, // 250 + 0x25, 0xD1, 0x2F, 0x0D, // 251 + 0x26, 0x00, 0x2F, 0x0D, // 252 + 0x26, 0x2F, 0x2A, 0x0C, // 253 + 0x26, 0x59, 0x2F, 0x0D, // 254 + 0x26, 0x88, 0x2A, 0x0C, // 255 + // Font Data: + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x33, 0x00, 0xE0, 0xFF, 0x33, // 33 + 0x00, 0x00, 0x00, 0x00, 0xE0, 0x07, 0x00, 0x00, 0xE0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, + 0x07, 0x00, 0x00, 0xE0, 0x07, // 34 + 0x00, 0x0C, 0x03, 0x00, 0x00, 0x0C, 0x33, 0x00, 0x00, 0x0C, 0x3F, 0x00, 0x00, 0xFC, 0x0F, 0x00, 0x80, 0xFF, 0x03, 0x00, 0xE0, + 0x0F, 0x03, 0x00, 0x60, 0x0C, 0x33, 0x00, 0x00, 0x0C, 0x3F, 0x00, 0x00, 0xFC, 0x0F, 0x00, 0x80, 0xFF, 0x03, 0x00, 0xE0, 0x0F, + 0x03, 0x00, 0x60, 0x0C, 0x03, 0x00, 0x00, 0x0C, 0x03, // 35 + 0x00, 0x00, 0x00, 0x00, 0x80, 0x07, 0x06, 0x00, 0xC0, 0x0F, 0x1E, 0x00, 0xC0, 0x18, 0x1C, 0x00, 0x60, 0x18, 0x38, 0x00, 0x60, + 0x30, 0x30, 0x00, 0xF0, 0xFF, 0xFF, 0x00, 0x60, 0x30, 0x30, 0x00, 0x60, 0x60, 0x38, 0x00, 0xC0, 0x60, 0x18, 0x00, 0xC0, 0xC1, + 0x1F, 0x00, 0x00, 0x81, 0x07, // 36 + 0x00, 0x00, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x00, 0x60, 0x30, 0x00, 0x00, 0x20, 0x20, 0x00, 0x00, 0x20, + 0x20, 0x20, 0x00, 0x60, 0x30, 0x38, 0x00, 0xC0, 0x1F, 0x1E, 0x00, 0x80, 0x8F, 0x0F, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0xF0, + 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x8F, 0x0F, 0x00, 0xC0, 0xC3, 0x1F, 0x00, 0xE0, 0x60, 0x30, 0x00, 0x20, 0x20, 0x20, + 0x00, 0x00, 0x20, 0x20, 0x00, 0x00, 0x60, 0x30, 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x00, 0x80, 0x0F, // 37 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x80, 0xE3, 0x1C, 0x00, 0xC0, 0x77, 0x38, 0x00, 0xE0, + 0x3C, 0x30, 0x00, 0x60, 0x38, 0x30, 0x00, 0x60, 0x78, 0x30, 0x00, 0xE0, 0xEC, 0x38, 0x00, 0xC0, 0x8F, 0x1B, 0x00, 0x80, 0x03, + 0x1F, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x00, 0xC0, 0x38, 0x00, 0x00, 0x00, 0x10, // 38 + 0x00, 0x00, 0x00, 0x00, 0xE0, 0x07, 0x00, 0x00, 0xE0, 0x07, // 39 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x0F, 0x00, 0x00, 0xFE, 0x7F, 0x00, 0x80, 0x0F, 0xF0, 0x01, 0xC0, 0x01, 0x80, 0x03, 0x60, + 0x00, 0x00, 0x06, 0x20, 0x00, 0x00, 0x04, // 40 + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x04, 0x60, 0x00, 0x00, 0x06, 0xC0, 0x01, 0x80, 0x03, 0x80, 0x0F, 0xF0, 0x01, 0x00, + 0xFE, 0x7F, 0x00, 0x00, 0xF0, 0x0F, // 41 + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x04, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x00, 0xE0, 0x03, 0x00, 0x00, 0xE0, + 0x03, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x00, 0x80, 0x04, 0x00, 0x00, 0x80, // 42 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, + 0x60, 0x00, 0x00, 0x00, 0xFF, 0x0F, 0x00, 0x00, 0xFF, 0x0F, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x60, + 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x60, // 43 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x03, 0x00, 0x00, 0xF0, 0x01, // 44 + 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, + 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, // 45 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, // 46 + 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0xE0, 0x0F, 0x00, 0x00, 0xFC, 0x01, 0x00, 0x80, 0x3F, 0x00, 0x00, 0xE0, + 0x03, 0x00, 0x00, 0x60, // 47 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x03, 0x00, 0x80, 0xFF, 0x0F, 0x00, 0xC0, 0x01, 0x1C, 0x00, 0xE0, 0x00, 0x38, 0x00, 0x60, + 0x00, 0x30, 0x00, 0x60, 0x00, 0x30, 0x00, 0x60, 0x00, 0x30, 0x00, 0xE0, 0x00, 0x38, 0x00, 0xC0, 0x01, 0x1C, 0x00, 0x80, 0xFF, + 0x0F, 0x00, 0x00, 0xFE, 0x03, // 48 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0xE0, 0xFF, 0x3F, // 49 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x30, 0x00, 0xC0, 0x03, 0x38, 0x00, 0xC0, 0x00, 0x3C, 0x00, 0x60, 0x00, 0x36, 0x00, 0x60, + 0x00, 0x33, 0x00, 0x60, 0x80, 0x31, 0x00, 0x60, 0xC0, 0x30, 0x00, 0x60, 0x60, 0x30, 0x00, 0xC0, 0x30, 0x30, 0x00, 0xC0, 0x1F, + 0x30, 0x00, 0x00, 0x0F, 0x30, // 50 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0xC0, 0x01, 0x0E, 0x00, 0xC0, 0x00, 0x1C, 0x00, 0x60, 0x00, 0x30, 0x00, 0x60, + 0x30, 0x30, 0x00, 0x60, 0x30, 0x30, 0x00, 0x60, 0x30, 0x30, 0x00, 0xC0, 0x38, 0x30, 0x00, 0xC0, 0x6F, 0x18, 0x00, 0x80, 0xC7, + 0x0F, 0x00, 0x00, 0x80, 0x07, // 51 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0xF0, 0x03, 0x00, 0x00, 0x3C, 0x03, 0x00, 0x00, + 0x0E, 0x03, 0x00, 0x80, 0x07, 0x03, 0x00, 0xC0, 0x01, 0x03, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x03, // 52 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x06, 0x00, 0x80, 0x3F, 0x0E, 0x00, 0xE0, 0x1F, 0x18, 0x00, 0x60, 0x08, 0x30, 0x00, 0x60, + 0x0C, 0x30, 0x00, 0x60, 0x0C, 0x30, 0x00, 0x60, 0x0C, 0x30, 0x00, 0x60, 0x0C, 0x30, 0x00, 0x60, 0x18, 0x1C, 0x00, 0x60, 0xF0, + 0x0F, 0x00, 0x00, 0xE0, 0x03, // 53 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x03, 0x00, 0x80, 0xFF, 0x0F, 0x00, 0xC0, 0x63, 0x1C, 0x00, 0xC0, 0x30, 0x38, 0x00, 0x60, + 0x18, 0x30, 0x00, 0x60, 0x18, 0x30, 0x00, 0x60, 0x18, 0x30, 0x00, 0x60, 0x18, 0x30, 0x00, 0xE0, 0x30, 0x18, 0x00, 0xC0, 0xF1, + 0x0F, 0x00, 0x80, 0xC1, 0x07, // 54 + 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x60, 0x00, 0x3C, 0x00, 0x60, + 0x80, 0x3F, 0x00, 0x60, 0xE0, 0x03, 0x00, 0x60, 0x78, 0x00, 0x00, 0x60, 0x0E, 0x00, 0x00, 0x60, 0x03, 0x00, 0x00, 0xE0, 0x01, + 0x00, 0x00, 0x60, // 55 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07, 0x00, 0x80, 0xC7, 0x1F, 0x00, 0xC0, 0x6F, 0x18, 0x00, 0xE0, 0x38, 0x30, 0x00, 0x60, + 0x30, 0x30, 0x00, 0x60, 0x30, 0x30, 0x00, 0x60, 0x30, 0x30, 0x00, 0xE0, 0x38, 0x30, 0x00, 0xC0, 0x6F, 0x18, 0x00, 0x80, 0xC7, + 0x1F, 0x00, 0x00, 0x80, 0x07, // 56 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x0C, 0x00, 0x80, 0x7F, 0x1C, 0x00, 0xC0, 0x61, 0x38, 0x00, 0x60, 0xC0, 0x30, 0x00, 0x60, + 0xC0, 0x30, 0x00, 0x60, 0xC0, 0x30, 0x00, 0x60, 0xC0, 0x30, 0x00, 0x60, 0x60, 0x18, 0x00, 0xC0, 0x31, 0x1E, 0x00, 0x80, 0xFF, + 0x0F, 0x00, 0x00, 0xFE, 0x01, // 57 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x30, 0x00, 0x00, 0x06, 0x30, // 58 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x30, 0x03, 0x00, 0x06, 0xF0, 0x01, // 59 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0xD8, 0x00, 0x00, 0x00, + 0xD8, 0x00, 0x00, 0x00, 0x8C, 0x01, 0x00, 0x00, 0x8C, 0x01, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x06, 0x03, 0x00, 0x00, 0x06, + 0x03, 0x00, 0x00, 0x03, 0x06, // 60 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x8C, 0x01, 0x00, 0x00, 0x8C, 0x01, 0x00, 0x00, 0x8C, 0x01, 0x00, 0x00, 0x8C, 0x01, 0x00, 0x00, + 0x8C, 0x01, 0x00, 0x00, 0x8C, 0x01, 0x00, 0x00, 0x8C, 0x01, 0x00, 0x00, 0x8C, 0x01, 0x00, 0x00, 0x8C, 0x01, 0x00, 0x00, 0x8C, + 0x01, 0x00, 0x00, 0x8C, 0x01, // 61 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x06, 0x00, 0x00, 0x06, 0x03, 0x00, 0x00, 0x06, 0x03, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, + 0x8C, 0x01, 0x00, 0x00, 0x8C, 0x01, 0x00, 0x00, 0xD8, 0x00, 0x00, 0x00, 0xD8, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x20, // 62 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x60, + 0x80, 0x33, 0x00, 0x60, 0xC0, 0x33, 0x00, 0x60, 0xE0, 0x00, 0x00, 0x60, 0x30, 0x00, 0x00, 0xC0, 0x38, 0x00, 0x00, 0xC0, 0x1F, + 0x00, 0x00, 0x00, 0x07, // 63 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x0F, 0x00, 0x00, 0xF8, 0x3F, 0x00, 0x00, 0x1E, 0xF0, 0x00, 0x00, 0x07, 0xC0, 0x01, 0x80, + 0xC3, 0x87, 0x01, 0xC0, 0xF1, 0x9F, 0x03, 0xC0, 0x38, 0x18, 0x03, 0xC0, 0x0C, 0x30, 0x03, 0x60, 0x0E, 0x30, 0x06, 0x60, 0x06, + 0x30, 0x06, 0x60, 0x06, 0x18, 0x06, 0x60, 0x06, 0x0C, 0x06, 0x60, 0x0C, 0x1E, 0x06, 0x60, 0xF8, 0x3F, 0x06, 0xE0, 0xFE, 0x31, + 0x06, 0xC0, 0x0E, 0x30, 0x06, 0xC0, 0x01, 0x18, 0x03, 0x80, 0x03, 0x1C, 0x03, 0x00, 0x07, 0x8F, 0x01, 0x00, 0xFE, 0x87, 0x01, + 0x00, 0xF8, 0xC1, 0x00, 0x00, 0x00, 0x40, // 64 + 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x00, 0xF0, 0x03, 0x00, 0x00, 0xFE, 0x01, 0x00, 0x80, + 0x8F, 0x01, 0x00, 0xE0, 0x83, 0x01, 0x00, 0x60, 0x80, 0x01, 0x00, 0xE0, 0x83, 0x01, 0x00, 0x80, 0x8F, 0x01, 0x00, 0x00, 0xFE, + 0x01, 0x00, 0x00, 0xF0, 0x03, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x30, // 65 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0x60, 0x30, 0x30, 0x00, 0x60, + 0x30, 0x30, 0x00, 0x60, 0x30, 0x30, 0x00, 0x60, 0x30, 0x30, 0x00, 0x60, 0x30, 0x30, 0x00, 0x60, 0x30, 0x30, 0x00, 0x60, 0x30, + 0x30, 0x00, 0xC0, 0x78, 0x30, 0x00, 0xC0, 0xFF, 0x18, 0x00, 0x80, 0xC7, 0x1F, 0x00, 0x00, 0x80, 0x07, // 66 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x01, 0x00, 0x00, 0xFF, 0x07, 0x00, 0x80, 0x07, 0x0F, 0x00, 0xC0, 0x01, 0x1C, 0x00, 0xC0, + 0x00, 0x18, 0x00, 0x60, 0x00, 0x30, 0x00, 0x60, 0x00, 0x30, 0x00, 0x60, 0x00, 0x30, 0x00, 0x60, 0x00, 0x30, 0x00, 0x60, 0x00, + 0x30, 0x00, 0x60, 0x00, 0x30, 0x00, 0xC0, 0x00, 0x18, 0x00, 0xC0, 0x01, 0x1C, 0x00, 0x80, 0x03, 0x0F, 0x00, 0x00, 0x02, + 0x03, // 67 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0x60, 0x00, 0x30, 0x00, 0x60, + 0x00, 0x30, 0x00, 0x60, 0x00, 0x30, 0x00, 0x60, 0x00, 0x30, 0x00, 0x60, 0x00, 0x30, 0x00, 0x60, 0x00, 0x30, 0x00, 0x60, 0x00, + 0x30, 0x00, 0xE0, 0x00, 0x18, 0x00, 0xC0, 0x01, 0x1C, 0x00, 0x80, 0x03, 0x0E, 0x00, 0x00, 0xFF, 0x07, 0x00, 0x00, 0xFC, + 0x01, // 68 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0x60, 0x30, 0x30, 0x00, 0x60, + 0x30, 0x30, 0x00, 0x60, 0x30, 0x30, 0x00, 0x60, 0x30, 0x30, 0x00, 0x60, 0x30, 0x30, 0x00, 0x60, 0x30, 0x30, 0x00, 0x60, 0x30, + 0x30, 0x00, 0x60, 0x30, 0x30, 0x00, 0x60, 0x30, 0x30, 0x00, 0x60, 0x30, 0x30, 0x00, 0x60, 0x00, 0x30, // 69 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0x60, 0x30, 0x00, 0x00, 0x60, + 0x30, 0x00, 0x00, 0x60, 0x30, 0x00, 0x00, 0x60, 0x30, 0x00, 0x00, 0x60, 0x30, 0x00, 0x00, 0x60, 0x30, 0x00, 0x00, 0x60, 0x30, + 0x00, 0x00, 0x60, 0x30, 0x00, 0x00, 0x60, 0x30, 0x00, 0x00, 0x60, // 70 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x01, 0x00, 0x00, 0xFF, 0x07, 0x00, 0x80, 0x07, 0x0F, 0x00, 0xC0, 0x01, 0x1C, 0x00, 0xC0, + 0x00, 0x18, 0x00, 0xE0, 0x00, 0x18, 0x00, 0x60, 0x00, 0x30, 0x00, 0x60, 0x00, 0x30, 0x00, 0x60, 0x00, 0x30, 0x00, 0x60, 0x60, + 0x30, 0x00, 0x60, 0x60, 0x30, 0x00, 0xE0, 0x60, 0x38, 0x00, 0xC0, 0x60, 0x18, 0x00, 0xC0, 0x61, 0x18, 0x00, 0x80, 0xE3, 0x0F, + 0x00, 0x00, 0xE2, 0x0F, // 71 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, + 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0xE0, 0xFF, 0x3F, // 72 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0xE0, 0xFF, 0x3F, // 73 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, + 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x38, 0x00, 0xE0, 0xFF, 0x1F, 0x00, 0xE0, 0xFF, 0x0F, // 74 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, + 0x70, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0xE7, 0x01, 0x00, 0x80, 0x83, + 0x07, 0x00, 0xC0, 0x01, 0x0F, 0x00, 0xE0, 0x00, 0x1E, 0x00, 0x60, 0x00, 0x38, 0x00, 0x20, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x20, // 75 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, + 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x00, 0x30, // 76 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0xE0, 0x01, 0x00, 0x00, 0xC0, + 0x0F, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0xE0, 0x07, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x3F, 0x00, 0x00, 0xE0, 0x07, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0xE0, 0xFF, 0x3F, + 0x00, 0xE0, 0xFF, 0x3F, // 77 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x80, + 0x03, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0x80, + 0x03, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x1C, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0xE0, 0xFF, 0x3F, // 78 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x01, 0x00, 0x00, 0xFF, 0x07, 0x00, 0x80, 0x07, 0x0F, 0x00, 0xC0, 0x01, 0x1C, 0x00, 0xC0, + 0x00, 0x18, 0x00, 0xE0, 0x00, 0x38, 0x00, 0x60, 0x00, 0x30, 0x00, 0x60, 0x00, 0x30, 0x00, 0x60, 0x00, 0x30, 0x00, 0x60, 0x00, + 0x30, 0x00, 0x60, 0x00, 0x30, 0x00, 0xE0, 0x00, 0x38, 0x00, 0xC0, 0x00, 0x18, 0x00, 0xC0, 0x01, 0x1C, 0x00, 0x80, 0x07, 0x0F, + 0x00, 0x00, 0xFF, 0x07, 0x00, 0x00, 0xFC, 0x01, // 79 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0x60, 0x60, 0x00, 0x00, 0x60, + 0x60, 0x00, 0x00, 0x60, 0x60, 0x00, 0x00, 0x60, 0x60, 0x00, 0x00, 0x60, 0x60, 0x00, 0x00, 0x60, 0x60, 0x00, 0x00, 0x60, 0x60, + 0x00, 0x00, 0x60, 0x60, 0x00, 0x00, 0xC0, 0x30, 0x00, 0x00, 0xC0, 0x3F, 0x00, 0x00, 0x00, 0x0F, // 80 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x01, 0x00, 0x00, 0xFF, 0x07, 0x00, 0x80, 0x07, 0x0F, 0x00, 0xC0, 0x01, 0x0C, 0x00, 0xC0, + 0x00, 0x18, 0x00, 0xE0, 0x00, 0x18, 0x00, 0x60, 0x00, 0x30, 0x00, 0x60, 0x00, 0x30, 0x00, 0x60, 0x00, 0x30, 0x00, 0x60, 0x00, + 0x36, 0x00, 0x60, 0x00, 0x36, 0x00, 0xE0, 0x00, 0x3C, 0x00, 0xC0, 0x00, 0x1C, 0x00, 0xC0, 0x01, 0x1C, 0x00, 0x80, 0x07, 0x3F, + 0x00, 0x00, 0xFF, 0x77, 0x00, 0x00, 0xFC, 0x61, // 81 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0x60, 0x30, 0x00, 0x00, 0x60, + 0x30, 0x00, 0x00, 0x60, 0x30, 0x00, 0x00, 0x60, 0x30, 0x00, 0x00, 0x60, 0x70, 0x00, 0x00, 0x60, 0xF0, 0x00, 0x00, 0x60, 0xF0, + 0x03, 0x00, 0x60, 0xB0, 0x07, 0x00, 0xE0, 0x18, 0x1F, 0x00, 0xC0, 0x1F, 0x3C, 0x00, 0x80, 0x0F, 0x30, 0x00, 0x00, 0x00, + 0x20, // 82 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x07, 0x0F, 0x00, 0xC0, 0x1F, 0x1C, 0x00, 0xC0, 0x18, 0x18, 0x00, 0x60, + 0x38, 0x38, 0x00, 0x60, 0x30, 0x30, 0x00, 0x60, 0x30, 0x30, 0x00, 0x60, 0x30, 0x30, 0x00, 0x60, 0x30, 0x30, 0x00, 0x60, 0x70, + 0x30, 0x00, 0xC0, 0x60, 0x18, 0x00, 0xC0, 0xE1, 0x18, 0x00, 0x80, 0xC3, 0x0F, 0x00, 0x00, 0x83, 0x07, // 83 + 0x60, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x60, + 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0x60, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x60, 0x00, + 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x60, // 84 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x03, 0x00, 0xE0, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, + 0x00, 0x38, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x1C, 0x00, 0xE0, 0xFF, 0x0F, 0x00, 0xE0, 0xFF, 0x03, // 85 + 0x20, 0x00, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0xF8, 0x01, 0x00, 0x00, + 0xC0, 0x0F, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, 0xF8, + 0x01, 0x00, 0x00, 0x3E, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0x20, // 86 + 0x60, 0x00, 0x00, 0x00, 0xE0, 0x07, 0x00, 0x00, 0x80, 0xFF, 0x00, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, + 0x00, 0x30, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0xE0, 0x0F, 0x00, 0x00, 0xFC, 0x01, 0x00, 0x80, 0x1F, 0x00, 0x00, 0xE0, 0x03, + 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0xE0, 0x03, 0x00, 0x00, 0x80, 0x1F, 0x00, 0x00, 0x00, 0xFC, 0x01, 0x00, 0x00, 0xE0, 0x0F, + 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x80, 0xFF, 0x00, 0x00, + 0xE0, 0x07, 0x00, 0x00, 0x60, // 87 + 0x00, 0x00, 0x20, 0x00, 0x20, 0x00, 0x30, 0x00, 0x60, 0x00, 0x3C, 0x00, 0xE0, 0x01, 0x1E, 0x00, 0xC0, 0x83, 0x07, 0x00, 0x00, + 0xCF, 0x03, 0x00, 0x00, 0xFE, 0x01, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0xFE, 0x01, 0x00, 0x00, 0xCF, 0x03, 0x00, 0xC0, 0x03, + 0x07, 0x00, 0xE0, 0x01, 0x1E, 0x00, 0x60, 0x00, 0x3C, 0x00, 0x20, 0x00, 0x30, 0x00, 0x00, 0x00, 0x20, // 88 + 0x20, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x1E, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0xF0, 0x3F, 0x00, 0x00, 0xF0, 0x3F, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x1E, + 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x20, // 89 + 0x00, 0x00, 0x30, 0x00, 0x60, 0x00, 0x38, 0x00, 0x60, 0x00, 0x3C, 0x00, 0x60, 0x00, 0x37, 0x00, 0x60, 0x80, 0x33, 0x00, 0x60, + 0xC0, 0x31, 0x00, 0x60, 0xE0, 0x30, 0x00, 0x60, 0x38, 0x30, 0x00, 0x60, 0x1C, 0x30, 0x00, 0x60, 0x0E, 0x30, 0x00, 0x60, 0x07, + 0x30, 0x00, 0xE0, 0x01, 0x30, 0x00, 0xE0, 0x00, 0x30, 0x00, 0x60, 0x00, 0x30, // 90 + 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0x07, 0xE0, 0xFF, 0xFF, 0x07, 0x60, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0x06, // 91 + 0x60, 0x00, 0x00, 0x00, 0xE0, 0x03, 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0x00, 0xFC, 0x01, 0x00, 0x00, 0xE0, 0x0F, 0x00, 0x00, + 0x00, 0x3E, 0x00, 0x00, 0x00, 0x30, // 92 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0x06, 0xE0, 0xFF, 0xFF, 0x07, 0xE0, + 0xFF, 0xFF, 0x07, // 93 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0xC0, 0x07, 0x00, 0x00, 0xE0, + 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0xC0, 0x07, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, + 0x20, // 94 + 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, + 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, // 95 + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x80, // 96 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0E, 0x00, 0x00, 0x1C, 0x1F, 0x00, 0x00, 0x8C, 0x39, 0x00, 0x00, 0x86, 0x31, 0x00, 0x00, + 0x86, 0x31, 0x00, 0x00, 0xC6, 0x30, 0x00, 0x00, 0xC6, 0x18, 0x00, 0x00, 0xCE, 0x0C, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xF8, + 0x3F, 0x00, 0x00, 0x00, 0x20, // 97 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0x00, 0x18, 0x0C, 0x00, 0x00, + 0x0C, 0x18, 0x00, 0x00, 0x06, 0x30, 0x00, 0x00, 0x06, 0x30, 0x00, 0x00, 0x06, 0x30, 0x00, 0x00, 0x0E, 0x38, 0x00, 0x00, 0x1C, + 0x1C, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xE0, 0x03, // 98 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0x1C, 0x1C, 0x00, 0x00, 0x0E, 0x38, 0x00, 0x00, + 0x06, 0x30, 0x00, 0x00, 0x06, 0x30, 0x00, 0x00, 0x06, 0x30, 0x00, 0x00, 0x0E, 0x38, 0x00, 0x00, 0x1C, 0x1C, 0x00, 0x00, 0x18, + 0x0C, // 99 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x03, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0x1C, 0x1C, 0x00, 0x00, 0x0E, 0x38, 0x00, 0x00, + 0x06, 0x30, 0x00, 0x00, 0x06, 0x30, 0x00, 0x00, 0x06, 0x30, 0x00, 0x00, 0x0C, 0x18, 0x00, 0x00, 0x18, 0x0C, 0x00, 0xE0, 0xFF, + 0x3F, 0x00, 0xE0, 0xFF, 0x3F, // 100 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x07, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xDC, 0x1C, 0x00, 0x00, 0xCE, 0x38, 0x00, 0x00, + 0xC6, 0x30, 0x00, 0x00, 0xC6, 0x30, 0x00, 0x00, 0xC6, 0x30, 0x00, 0x00, 0xCE, 0x38, 0x00, 0x00, 0xDC, 0x18, 0x00, 0x00, 0xF8, + 0x0C, 0x00, 0x00, 0xF0, 0x04, // 101 + 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0xC0, 0xFF, 0x3F, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0x60, 0x06, 0x00, 0x00, 0x60, + 0x06, 0x00, 0x00, 0x60, 0x06, // 102 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x83, 0x01, 0x00, 0xF8, 0x8F, 0x03, 0x00, 0x1C, 0x1C, 0x07, 0x00, 0x0E, 0x38, 0x06, 0x00, + 0x06, 0x30, 0x06, 0x00, 0x06, 0x30, 0x06, 0x00, 0x06, 0x30, 0x06, 0x00, 0x0C, 0x18, 0x07, 0x00, 0x18, 0x8C, 0x03, 0x00, 0xFE, + 0xFF, 0x01, 0x00, 0xFE, 0xFF, // 103 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x0C, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0xFC, + 0x3F, 0x00, 0x00, 0xF8, 0x3F, // 104 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xFE, 0x3F, 0x00, 0x60, 0xFE, 0x3F, // 105 + 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x60, 0xFE, 0xFF, 0x07, 0x60, 0xFE, 0xFF, 0x03, // 106 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, + 0xE0, 0x00, 0x00, 0x00, 0xF0, 0x01, 0x00, 0x00, 0x98, 0x07, 0x00, 0x00, 0x0C, 0x0E, 0x00, 0x00, 0x06, 0x3C, 0x00, 0x00, 0x02, + 0x30, 0x00, 0x00, 0x00, 0x20, // 107 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0xE0, 0xFF, 0x3F, // 108 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0xFC, 0x3F, 0x00, 0x00, 0xF8, + 0x3F, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0E, 0x00, + 0x00, 0x00, 0xFC, 0x3F, 0x00, 0x00, 0xF8, 0x3F, // 109 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x0C, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0xFC, + 0x3F, 0x00, 0x00, 0xF8, 0x3F, // 110 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0x1C, 0x1C, 0x00, 0x00, 0x0E, 0x38, 0x00, 0x00, + 0x06, 0x30, 0x00, 0x00, 0x06, 0x30, 0x00, 0x00, 0x06, 0x30, 0x00, 0x00, 0x0E, 0x38, 0x00, 0x00, 0x1C, 0x1C, 0x00, 0x00, 0xF8, + 0x0F, 0x00, 0x00, 0xF0, 0x07, // 111 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x07, 0x00, 0xFE, 0xFF, 0x07, 0x00, 0x18, 0x0C, 0x00, 0x00, + 0x0C, 0x18, 0x00, 0x00, 0x06, 0x30, 0x00, 0x00, 0x06, 0x30, 0x00, 0x00, 0x06, 0x30, 0x00, 0x00, 0x0E, 0x38, 0x00, 0x00, 0x1C, + 0x1C, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xE0, 0x03, // 112 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x03, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0x1C, 0x1C, 0x00, 0x00, 0x0E, 0x38, 0x00, 0x00, + 0x06, 0x30, 0x00, 0x00, 0x06, 0x30, 0x00, 0x00, 0x06, 0x30, 0x00, 0x00, 0x0C, 0x18, 0x00, 0x00, 0x18, 0x0C, 0x00, 0x00, 0xFE, + 0xFF, 0x07, 0x00, 0xFE, 0xFF, 0x07, // 113 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, // 114 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x0C, 0x00, 0x00, 0x7C, 0x1C, 0x00, 0x00, 0xEE, 0x38, 0x00, 0x00, 0xC6, 0x30, 0x00, 0x00, + 0xC6, 0x30, 0x00, 0x00, 0xC6, 0x31, 0x00, 0x00, 0xC6, 0x31, 0x00, 0x00, 0x8E, 0x39, 0x00, 0x00, 0x9C, 0x1F, 0x00, 0x00, 0x18, + 0x0F, // 115 + 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0xC0, 0xFF, 0x1F, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0x00, 0x06, 0x30, 0x00, 0x00, + 0x06, 0x30, 0x00, 0x00, 0x06, 0x30, // 116 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x0F, 0x00, 0x00, 0xFE, 0x1F, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, + 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0xFE, + 0x3F, 0x00, 0x00, 0xFE, 0x3F, // 117 + 0x00, 0x06, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0xC0, 0x07, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, + 0x00, 0x38, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0xC0, 0x07, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, + 0x06, // 118 + 0x00, 0x0E, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0xF0, 0x03, 0x00, 0x00, 0x80, 0x1F, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, + 0x80, 0x1F, 0x00, 0x00, 0xE0, 0x03, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0xE0, + 0x03, 0x00, 0x00, 0x80, 0x1F, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x80, 0x1F, 0x00, 0x00, 0xF0, 0x03, 0x00, 0x00, 0x7E, 0x00, + 0x00, 0x00, 0x0E, // 119 + 0x00, 0x02, 0x20, 0x00, 0x00, 0x06, 0x30, 0x00, 0x00, 0x1E, 0x3C, 0x00, 0x00, 0x38, 0x0E, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, + 0xC0, 0x01, 0x00, 0x00, 0xE0, 0x07, 0x00, 0x00, 0x38, 0x0E, 0x00, 0x00, 0x1C, 0x3C, 0x00, 0x00, 0x0E, 0x30, 0x00, 0x00, 0x02, + 0x20, // 120 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x06, 0x00, 0xF0, 0x01, 0x06, 0x00, 0x80, 0x0F, 0x07, 0x00, + 0x00, 0xFE, 0x03, 0x00, 0x00, 0xFC, 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x00, 0xF8, 0x03, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, + 0x06, // 121 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x06, 0x3C, 0x00, 0x00, 0x06, 0x3E, 0x00, 0x00, 0x06, 0x37, 0x00, 0x00, + 0xC6, 0x33, 0x00, 0x00, 0xE6, 0x30, 0x00, 0x00, 0x76, 0x30, 0x00, 0x00, 0x3E, 0x30, 0x00, 0x00, 0x1E, 0x30, 0x00, 0x00, 0x06, + 0x30, // 122 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xC0, 0x03, 0x00, 0xC0, 0x7F, 0xFE, 0x03, 0xE0, 0x3F, 0xFC, 0x07, 0x60, + 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0x06, // 123 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0x0F, 0xE0, 0xFF, 0xFF, 0x0F, // 124 + 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0x06, 0xE0, 0x3F, 0xFC, 0x07, 0xC0, 0x7F, 0xFF, 0x03, 0x00, + 0xC0, 0x03, 0x00, 0x00, 0x80, 0x01, // 125 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, + 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x60, // 126 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x01, 0x00, 0x00, 0xFF, 0x07, 0x00, 0x80, 0x07, 0x0F, 0x00, 0xC0, 0x01, 0x1C, 0x00, 0xC0, + 0x00, 0x18, 0x00, 0x62, 0x00, 0x30, 0x00, 0x66, 0x00, 0x30, 0x00, 0x6C, 0x00, 0x30, 0x00, 0x6C, 0x00, 0x30, 0x00, 0x66, 0x00, + 0x30, 0x00, 0x62, 0x00, 0x30, 0x00, 0xC0, 0x00, 0x18, 0x00, 0xC0, 0x01, 0x1C, 0x00, 0x80, 0x03, 0x0F, 0x00, 0x00, 0x02, + 0x03, // 129 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0x60, 0x00, 0x30, 0x00, 0x60, + 0x00, 0x30, 0x00, 0x62, 0x00, 0x30, 0x00, 0x66, 0x00, 0x30, 0x00, 0x6C, 0x00, 0x30, 0x00, 0x6C, 0x00, 0x30, 0x00, 0x66, 0x00, + 0x30, 0x00, 0xE2, 0x00, 0x18, 0x00, 0xC0, 0x01, 0x1C, 0x00, 0x80, 0x03, 0x0E, 0x00, 0x00, 0xFF, 0x07, 0x00, 0x00, 0xFC, + 0x01, // 130 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0x60, 0x30, 0x30, 0x00, 0x60, + 0x30, 0x30, 0x00, 0x62, 0x30, 0x30, 0x00, 0x66, 0x30, 0x30, 0x00, 0x6C, 0x30, 0x30, 0x00, 0x6C, 0x30, 0x30, 0x00, 0x66, 0x30, + 0x30, 0x00, 0x62, 0x30, 0x30, 0x00, 0x60, 0x30, 0x30, 0x00, 0x60, 0x30, 0x30, 0x00, 0x60, 0x00, 0x30, // 131 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x80, + 0x03, 0x00, 0x00, 0x02, 0x0E, 0x00, 0x00, 0x06, 0x3C, 0x00, 0x00, 0x0C, 0x70, 0x00, 0x00, 0x0C, 0xE0, 0x01, 0x00, 0x06, 0x80, + 0x03, 0x00, 0x02, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x1C, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0xE0, 0xFF, 0x3F, // 132 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0x60, 0x30, 0x00, 0x00, 0x60, + 0x30, 0x00, 0x00, 0x62, 0x30, 0x00, 0x00, 0x66, 0x30, 0x00, 0x00, 0x6C, 0x70, 0x00, 0x00, 0x6C, 0xF0, 0x00, 0x00, 0x66, 0xF0, + 0x03, 0x00, 0x62, 0xB0, 0x07, 0x00, 0xE0, 0x18, 0x1F, 0x00, 0xC0, 0x1F, 0x3C, 0x00, 0x80, 0x0F, 0x30, 0x00, 0x00, 0x00, + 0x20, // 133 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x07, 0x0F, 0x00, 0xC0, 0x1F, 0x1C, 0x00, 0xC0, 0x18, 0x18, 0x00, 0x62, + 0x38, 0x38, 0x00, 0x66, 0x30, 0x30, 0x00, 0x6C, 0x30, 0x30, 0x00, 0x6C, 0x30, 0x30, 0x00, 0x66, 0x30, 0x30, 0x00, 0x62, 0x70, + 0x30, 0x00, 0xC0, 0x60, 0x18, 0x00, 0xC0, 0xE1, 0x18, 0x00, 0x80, 0xC3, 0x0F, 0x00, 0x00, 0x83, 0x07, // 134 + 0x60, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x66, + 0x00, 0x00, 0x00, 0xEC, 0xFF, 0x3F, 0x00, 0xEC, 0xFF, 0x3F, 0x00, 0x66, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x60, 0x00, + 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x60, // 135 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x03, 0x00, 0xE0, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, + 0x00, 0x38, 0x00, 0x0E, 0x00, 0x30, 0x00, 0x1B, 0x00, 0x30, 0x00, 0x11, 0x00, 0x30, 0x00, 0x1B, 0x00, 0x30, 0x00, 0x0E, 0x00, + 0x30, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x1C, 0x00, 0xE0, 0xFF, 0x0F, 0x00, 0xE0, 0xFF, 0x03, // 136 + 0x00, 0x00, 0x30, 0x00, 0x60, 0x00, 0x38, 0x00, 0x60, 0x00, 0x3C, 0x00, 0x60, 0x00, 0x37, 0x00, 0x60, 0x80, 0x33, 0x00, 0x62, + 0xC0, 0x31, 0x00, 0x66, 0xE0, 0x30, 0x00, 0x6C, 0x38, 0x30, 0x00, 0x6C, 0x1C, 0x30, 0x00, 0x66, 0x0E, 0x30, 0x00, 0x62, 0x07, + 0x30, 0x00, 0xE0, 0x01, 0x30, 0x00, 0xE0, 0x00, 0x30, 0x00, 0x60, 0x00, 0x30, // 137 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0x1C, 0x1C, 0x00, 0x20, 0x0E, 0x38, 0x00, 0x60, + 0x06, 0x30, 0x00, 0xC0, 0x06, 0x30, 0x00, 0xC0, 0x06, 0x30, 0x00, 0x60, 0x0E, 0x38, 0x00, 0x20, 0x1C, 0x1C, 0x00, 0x00, 0x18, + 0x0C, // 138 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x03, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0x1C, 0x1C, 0x00, 0x00, 0x0E, 0x38, 0x00, 0x00, + 0x06, 0x30, 0x00, 0x00, 0x06, 0x30, 0x00, 0x00, 0x06, 0x30, 0x00, 0x00, 0x0C, 0x18, 0x00, 0x00, 0x18, 0x0C, 0x00, 0xE0, 0xFF, + 0x3F, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x03, 0x00, 0x00, 0xE0, 0x01, // 139 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x07, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xDC, 0x1C, 0x00, 0x20, 0xCE, 0x38, 0x00, 0x60, + 0xC6, 0x30, 0x00, 0xC0, 0xC6, 0x30, 0x00, 0xC0, 0xC6, 0x30, 0x00, 0x60, 0xCE, 0x38, 0x00, 0x20, 0xDC, 0x18, 0x00, 0x00, 0xF8, + 0x0C, 0x00, 0x00, 0xF0, 0x04, // 140 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x20, 0x18, 0x00, 0x00, 0x60, + 0x0C, 0x00, 0x00, 0xC0, 0x06, 0x00, 0x00, 0xC0, 0x06, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00, 0x20, 0x0E, 0x00, 0x00, 0x00, 0xFC, + 0x3F, 0x00, 0x00, 0xF8, 0x3F, // 141 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xFE, 0x3F, 0x00, 0x60, 0xFE, 0x3F, 0x00, 0xC0, 0x0C, 0x00, 0x00, 0xC0, + 0x06, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00, 0x20, 0x06, // 142 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x0C, 0x00, 0x00, 0x7C, 0x1C, 0x00, 0x20, 0xEE, 0x38, 0x00, 0x60, 0xC6, 0x30, 0x00, 0xC0, + 0xC6, 0x30, 0x00, 0xC0, 0xC6, 0x31, 0x00, 0x60, 0xC6, 0x31, 0x00, 0x20, 0x8E, 0x39, 0x00, 0x00, 0x9C, 0x1F, 0x00, 0x00, 0x18, + 0x0F, // 143 + 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0xC0, 0xFF, 0x1F, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0x00, 0x06, 0x30, 0x00, 0x00, + 0x06, 0x30, 0x00, 0x00, 0x06, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x03, 0x00, 0x00, 0xE0, 0x01, // 144 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x0F, 0x00, 0x00, 0xFE, 0x1F, 0x00, 0x00, 0x00, 0x38, 0x00, 0x70, + 0x00, 0x30, 0x00, 0xD8, 0x00, 0x30, 0x00, 0x88, 0x00, 0x30, 0x00, 0xD8, 0x00, 0x18, 0x00, 0x70, 0x00, 0x0C, 0x00, 0x00, 0xFE, + 0x3F, 0x00, 0x00, 0xFE, 0x3F, // 145 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x06, 0x3C, 0x00, 0x00, 0x06, 0x3E, 0x00, 0x20, 0x06, 0x37, 0x00, 0x60, + 0xC6, 0x33, 0x00, 0xC0, 0xE6, 0x30, 0x00, 0xC0, 0x76, 0x30, 0x00, 0x60, 0x3E, 0x30, 0x00, 0x20, 0x1E, 0x30, 0x00, 0x00, 0x06, + 0x30, // 146 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0xE8, 0xFF, 0x3F, 0x00, 0x0E, 0x00, 0x30, 0x00, 0x06, + 0x00, 0x30, 0x00, 0x02, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x00, 0x30, // 147 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE8, 0xFF, 0x3F, 0x00, 0xEE, 0xFF, 0x3F, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x02, // 148 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, + 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x60, 0x03, 0x30, 0x00, 0xE0, 0x01, + 0x30, 0x00, 0x00, 0x00, 0x30, // 149 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, + 0x03, 0x00, 0x00, 0xE0, 0x01, // 150 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0x60, 0x30, 0x00, 0x00, 0x60, + 0x30, 0x00, 0x00, 0x60, 0x30, 0x00, 0x00, 0x60, 0x30, 0x00, 0x00, 0x68, 0x70, 0x00, 0x00, 0x6E, 0xF0, 0x00, 0x00, 0x66, 0xF0, + 0x03, 0x00, 0x62, 0xB0, 0x07, 0x00, 0xE0, 0x18, 0x1F, 0x00, 0xC0, 0x1F, 0x3C, 0x00, 0x80, 0x0F, 0x30, 0x00, 0x00, 0x00, + 0x20, // 151 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x80, 0x0C, 0x00, 0x00, 0xE0, + 0x06, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00, 0x20, 0x06, // 152 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xFF, 0x07, 0x00, 0xE6, 0xFF, 0x07, // 161 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x07, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0x1C, 0x9C, 0x07, 0x00, 0x0E, 0x78, 0x00, 0x00, + 0x06, 0x3F, 0x00, 0x00, 0xF6, 0x30, 0x00, 0x00, 0x0E, 0x30, 0x00, 0xE0, 0x0D, 0x1C, 0x00, 0x00, 0x1C, 0x0E, 0x00, 0x00, 0x10, + 0x06, // 162 + 0x00, 0x60, 0x10, 0x00, 0x00, 0x60, 0x38, 0x00, 0x00, 0x7F, 0x1C, 0x00, 0xC0, 0xFF, 0x1F, 0x00, 0xE0, 0xE0, 0x19, 0x00, 0x60, + 0x60, 0x18, 0x00, 0x60, 0x60, 0x18, 0x00, 0x60, 0x60, 0x30, 0x00, 0xE0, 0x00, 0x30, 0x00, 0xC0, 0x01, 0x30, 0x00, 0x80, 0x01, + 0x38, 0x00, 0x00, 0x00, 0x10, // 163 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x04, 0x00, 0x00, 0xF7, 0x0E, 0x00, 0x00, 0xFE, 0x07, 0x00, 0x00, 0x0C, 0x03, 0x00, 0x00, + 0x06, 0x06, 0x00, 0x00, 0x06, 0x06, 0x00, 0x00, 0x06, 0x06, 0x00, 0x00, 0x06, 0x06, 0x00, 0x00, 0x0C, 0x03, 0x00, 0x00, 0xFE, + 0x07, 0x00, 0x00, 0xF7, 0x0E, 0x00, 0x00, 0x02, 0x04, // 164 + 0xE0, 0x60, 0x06, 0x00, 0xC0, 0x61, 0x06, 0x00, 0x80, 0x67, 0x06, 0x00, 0x00, 0x7E, 0x06, 0x00, 0x00, 0x7C, 0x06, 0x00, 0x00, + 0xF0, 0x3F, 0x00, 0x00, 0xF0, 0x3F, 0x00, 0x00, 0x7C, 0x06, 0x00, 0x00, 0x7E, 0x06, 0x00, 0x80, 0x67, 0x06, 0x00, 0xC0, 0x61, + 0x06, 0x00, 0xE0, 0x60, 0x06, 0x00, 0x20, // 165 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x7F, 0xF8, 0x0F, 0xE0, 0x7F, 0xF8, 0x0F, // 166 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x80, 0xF3, 0xC1, 0x00, 0xC0, 0x1F, 0xC3, 0x03, 0xE0, 0x0C, 0x07, 0x03, 0x60, + 0x1C, 0x06, 0x06, 0x60, 0x18, 0x0C, 0x06, 0x60, 0x30, 0x1C, 0x06, 0xE0, 0x70, 0x38, 0x07, 0xC0, 0xE1, 0xF4, 0x03, 0x80, 0xC1, + 0xE7, 0x01, 0x00, 0x80, 0x03, // 167 + 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, + 0x00, 0x00, 0x00, 0x60, // 168 + 0x00, 0xF8, 0x00, 0x00, 0x00, 0xFE, 0x03, 0x00, 0x00, 0x07, 0x07, 0x00, 0x80, 0x01, 0x0C, 0x00, 0xC0, 0x79, 0x1C, 0x00, 0xC0, + 0xFE, 0x19, 0x00, 0x60, 0x86, 0x31, 0x00, 0x60, 0x03, 0x33, 0x00, 0x60, 0x03, 0x33, 0x00, 0x60, 0x03, 0x33, 0x00, 0x60, 0x03, + 0x33, 0x00, 0x60, 0x87, 0x33, 0x00, 0xC0, 0x86, 0x19, 0x00, 0xC0, 0x85, 0x1C, 0x00, 0x80, 0x01, 0x0C, 0x00, 0x00, 0x07, 0x07, + 0x00, 0x00, 0xFE, 0x03, 0x00, 0x00, 0xF8, // 169 + 0x00, 0x00, 0x00, 0x00, 0xC0, 0x1C, 0x00, 0x00, 0xE0, 0x3E, 0x00, 0x00, 0x60, 0x32, 0x00, 0x00, 0x60, 0x32, 0x00, 0x00, 0xE0, + 0x3F, 0x00, 0x00, 0xC0, 0x3F, // 170 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xE0, 0x03, 0x00, 0x00, 0x78, 0x0F, 0x00, 0x00, 0x1C, 0x1C, 0x00, 0x00, + 0x84, 0x10, 0x00, 0x00, 0xE0, 0x03, 0x00, 0x00, 0x78, 0x0F, 0x00, 0x00, 0x1C, 0x1C, 0x00, 0x00, 0x04, 0x10, // 171 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, + 0x0C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0xFC, + 0x01, 0x00, 0x00, 0xFC, 0x01, // 172 + 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, + 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, // 173 + 0x00, 0xF8, 0x00, 0x00, 0x00, 0xFE, 0x03, 0x00, 0x00, 0x07, 0x07, 0x00, 0x80, 0x01, 0x0C, 0x00, 0xC0, 0x01, 0x1C, 0x00, 0xC0, + 0xFE, 0x1B, 0x00, 0x60, 0xFE, 0x33, 0x00, 0x60, 0x66, 0x30, 0x00, 0x60, 0x66, 0x30, 0x00, 0x60, 0xE6, 0x30, 0x00, 0x60, 0xFE, + 0x31, 0x00, 0x60, 0x3C, 0x33, 0x00, 0xC0, 0x00, 0x1A, 0x00, 0xC0, 0x01, 0x1C, 0x00, 0x80, 0x01, 0x0C, 0x00, 0x00, 0x07, 0x07, + 0x00, 0x00, 0xFE, 0x03, 0x00, 0x00, 0xF8, // 174 + 0x0C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0C, + 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0C, 0x00, + 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0C, // 175 + 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x40, 0x04, 0x00, 0x00, 0x20, 0x08, 0x00, 0x00, 0x20, 0x08, 0x00, 0x00, 0x20, + 0x08, 0x00, 0x00, 0x40, 0x04, 0x00, 0x00, 0x80, 0x03, // 176 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x00, 0x00, 0x60, 0x30, 0x00, 0x00, 0x60, 0x30, 0x00, 0x00, 0x60, 0x30, 0x00, 0x00, + 0x60, 0x30, 0x00, 0x00, 0xFF, 0x3F, 0x00, 0x00, 0xFF, 0x3F, 0x00, 0x00, 0x60, 0x30, 0x00, 0x00, 0x60, 0x30, 0x00, 0x00, 0x60, + 0x30, 0x00, 0x00, 0x60, 0x30, 0x00, 0x00, 0x60, 0x30, // 177 + 0x40, 0x20, 0x00, 0x00, 0x60, 0x30, 0x00, 0x00, 0x20, 0x38, 0x00, 0x00, 0x20, 0x2C, 0x00, 0x00, 0x20, 0x26, 0x00, 0x00, 0xE0, + 0x23, 0x00, 0x00, 0xC0, 0x21, // 178 + 0x40, 0x10, 0x00, 0x00, 0x60, 0x30, 0x00, 0x00, 0x20, 0x20, 0x00, 0x00, 0x20, 0x22, 0x00, 0x00, 0x20, 0x22, 0x00, 0x00, 0xE0, + 0x3D, 0x00, 0x00, 0xC0, 0x1D, // 179 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x60, + 0x00, 0x00, 0x00, 0x20, // 180 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x07, 0x00, 0xFE, 0xFF, 0x07, 0x00, 0x00, 0x1C, 0x00, 0x00, + 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0xFE, + 0x3F, 0x00, 0x00, 0xFE, 0x3F, // 181 + 0x00, 0x0F, 0x00, 0x00, 0xC0, 0x3F, 0x00, 0x00, 0xC0, 0x3F, 0x00, 0x00, 0xE0, 0x7F, 0x00, 0x00, 0xE0, 0x7F, 0x00, 0x00, 0xE0, + 0xFF, 0xFF, 0x07, 0xE0, 0xFF, 0xFF, 0x07, 0x60, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0x07, 0xE0, 0xFF, + 0xFF, 0x07, 0x60, 0x00, 0x00, 0x00, 0x60, // 182 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x60, // 183 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0xC0, 0x02, 0x00, 0x00, 0x80, 0x03, 0x00, + 0x00, 0x00, 0x01, // 184 + 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xE0, 0x3F, 0x00, 0x00, 0xE0, + 0x3F, // 185 + 0x00, 0x00, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x00, 0xE0, 0x38, 0x00, 0x00, 0x60, 0x30, 0x00, 0x00, 0xE0, + 0x38, 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x00, 0x80, 0x0F, // 186 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x10, 0x00, 0x00, 0x1C, 0x1C, 0x00, 0x00, + 0x78, 0x0F, 0x00, 0x00, 0xE0, 0x03, 0x00, 0x00, 0x84, 0x10, 0x00, 0x00, 0x1C, 0x1C, 0x00, 0x00, 0x78, 0x0F, 0x00, 0x00, 0xE0, + 0x03, 0x00, 0x00, 0x80, // 187 + 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x20, 0x00, 0xE0, 0x3F, 0x38, 0x00, 0xE0, + 0x3F, 0x1C, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x38, + 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x07, 0x0C, 0x00, 0xC0, 0x01, 0x0E, 0x00, 0xE0, 0x80, 0x0B, + 0x00, 0x60, 0xC0, 0x08, 0x00, 0x00, 0xE0, 0x3F, 0x00, 0x00, 0xE0, 0x3F, 0x00, 0x00, 0x00, 0x08, // 188 + 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x20, 0x00, 0xE0, 0x3F, 0x30, 0x00, 0xE0, + 0x3F, 0x1C, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x4E, 0x20, 0x00, 0x00, 0x67, 0x30, 0x00, 0xC0, 0x21, 0x38, 0x00, 0xE0, 0x20, 0x2C, + 0x00, 0x60, 0x20, 0x26, 0x00, 0x00, 0xE0, 0x27, 0x00, 0x00, 0xC0, 0x21, // 189 + 0x40, 0x10, 0x00, 0x00, 0x60, 0x30, 0x00, 0x00, 0x20, 0x20, 0x00, 0x00, 0x20, 0x22, 0x20, 0x00, 0x20, 0x22, 0x30, 0x00, 0xE0, + 0x3D, 0x38, 0x00, 0xC0, 0x1D, 0x0E, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x0E, 0x0C, 0x00, 0x00, 0x07, 0x0E, 0x00, 0x80, 0x83, 0x0B, 0x00, 0xE0, 0xC0, 0x08, + 0x00, 0x60, 0xE0, 0x3F, 0x00, 0x20, 0xE0, 0x3F, 0x00, 0x00, 0x00, 0x08, // 190 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0xF8, 0x03, 0x00, 0x00, 0x1E, 0x03, 0x00, + 0x00, 0x07, 0x07, 0x00, 0xE6, 0x03, 0x06, 0x00, 0xE6, 0x01, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, + 0x80, 0x03, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0xC0, // 191 + 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x00, 0xF0, 0x03, 0x00, 0x00, 0xFE, 0x01, 0x00, 0x82, + 0x8F, 0x01, 0x00, 0xE6, 0x83, 0x01, 0x00, 0x6E, 0x80, 0x01, 0x00, 0xE8, 0x83, 0x01, 0x00, 0x80, 0x8F, 0x01, 0x00, 0x00, 0xFE, + 0x01, 0x00, 0x00, 0xF0, 0x03, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x30, // 192 + 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x00, 0xF0, 0x03, 0x00, 0x00, 0xFE, 0x01, 0x00, 0x80, + 0x8F, 0x01, 0x00, 0xE8, 0x83, 0x01, 0x00, 0x6E, 0x80, 0x01, 0x00, 0xE6, 0x83, 0x01, 0x00, 0x82, 0x8F, 0x01, 0x00, 0x00, 0xFE, + 0x01, 0x00, 0x00, 0xF0, 0x03, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x30, // 193 + 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x00, 0xF0, 0x03, 0x00, 0x00, 0xFE, 0x01, 0x00, 0x88, + 0x8F, 0x01, 0x00, 0xEC, 0x83, 0x01, 0x00, 0x66, 0x80, 0x01, 0x00, 0xE6, 0x83, 0x01, 0x00, 0x8C, 0x8F, 0x01, 0x00, 0x08, 0xFE, + 0x01, 0x00, 0x00, 0xF0, 0x03, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x30, // 194 + 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x00, 0xF0, 0x03, 0x00, 0x0C, 0xFE, 0x01, 0x00, 0x8E, + 0x8F, 0x01, 0x00, 0xE6, 0x83, 0x01, 0x00, 0x66, 0x80, 0x01, 0x00, 0xEC, 0x83, 0x01, 0x00, 0x8C, 0x8F, 0x01, 0x00, 0x0E, 0xFE, + 0x01, 0x00, 0x06, 0xF0, 0x03, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x30, // 195 + 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x00, 0xF0, 0x03, 0x00, 0x00, 0xFE, 0x01, 0x00, 0x8C, + 0x8F, 0x01, 0x00, 0xEC, 0x83, 0x01, 0x00, 0x60, 0x80, 0x01, 0x00, 0xE0, 0x83, 0x01, 0x00, 0x8C, 0x8F, 0x01, 0x00, 0x0C, 0xFE, + 0x01, 0x00, 0x00, 0xF0, 0x03, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x30, // 196 + 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x00, 0xF0, 0x03, 0x00, 0x00, 0xFE, 0x01, 0x00, 0x9C, + 0x8F, 0x01, 0x00, 0xE2, 0x83, 0x01, 0x00, 0x62, 0x80, 0x01, 0x00, 0xE2, 0x83, 0x01, 0x00, 0x9C, 0x8F, 0x01, 0x00, 0x00, 0xFE, + 0x01, 0x00, 0x00, 0xF0, 0x03, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x30, // 197 + 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0xF0, 0x01, 0x00, 0x00, + 0xBC, 0x01, 0x00, 0x00, 0x8F, 0x01, 0x00, 0xC0, 0x83, 0x01, 0x00, 0xE0, 0x80, 0x01, 0x00, 0x60, 0x80, 0x01, 0x00, 0x60, 0x80, + 0x01, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0x60, 0x30, 0x30, 0x00, 0x60, 0x30, 0x30, 0x00, 0x60, 0x30, 0x30, + 0x00, 0x60, 0x30, 0x30, 0x00, 0x60, 0x30, 0x30, 0x00, 0x60, 0x30, 0x30, 0x00, 0x60, 0x30, 0x30, 0x00, 0x60, 0x30, 0x30, 0x00, + 0x60, 0x30, 0x30, 0x00, 0x60, 0x00, 0x30, // 198 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x01, 0x00, 0x00, 0xFF, 0x07, 0x00, 0x80, 0x07, 0x0F, 0x00, 0xC0, 0x01, 0x1C, 0x00, 0xC0, + 0x00, 0x18, 0x00, 0x60, 0x00, 0x30, 0x02, 0x60, 0x00, 0x30, 0x02, 0x60, 0x00, 0xF0, 0x02, 0x60, 0x00, 0xB0, 0x03, 0x60, 0x00, + 0x30, 0x01, 0x60, 0x00, 0x30, 0x00, 0xC0, 0x00, 0x18, 0x00, 0xC0, 0x01, 0x1C, 0x00, 0x80, 0x03, 0x0F, 0x00, 0x00, 0x02, + 0x03, // 199 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0x60, 0x30, 0x30, 0x00, 0x60, + 0x30, 0x30, 0x00, 0x62, 0x30, 0x30, 0x00, 0x66, 0x30, 0x30, 0x00, 0x6E, 0x30, 0x30, 0x00, 0x68, 0x30, 0x30, 0x00, 0x60, 0x30, + 0x30, 0x00, 0x60, 0x30, 0x30, 0x00, 0x60, 0x30, 0x30, 0x00, 0x60, 0x30, 0x30, 0x00, 0x60, 0x00, 0x30, // 200 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0x60, 0x30, 0x30, 0x00, 0x60, + 0x30, 0x30, 0x00, 0x60, 0x30, 0x30, 0x00, 0x68, 0x30, 0x30, 0x00, 0x6E, 0x30, 0x30, 0x00, 0x66, 0x30, 0x30, 0x00, 0x62, 0x30, + 0x30, 0x00, 0x60, 0x30, 0x30, 0x00, 0x60, 0x30, 0x30, 0x00, 0x60, 0x30, 0x30, 0x00, 0x60, 0x00, 0x30, // 201 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0x60, 0x30, 0x30, 0x00, 0x60, + 0x30, 0x30, 0x00, 0x68, 0x30, 0x30, 0x00, 0x6C, 0x30, 0x30, 0x00, 0x66, 0x30, 0x30, 0x00, 0x66, 0x30, 0x30, 0x00, 0x6C, 0x30, + 0x30, 0x00, 0x68, 0x30, 0x30, 0x00, 0x60, 0x30, 0x30, 0x00, 0x60, 0x30, 0x30, 0x00, 0x60, 0x00, 0x30, // 202 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0x60, 0x30, 0x30, 0x00, 0x60, + 0x30, 0x30, 0x00, 0x6C, 0x30, 0x30, 0x00, 0x6C, 0x30, 0x30, 0x00, 0x60, 0x30, 0x30, 0x00, 0x60, 0x30, 0x30, 0x00, 0x6C, 0x30, + 0x30, 0x00, 0x6C, 0x30, 0x30, 0x00, 0x60, 0x30, 0x30, 0x00, 0x60, 0x30, 0x30, 0x00, 0x60, 0x00, 0x30, // 203 + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xE6, 0xFF, 0x3F, 0x00, 0xEE, 0xFF, 0x3F, 0x00, 0x08, // 204 + 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xEE, 0xFF, 0x3F, 0x00, 0xE6, 0xFF, 0x3F, 0x00, 0x02, // 205 + 0x08, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0xE6, 0xFF, 0x3F, 0x00, 0xE6, 0xFF, 0x3F, 0x00, 0x0C, 0x00, 0x00, 0x00, + 0x08, // 206 + 0x0C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0x0C, 0x00, 0x00, 0x00, + 0x0C, // 207 + 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0x60, 0x30, 0x30, 0x00, 0x60, + 0x30, 0x30, 0x00, 0x60, 0x30, 0x30, 0x00, 0x60, 0x30, 0x30, 0x00, 0x60, 0x30, 0x30, 0x00, 0x60, 0x00, 0x30, 0x00, 0x60, 0x00, + 0x30, 0x00, 0xE0, 0x00, 0x18, 0x00, 0xC0, 0x01, 0x1C, 0x00, 0x80, 0x03, 0x0E, 0x00, 0x00, 0xFF, 0x07, 0x00, 0x00, 0xFC, + 0x01, // 208 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x8C, + 0x03, 0x00, 0x00, 0x0E, 0x0E, 0x00, 0x00, 0x06, 0x3C, 0x00, 0x00, 0x06, 0x70, 0x00, 0x00, 0x0C, 0xE0, 0x01, 0x00, 0x0C, 0x80, + 0x03, 0x00, 0x0E, 0x00, 0x0F, 0x00, 0x06, 0x00, 0x1C, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0xE0, 0xFF, 0x3F, // 209 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x01, 0x00, 0x00, 0xFF, 0x07, 0x00, 0x80, 0x07, 0x0F, 0x00, 0xC0, 0x01, 0x1C, 0x00, 0xC0, + 0x00, 0x18, 0x00, 0xE0, 0x00, 0x38, 0x00, 0x62, 0x00, 0x30, 0x00, 0x66, 0x00, 0x30, 0x00, 0x6E, 0x00, 0x30, 0x00, 0x68, 0x00, + 0x30, 0x00, 0x60, 0x00, 0x30, 0x00, 0xE0, 0x00, 0x38, 0x00, 0xC0, 0x00, 0x18, 0x00, 0xC0, 0x01, 0x1C, 0x00, 0x80, 0x07, 0x0F, + 0x00, 0x00, 0xFF, 0x07, 0x00, 0x00, 0xFC, 0x01, // 210 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x01, 0x00, 0x00, 0xFF, 0x07, 0x00, 0x80, 0x07, 0x0F, 0x00, 0xC0, 0x01, 0x1C, 0x00, 0xC0, + 0x00, 0x18, 0x00, 0xE0, 0x00, 0x38, 0x00, 0x60, 0x00, 0x30, 0x00, 0x68, 0x00, 0x30, 0x00, 0x6E, 0x00, 0x30, 0x00, 0x66, 0x00, + 0x30, 0x00, 0x62, 0x00, 0x30, 0x00, 0xE0, 0x00, 0x38, 0x00, 0xC0, 0x00, 0x18, 0x00, 0xC0, 0x01, 0x1C, 0x00, 0x80, 0x07, 0x0F, + 0x00, 0x00, 0xFF, 0x07, 0x00, 0x00, 0xFC, 0x01, // 211 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x01, 0x00, 0x00, 0xFF, 0x07, 0x00, 0x80, 0x07, 0x0F, 0x00, 0xC0, 0x01, 0x1C, 0x00, 0xC0, + 0x00, 0x18, 0x00, 0xE0, 0x00, 0x38, 0x00, 0x68, 0x00, 0x30, 0x00, 0x6C, 0x00, 0x30, 0x00, 0x66, 0x00, 0x30, 0x00, 0x66, 0x00, + 0x30, 0x00, 0x6C, 0x00, 0x30, 0x00, 0xE8, 0x00, 0x38, 0x00, 0xC0, 0x00, 0x18, 0x00, 0xC0, 0x01, 0x1C, 0x00, 0x80, 0x07, 0x0F, + 0x00, 0x00, 0xFF, 0x07, 0x00, 0x00, 0xFC, 0x01, // 212 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x01, 0x00, 0x00, 0xFF, 0x07, 0x00, 0x80, 0x07, 0x0F, 0x00, 0xC0, 0x01, 0x1C, 0x00, 0xCC, + 0x00, 0x18, 0x00, 0xEE, 0x00, 0x38, 0x00, 0x66, 0x00, 0x30, 0x00, 0x66, 0x00, 0x30, 0x00, 0x6C, 0x00, 0x30, 0x00, 0x6C, 0x00, + 0x30, 0x00, 0x6E, 0x00, 0x30, 0x00, 0xE6, 0x00, 0x38, 0x00, 0xC0, 0x00, 0x18, 0x00, 0xC0, 0x01, 0x1C, 0x00, 0x80, 0x07, 0x0F, + 0x00, 0x00, 0xFF, 0x07, 0x00, 0x00, 0xFC, 0x01, // 213 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x01, 0x00, 0x00, 0xFF, 0x07, 0x00, 0x80, 0x07, 0x0F, 0x00, 0xC0, 0x01, 0x1C, 0x00, 0xC0, + 0x00, 0x18, 0x00, 0xE0, 0x00, 0x38, 0x00, 0x6C, 0x00, 0x30, 0x00, 0x6C, 0x00, 0x30, 0x00, 0x60, 0x00, 0x30, 0x00, 0x60, 0x00, + 0x30, 0x00, 0x6C, 0x00, 0x30, 0x00, 0xEC, 0x00, 0x38, 0x00, 0xC0, 0x00, 0x18, 0x00, 0xC0, 0x01, 0x1C, 0x00, 0x80, 0x07, 0x0F, + 0x00, 0x00, 0xFF, 0x07, 0x00, 0x00, 0xFC, 0x01, // 214 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x03, 0x00, 0x00, 0x8E, 0x03, 0x00, 0x00, 0xDC, 0x01, 0x00, 0x00, + 0xF8, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0xDC, 0x01, 0x00, 0x00, 0x8E, 0x03, 0x00, 0x00, 0x06, + 0x03, // 215 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x21, 0x00, 0x00, 0xFF, 0x77, 0x00, 0x80, 0x07, 0x3F, 0x00, 0xC0, 0x01, 0x1E, 0x00, 0xC0, + 0x00, 0x1F, 0x00, 0xE0, 0x80, 0x3B, 0x00, 0x60, 0xC0, 0x31, 0x00, 0x60, 0xE0, 0x30, 0x00, 0x60, 0x70, 0x30, 0x00, 0x60, 0x38, + 0x30, 0x00, 0x60, 0x1C, 0x30, 0x00, 0xE0, 0x0E, 0x38, 0x00, 0xC0, 0x07, 0x18, 0x00, 0xC0, 0x03, 0x1C, 0x00, 0xE0, 0x07, 0x0F, + 0x00, 0x70, 0xFF, 0x07, 0x00, 0x20, 0xFC, 0x01, // 216 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x03, 0x00, 0xE0, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, + 0x00, 0x38, 0x00, 0x02, 0x00, 0x30, 0x00, 0x06, 0x00, 0x30, 0x00, 0x0E, 0x00, 0x30, 0x00, 0x08, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x1C, 0x00, 0xE0, 0xFF, 0x0F, 0x00, 0xE0, 0xFF, 0x03, // 217 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x03, 0x00, 0xE0, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, + 0x00, 0x38, 0x00, 0x00, 0x00, 0x30, 0x00, 0x08, 0x00, 0x30, 0x00, 0x0E, 0x00, 0x30, 0x00, 0x06, 0x00, 0x30, 0x00, 0x02, 0x00, + 0x30, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x1C, 0x00, 0xE0, 0xFF, 0x0F, 0x00, 0xE0, 0xFF, 0x03, // 218 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x03, 0x00, 0xE0, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, + 0x00, 0x38, 0x00, 0x08, 0x00, 0x30, 0x00, 0x0C, 0x00, 0x30, 0x00, 0x06, 0x00, 0x30, 0x00, 0x06, 0x00, 0x30, 0x00, 0x0C, 0x00, + 0x30, 0x00, 0x08, 0x00, 0x38, 0x00, 0x00, 0x00, 0x1C, 0x00, 0xE0, 0xFF, 0x0F, 0x00, 0xE0, 0xFF, 0x03, // 219 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x03, 0x00, 0xE0, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, + 0x00, 0x38, 0x00, 0x0C, 0x00, 0x30, 0x00, 0x0C, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x0C, 0x00, + 0x30, 0x00, 0x0C, 0x00, 0x38, 0x00, 0x00, 0x00, 0x1C, 0x00, 0xE0, 0xFF, 0x0F, 0x00, 0xE0, 0xFF, 0x03, // 220 + 0x20, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x1E, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x08, 0xF0, 0x3F, 0x00, 0x0E, 0xF0, 0x3F, 0x00, 0x06, 0x3C, 0x00, 0x00, 0x02, 0x1E, + 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x20, // 221 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0xE0, 0xFF, 0x3F, 0x00, 0x00, 0x03, 0x06, 0x00, 0x00, + 0x03, 0x06, 0x00, 0x00, 0x03, 0x06, 0x00, 0x00, 0x03, 0x06, 0x00, 0x00, 0x03, 0x06, 0x00, 0x00, 0x03, 0x06, 0x00, 0x00, 0x03, + 0x06, 0x00, 0x00, 0x03, 0x07, 0x00, 0x00, 0x86, 0x03, 0x00, 0x00, 0xFE, 0x01, 0x00, 0x00, 0xF8, // 222 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x3F, 0x00, 0xC0, 0xFF, 0x3F, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x60, + 0x00, 0x08, 0x00, 0x60, 0x00, 0x1C, 0x00, 0x60, 0x00, 0x38, 0x00, 0xE0, 0x78, 0x30, 0x00, 0xC0, 0x7F, 0x30, 0x00, 0x80, 0xC7, + 0x30, 0x00, 0x00, 0x80, 0x39, 0x00, 0x00, 0x80, 0x1F, 0x00, 0x00, 0x00, 0x0F, // 223 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0E, 0x00, 0x00, 0x1C, 0x1F, 0x00, 0x00, 0x8C, 0x39, 0x00, 0x20, 0x86, 0x31, 0x00, 0x60, + 0x86, 0x31, 0x00, 0xE0, 0xC6, 0x30, 0x00, 0x80, 0xC6, 0x18, 0x00, 0x00, 0xCE, 0x0C, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xF8, + 0x3F, 0x00, 0x00, 0x00, 0x20, // 224 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0E, 0x00, 0x00, 0x1C, 0x1F, 0x00, 0x00, 0x8C, 0x39, 0x00, 0x00, 0x86, 0x31, 0x00, 0x80, + 0x86, 0x31, 0x00, 0xE0, 0xC6, 0x30, 0x00, 0x60, 0xC6, 0x18, 0x00, 0x20, 0xCE, 0x0C, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xF8, + 0x3F, 0x00, 0x00, 0x00, 0x20, // 225 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0E, 0x00, 0x00, 0x1C, 0x1F, 0x00, 0x80, 0x8C, 0x39, 0x00, 0xC0, 0x86, 0x31, 0x00, 0x60, + 0x86, 0x31, 0x00, 0x60, 0xC6, 0x30, 0x00, 0xC0, 0xC6, 0x18, 0x00, 0x80, 0xCE, 0x0C, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xF8, + 0x3F, 0x00, 0x00, 0x00, 0x20, // 226 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0E, 0x00, 0xC0, 0x1C, 0x1F, 0x00, 0xE0, 0x8C, 0x39, 0x00, 0x60, 0x86, 0x31, 0x00, 0x60, + 0x86, 0x31, 0x00, 0xC0, 0xC6, 0x30, 0x00, 0xC0, 0xC6, 0x18, 0x00, 0xE0, 0xCE, 0x0C, 0x00, 0x60, 0xFC, 0x1F, 0x00, 0x00, 0xF8, + 0x3F, 0x00, 0x00, 0x00, 0x20, // 227 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0E, 0x00, 0x00, 0x1C, 0x1F, 0x00, 0xC0, 0x8C, 0x39, 0x00, 0xC0, 0x86, 0x31, 0x00, 0x00, + 0x86, 0x31, 0x00, 0x00, 0xC6, 0x30, 0x00, 0xC0, 0xC6, 0x18, 0x00, 0xC0, 0xCE, 0x0C, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xF8, + 0x3F, 0x00, 0x00, 0x00, 0x20, // 228 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0E, 0x00, 0x00, 0x1C, 0x1F, 0x00, 0x00, 0x8C, 0x39, 0x00, 0x70, 0x86, 0x31, 0x00, 0x88, + 0x86, 0x31, 0x00, 0x88, 0xC6, 0x30, 0x00, 0x88, 0xC6, 0x18, 0x00, 0x70, 0xCE, 0x0C, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xF8, + 0x3F, 0x00, 0x00, 0x00, 0x20, // 229 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0F, 0x00, 0x00, 0x9C, 0x1F, 0x00, 0x00, 0xCC, 0x39, 0x00, 0x00, 0xC6, 0x30, 0x00, 0x00, + 0xC6, 0x30, 0x00, 0x00, 0xC6, 0x30, 0x00, 0x00, 0xC6, 0x30, 0x00, 0x00, 0x66, 0x18, 0x00, 0x00, 0x6E, 0x1C, 0x00, 0x00, 0xFC, + 0x0F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xCC, 0x1C, 0x00, 0x00, 0xCE, 0x38, 0x00, 0x00, 0xC6, 0x30, 0x00, 0x00, 0xC6, 0x30, + 0x00, 0x00, 0xC6, 0x30, 0x00, 0x00, 0xC6, 0x30, 0x00, 0x00, 0xCC, 0x18, 0x00, 0x00, 0xF8, 0x0C, 0x00, 0x00, 0xE0, 0x04, // 230 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0x1C, 0x1C, 0x00, 0x00, 0x0E, 0x38, 0x02, 0x00, + 0x06, 0x30, 0x02, 0x00, 0x06, 0xF0, 0x02, 0x00, 0x06, 0xB0, 0x03, 0x00, 0x0E, 0x38, 0x01, 0x00, 0x1C, 0x1C, 0x00, 0x00, 0x18, + 0x0C, // 231 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x07, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xDC, 0x1C, 0x00, 0x20, 0xCE, 0x38, 0x00, 0x60, + 0xC6, 0x30, 0x00, 0xE0, 0xC6, 0x30, 0x00, 0x80, 0xC6, 0x30, 0x00, 0x00, 0xCE, 0x38, 0x00, 0x00, 0xDC, 0x18, 0x00, 0x00, 0xF8, + 0x0C, 0x00, 0x00, 0xF0, 0x04, // 232 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x07, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xDC, 0x1C, 0x00, 0x00, 0xCE, 0x38, 0x00, 0x80, + 0xC6, 0x30, 0x00, 0xE0, 0xC6, 0x30, 0x00, 0x60, 0xC6, 0x30, 0x00, 0x20, 0xCE, 0x38, 0x00, 0x00, 0xDC, 0x18, 0x00, 0x00, 0xF8, + 0x0C, 0x00, 0x00, 0xF0, 0x04, // 233 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x07, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xDC, 0x1C, 0x00, 0x80, 0xCE, 0x38, 0x00, 0xC0, + 0xC6, 0x30, 0x00, 0x60, 0xC6, 0x30, 0x00, 0x60, 0xC6, 0x30, 0x00, 0xC0, 0xCE, 0x38, 0x00, 0x80, 0xDC, 0x18, 0x00, 0x00, 0xF8, + 0x0C, 0x00, 0x00, 0xF0, 0x04, // 234 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x07, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xDC, 0x1C, 0x00, 0xC0, 0xCE, 0x38, 0x00, 0xC0, + 0xC6, 0x30, 0x00, 0x00, 0xC6, 0x30, 0x00, 0x00, 0xC6, 0x30, 0x00, 0xC0, 0xCE, 0x38, 0x00, 0xC0, 0xDC, 0x18, 0x00, 0x00, 0xF8, + 0x0C, 0x00, 0x00, 0xF0, 0x04, // 235 + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x60, 0xFE, 0x3F, 0x00, 0xE0, 0xFE, 0x3F, 0x00, 0x80, // 236 + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xE0, 0xFE, 0x3F, 0x00, 0x60, 0xFE, 0x3F, 0x00, 0x20, // 237 + 0x80, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x60, 0xFE, 0x3F, 0x00, 0x60, 0xFE, 0x3F, 0x00, 0xC0, 0x00, 0x00, 0x00, + 0x80, // 238 + 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0xC0, 0x00, 0x00, 0x00, + 0xC0, // 239 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0x1D, 0x1C, 0x00, 0xA0, 0x0F, 0x38, 0x00, 0xA0, + 0x06, 0x30, 0x00, 0xE0, 0x06, 0x30, 0x00, 0xC0, 0x06, 0x30, 0x00, 0xC0, 0x0F, 0x38, 0x00, 0x20, 0x1F, 0x1C, 0x00, 0x00, 0xFC, + 0x0F, 0x00, 0x00, 0xE0, 0x07, // 240 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0xC0, 0xFE, 0x3F, 0x00, 0xE0, 0x18, 0x00, 0x00, 0x60, + 0x0C, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00, 0xC0, 0x06, 0x00, 0x00, 0xC0, 0x06, 0x00, 0x00, 0xE0, 0x0E, 0x00, 0x00, 0x60, 0xFC, + 0x3F, 0x00, 0x00, 0xF8, 0x3F, // 241 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0x1C, 0x1C, 0x00, 0x20, 0x0E, 0x38, 0x00, 0x60, + 0x06, 0x30, 0x00, 0xE0, 0x06, 0x30, 0x00, 0x80, 0x06, 0x30, 0x00, 0x00, 0x0E, 0x38, 0x00, 0x00, 0x1C, 0x1C, 0x00, 0x00, 0xF8, + 0x0F, 0x00, 0x00, 0xF0, 0x07, // 242 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0x1C, 0x1C, 0x00, 0x00, 0x0E, 0x38, 0x00, 0x80, + 0x06, 0x30, 0x00, 0xE0, 0x06, 0x30, 0x00, 0x60, 0x06, 0x30, 0x00, 0x20, 0x0E, 0x38, 0x00, 0x00, 0x1C, 0x1C, 0x00, 0x00, 0xF8, + 0x0F, 0x00, 0x00, 0xF0, 0x07, // 243 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0x1C, 0x1C, 0x00, 0x80, 0x0E, 0x38, 0x00, 0xC0, + 0x06, 0x30, 0x00, 0x60, 0x06, 0x30, 0x00, 0x60, 0x06, 0x30, 0x00, 0xC0, 0x0E, 0x38, 0x00, 0x80, 0x1C, 0x1C, 0x00, 0x00, 0xF8, + 0x0F, 0x00, 0x00, 0xF0, 0x07, // 244 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0xC0, 0x1C, 0x1C, 0x00, 0xE0, 0x0E, 0x38, 0x00, 0x60, + 0x06, 0x30, 0x00, 0x60, 0x06, 0x30, 0x00, 0xC0, 0x06, 0x30, 0x00, 0xC0, 0x0E, 0x38, 0x00, 0xE0, 0x1C, 0x1C, 0x00, 0x60, 0xF8, + 0x0F, 0x00, 0x00, 0xF0, 0x07, // 245 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0x1C, 0x1C, 0x00, 0xC0, 0x0E, 0x38, 0x00, 0xC0, + 0x06, 0x30, 0x00, 0x00, 0x06, 0x30, 0x00, 0x00, 0x06, 0x30, 0x00, 0xC0, 0x0E, 0x38, 0x00, 0xC0, 0x1C, 0x1C, 0x00, 0x00, 0xF8, + 0x0F, 0x00, 0x00, 0xF0, 0x07, // 246 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x00, 0xB6, 0x01, 0x00, 0x00, 0xB6, 0x01, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, + 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, // 247 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x67, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x1C, 0x1C, 0x00, 0x00, + 0x0E, 0x3F, 0x00, 0x00, 0x86, 0x33, 0x00, 0x00, 0xE6, 0x31, 0x00, 0x00, 0x76, 0x30, 0x00, 0x00, 0x3E, 0x38, 0x00, 0x00, 0x1C, + 0x1C, 0x00, 0x00, 0xFF, 0x0F, 0x00, 0x00, 0xF3, 0x07, // 248 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x0F, 0x00, 0x00, 0xFE, 0x1F, 0x00, 0x20, 0x00, 0x38, 0x00, 0x60, + 0x00, 0x30, 0x00, 0xE0, 0x00, 0x30, 0x00, 0x80, 0x00, 0x30, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0xFE, + 0x3F, 0x00, 0x00, 0xFE, 0x3F, // 249 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x0F, 0x00, 0x00, 0xFE, 0x1F, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, + 0x00, 0x30, 0x00, 0x80, 0x00, 0x30, 0x00, 0xE0, 0x00, 0x30, 0x00, 0x60, 0x00, 0x18, 0x00, 0x20, 0x00, 0x0C, 0x00, 0x00, 0xFE, + 0x3F, 0x00, 0x00, 0xFE, 0x3F, // 250 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x0F, 0x00, 0x00, 0xFE, 0x1F, 0x00, 0x80, 0x00, 0x38, 0x00, 0xC0, + 0x00, 0x30, 0x00, 0x60, 0x00, 0x30, 0x00, 0x60, 0x00, 0x30, 0x00, 0xC0, 0x00, 0x18, 0x00, 0x80, 0x00, 0x0C, 0x00, 0x00, 0xFE, + 0x3F, 0x00, 0x00, 0xFE, 0x3F, // 251 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x0F, 0x00, 0x00, 0xFE, 0x1F, 0x00, 0xC0, 0x00, 0x38, 0x00, 0xC0, + 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0xC0, 0x00, 0x18, 0x00, 0xC0, 0x00, 0x0C, 0x00, 0x00, 0xFE, + 0x3F, 0x00, 0x00, 0xFE, 0x3F, // 252 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x06, 0x00, 0xF0, 0x01, 0x06, 0x00, 0x80, 0x0F, 0x07, 0x80, + 0x00, 0xFE, 0x03, 0xE0, 0x00, 0xFC, 0x00, 0x60, 0xC0, 0x1F, 0x00, 0x20, 0xF8, 0x03, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, + 0x06, // 253 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0x07, 0xE0, 0xFF, 0xFF, 0x07, 0x00, 0x1C, 0x18, 0x00, 0x00, + 0x06, 0x30, 0x00, 0x00, 0x06, 0x30, 0x00, 0x00, 0x06, 0x30, 0x00, 0x00, 0x0E, 0x38, 0x00, 0x00, 0x1C, 0x1C, 0x00, 0x00, 0xF8, + 0x0F, 0x00, 0x00, 0xF0, 0x03, // 254 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x06, 0xC0, 0xF0, 0x01, 0x06, 0xC0, 0x80, 0x0F, 0x07, 0x00, + 0x00, 0xFE, 0x03, 0x00, 0x00, 0xFC, 0x00, 0xC0, 0xC0, 0x1F, 0x00, 0xC0, 0xF8, 0x03, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, + 0x06, // 255 +}; \ No newline at end of file diff --git a/src/graphics/fonts/OLEDDisplayFontsCS.h b/src/graphics/fonts/OLEDDisplayFontsCS.h new file mode 100644 index 000000000..322fbc936 --- /dev/null +++ b/src/graphics/fonts/OLEDDisplayFontsCS.h @@ -0,0 +1,16 @@ +#ifndef OLEDDISPLAYFONTSCS_h +#define OLEDDISPLAYFONTSCS_h + +#ifdef ARDUINO +#include +#elif __MBED__ +#define PROGMEM +#endif + +/** + * Localization for Czech and Slovak language containing glyphs with diacritic. + */ +extern const uint8_t ArialMT_Plain_10_CS[] PROGMEM; +extern const uint8_t ArialMT_Plain_16_CS[] PROGMEM; +extern const uint8_t ArialMT_Plain_24_CS[] PROGMEM; +#endif \ No newline at end of file diff --git a/src/graphics/fonts/OLEDDisplayFontsUA.cpp b/src/graphics/fonts/OLEDDisplayFontsUA.cpp index 0295ee6ba..2a97526ef 100644 --- a/src/graphics/fonts/OLEDDisplayFontsUA.cpp +++ b/src/graphics/fonts/OLEDDisplayFontsUA.cpp @@ -166,71 +166,71 @@ const uint8_t ArialMT_Plain_10_UA[] PROGMEM = { 0x04, 0x6F, 0x10, 0x09, // 188 0x04, 0x7F, 0x10, 0x09, // 189 0x04, 0x8F, 0x10, 0x09, // 190 - 0x04, 0x9F, 0x0A, 0x06, // 191 - 0x04, 0xA9, 0x0C, 0x07, // 192 - 0x04, 0xB5, 0x0C, 0x07, // 193 - 0x04, 0xC1, 0x0C, 0x07, // 194 - 0x04, 0xCD, 0x0B, 0x07, // 195 - 0x04, 0xD8, 0x0C, 0x07, // 196 - 0x04, 0xE4, 0x0C, 0x07, // 197 - 0x04, 0xF0, 0x0C, 0x07, // 198 - 0x04, 0xFC, 0x0C, 0x07, // 199 - 0x05, 0x08, 0x0C, 0x07, // 200 - 0x05, 0x14, 0x0C, 0x07, // 201 - 0x05, 0x20, 0x0C, 0x07, // 202 - 0x05, 0x2C, 0x0C, 0x07, // 203 - 0x05, 0x38, 0x0C, 0x07, // 204 - 0x05, 0x44, 0x0C, 0x07, // 205 - 0x05, 0x50, 0x0C, 0x07, // 206 - 0x05, 0x5C, 0x0C, 0x07, // 207 - 0x05, 0x68, 0x0B, 0x07, // 208 - 0x05, 0x73, 0x0C, 0x07, // 209 - 0x05, 0x7F, 0x0B, 0x07, // 210 - 0x05, 0x8A, 0x0C, 0x07, // 211 - 0x05, 0x96, 0x0B, 0x07, // 212 - 0x05, 0xA1, 0x0C, 0x07, // 213 - 0x05, 0xAD, 0x0C, 0x07, // 214 - 0x05, 0xB9, 0x0C, 0x07, // 215 - 0x05, 0xC5, 0x0C, 0x07, // 216 - 0x05, 0xD1, 0x0E, 0x08, // 217 - 0x05, 0xDF, 0x0C, 0x07, // 218 - 0x05, 0xEB, 0x0C, 0x07, // 219 - 0x05, 0xF7, 0x0C, 0x07, // 220 - 0x06, 0x03, 0x0C, 0x07, // 221 - 0x06, 0x0F, 0x0C, 0x07, // 222 - 0x06, 0x1B, 0x0C, 0x07, // 223 - 0x06, 0x27, 0x0C, 0x07, // 224 - 0x06, 0x33, 0x0C, 0x07, // 225 - 0x06, 0x3F, 0x0C, 0x07, // 226 - 0x06, 0x4B, 0x0B, 0x07, // 227 - 0x06, 0x56, 0x0C, 0x07, // 228 - 0x06, 0x62, 0x0B, 0x07, // 229 - 0x06, 0x6D, 0x0C, 0x07, // 230 - 0x06, 0x79, 0x0C, 0x07, // 231 - 0x06, 0x85, 0x0C, 0x07, // 232 - 0x06, 0x91, 0x0C, 0x07, // 233 - 0x06, 0x9D, 0x0C, 0x07, // 234 - 0x06, 0xA9, 0x0C, 0x07, // 235 - 0x06, 0xB5, 0x0C, 0x07, // 236 - 0x06, 0xC1, 0x0C, 0x07, // 237 - 0x06, 0xCD, 0x0C, 0x07, // 238 - 0x06, 0xD9, 0x0C, 0x07, // 239 - 0x06, 0xE5, 0x0B, 0x07, // 240 - 0x06, 0xF0, 0x0C, 0x07, // 241 - 0x06, 0xFC, 0x0B, 0x07, // 242 - 0x07, 0x07, 0x0C, 0x07, // 243 - 0x07, 0x13, 0x0B, 0x07, // 244 - 0x07, 0x1E, 0x0C, 0x07, // 245 - 0x07, 0x2A, 0x0C, 0x07, // 246 - 0x07, 0x36, 0x0C, 0x07, // 247 - 0x07, 0x42, 0x0C, 0x07, // 248 - 0x07, 0x4E, 0x0E, 0x08, // 249 - 0x07, 0x5C, 0x0C, 0x07, // 250 - 0x07, 0x68, 0x0C, 0x07, // 251 - 0x07, 0x74, 0x0C, 0x07, // 252 - 0x07, 0x80, 0x0C, 0x07, // 253 - 0x07, 0x8C, 0x0C, 0x07, // 254 - 0x07, 0x98, 0x0C, 0x07, // 255 + 0x04, 0x9F, 0x06, 0x04, // 191 + 0x04, 0xA5, 0x0A, 0x06, // 192 + 0x04, 0xAF, 0x0A, 0x06, // 193 + 0x04, 0xB9, 0x0A, 0x06, // 194 + 0x04, 0xC3, 0x09, 0x06, // 195 + 0x04, 0xCC, 0x0A, 0x06, // 196 + 0x04, 0xD6, 0x0A, 0x06, // 197 + 0x04, 0xE0, 0x0A, 0x06, // 198 + 0x04, 0xEA, 0x08, 0x05, // 199 + 0x04, 0xF2, 0x0A, 0x06, // 200 + 0x04, 0xFC, 0x0A, 0x06, // 201 + 0x05, 0x06, 0x0A, 0x06, // 202 + 0x05, 0x10, 0x0A, 0x06, // 203 + 0x05, 0x1A, 0x0A, 0x06, // 204 + 0x05, 0x24, 0x0A, 0x06, // 205 + 0x05, 0x2E, 0x0A, 0x06, // 206 + 0x05, 0x38, 0x0A, 0x06, // 207 + 0x05, 0x42, 0x09, 0x06, // 208 + 0x05, 0x4B, 0x0A, 0x06, // 209 + 0x05, 0x55, 0x09, 0x06, // 210 + 0x05, 0x5E, 0x0A, 0x06, // 211 + 0x05, 0x68, 0x09, 0x06, // 212 + 0x05, 0x71, 0x0A, 0x06, // 213 + 0x05, 0x7B, 0x0A, 0x06, // 214 + 0x05, 0x85, 0x08, 0x05, // 215 + 0x05, 0x8D, 0x0A, 0x06, // 216 + 0x05, 0x97, 0x0C, 0x07, // 217 + 0x05, 0xA3, 0x0A, 0x06, // 218 + 0x05, 0xAD, 0x0A, 0x06, // 219 + 0x05, 0xB7, 0x08, 0x05, // 220 + 0x05, 0xBF, 0x0A, 0x06, // 221 + 0x05, 0xC9, 0x0A, 0x06, // 222 + 0x05, 0xD3, 0x0A, 0x06, // 223 + 0x05, 0xDD, 0x08, 0x05, // 224 + 0x05, 0xE5, 0x08, 0x05, // 225 + 0x05, 0xED, 0x08, 0x05, // 226 + 0x05, 0xF5, 0x07, 0x05, // 227 + 0x05, 0xFC, 0x0A, 0x06, // 228 + 0x06, 0x06, 0x09, 0x06, // 229 + 0x06, 0x0F, 0x0A, 0x06, // 230 + 0x06, 0x19, 0x08, 0x05, // 231 + 0x06, 0x21, 0x0A, 0x06, // 232 + 0x06, 0x2B, 0x0A, 0x06, // 233 + 0x06, 0x35, 0x06, 0x04, // 234 + 0x06, 0x3B, 0x08, 0x05, // 235 + 0x06, 0x43, 0x0A, 0x06, // 236 + 0x06, 0x4D, 0x08, 0x05, // 237 + 0x06, 0x55, 0x08, 0x05, // 238 + 0x06, 0x5D, 0x08, 0x05, // 239 + 0x06, 0x65, 0x05, 0x04, // 240 + 0x06, 0x6A, 0x08, 0x05, // 241 + 0x06, 0x72, 0x05, 0x04, // 242 + 0x06, 0x77, 0x08, 0x05, // 243 + 0x06, 0x7F, 0x09, 0x06, // 244 + 0x06, 0x88, 0x0A, 0x06, // 245 + 0x06, 0x92, 0x08, 0x05, // 246 + 0x06, 0x9A, 0x08, 0x05, // 247 + 0x06, 0xA2, 0x0A, 0x06, // 248 + 0x06, 0xAC, 0x0C, 0x07, // 249 + 0x06, 0xB8, 0x08, 0x05, // 250 + 0x06, 0xC0, 0x08, 0x05, // 251 + 0x06, 0xC8, 0x08, 0x05, // 252 + 0x06, 0xD0, 0x08, 0x05, // 253 + 0x06, 0xD8, 0x0A, 0x06, // 254 + 0x06, 0xE2, 0x08, 0x05, // 255 // Font Data: 0x00, 0x00, 0xF8, 0x02, // 33 0x38, 0x00, 0x00, 0x00, 0x38, // 34 @@ -356,69 +356,1568 @@ const uint8_t ArialMT_Plain_10_UA[] PROGMEM = { 0x00, 0x00, 0x10, 0x02, 0x78, 0x01, 0xC0, 0x00, 0x20, 0x01, 0x90, 0x01, 0xC8, 0x03, 0x00, 0x01, // 188 0x00, 0x00, 0x10, 0x02, 0x78, 0x01, 0x80, 0x00, 0x60, 0x00, 0x50, 0x02, 0x48, 0x03, 0xC0, 0x02, // 189 0x48, 0x00, 0x58, 0x00, 0x68, 0x03, 0x80, 0x00, 0x60, 0x01, 0x90, 0x01, 0xC8, 0x03, 0x00, 0x01, // 190 - 0x00, 0x00, 0x00, 0x00, 0x28, 0x02, 0xE0, 0x03, 0x28, 0x02, // 191 - 0x00, 0x00, 0xF0, 0x03, 0x88, 0x00, 0x88, 0x00, 0x88, 0x00, 0xF0, 0x03, // 192 - 0x00, 0x00, 0xF8, 0x03, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0x88, 0x01, // 193 - 0x00, 0x00, 0xF8, 0x03, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0xB0, 0x01, // 194 - 0x00, 0x00, 0xF8, 0x03, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x18, // 195 - 0x00, 0x00, 0x00, 0x02, 0xFC, 0x03, 0x04, 0x02, 0xFC, 0x03, 0x00, 0x02, // 196 - 0x00, 0x00, 0xF8, 0x03, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0x08, 0x02, // 197 - 0x00, 0x00, 0xB8, 0x03, 0x40, 0x00, 0xF8, 0x03, 0x40, 0x00, 0xB8, 0x03, // 198 - 0x00, 0x00, 0x08, 0x02, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0xB0, 0x01, // 199 - 0x00, 0x00, 0xF8, 0x03, 0x80, 0x00, 0x40, 0x00, 0x20, 0x00, 0xF8, 0x03, // 200 - 0x00, 0x00, 0xE0, 0x03, 0x08, 0x01, 0x90, 0x00, 0x48, 0x00, 0xE0, 0x03, // 201 - 0x00, 0x00, 0xF8, 0x03, 0x40, 0x00, 0xA0, 0x00, 0x10, 0x01, 0x08, 0x02, // 202 - 0x00, 0x00, 0x00, 0x02, 0xF0, 0x01, 0x08, 0x00, 0x08, 0x00, 0xF8, 0x03, // 203 - 0x00, 0x00, 0xF8, 0x03, 0x10, 0x00, 0x60, 0x00, 0x10, 0x00, 0xF8, 0x03, // 204 - 0x00, 0x00, 0xF8, 0x03, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0xF8, 0x03, // 205 - 0x00, 0x00, 0xF0, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x02, 0xF0, 0x01, // 206 - 0x00, 0x00, 0xF8, 0x03, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0xF8, 0x03, // 207 - 0x00, 0x00, 0xF8, 0x03, 0x48, 0x00, 0x48, 0x00, 0x48, 0x00, 0x30, // 208 - 0x00, 0x00, 0xF0, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x02, 0x10, 0x01, // 209 - 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0xF8, 0x03, 0x08, 0x00, 0x08, // 210 - 0x00, 0x00, 0x38, 0x00, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0xF8, 0x01, // 211 - 0x00, 0x00, 0x70, 0x00, 0x88, 0x00, 0xF8, 0x03, 0x88, 0x00, 0x70, // 212 - 0x00, 0x00, 0x18, 0x03, 0xA0, 0x00, 0x40, 0x00, 0xA0, 0x00, 0x18, 0x03, // 213 - 0x00, 0x00, 0xF8, 0x03, 0x00, 0x02, 0x00, 0x02, 0xF8, 0x03, 0x00, 0x02, // 214 - 0x00, 0x00, 0x38, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0xF8, 0x03, // 215 - 0x00, 0x00, 0xF8, 0x03, 0x00, 0x02, 0xF8, 0x03, 0x00, 0x02, 0xF8, 0x03, // 216 - 0x00, 0x00, 0xF8, 0x03, 0x00, 0x02, 0xF8, 0x03, 0x00, 0x02, 0xF8, 0x03, 0x00, 0x06, // 217 - 0x00, 0x00, 0x08, 0x00, 0xF8, 0x03, 0x40, 0x02, 0x40, 0x02, 0x80, 0x01, // 218 - 0x00, 0x00, 0xF8, 0x03, 0x40, 0x02, 0x40, 0x02, 0x80, 0x01, 0xF8, 0x03, // 219 - 0x00, 0x00, 0xF8, 0x03, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x80, 0x01, // 220 - 0x00, 0x00, 0x10, 0x01, 0x08, 0x02, 0x48, 0x02, 0x48, 0x02, 0xF0, 0x01, // 221 - 0x00, 0x00, 0xF8, 0x03, 0x40, 0x00, 0xF0, 0x01, 0x08, 0x02, 0xF0, 0x01, // 222 - 0x00, 0x00, 0x30, 0x02, 0x48, 0x01, 0xC8, 0x00, 0x48, 0x00, 0xF8, 0x03, // 223 - 0x00, 0x00, 0x00, 0x01, 0xA0, 0x02, 0xA0, 0x02, 0xA0, 0x02, 0xC0, 0x03, // 224 - 0x00, 0x00, 0xE0, 0x01, 0x50, 0x02, 0x50, 0x02, 0x48, 0x02, 0x88, 0x01, // 225 - 0x00, 0x00, 0xE0, 0x03, 0xA0, 0x02, 0xA0, 0x02, 0xA0, 0x02, 0x40, 0x01, // 226 - 0x00, 0x00, 0xE0, 0x03, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x60, // 227 - 0x00, 0x00, 0x00, 0x02, 0xC0, 0x03, 0x20, 0x02, 0xE0, 0x03, 0x00, 0x02, // 228 - 0x00, 0x00, 0xC0, 0x01, 0xA0, 0x02, 0xA0, 0x02, 0xA0, 0x02, 0xC0, // 229 - 0x00, 0x00, 0x60, 0x03, 0x80, 0x00, 0xE0, 0x03, 0x80, 0x00, 0x60, 0x03, // 230 - 0x00, 0x00, 0x20, 0x02, 0xA0, 0x02, 0xA0, 0x02, 0xA0, 0x02, 0x40, 0x01, // 231 - 0x00, 0x00, 0xE0, 0x03, 0x00, 0x01, 0x80, 0x00, 0x40, 0x00, 0xE0, 0x03, // 232 - 0x00, 0x00, 0xE0, 0x03, 0x00, 0x01, 0x98, 0x00, 0x40, 0x00, 0xE0, 0x03, // 233 - 0x00, 0x00, 0xE0, 0x03, 0x80, 0x00, 0x80, 0x00, 0x40, 0x01, 0x20, 0x02, // 234 - 0x00, 0x00, 0x00, 0x02, 0xC0, 0x01, 0x20, 0x00, 0x20, 0x00, 0xE0, 0x03, // 235 - 0x00, 0x00, 0xE0, 0x03, 0x40, 0x00, 0x80, 0x00, 0x40, 0x00, 0xE0, 0x03, // 236 - 0x00, 0x00, 0xE0, 0x03, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0xE0, 0x03, // 237 - 0x00, 0x00, 0xC0, 0x01, 0x20, 0x02, 0x20, 0x02, 0x20, 0x02, 0xC0, 0x01, // 238 - 0x00, 0x00, 0xE0, 0x03, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0xE0, 0x03, // 239 - 0x00, 0x00, 0xE0, 0x03, 0xA0, 0x00, 0xA0, 0x00, 0xA0, 0x00, 0x40, // 240 - 0x00, 0x00, 0xC0, 0x01, 0x20, 0x02, 0x20, 0x02, 0x20, 0x02, 0x40, 0x02, // 241 - 0x00, 0x00, 0x20, 0x00, 0x20, 0x00, 0xE0, 0x03, 0x20, 0x00, 0x20, // 242 - 0x00, 0x00, 0x60, 0x00, 0x80, 0x02, 0x80, 0x02, 0x80, 0x02, 0xE0, 0x01, // 243 - 0x00, 0x00, 0xC0, 0x00, 0x20, 0x01, 0xE0, 0x03, 0x20, 0x01, 0xC0, // 244 - 0x00, 0x00, 0x20, 0x02, 0x40, 0x01, 0x80, 0x00, 0x40, 0x01, 0x20, 0x02, // 245 - 0x00, 0x00, 0xE0, 0x03, 0x00, 0x02, 0x00, 0x02, 0xE0, 0x03, 0x00, 0x02, // 246 - 0x00, 0x00, 0x60, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0xE0, 0x03, // 247 - 0x00, 0x00, 0xE0, 0x03, 0x00, 0x02, 0xE0, 0x03, 0x00, 0x02, 0xE0, 0x03, // 248 - 0x00, 0x00, 0xE0, 0x03, 0x00, 0x02, 0xE0, 0x03, 0x00, 0x02, 0xE0, 0x03, 0x00, 0x06, // 249 - 0x00, 0x00, 0x20, 0x00, 0xE0, 0x03, 0x80, 0x02, 0x80, 0x02, 0x00, 0x01, // 250 - 0x00, 0x00, 0xE0, 0x03, 0x80, 0x02, 0x80, 0x02, 0x00, 0x01, 0xE0, 0x03, // 251 - 0x00, 0x00, 0xE0, 0x03, 0x80, 0x02, 0x80, 0x02, 0x80, 0x02, 0x00, 0x01, // 252 - 0x00, 0x00, 0x40, 0x01, 0x20, 0x02, 0xA0, 0x02, 0xA0, 0x02, 0xC0, 0x01, // 253 - 0x00, 0x00, 0xE0, 0x03, 0x80, 0x00, 0xC0, 0x01, 0x20, 0x02, 0xC0, 0x01, // 254 - 0x00, 0x00, 0x40, 0x02, 0xA0, 0x01, 0xA0, 0x00, 0xA0, 0x00, 0xE0, 0x03, // 255 + 0x28, 0x02, 0xE0, 0x03, 0x28, 0x02, // 191 + 0xF0, 0x03, 0x88, 0x00, 0x88, 0x00, 0x88, 0x00, 0xF0, 0x03, // 192 + 0xF8, 0x03, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0x88, 0x01, // 193 + 0xF8, 0x03, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0xB0, 0x01, // 194 + 0xF8, 0x03, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x18, // 195 + 0x00, 0x02, 0xFC, 0x03, 0x04, 0x02, 0xFC, 0x03, 0x00, 0x02, // 196 + 0xF8, 0x03, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0x08, 0x02, // 197 + 0xB8, 0x03, 0x40, 0x00, 0xF8, 0x03, 0x40, 0x00, 0xB8, 0x03, // 198 + 0x08, 0x02, 0x48, 0x02, 0x48, 0x02, 0xB0, 0x01, // 199 + 0xF8, 0x03, 0x80, 0x00, 0x40, 0x00, 0x20, 0x00, 0xF8, 0x03, // 200 + 0xE0, 0x03, 0x08, 0x01, 0x90, 0x00, 0x48, 0x00, 0xE0, 0x03, // 201 + 0xF8, 0x03, 0x40, 0x00, 0xA0, 0x00, 0x10, 0x01, 0x08, 0x02, // 202 + 0x00, 0x02, 0xF0, 0x01, 0x08, 0x00, 0x08, 0x00, 0xF8, 0x03, // 203 + 0xF8, 0x03, 0x10, 0x00, 0x60, 0x00, 0x10, 0x00, 0xF8, 0x03, // 204 + 0xF8, 0x03, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0xF8, 0x03, // 205 + 0xF0, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x02, 0xF0, 0x01, // 206 + 0xF8, 0x03, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0xF8, 0x03, // 207 + 0xF8, 0x03, 0x48, 0x00, 0x48, 0x00, 0x48, 0x00, 0x30, // 208 + 0xF0, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x02, 0x10, 0x01, // 209 + 0x08, 0x00, 0x08, 0x00, 0xF8, 0x03, 0x08, 0x00, 0x08, // 210 + 0x38, 0x00, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0xF8, 0x01, // 211 + 0x70, 0x00, 0x88, 0x00, 0xF8, 0x03, 0x88, 0x00, 0x70, // 212 + 0x18, 0x03, 0xA0, 0x00, 0x40, 0x00, 0xA0, 0x00, 0x18, 0x03, // 213 + 0xF8, 0x03, 0x00, 0x02, 0x00, 0x02, 0xF8, 0x03, 0x00, 0x02, // 214 + 0x38, 0x00, 0x40, 0x00, 0x40, 0x00, 0xF8, 0x03, // 215 + 0xF8, 0x03, 0x00, 0x02, 0xF8, 0x03, 0x00, 0x02, 0xF8, 0x03, // 216 + 0xF8, 0x03, 0x00, 0x02, 0xF8, 0x03, 0x00, 0x02, 0xF8, 0x03, 0x00, 0x06, // 217 + 0x08, 0x00, 0xF8, 0x03, 0x40, 0x02, 0x40, 0x02, 0x80, 0x01, // 218 + 0xF8, 0x03, 0x40, 0x02, 0x40, 0x02, 0x80, 0x01, 0xF8, 0x03, // 219 + 0xF8, 0x03, 0x40, 0x02, 0x40, 0x02, 0x80, 0x01, // 220 + 0x10, 0x01, 0x08, 0x02, 0x48, 0x02, 0x48, 0x02, 0xF0, 0x01, // 221 + 0xF8, 0x03, 0x40, 0x00, 0xF0, 0x01, 0x08, 0x02, 0xF0, 0x01, // 222 + 0x30, 0x02, 0x48, 0x01, 0xC8, 0x00, 0x48, 0x00, 0xF8, 0x03, // 223 + 0x00, 0x01, 0xA0, 0x02, 0xA0, 0x02, 0xE0, 0x01, // 224 + 0xE0, 0x01, 0x50, 0x02, 0x48, 0x02, 0x88, 0x01, // 225 + 0xE0, 0x03, 0xA0, 0x02, 0xA0, 0x02, 0x40, 0x01, // 226 + 0xE0, 0x03, 0x20, 0x00, 0x20, 0x00, 0x60, // 227 + 0x00, 0x02, 0xC0, 0x03, 0x20, 0x02, 0xE0, 0x03, 0x00, 0x02, // 228 + 0xC0, 0x01, 0xA0, 0x02, 0xA0, 0x02, 0xA0, 0x02, 0xC0, // 229 + 0x60, 0x03, 0x80, 0x00, 0xE0, 0x03, 0x80, 0x00, 0x60, 0x03, // 230 + 0x20, 0x02, 0xA0, 0x02, 0xA0, 0x02, 0x40, 0x01, // 231 + 0xE0, 0x03, 0x00, 0x01, 0x80, 0x00, 0x40, 0x00, 0xE0, 0x03, // 232 + 0xE0, 0x03, 0x08, 0x01, 0x88, 0x00, 0x48, 0x00, 0xE0, 0x03, // 233 + 0xE0, 0x03, 0x80, 0x00, 0x60, 0x03, // 234 + 0x00, 0x02, 0xC0, 0x01, 0x20, 0x00, 0xE0, 0x03, // 235 + 0xE0, 0x03, 0x40, 0x00, 0x80, 0x00, 0x40, 0x00, 0xE0, 0x03, // 236 + 0xE0, 0x03, 0x80, 0x00, 0x80, 0x00, 0xE0, 0x03, // 237 + 0xC0, 0x01, 0x20, 0x02, 0x20, 0x02, 0xC0, 0x01, // 238 + 0xE0, 0x03, 0x20, 0x00, 0x20, 0x00, 0xE0, 0x03, // 239 + 0xE0, 0x03, 0xA0, 0x00, 0x40, // 240 + 0xC0, 0x01, 0x20, 0x02, 0x20, 0x02, 0x40, 0x01, // 241 + 0x20, 0x00, 0xE0, 0x03, 0x20, // 242 + 0x60, 0x00, 0x80, 0x02, 0x80, 0x02, 0xE0, 0x01, // 243 + 0xC0, 0x00, 0x20, 0x01, 0xE0, 0x03, 0x20, 0x01, 0xC0, // 244 + 0x20, 0x02, 0x40, 0x01, 0x80, 0x00, 0x40, 0x01, 0x20, 0x02, // 245 + 0xE0, 0x03, 0x00, 0x02, 0xE0, 0x03, 0x00, 0x06, // 246 + 0x60, 0x00, 0x80, 0x00, 0x80, 0x00, 0xE0, 0x03, // 247 + 0xE0, 0x03, 0x00, 0x02, 0xE0, 0x03, 0x00, 0x02, 0xE0, 0x03, // 248 + 0xE0, 0x03, 0x00, 0x02, 0xE0, 0x03, 0x00, 0x02, 0xE0, 0x03, 0x00, 0x06, // 249 + 0x20, 0x00, 0xE0, 0x03, 0x80, 0x02, 0x00, 0x01, // 250 + 0xE0, 0x03, 0x80, 0x02, 0x00, 0x01, 0xE0, 0x03, // 251 + 0xE0, 0x03, 0x80, 0x02, 0x80, 0x02, 0x00, 0x01, // 252 + 0x40, 0x01, 0x20, 0x02, 0xA0, 0x02, 0xC0, 0x01, // 253 + 0xE0, 0x03, 0x80, 0x00, 0xC0, 0x01, 0x20, 0x02, 0xC0, 0x01, // 254 + 0x40, 0x02, 0xA0, 0x01, 0xA0, 0x00, 0xE0, 0x03, // 255 +}; + +const uint8_t ArialMT_Plain_16_UA[] PROGMEM = { + 0x10, // Width: 16 + 0x13, // Height: 19 + 0x20, // First Char: 32 + 0xE0, // Numbers of Chars: 224 + // Jump Table: + 0xFF, 0xFF, 0x00, 0x04, // 32= :65535 + 0x00, 0x00, 0x08, 0x05, // 33=!:0 + 0x00, 0x08, 0x0D, 0x06, // 34=":8 + 0x00, 0x15, 0x1A, 0x09, // 35=#:21 + 0x00, 0x2F, 0x17, 0x09, // 36=$:47 + 0x00, 0x46, 0x26, 0x0E, // 37=%:70 + 0x00, 0x6C, 0x1D, 0x0B, // 38=&:108 + 0x00, 0x89, 0x04, 0x03, // 39=':137 + 0x00, 0x8D, 0x0C, 0x05, // 40=(:141 + 0x00, 0x99, 0x0B, 0x05, // 41=):153 + 0x00, 0xA4, 0x0D, 0x06, // 42=*:164 + 0x00, 0xB1, 0x17, 0x09, // 43=+:177 + 0x00, 0xC8, 0x09, 0x04, // 44=,:200 + 0x00, 0xD1, 0x0B, 0x05, // 45=-:209 + 0x00, 0xDC, 0x08, 0x04, // 46=.:220 + 0x00, 0xE4, 0x0A, 0x04, // 47=/:228 + 0x00, 0xEE, 0x17, 0x09, // 48=0:238 + 0x01, 0x05, 0x11, 0x09, // 49=1:261 + 0x01, 0x16, 0x17, 0x09, // 50=2:278 + 0x01, 0x2D, 0x17, 0x09, // 51=3:301 + 0x01, 0x44, 0x17, 0x09, // 52=4:324 + 0x01, 0x5B, 0x17, 0x09, // 53=5:347 + 0x01, 0x72, 0x17, 0x09, // 54=6:370 + 0x01, 0x89, 0x16, 0x09, // 55=7:393 + 0x01, 0x9F, 0x17, 0x09, // 56=8:415 + 0x01, 0xB6, 0x17, 0x09, // 57=9:438 + 0x01, 0xCD, 0x05, 0x04, // 58=::461 + 0x01, 0xD2, 0x06, 0x04, // 59=;:466 + 0x01, 0xD8, 0x17, 0x09, // 60=<:472 + 0x01, 0xEF, 0x17, 0x09, // 61==:495 + 0x02, 0x06, 0x17, 0x09, // 62=>:518 + 0x02, 0x1D, 0x16, 0x09, // 63=?:541 + 0x02, 0x33, 0x2F, 0x10, // 64=@:563 + 0x02, 0x62, 0x1D, 0x0B, // 65=A:610 + 0x02, 0x7F, 0x1D, 0x0B, // 66=B:639 + 0x02, 0x9C, 0x20, 0x0C, // 67=C:668 + 0x02, 0xBC, 0x20, 0x0C, // 68=D:700 + 0x02, 0xDC, 0x1D, 0x0B, // 69=E:732 + 0x02, 0xF9, 0x19, 0x0A, // 70=F:761 + 0x03, 0x12, 0x20, 0x0C, // 71=G:786 + 0x03, 0x32, 0x1D, 0x0B, // 72=H:818 + 0x03, 0x4F, 0x05, 0x03, // 73=I:847 + 0x03, 0x54, 0x14, 0x08, // 74=J:852 + 0x03, 0x68, 0x1D, 0x0B, // 75=K:872 + 0x03, 0x85, 0x17, 0x09, // 76=L:901 + 0x03, 0x9C, 0x23, 0x0D, // 77=M:924 + 0x03, 0xBF, 0x1D, 0x0B, // 78=N:959 + 0x03, 0xDC, 0x20, 0x0C, // 79=O:988 + 0x03, 0xFC, 0x1C, 0x0B, // 80=P:1020 + 0x04, 0x18, 0x20, 0x0C, // 81=Q:1048 + 0x04, 0x38, 0x1D, 0x0B, // 82=R:1080 + 0x04, 0x55, 0x1D, 0x0B, // 83=S:1109 + 0x04, 0x72, 0x19, 0x09, // 84=T:1138 + 0x04, 0x8B, 0x1D, 0x0B, // 85=U:1163 + 0x04, 0xA8, 0x1C, 0x0B, // 86=V:1192 + 0x04, 0xC4, 0x2B, 0x0F, // 87=W:1220 + 0x04, 0xEF, 0x20, 0x0B, // 88=X:1263 + 0x05, 0x0F, 0x19, 0x09, // 89=Y:1295 + 0x05, 0x28, 0x1A, 0x09, // 90=Z:1320 + 0x05, 0x42, 0x0C, 0x04, // 91=[:1346 + 0x05, 0x4E, 0x0B, 0x04, // 92=\:1358 + 0x05, 0x59, 0x09, 0x04, // 93=]:1369 + 0x05, 0x62, 0x14, 0x07, // 94=^:1378 + 0x05, 0x76, 0x1B, 0x09, // 95=_:1398 + 0x05, 0x91, 0x07, 0x05, // 96=`:1425 + 0x05, 0x98, 0x17, 0x09, // 97=a:1432 + 0x05, 0xAF, 0x17, 0x09, // 98=b:1455 + 0x05, 0xC6, 0x14, 0x08, // 99=c:1478 + 0x05, 0xDA, 0x17, 0x09, // 100=d:1498 + 0x05, 0xF1, 0x17, 0x09, // 101=e:1521 + 0x06, 0x08, 0x0A, 0x04, // 102=f:1544 + 0x06, 0x12, 0x17, 0x09, // 103=g:1554 + 0x06, 0x29, 0x14, 0x08, // 104=h:1577 + 0x06, 0x3D, 0x05, 0x04, // 105=i:1597 + 0x06, 0x42, 0x06, 0x03, // 106=j:1602 + 0x06, 0x48, 0x17, 0x08, // 107=k:1608 + 0x06, 0x5F, 0x05, 0x03, // 108=l:1631 + 0x06, 0x64, 0x23, 0x0D, // 109=m:1636 + 0x06, 0x87, 0x14, 0x08, // 110=n:1671 + 0x06, 0x9B, 0x17, 0x09, // 111=o:1691 + 0x06, 0xB2, 0x17, 0x09, // 112=p:1714 + 0x06, 0xC9, 0x18, 0x09, // 113=q:1737 + 0x06, 0xE1, 0x0D, 0x05, // 114=r:1761 + 0x06, 0xEE, 0x14, 0x08, // 115=s:1774 + 0x07, 0x02, 0x0B, 0x04, // 116=t:1794 + 0x07, 0x0D, 0x14, 0x08, // 117=u:1805 + 0x07, 0x21, 0x13, 0x07, // 118=v:1825 + 0x07, 0x34, 0x1F, 0x0B, // 119=w:1844 + 0x07, 0x53, 0x14, 0x07, // 120=x:1875 + 0x07, 0x67, 0x13, 0x07, // 121=y:1895 + 0x07, 0x7A, 0x14, 0x07, // 122=z:1914 + 0x07, 0x8E, 0x0F, 0x05, // 123={:1934 + 0x07, 0x9D, 0x06, 0x03, // 124=|:1949 + 0x07, 0xA3, 0x0E, 0x05, // 125=}:1955 + 0x07, 0xB1, 0x17, 0x09, // 126=~:1969 + 0x07, 0xC8, 0x1D, 0x0C, // 127=:1992 + 0x07, 0xE5, 0x26, 0x0E, // 1026=Ђ:2021 + 0x08, 0x0B, 0x19, 0x09, // 1027=Ѓ:2059 + 0x08, 0x24, 0x06, 0x04, // 8218=‚:2084 + 0x08, 0x2A, 0x10, 0x06, // 1107=ѓ:2090 + 0x08, 0x3A, 0x09, 0x05, // 8222=„:2106 + 0x08, 0x43, 0x26, 0x10, // 8230=…:2115 + 0x08, 0x69, 0x16, 0x09, // 8224=†:2153 + 0x08, 0x7F, 0x17, 0x09, // 8225=‡:2175 + 0x08, 0x96, 0x17, 0x09, // 8364=€:2198 + 0x08, 0xAD, 0x32, 0x11, // 8240=‰:2221 + 0x08, 0xDF, 0x2F, 0x11, // 1033=Љ:2271 + 0x09, 0x0E, 0x0B, 0x05, // 8249=‹:2318 + 0x09, 0x19, 0x2C, 0x10, // 1034=Њ:2329 + 0x09, 0x45, 0x1A, 0x09, // 1036=Ќ:2373 + 0x09, 0x5F, 0x23, 0x0D, // 1035=Ћ:2399 + 0x09, 0x82, 0x1D, 0x0C, // 1039=Џ:2434 + 0x09, 0x9F, 0x15, 0x08, // 1106=ђ:2463 + 0x09, 0xB4, 0x04, 0x04, // 8216=‘:2484 + 0x09, 0xB8, 0x04, 0x04, // 8217=’:2488 + 0x09, 0xBC, 0x07, 0x05, // 8220=“:2492 + 0x09, 0xC3, 0x0A, 0x05, // 8221=”:2499 + 0x09, 0xCD, 0x0E, 0x06, // 8226=•:2509 + 0x09, 0xDB, 0x1A, 0x09, // 8211=–:2523 + 0x09, 0xF5, 0x2F, 0x10, // 8212=—:2549 + 0x0A, 0x24, 0x1D, 0x0C, // 65533=�:2596 + 0x0A, 0x41, 0x2C, 0x10, // 8482=™:2625 + 0x0A, 0x6D, 0x29, 0x0F, // 1113=љ:2669 + 0x0A, 0x96, 0x0B, 0x05, // 8250=›:2710 + 0x0A, 0xA1, 0x23, 0x0D, // 1114=њ:2721 + 0x0A, 0xC4, 0x14, 0x07, // 1116=ќ:2756 + 0x0A, 0xD8, 0x14, 0x08, // 1115=ћ:2776 + 0x0A, 0xEC, 0x14, 0x08, // 1119=џ:2796 + 0xFF, 0xFF, 0x00, 0x04, // 160= :65535 + 0x0B, 0x00, 0x1C, 0x0A, // 1038=Ў:2816 + 0x0B, 0x1C, 0x13, 0x07, // 1118=ў:2844 + 0x0B, 0x2F, 0x14, 0x08, // 1032=Ј:2863 + 0x0B, 0x43, 0x14, 0x09, // 164=¤:2883 + 0x0B, 0x57, 0x16, 0x08, // 1168=Ґ:2903 + 0x0B, 0x6D, 0x06, 0x03, // 166=¦:2925 + 0x0B, 0x73, 0x17, 0x09, // 167=§:2931 + 0x0B, 0x8A, 0x1D, 0x0B, // 1025=Ё:2954 + 0x0B, 0xA7, 0x23, 0x0C, // 169=©:2983 + 0x0B, 0xCA, 0x20, 0x0C, // 1028=Є:3018 + 0x0B, 0xEA, 0x14, 0x09, // 171=«:3050 + 0x0B, 0xFE, 0x17, 0x09, // 172=¬:3070 + 0x0C, 0x15, 0x0B, 0x05, // 173=­:3093 + 0x0C, 0x20, 0x23, 0x0C, // 174=®:3104 + 0x0C, 0x43, 0x07, 0x03, // 1031=Ї:3139 + 0x0C, 0x4A, 0x0D, 0x06, // 176=°:3146 + 0x0C, 0x57, 0x17, 0x09, // 177=±:3159 + 0x0C, 0x6E, 0x05, 0x03, // 1030=І:3182 + 0x0C, 0x73, 0x05, 0x04, // 1110=і:3187 + 0x0C, 0x78, 0x10, 0x07, // 1169=ґ:3192 + 0x0C, 0x88, 0x17, 0x09, // 181=µ:3208 + 0x0C, 0x9F, 0x19, 0x09, // 182=¶:3231 + 0x0C, 0xB8, 0x08, 0x05, // 183=·:3256 + 0x0C, 0xC0, 0x17, 0x09, // 1105=ё:3264 + 0x0C, 0xD7, 0x2F, 0x11, // 8470=№:3287 + 0x0D, 0x06, 0x14, 0x08, // 1108=є:3334 + 0x0D, 0x1A, 0x17, 0x09, // 187=»:3354 + 0x0D, 0x31, 0x06, 0x03, // 1112=ј:3377 + 0x0D, 0x37, 0x1D, 0x0B, // 1029=Ѕ:3383 + 0x0D, 0x54, 0x14, 0x08, // 1109=ѕ:3412 + 0x0D, 0x68, 0x07, 0x03, // 1111=ї:3432 + 0x0D, 0x6F, 0x1D, 0x0B, // 1040=А:3439 + 0x0D, 0x8C, 0x1D, 0x0B, // 1041=Б:3468 + 0x0D, 0xA9, 0x1D, 0x0B, // 1042=В:3497 + 0x0D, 0xC6, 0x19, 0x09, // 1043=Г:3526 + 0x0D, 0xDF, 0x1E, 0x0B, // 1044=Д:3551 + 0x0D, 0xFD, 0x1D, 0x0B, // 1045=Е:3581 + 0x0E, 0x1A, 0x29, 0x0E, // 1046=Ж:3610 + 0x0E, 0x43, 0x1A, 0x0A, // 1047=З:3651 + 0x0E, 0x5D, 0x20, 0x0C, // 1048=И:3677 + 0x0E, 0x7D, 0x20, 0x0C, // 1049=Й:3709 + 0x0E, 0x9D, 0x1A, 0x09, // 1050=К:3741 + 0x0E, 0xB7, 0x1D, 0x0B, // 1051=Л:3767 + 0x0E, 0xD4, 0x23, 0x0D, // 1052=М:3796 + 0x0E, 0xF7, 0x1D, 0x0B, // 1053=Н:3831 + 0x0F, 0x14, 0x20, 0x0C, // 1054=О:3860 + 0x0F, 0x34, 0x1D, 0x0B, // 1055=П:3892 + 0x0F, 0x51, 0x1C, 0x0B, // 1056=Р:3921 + 0x0F, 0x6D, 0x20, 0x0C, // 1057=С:3949 + 0x0F, 0x8D, 0x19, 0x09, // 1058=Т:3981 + 0x0F, 0xA6, 0x1C, 0x0A, // 1059=У:4006 + 0x0F, 0xC2, 0x1D, 0x0B, // 1060=Ф:4034 + 0x0F, 0xDF, 0x20, 0x0B, // 1061=Х:4063 + 0x0F, 0xFF, 0x21, 0x0C, // 1062=Ц:4095 + 0x10, 0x20, 0x1A, 0x0A, // 1063=Ч:4128 + 0x10, 0x3A, 0x23, 0x0D, // 1064=Ш:4154 + 0x10, 0x5D, 0x27, 0x0E, // 1065=Щ:4189 + 0x10, 0x84, 0x23, 0x0D, // 1066=Ъ:4228 + 0x10, 0xA7, 0x26, 0x0E, // 1067=Ы:4263 + 0x10, 0xCD, 0x1D, 0x0B, // 1068=Ь:4301 + 0x10, 0xEA, 0x20, 0x0C, // 1069=Э:4330 + 0x11, 0x0A, 0x2C, 0x10, // 1070=Ю:4362 + 0x11, 0x36, 0x20, 0x0C, // 1071=Я:4406 + 0x11, 0x56, 0x17, 0x09, // 1072=а:4438 + 0x11, 0x6D, 0x17, 0x09, // 1073=б:4461 + 0x11, 0x84, 0x17, 0x09, // 1074=в:4484 + 0x11, 0x9B, 0x10, 0x06, // 1075=г:4507 + 0x11, 0xAB, 0x18, 0x09, // 1076=д:4523 + 0x11, 0xC3, 0x17, 0x09, // 1077=е:4547 + 0x11, 0xDA, 0x1D, 0x0A, // 1078=ж:4570 + 0x11, 0xF7, 0x11, 0x07, // 1079=з:4599 + 0x12, 0x08, 0x14, 0x08, // 1080=и:4616 + 0x12, 0x1C, 0x14, 0x08, // 1081=й:4636 + 0x12, 0x30, 0x14, 0x07, // 1082=к:4656 + 0x12, 0x44, 0x14, 0x08, // 1083=л:4676 + 0x12, 0x58, 0x1D, 0x0B, // 1084=м:4696 + 0x12, 0x75, 0x14, 0x08, // 1085=н:4725 + 0x12, 0x89, 0x17, 0x09, // 1086=о:4745 + 0x12, 0xA0, 0x14, 0x08, // 1087=п:4768 + 0x12, 0xB4, 0x17, 0x09, // 1088=р:4788 + 0x12, 0xCB, 0x14, 0x08, // 1089=с:4811 + 0x12, 0xDF, 0x13, 0x07, // 1090=т:4831 + 0x12, 0xF2, 0x13, 0x07, // 1091=у:4850 + 0x13, 0x05, 0x23, 0x0D, // 1092=ф:4869 + 0x13, 0x28, 0x14, 0x07, // 1093=х:4904 + 0x13, 0x3C, 0x1B, 0x09, // 1094=ц:4924 + 0x13, 0x57, 0x14, 0x08, // 1095=ч:4951 + 0x13, 0x6B, 0x1D, 0x0B, // 1096=ш:4971 + 0x13, 0x88, 0x21, 0x0B, // 1097=щ:5000 + 0x13, 0xA9, 0x1A, 0x0A, // 1098=ъ:5033 + 0x13, 0xC3, 0x20, 0x0C, // 1099=ы:5059 + 0x13, 0xE3, 0x17, 0x09, // 1100=ь:5091 + 0x13, 0xFA, 0x14, 0x08, // 1101=э:5114 + 0x14, 0x0E, 0x20, 0x0C, // 1102=ю:5134 + 0x14, 0x2E, 0x17, 0x09, // 1103=я:5166 + // Font Data: + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x5F, // 33 + 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, // 34 + 0x80, 0x08, 0x00, 0x80, 0x78, 0x00, 0xC0, 0x0F, 0x00, 0xB8, 0x08, 0x00, 0x80, 0x08, 0x00, 0x80, 0x78, 0x00, 0xC0, 0x0F, 0x00, + 0xB8, 0x08, 0x00, 0x80, 0x08, // 35 + 0x00, 0x00, 0x00, 0xE0, 0x10, 0x00, 0x10, 0x21, 0x00, 0x08, 0x43, 0x00, 0xFC, 0xFF, 0x00, 0x08, 0x42, 0x00, 0x18, 0x22, 0x00, + 0x20, 0x1C, // 36 + 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x08, 0x01, 0x00, 0x08, 0x01, 0x00, 0x08, 0x61, 0x00, 0xF0, 0x18, 0x00, 0x00, 0x06, 0x00, + 0xC0, 0x01, 0x00, 0x30, 0x3C, 0x00, 0x08, 0x42, 0x00, 0x00, 0x42, 0x00, 0x00, 0x42, 0x00, 0x00, 0x3C, // 37 + 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x70, 0x22, 0x00, 0x88, 0x41, 0x00, 0x08, 0x43, 0x00, 0x88, 0x44, 0x00, 0x70, 0x28, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x28, 0x00, 0x00, 0x44, // 38 + 0x00, 0x00, 0x00, 0x78, // 39 + 0x00, 0x00, 0x00, 0x80, 0x3F, 0x00, 0x70, 0xC0, 0x01, 0x08, 0x00, 0x02, // 40 + 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x70, 0xC0, 0x01, 0x80, 0x3F, // 41 + 0x10, 0x00, 0x00, 0xD0, 0x00, 0x00, 0x38, 0x00, 0x00, 0xD0, 0x00, 0x00, 0x10, // 42 + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0xC0, 0x1F, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x02, // 43 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, // 44 + 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, // 45 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, // 46 + 0x00, 0x60, 0x00, 0x00, 0x1E, 0x00, 0xE0, 0x01, 0x00, 0x18, // 47 + 0x00, 0x00, 0x00, 0xE0, 0x1F, 0x00, 0x10, 0x20, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x10, 0x20, 0x00, + 0xE0, 0x1F, // 48 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, 0x00, 0x00, 0xF8, 0x7F, // 49 + 0x00, 0x00, 0x00, 0x20, 0x40, 0x00, 0x10, 0x60, 0x00, 0x08, 0x50, 0x00, 0x08, 0x48, 0x00, 0x08, 0x44, 0x00, 0x10, 0x43, 0x00, + 0xE0, 0x40, // 50 + 0x00, 0x00, 0x00, 0x20, 0x10, 0x00, 0x10, 0x20, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x88, 0x41, 0x00, 0xF0, 0x22, 0x00, + 0x00, 0x1C, // 51 + 0x00, 0x0C, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x09, 0x00, 0xC0, 0x08, 0x00, 0x20, 0x08, 0x00, 0x10, 0x08, 0x00, 0xF8, 0x7F, 0x00, + 0x00, 0x08, // 52 + 0x00, 0x00, 0x00, 0xC0, 0x11, 0x00, 0xB8, 0x20, 0x00, 0x88, 0x40, 0x00, 0x88, 0x40, 0x00, 0x88, 0x40, 0x00, 0x08, 0x21, 0x00, + 0x08, 0x1E, // 53 + 0x00, 0x00, 0x00, 0xE0, 0x1F, 0x00, 0x10, 0x21, 0x00, 0x88, 0x40, 0x00, 0x88, 0x40, 0x00, 0x88, 0x40, 0x00, 0x10, 0x21, 0x00, + 0x20, 0x1E, // 54 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x78, 0x00, 0x88, 0x07, 0x00, 0x68, 0x00, 0x00, + 0x18, // 55 + 0x00, 0x00, 0x00, 0x60, 0x1C, 0x00, 0x90, 0x22, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x90, 0x22, 0x00, + 0x60, 0x1C, // 56 + 0x00, 0x00, 0x00, 0xE0, 0x11, 0x00, 0x10, 0x22, 0x00, 0x08, 0x44, 0x00, 0x08, 0x44, 0x00, 0x08, 0x44, 0x00, 0x10, 0x22, 0x00, + 0xE0, 0x1F, // 57 + 0x00, 0x00, 0x00, 0x40, 0x40, // 58 + 0x00, 0x00, 0x00, 0x40, 0xC0, 0x01, // 59 + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x05, 0x00, 0x80, 0x08, 0x00, 0x80, 0x08, 0x00, 0x80, 0x08, 0x00, + 0x40, 0x10, // 60 + 0x00, 0x00, 0x00, 0x80, 0x08, 0x00, 0x80, 0x08, 0x00, 0x80, 0x08, 0x00, 0x80, 0x08, 0x00, 0x80, 0x08, 0x00, 0x80, 0x08, 0x00, + 0x80, 0x08, // 61 + 0x00, 0x00, 0x00, 0x40, 0x10, 0x00, 0x80, 0x08, 0x00, 0x80, 0x08, 0x00, 0x80, 0x08, 0x00, 0x00, 0x05, 0x00, 0x00, 0x05, 0x00, + 0x00, 0x02, // 62 + 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x10, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x5C, 0x00, 0x08, 0x02, 0x00, 0x10, 0x01, 0x00, + 0xE0, // 63 + 0x00, 0x00, 0x00, 0x00, 0x3F, 0x00, 0xC0, 0x40, 0x00, 0x20, 0x80, 0x00, 0x10, 0x1E, 0x01, 0x10, 0x21, 0x01, 0x88, 0x40, 0x02, + 0x48, 0x40, 0x02, 0x48, 0x40, 0x02, 0x48, 0x20, 0x02, 0x88, 0x7C, 0x02, 0xC8, 0x43, 0x02, 0x10, 0x40, 0x02, 0x10, 0x20, 0x01, + 0x60, 0x10, 0x01, 0x80, 0x8F, // 64 + 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x1C, 0x00, 0x80, 0x07, 0x00, 0x70, 0x04, 0x00, 0x08, 0x04, 0x00, 0x70, 0x04, 0x00, + 0x80, 0x07, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x60, // 65 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, + 0x08, 0x41, 0x00, 0x90, 0x22, 0x00, 0x60, 0x1C, // 66 + 0x00, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x20, 0x10, 0x00, 0x10, 0x20, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, + 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x10, 0x20, 0x00, 0x20, 0x10, // 67 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, + 0x08, 0x40, 0x00, 0x10, 0x20, 0x00, 0x20, 0x10, 0x00, 0xC0, 0x0F, // 68 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, + 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x40, // 69 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x08, 0x02, 0x00, 0x08, 0x02, 0x00, 0x08, 0x02, 0x00, 0x08, 0x02, 0x00, 0x08, 0x02, 0x00, + 0x08, 0x02, 0x00, 0x08, // 70 + 0x00, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x20, 0x10, 0x00, 0x10, 0x20, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x08, 0x42, 0x00, + 0x08, 0x42, 0x00, 0x10, 0x22, 0x00, 0x20, 0x12, 0x00, 0x00, 0x0E, // 71 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0xF8, 0x7F, // 72 + 0x00, 0x00, 0x00, 0xF8, 0x7F, // 73 + 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0xF8, 0x3F, // 74 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x04, 0x00, 0x00, 0x02, 0x00, 0x00, 0x01, 0x00, 0x80, 0x03, 0x00, 0x40, 0x04, 0x00, + 0x20, 0x18, 0x00, 0x10, 0x20, 0x00, 0x08, 0x40, // 75 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, + 0x00, 0x40, // 76 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x30, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x60, 0x00, + 0x00, 0x1C, 0x00, 0x00, 0x03, 0x00, 0xC0, 0x00, 0x00, 0x30, 0x00, 0x00, 0xF8, 0x7F, // 77 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x10, 0x00, 0x00, 0x60, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x04, 0x00, + 0x00, 0x18, 0x00, 0x00, 0x20, 0x00, 0xF8, 0x7F, // 78 + 0x00, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x20, 0x10, 0x00, 0x10, 0x20, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, + 0x08, 0x40, 0x00, 0x10, 0x20, 0x00, 0x20, 0x10, 0x00, 0xC0, 0x0F, // 79 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x08, 0x02, 0x00, 0x08, 0x02, 0x00, 0x08, 0x02, 0x00, 0x08, 0x02, 0x00, 0x08, 0x02, 0x00, + 0x08, 0x02, 0x00, 0x10, 0x01, 0x00, 0xE0, // 80 + 0x00, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x20, 0x10, 0x00, 0x10, 0x20, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x08, 0x50, 0x00, + 0x08, 0x50, 0x00, 0x10, 0x20, 0x00, 0x20, 0x70, 0x00, 0xC0, 0x4F, // 81 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x08, 0x02, 0x00, 0x08, 0x02, 0x00, 0x08, 0x02, 0x00, 0x08, 0x02, 0x00, 0x08, 0x0E, 0x00, + 0x08, 0x1A, 0x00, 0x10, 0x21, 0x00, 0xE0, 0x40, // 82 + 0x00, 0x00, 0x00, 0x60, 0x10, 0x00, 0x90, 0x20, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x42, 0x00, + 0x08, 0x42, 0x00, 0x10, 0x22, 0x00, 0x20, 0x1C, // 83 + 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x08, // 84 + 0x00, 0x00, 0x00, 0xF8, 0x1F, 0x00, 0x00, 0x20, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x20, 0x00, 0xF8, 0x1F, // 85 + 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x18, 0x00, 0x00, 0x60, 0x00, 0x00, 0x18, 0x00, + 0x00, 0x07, 0x00, 0xE0, 0x00, 0x00, 0x18, // 86 + 0x18, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x60, 0x00, 0x00, 0x1C, 0x00, 0x80, 0x03, 0x00, 0x70, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x70, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x60, 0x00, 0x00, 0x1E, 0x00, 0xE0, 0x01, 0x00, + 0x18, // 87 + 0x00, 0x40, 0x00, 0x08, 0x20, 0x00, 0x10, 0x18, 0x00, 0x60, 0x04, 0x00, 0x80, 0x02, 0x00, 0x00, 0x01, 0x00, 0x80, 0x02, 0x00, + 0x60, 0x0C, 0x00, 0x10, 0x10, 0x00, 0x08, 0x20, 0x00, 0x00, 0x40, // 88 + 0x08, 0x00, 0x00, 0x30, 0x00, 0x00, 0x40, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x7E, 0x00, 0x80, 0x01, 0x00, 0x40, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x08, // 89 + 0x00, 0x40, 0x00, 0x08, 0x60, 0x00, 0x08, 0x58, 0x00, 0x08, 0x44, 0x00, 0x08, 0x43, 0x00, 0x88, 0x40, 0x00, 0x68, 0x40, 0x00, + 0x18, 0x40, 0x00, 0x08, 0x40, // 90 + 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x03, 0x08, 0x00, 0x02, 0x08, 0x00, 0x02, // 91 + 0x18, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x60, // 92 + 0x08, 0x00, 0x02, 0x08, 0x00, 0x02, 0xF8, 0xFF, 0x03, // 93 + 0x00, 0x01, 0x00, 0xC0, 0x00, 0x00, 0x30, 0x00, 0x00, 0x08, 0x00, 0x00, 0x30, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x01, // 94 + 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, // 95 + 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x10, // 96 + 0x00, 0x00, 0x00, 0x00, 0x39, 0x00, 0x80, 0x44, 0x00, 0x40, 0x44, 0x00, 0x40, 0x44, 0x00, 0x40, 0x42, 0x00, 0x40, 0x22, 0x00, + 0x80, 0x7F, // 97 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x80, 0x20, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x80, 0x20, 0x00, + 0x00, 0x1F, // 98 + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x80, 0x20, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x80, 0x20, // 99 + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x80, 0x20, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x80, 0x20, 0x00, + 0xF8, 0x7F, // 100 + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x80, 0x24, 0x00, 0x40, 0x44, 0x00, 0x40, 0x44, 0x00, 0x40, 0x44, 0x00, 0x80, 0x24, 0x00, + 0x00, 0x17, // 101 + 0x40, 0x00, 0x00, 0xF0, 0x7F, 0x00, 0x48, 0x00, 0x00, 0x48, // 102 + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x01, 0x80, 0x20, 0x02, 0x40, 0x40, 0x02, 0x40, 0x40, 0x02, 0x40, 0x40, 0x02, 0x80, 0x20, 0x01, + 0xC0, 0xFF, // 103 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x80, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x80, 0x7F, // 104 + 0x00, 0x00, 0x00, 0xC8, 0x7F, // 105 + 0x00, 0x00, 0x02, 0xC8, 0xFF, 0x01, // 106 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x04, 0x00, 0x00, 0x06, 0x00, 0x00, 0x19, 0x00, 0x80, 0x20, 0x00, + 0x40, 0x40, // 107 + 0x00, 0x00, 0x00, 0xF8, 0x7F, // 108 + 0x00, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x80, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x80, 0x7F, 0x00, + 0x80, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x80, 0x7F, // 109 + 0x00, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x80, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x80, 0x7F, // 110 + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x80, 0x20, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x80, 0x20, 0x00, + 0x00, 0x1F, // 111 + 0x00, 0x00, 0x00, 0xC0, 0xFF, 0x03, 0x80, 0x20, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x80, 0x20, 0x00, + 0x00, 0x1F, // 112 + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x80, 0x20, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x80, 0x20, 0x00, + 0xC0, 0xFF, 0x03, // 113 + 0x00, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x80, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, // 114 + 0x00, 0x00, 0x00, 0x80, 0x23, 0x00, 0x40, 0x44, 0x00, 0x40, 0x44, 0x00, 0x40, 0x44, 0x00, 0x40, 0x44, 0x00, 0x80, 0x38, // 115 + 0x40, 0x00, 0x00, 0xF0, 0x7F, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, // 116 + 0x00, 0x00, 0x00, 0xC0, 0x3F, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x20, 0x00, 0xC0, 0x7F, // 117 + 0xC0, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x60, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x03, 0x00, 0xC0, // 118 + 0xC0, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x60, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x03, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x03, 0x00, + 0x00, 0x1C, 0x00, 0x00, 0x60, 0x00, 0x00, 0x1F, 0x00, 0xC0, // 119 + 0x40, 0x40, 0x00, 0x80, 0x20, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x04, 0x00, 0x00, 0x1B, 0x00, 0x80, 0x20, 0x00, 0x40, 0x40, // 120 + 0xC0, 0x01, 0x00, 0x00, 0x06, 0x02, 0x00, 0x38, 0x02, 0x00, 0xC0, 0x01, 0x00, 0x38, 0x00, 0x00, 0x07, 0x00, 0xC0, // 121 + 0x40, 0x40, 0x00, 0x40, 0x60, 0x00, 0x40, 0x58, 0x00, 0x40, 0x44, 0x00, 0x40, 0x43, 0x00, 0xC0, 0x40, 0x00, 0x40, 0x40, // 122 + 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0xF0, 0xFB, 0x01, 0x08, 0x00, 0x02, 0x08, 0x00, 0x02, // 123 + 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x03, // 124 + 0x08, 0x00, 0x02, 0x08, 0x00, 0x02, 0xF0, 0xFB, 0x01, 0x00, 0x04, 0x00, 0x00, 0x04, // 125 + 0x00, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x01, // 126 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x7F, 0x00, 0x20, 0x40, 0x00, 0x20, 0x40, 0x00, 0x20, 0x40, 0x00, 0x20, 0x40, 0x00, + 0x20, 0x40, 0x00, 0x20, 0x40, 0x00, 0xE0, 0x7F, // 127 + 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x08, 0x02, 0x00, 0x08, 0x01, 0x00, + 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, 0x00, 0x3E, // 1026 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x08, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x09, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x08, // 1027 + 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, // 8218 + 0x00, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x40, 0x00, 0x00, 0x50, 0x00, 0x00, 0x48, 0x00, 0x00, 0x40, // 1107 + 0x00, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, // 8222 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, // 8230 + 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0xF8, 0xFF, 0x03, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, + 0x40, // 8224 + 0x00, 0x00, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0xF8, 0xFF, 0x03, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, + 0x40, 0x40, // 8225 + 0x00, 0x05, 0x00, 0xC0, 0x1F, 0x00, 0x20, 0x25, 0x00, 0x10, 0x45, 0x00, 0x08, 0x45, 0x00, 0x08, 0x45, 0x00, 0x08, 0x45, 0x00, + 0x10, 0x20, // 8364 + 0xF0, 0x00, 0x00, 0x08, 0x01, 0x00, 0x08, 0x01, 0x00, 0x08, 0x71, 0x00, 0xF0, 0x0C, 0x00, 0x00, 0x03, 0x00, 0xE0, 0x3C, 0x00, + 0x18, 0x42, 0x00, 0x00, 0x42, 0x00, 0x00, 0x42, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x42, 0x00, + 0x00, 0x42, 0x00, 0x00, 0x42, 0x00, 0x00, 0x3C, // 8240 + 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0xF8, 0x3F, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x08, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, + 0x00, 0x41, 0x00, 0x00, 0x3E, // 1033 + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x1B, 0x00, 0x80, 0x20, // 8249 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, + 0xF8, 0x7F, 0x00, 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, + 0x00, 0x3E, // 1034 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x82, 0x02, 0x00, 0x61, 0x04, 0x00, 0x10, 0x08, 0x00, + 0x08, 0x30, 0x00, 0x08, 0x40, // 1036 + 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x08, 0x02, 0x00, 0x08, 0x01, 0x00, + 0x08, 0x01, 0x00, 0x08, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x7E, // 1035 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x40, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0xF8, 0x7F, // 1039 + 0x10, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x90, 0x00, 0x00, 0x50, 0x00, 0x00, 0x50, 0x00, 0x00, 0x40, 0x00, 0x02, 0x80, 0xFF, + 0x03, // 1106 + 0x00, 0x00, 0x00, 0x38, // 8216 + 0x00, 0x00, 0x00, 0x38, // 8217 + 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, // 8220 + 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, // 8221 + 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x80, 0x07, 0x00, 0x80, 0x07, 0x00, 0x00, 0x03, // 8226 + 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x04, // 8211 + 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x04, // 8212 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x7F, 0x00, 0x20, 0x40, 0x00, 0x20, 0x40, 0x00, 0x20, 0x40, 0x00, 0x20, 0x40, 0x00, + 0x20, 0x40, 0x00, 0x20, 0x40, 0x00, 0xE0, 0x7F, // 65533 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0xF8, 0x01, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xF8, 0x01, 0x00, 0x18, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x01, 0x00, 0xE0, 0x00, 0x00, 0x18, 0x00, 0x00, + 0xF8, 0x01, // 8482 + 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0xC0, 0x3F, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, + 0xC0, 0x7F, 0x00, 0x00, 0x44, 0x00, 0x00, 0x44, 0x00, 0x00, 0x44, 0x00, 0x00, 0x44, 0x00, 0x00, 0x64, 0x00, 0x00, + 0x38, // 1113 + 0x00, 0x00, 0x00, 0x80, 0x20, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x04, // 8250 + 0x00, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0xC0, 0x7F, 0x00, + 0x00, 0x44, 0x00, 0x00, 0x44, 0x00, 0x00, 0x44, 0x00, 0x00, 0x44, 0x00, 0x00, 0x38, // 1114 + 0x00, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x00, 0x04, 0x00, 0x10, 0x04, 0x00, 0x08, 0x1B, 0x00, 0xC0, 0x20, 0x00, 0x40, + 0x40, // 1116 + 0x10, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x90, 0x00, 0x00, 0x50, 0x00, 0x00, 0x50, 0x00, 0x00, 0x40, 0x00, 0x00, 0x80, + 0x7F, // 1115 + 0x00, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x40, 0x00, 0xC0, + 0x7F, // 1119 + 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x60, 0x40, 0x00, 0x81, 0x41, 0x00, 0x02, 0x66, 0x00, 0x02, 0x18, 0x00, 0x02, 0x06, 0x00, + 0x81, 0x01, 0x00, 0x60, 0x00, 0x00, 0x18, // 1038 + 0xC0, 0x01, 0x00, 0x08, 0x06, 0x02, 0x10, 0x38, 0x02, 0x10, 0xC0, 0x01, 0x10, 0x38, 0x00, 0x08, 0x07, 0x00, 0xC0, // 1118 + 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0xF8, + 0x3F, // 1032 + 0x00, 0x00, 0x00, 0x40, 0x0B, 0x00, 0x80, 0x04, 0x00, 0x40, 0x08, 0x00, 0x40, 0x08, 0x00, 0x80, 0x04, 0x00, 0x40, 0x0B, // 164 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x0F, // 1168 + 0x00, 0x00, 0x00, 0xF8, 0xF1, 0x03, // 166 + 0x00, 0x86, 0x00, 0x70, 0x09, 0x01, 0xC8, 0x10, 0x02, 0x88, 0x10, 0x02, 0x08, 0x21, 0x02, 0x08, 0x61, 0x02, 0x30, 0xD2, 0x01, + 0x00, 0x0C, // 167 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x08, 0x41, 0x00, 0x0A, 0x41, 0x00, 0x08, 0x41, 0x00, 0x0A, 0x41, 0x00, 0x08, 0x41, 0x00, + 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x40, // 1025 + 0xC0, 0x0F, 0x00, 0x20, 0x10, 0x00, 0x10, 0x20, 0x00, 0xC8, 0x47, 0x00, 0x28, 0x48, 0x00, 0x28, 0x48, 0x00, 0x28, 0x48, 0x00, + 0x28, 0x48, 0x00, 0x48, 0x44, 0x00, 0x10, 0x20, 0x00, 0x20, 0x10, 0x00, 0xC0, 0x0F, // 169 + 0x00, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x20, 0x11, 0x00, 0x10, 0x21, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, + 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x10, 0x20, 0x00, 0x20, 0x10, // 1028 + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x1B, 0x00, 0x80, 0x20, 0x00, 0x00, 0x04, 0x00, 0x00, 0x1B, 0x00, 0x80, 0x20, // 171 + 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x80, 0x0F, // 172 + 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, // 173 + 0xC0, 0x0F, 0x00, 0x20, 0x10, 0x00, 0x10, 0x20, 0x00, 0xE8, 0x4F, 0x00, 0x28, 0x41, 0x00, 0x28, 0x41, 0x00, 0x28, 0x43, 0x00, + 0x28, 0x45, 0x00, 0xC8, 0x48, 0x00, 0x10, 0x20, 0x00, 0x20, 0x10, 0x00, 0xC0, 0x0F, // 174 + 0x02, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x02, // 1031 + 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x48, 0x00, 0x00, 0x48, 0x00, 0x00, 0x30, // 176 + 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, 0xE0, 0x4F, 0x00, 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, + 0x00, 0x41, // 177 + 0x00, 0x00, 0x00, 0xF8, 0x7F, // 1030 + 0x00, 0x00, 0x00, 0xC8, 0x7F, // 1110 + 0x00, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x78, // 1169 + 0x00, 0x00, 0x00, 0xC0, 0xFF, 0x03, 0x00, 0x20, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x20, 0x00, + 0xC0, 0x7F, // 181 + 0xF0, 0x00, 0x00, 0xF8, 0x00, 0x00, 0xF8, 0x01, 0x00, 0xF8, 0x01, 0x00, 0xF8, 0xFF, 0x03, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, + 0xF8, 0xFF, 0x03, 0x08, // 182 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, // 183 + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x80, 0x24, 0x00, 0x50, 0x44, 0x00, 0x40, 0x44, 0x00, 0x50, 0x44, 0x00, 0x80, 0x24, 0x00, + 0x00, 0x17, // 1105 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x20, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x06, 0x00, 0x00, 0x08, 0x00, + 0x00, 0x10, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x80, 0x27, 0x00, 0x40, 0x28, 0x00, 0x40, 0x28, 0x00, 0x40, 0x28, 0x00, + 0x40, 0x28, 0x00, 0x80, 0x27, // 8470 + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x80, 0x24, 0x00, 0x40, 0x44, 0x00, 0x40, 0x44, 0x00, 0x80, 0x20, 0x00, 0x00, + 0x11, // 1108 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x20, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x04, 0x00, 0x80, 0x20, 0x00, 0x00, 0x1B, 0x00, + 0x00, 0x04, // 187 + 0x00, 0x00, 0x02, 0xC8, 0xFF, 0x01, // 1112 + 0x00, 0x00, 0x00, 0x60, 0x10, 0x00, 0x90, 0x20, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x42, 0x00, + 0x08, 0x42, 0x00, 0x10, 0x22, 0x00, 0x20, 0x1C, // 1029 + 0x00, 0x00, 0x00, 0x80, 0x23, 0x00, 0x40, 0x44, 0x00, 0x40, 0x44, 0x00, 0x40, 0x44, 0x00, 0x40, 0x44, 0x00, 0x80, + 0x38, // 1109 + 0x10, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x10, // 1111 + 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x1C, 0x00, 0x80, 0x07, 0x00, 0x70, 0x04, 0x00, 0x08, 0x04, 0x00, 0x70, 0x04, 0x00, + 0x80, 0x07, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x60, // 1040 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, + 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x00, 0x3E, // 1041 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, + 0x08, 0x41, 0x00, 0x90, 0x22, 0x00, 0x60, 0x1C, // 1042 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x08, // 1043 + 0x00, 0xC0, 0x03, 0x00, 0x60, 0x00, 0x00, 0x5C, 0x00, 0xF8, 0x43, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, + 0x08, 0x40, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0xC0, 0x03, // 1044 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, + 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x40, // 1045 + 0x08, 0x30, 0x00, 0x10, 0x08, 0x00, 0x60, 0x04, 0x00, 0x80, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0xF8, 0x7F, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x80, 0x02, 0x00, 0x60, 0x04, 0x00, 0x10, 0x08, 0x00, 0x08, 0x30, 0x00, 0x08, + 0x40, // 1046 + 0x00, 0x00, 0x00, 0x20, 0x10, 0x00, 0x10, 0x20, 0x00, 0x08, 0x40, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x88, 0x42, 0x00, + 0x70, 0x42, 0x00, 0x00, 0x3C, // 1047 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x30, 0x00, 0x00, 0x08, 0x00, 0x00, 0x04, 0x00, 0x00, 0x02, 0x00, 0x00, 0x01, 0x00, + 0x80, 0x00, 0x00, 0x40, 0x00, 0x00, 0x30, 0x00, 0x00, 0xF8, 0x7F, // 1048 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x30, 0x00, 0x00, 0x08, 0x00, 0x01, 0x04, 0x00, 0x02, 0x02, 0x00, 0x02, 0x01, 0x00, + 0x82, 0x00, 0x00, 0x41, 0x00, 0x00, 0x30, 0x00, 0x00, 0xF8, 0x7F, // 1049 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x80, 0x02, 0x00, 0x60, 0x04, 0x00, 0x10, 0x08, 0x00, + 0x08, 0x30, 0x00, 0x08, 0x40, // 1050 + 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0xF8, 0x3F, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0xF8, 0x7F, // 1051 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x30, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x60, 0x00, + 0x00, 0x1C, 0x00, 0x00, 0x03, 0x00, 0xC0, 0x00, 0x00, 0x30, 0x00, 0x00, 0xF8, 0x7F, // 1052 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0xF8, 0x7F, // 1053 + 0x00, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x20, 0x10, 0x00, 0x10, 0x20, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, + 0x08, 0x40, 0x00, 0x10, 0x20, 0x00, 0x20, 0x10, 0x00, 0xC0, 0x0F, // 1054 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0xF8, 0x7F, // 1055 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x08, 0x02, 0x00, 0x08, 0x02, 0x00, 0x08, 0x02, 0x00, 0x08, 0x02, 0x00, 0x08, 0x02, 0x00, + 0x08, 0x02, 0x00, 0x10, 0x01, 0x00, 0xE0, // 1056 + 0x00, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x20, 0x10, 0x00, 0x10, 0x20, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, + 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x10, 0x20, 0x00, 0x20, 0x10, // 1057 + 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x08, // 1058 + 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x60, 0x40, 0x00, 0x80, 0x41, 0x00, 0x00, 0x66, 0x00, 0x00, 0x18, 0x00, 0x00, 0x06, 0x00, + 0x80, 0x01, 0x00, 0x60, 0x00, 0x00, 0x18, // 1059 + 0x00, 0x00, 0x00, 0x80, 0x07, 0x00, 0x40, 0x08, 0x00, 0x20, 0x10, 0x00, 0x20, 0x10, 0x00, 0xF8, 0x7F, 0x00, 0x20, 0x10, 0x00, + 0x20, 0x10, 0x00, 0x40, 0x08, 0x00, 0x80, 0x07, // 1060 + 0x00, 0x40, 0x00, 0x08, 0x20, 0x00, 0x10, 0x18, 0x00, 0x60, 0x04, 0x00, 0x80, 0x02, 0x00, 0x00, 0x01, 0x00, 0x80, 0x02, 0x00, + 0x60, 0x0C, 0x00, 0x10, 0x10, 0x00, 0x08, 0x20, 0x00, 0x00, 0x40, // 1061 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0xC0, 0x03, // 1062 + 0x00, 0x00, 0x00, 0xF8, 0x03, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, + 0x00, 0x02, 0x00, 0xF8, 0x7F, // 1063 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0xF8, 0x7F, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0xF8, 0x7F, // 1064 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0xF8, 0x7F, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0xC0, 0x03, // 1065 + 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, + 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, 0x00, 0x3E, // 1066 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, + 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x7F, // 1067 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, + 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, 0x00, 0x3E, // 1068 + 0x00, 0x00, 0x00, 0x20, 0x10, 0x00, 0x10, 0x20, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, + 0x08, 0x41, 0x00, 0x10, 0x21, 0x00, 0x20, 0x11, 0x00, 0xC0, 0x0F, // 1069 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0xC0, 0x0F, 0x00, 0x20, 0x10, 0x00, + 0x10, 0x20, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x10, 0x20, 0x00, 0x20, 0x10, 0x00, + 0xC0, 0x0F, // 1070 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x40, 0x00, 0x10, 0x21, 0x00, 0x08, 0x1A, 0x00, 0x08, 0x0E, 0x00, 0x08, 0x02, 0x00, + 0x08, 0x02, 0x00, 0x08, 0x02, 0x00, 0x08, 0x02, 0x00, 0xF8, 0x7F, // 1071 + 0x00, 0x00, 0x00, 0x00, 0x39, 0x00, 0x80, 0x44, 0x00, 0x40, 0x44, 0x00, 0x40, 0x44, 0x00, 0x40, 0x42, 0x00, 0x40, 0x22, 0x00, + 0x80, 0x7F, // 1072 + 0x00, 0x00, 0x00, 0xE0, 0x1F, 0x00, 0x90, 0x20, 0x00, 0x48, 0x40, 0x00, 0x48, 0x40, 0x00, 0x48, 0x40, 0x00, 0x88, 0x20, 0x00, + 0x08, 0x1F, // 1073 + 0x00, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x40, 0x44, 0x00, 0x40, 0x44, 0x00, 0x40, 0x44, 0x00, 0x40, 0x44, 0x00, 0x40, 0x44, 0x00, + 0x80, 0x3B, // 1074 + 0x00, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, // 1075 + 0x00, 0xC0, 0x01, 0x00, 0x70, 0x00, 0xC0, 0x4F, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0xC0, 0x7F, 0x00, + 0x00, 0xC0, 0x01, // 1076 + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x80, 0x24, 0x00, 0x40, 0x44, 0x00, 0x40, 0x44, 0x00, 0x40, 0x44, 0x00, 0x80, 0x24, 0x00, + 0x00, 0x17, // 1077 + 0xC0, 0x20, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0xC0, 0x7F, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, + 0x00, 0x1B, 0x00, 0xC0, 0x20, 0x00, 0x40, 0x40, // 1078 + 0x80, 0x20, 0x00, 0x40, 0x40, 0x00, 0x40, 0x44, 0x00, 0x40, 0x44, 0x00, 0x40, 0x44, 0x00, 0x80, 0x3B, // 1079 + 0x00, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x00, 0x30, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x02, 0x00, 0x80, 0x01, 0x00, 0xC0, + 0x7F, // 1080 + 0x00, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x08, 0x30, 0x00, 0x10, 0x0C, 0x00, 0x10, 0x02, 0x00, 0x90, 0x01, 0x00, 0xC8, + 0x7F, // 1081 + 0x00, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x1B, 0x00, 0xC0, 0x20, 0x00, 0x40, + 0x40, // 1082 + 0x00, 0x40, 0x00, 0xC0, 0x3F, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0xC0, + 0x7F, // 1083 + 0x00, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x06, 0x00, 0x00, 0x18, 0x00, 0x00, 0x60, 0x00, 0x00, 0x18, 0x00, + 0x00, 0x06, 0x00, 0xC0, 0x01, 0x00, 0xC0, 0x7F, // 1084 + 0x00, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0xC0, + 0x7F, // 1085 + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x80, 0x20, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x80, 0x20, 0x00, + 0x00, 0x1F, // 1086 + 0x00, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0xC0, + 0x7F, // 1087 + 0x00, 0x00, 0x00, 0xC0, 0xFF, 0x03, 0x80, 0x20, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x80, 0x20, 0x00, + 0x00, 0x1F, // 1088 + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x80, 0x20, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x80, + 0x20, // 1089 + 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, // 1090 + 0xC0, 0x01, 0x00, 0x00, 0x06, 0x02, 0x00, 0x38, 0x02, 0x00, 0xC0, 0x01, 0x00, 0x38, 0x00, 0x00, 0x07, 0x00, 0xC0, // 1091 + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x80, 0x20, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x80, 0x20, 0x00, 0xF8, 0xFF, 0x03, + 0x80, 0x20, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x80, 0x20, 0x00, 0x00, 0x1F, // 1092 + 0x40, 0x40, 0x00, 0x80, 0x20, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x04, 0x00, 0x00, 0x1B, 0x00, 0x80, 0x20, 0x00, 0x40, + 0x40, // 1093 + 0x00, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, + 0xC0, 0x7F, 0x00, 0x00, 0xC0, 0x03, // 1094 + 0x00, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0x04, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0xC0, + 0x7F, // 1095 + 0x00, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0xC0, 0x7F, 0x00, 0x00, 0x40, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0xC0, 0x7F, // 1096 + 0x00, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0xC0, 0x7F, 0x00, 0x00, 0x40, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0xC0, 0x7F, 0x00, 0x00, 0xC0, 0x03, // 1097 + 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x00, 0x44, 0x00, 0x00, 0x44, 0x00, 0x00, 0x44, 0x00, + 0x00, 0x44, 0x00, 0x00, 0x38, // 1098 + 0x00, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x00, 0x44, 0x00, 0x00, 0x44, 0x00, 0x00, 0x44, 0x00, 0x00, 0x44, 0x00, 0x00, 0x44, 0x00, + 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x7F, // 1099 + 0x00, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x00, 0x44, 0x00, 0x00, 0x44, 0x00, 0x00, 0x44, 0x00, 0x00, 0x44, 0x00, 0x00, 0x44, 0x00, + 0x00, 0x38, // 1100 + 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x80, 0x20, 0x00, 0x40, 0x44, 0x00, 0x40, 0x44, 0x00, 0x80, 0x24, 0x00, 0x00, + 0x1F, // 1101 + 0x00, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x1F, 0x00, 0x80, 0x20, 0x00, 0x40, 0x40, 0x00, + 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x80, 0x20, 0x00, 0x00, 0x1F, // 1102 + 0x00, 0x00, 0x00, 0x80, 0x63, 0x00, 0x40, 0x14, 0x00, 0x40, 0x0C, 0x00, 0x40, 0x04, 0x00, 0x40, 0x04, 0x00, 0x40, 0x04, 0x00, + 0xC0, 0x7F, // 1103 +}; + +const uint8_t ArialMT_Plain_24_UA[] PROGMEM = { + 0x18, // Width: 24 + 0x1C, // Height: 28 + 0x20, // First Char: 32 + 0xE0, // Numbers of Chars: 224 + // Jump Table: + 0xFF, 0xFF, 0x00, 0x07, // 32= :65535 + 0x00, 0x00, 0x13, 0x08, // 33=!:0 + 0x00, 0x13, 0x1A, 0x09, // 34=":19 + 0x00, 0x2D, 0x33, 0x0D, // 35=#:45 + 0x00, 0x60, 0x2F, 0x0D, // 36=$:96 + 0x00, 0x8F, 0x4F, 0x15, // 37=%:143 + 0x00, 0xDE, 0x3B, 0x10, // 38=&:222 + 0x01, 0x19, 0x0A, 0x05, // 39=':281 + 0x01, 0x23, 0x1C, 0x08, // 40=(:291 + 0x01, 0x3F, 0x1B, 0x08, // 41=):319 + 0x01, 0x5A, 0x22, 0x09, // 42=*:346 + 0x01, 0x7C, 0x33, 0x0E, // 43=+:380 + 0x01, 0xAF, 0x10, 0x07, // 44=,:431 + 0x01, 0xBF, 0x1B, 0x08, // 45=-:447 + 0x01, 0xDA, 0x0F, 0x07, // 46=.:474 + 0x01, 0xE9, 0x1A, 0x07, // 47=/:489 + 0x02, 0x03, 0x2F, 0x0D, // 48=0:515 + 0x02, 0x32, 0x23, 0x0D, // 49=1:562 + 0x02, 0x55, 0x2F, 0x0D, // 50=2:597 + 0x02, 0x84, 0x2F, 0x0D, // 51=3:644 + 0x02, 0xB3, 0x2F, 0x0D, // 52=4:691 + 0x02, 0xE2, 0x2F, 0x0D, // 53=5:738 + 0x03, 0x11, 0x2F, 0x0D, // 54=6:785 + 0x03, 0x40, 0x2E, 0x0D, // 55=7:832 + 0x03, 0x6E, 0x2F, 0x0D, // 56=8:878 + 0x03, 0x9D, 0x2F, 0x0D, // 57=9:925 + 0x03, 0xCC, 0x0F, 0x07, // 58=::972 + 0x03, 0xDB, 0x10, 0x07, // 59=;:987 + 0x03, 0xEB, 0x2F, 0x0E, // 60=<:1003 + 0x04, 0x1A, 0x2F, 0x0E, // 61==:1050 + 0x04, 0x49, 0x2E, 0x0E, // 62=>:1097 + 0x04, 0x77, 0x2E, 0x0D, // 63=?:1143 + 0x04, 0xA5, 0x5C, 0x18, // 64=@:1189 + 0x05, 0x01, 0x3B, 0x0F, // 65=A:1281 + 0x05, 0x3C, 0x3B, 0x10, // 66=B:1340 + 0x05, 0x77, 0x3F, 0x11, // 67=C:1399 + 0x05, 0xB6, 0x3F, 0x11, // 68=D:1462 + 0x05, 0xF5, 0x3B, 0x10, // 69=E:1525 + 0x06, 0x30, 0x36, 0x0F, // 70=F:1584 + 0x06, 0x66, 0x43, 0x13, // 71=G:1638 + 0x06, 0xA9, 0x3B, 0x11, // 72=H:1705 + 0x06, 0xE4, 0x0F, 0x06, // 73=I:1764 + 0x06, 0xF3, 0x27, 0x0C, // 74=J:1779 + 0x07, 0x1A, 0x3F, 0x10, // 75=K:1818 + 0x07, 0x59, 0x2F, 0x0D, // 76=L:1881 + 0x07, 0x88, 0x43, 0x13, // 77=M:1928 + 0x07, 0xCB, 0x3B, 0x11, // 78=N:1995 + 0x08, 0x06, 0x47, 0x13, // 79=O:2054 + 0x08, 0x4D, 0x3A, 0x10, // 80=P:2125 + 0x08, 0x87, 0x48, 0x13, // 81=Q:2183 + 0x08, 0xCF, 0x3F, 0x11, // 82=R:2255 + 0x09, 0x0E, 0x3B, 0x10, // 83=S:2318 + 0x09, 0x49, 0x36, 0x0E, // 84=T:2377 + 0x09, 0x7F, 0x3B, 0x11, // 85=U:2431 + 0x09, 0xBA, 0x39, 0x0F, // 86=V:2490 + 0x09, 0xF3, 0x5A, 0x17, // 87=W:2547 + 0x0A, 0x4D, 0x3B, 0x0F, // 88=X:2637 + 0x0A, 0x88, 0x3D, 0x10, // 89=Y:2696 + 0x0A, 0xC5, 0x37, 0x0F, // 90=Z:2757 + 0x0A, 0xFC, 0x14, 0x07, // 91=[:2812 + 0x0B, 0x10, 0x1B, 0x07, // 92=\:2832 + 0x0B, 0x2B, 0x18, 0x07, // 93=]:2859 + 0x0B, 0x43, 0x2A, 0x0C, // 94=^:2883 + 0x0B, 0x6D, 0x34, 0x0D, // 95=_:2925 + 0x0B, 0xA1, 0x12, 0x08, // 96=`:2977 + 0x0B, 0xB3, 0x2F, 0x0D, // 97=a:2995 + 0x0B, 0xE2, 0x33, 0x0E, // 98=b:3042 + 0x0C, 0x15, 0x2B, 0x0C, // 99=c:3093 + 0x0C, 0x40, 0x2F, 0x0E, // 100=d:3136 + 0x0C, 0x6F, 0x2F, 0x0D, // 101=e:3183 + 0x0C, 0x9E, 0x1A, 0x07, // 102=f:3230 + 0x0C, 0xB8, 0x30, 0x0E, // 103=g:3256 + 0x0C, 0xE8, 0x2F, 0x0E, // 104=h:3304 + 0x0D, 0x17, 0x0F, 0x05, // 105=i:3351 + 0x0D, 0x26, 0x10, 0x06, // 106=j:3366 + 0x0D, 0x36, 0x2F, 0x0C, // 107=k:3382 + 0x0D, 0x65, 0x0F, 0x06, // 108=l:3429 + 0x0D, 0x74, 0x47, 0x14, // 109=m:3444 + 0x0D, 0xBB, 0x2F, 0x0E, // 110=n:3515 + 0x0D, 0xEA, 0x2F, 0x0D, // 111=o:3562 + 0x0E, 0x19, 0x33, 0x0E, // 112=p:3609 + 0x0E, 0x4C, 0x30, 0x0E, // 113=q:3660 + 0x0E, 0x7C, 0x1E, 0x08, // 114=r:3708 + 0x0E, 0x9A, 0x2B, 0x0C, // 115=s:3738 + 0x0E, 0xC5, 0x1B, 0x07, // 116=t:3781 + 0x0E, 0xE0, 0x2F, 0x0E, // 117=u:3808 + 0x0F, 0x0F, 0x2A, 0x0B, // 118=v:3855 + 0x0F, 0x39, 0x42, 0x11, // 119=w:3897 + 0x0F, 0x7B, 0x2B, 0x0B, // 120=x:3963 + 0x0F, 0xA6, 0x2A, 0x0C, // 121=y:4006 + 0x0F, 0xD0, 0x2B, 0x0C, // 122=z:4048 + 0x0F, 0xFB, 0x1C, 0x08, // 123={:4091 + 0x10, 0x17, 0x10, 0x06, // 124=|:4119 + 0x10, 0x27, 0x1B, 0x08, // 125=}:4135 + 0x10, 0x42, 0x33, 0x0E, // 126=~:4162 + 0xFF, 0xFF, 0x00, 0x12, // 127:65535 + 0x10, 0x75, 0x4F, 0x15, // 1026=� �..:4213 + 0x10, 0xC4, 0x32, 0x0D, // 1027=� �.:4292 + 0x10, 0xF6, 0x0C, 0x05, // 8218=��.�.:4342 + 0x11, 0x02, 0x22, 0x09, // 1107=�.�..:4354 + 0x11, 0x24, 0x1C, 0x08, // 8222=��.�.:4388 + 0x11, 0x40, 0x4B, 0x18, // 8230=��.�.:4416 + 0x11, 0x8B, 0x32, 0x0D, // 8224=��.� :4491 + 0x11, 0xBD, 0x33, 0x0D, // 8225=��.�.:4541 + 0x11, 0xF0, 0x2F, 0x0D, // 8364=��..�.:4592 + 0x12, 0x1F, 0x63, 0x1A, // 8240=��.��:4639 + 0x12, 0x82, 0x5F, 0x19, // 1033=� �.�:4738 + 0x12, 0xE1, 0x17, 0x08, // 8249=��.�..:4833 + 0x12, 0xF8, 0x5B, 0x18, // 1034=� �.:4856 + 0x13, 0x53, 0x37, 0x0E, // 1036=� �.:4947 + 0x13, 0x8A, 0x4F, 0x16, // 1035=� �..:5002 + 0x13, 0xD9, 0x3B, 0x11, // 1039=� �.:5081 + 0x14, 0x14, 0x30, 0x0E, // 1106=�.�..:5140 + 0x14, 0x44, 0x0A, 0x05, // 8216=��.Ч.:5188 + 0x14, 0x4E, 0x0A, 0x05, // 8217=��.�..:5198 + 0x14, 0x58, 0x1A, 0x08, // 8220=��.�.:5208 + 0x14, 0x72, 0x1A, 0x08, // 8221=��.�.:5234 + 0x14, 0x8C, 0x1B, 0x08, // 8226=��.�.:5260 + 0x14, 0xA7, 0x33, 0x0D, // 8211=��.�..:5287 + 0x14, 0xDA, 0x5F, 0x18, // 8212=��.�..:5338 + 0xFF, 0xFF, 0x00, 0x12, // 65533=��.�.:65535 + 0x15, 0x39, 0x5B, 0x18, // 8482=��..�.:5433 + 0x15, 0x94, 0x53, 0x16, // 1113=�.�..:5524 + 0x15, 0xE7, 0x1B, 0x08, // 8250=��.�.:5607 + 0x16, 0x02, 0x4B, 0x14, // 1114=�.�.:5634 + 0x16, 0x4D, 0x2B, 0x0B, // 1116=�.�.:5709 + 0x16, 0x78, 0x2F, 0x0E, // 1115=�.�.�:5752 + 0x16, 0xA7, 0x2F, 0x0D, // 1119=�.�.:5799 + 0xFF, 0xFF, 0x00, 0x07, // 160=�.� :65535 + 0x16, 0xD6, 0x36, 0x0F, // 1038=� �.:5846 + 0x17, 0x0C, 0x2A, 0x0C, // 1118=�.�.:5900 + 0x17, 0x36, 0x27, 0x0C, // 1032=� �..:5942 + 0x17, 0x5D, 0x33, 0x0D, // 164=�.�.:5981 + 0x17, 0x90, 0x2A, 0x0C, // 1168=�.�.:6032 + 0x17, 0xBA, 0x10, 0x06, // 166=�.�.:6074 + 0x17, 0xCA, 0x2F, 0x0D, // 167=�.�.:6090 + 0x17, 0xF9, 0x3B, 0x10, // 1025=� �.:6137 + 0x18, 0x34, 0x47, 0x12, // 169=�.��:6196 + 0x18, 0x7B, 0x3F, 0x11, // 1028=� �..:6267 + 0x18, 0xBA, 0x27, 0x0D, // 171=�.�.:6330 + 0x18, 0xE1, 0x2F, 0x0E, // 172=�.�.:6369 + 0x19, 0x10, 0x1B, 0x08, // 173=�.�:6416 + 0x19, 0x2B, 0x47, 0x12, // 174=�.�.:6443 + 0x19, 0x72, 0x15, 0x06, // 1031=� �..:6514 + 0x19, 0x87, 0x1E, 0x0A, // 176=�.��:6535 + 0x19, 0xA5, 0x33, 0x0D, // 177=�.�.:6565 + 0x19, 0xD8, 0x0F, 0x06, // 1030=� �. :6616 + 0x19, 0xE7, 0x0F, 0x05, // 1110=�.�..:6631 + 0x19, 0xF6, 0x22, 0x0A, // 1169=�.�.:6646 + 0x1A, 0x18, 0x2F, 0x0E, // 181=�.�.:6680 + 0x1A, 0x47, 0x32, 0x0D, // 182=�.�.:6727 + 0x1A, 0x79, 0x13, 0x08, // 183=�.��:6777 + 0x1A, 0x8C, 0x2F, 0x0D, // 1105=�.�.:6796 + 0x1A, 0xBB, 0x63, 0x1A, // 8470=��..�..:6843 + 0x1B, 0x1E, 0x2B, 0x0C, // 1108=�.�..:6942 + 0x1B, 0x49, 0x2F, 0x0D, // 187=�.�.:6985 + 0x1B, 0x78, 0x10, 0x06, // 1112=�.Ч.:7032 + 0x1B, 0x88, 0x3B, 0x10, // 1029=� �..:7048 + 0x1B, 0xC3, 0x2B, 0x0C, // 1109=�.�..:7107 + 0x1B, 0xEE, 0x16, 0x06, // 1111=�.�..:7150 + 0x1C, 0x04, 0x3B, 0x0F, // 1040=� �.:7172 + 0x1C, 0x3F, 0x3B, 0x10, // 1041=� �.:7231 + 0x1C, 0x7A, 0x3B, 0x10, // 1042=� �..:7290 + 0x1C, 0xB5, 0x32, 0x0D, // 1043=� �..:7349 + 0x1C, 0xE7, 0x40, 0x10, // 1044=� �..:7399 + 0x1D, 0x27, 0x3B, 0x10, // 1045=� �..:7463 + 0x1D, 0x62, 0x57, 0x16, // 1046=� �..:7522 + 0x1D, 0xB9, 0x37, 0x0F, // 1047=� �..:7609 + 0x1D, 0xF0, 0x3B, 0x11, // 1048=� Ч.:7664 + 0x1E, 0x2B, 0x3B, 0x11, // 1049=� �..:7723 + 0x1E, 0x66, 0x37, 0x0E, // 1050=� �.:7782 + 0x1E, 0x9D, 0x37, 0x10, // 1051=� �.�:7837 + 0x1E, 0xD4, 0x43, 0x13, // 1052=� �.:7892 + 0x1F, 0x17, 0x3B, 0x11, // 1053=� �.:7959 + 0x1F, 0x52, 0x47, 0x13, // 1054=� �.:8018 + 0x1F, 0x99, 0x3B, 0x11, // 1055=� �.:8089 + 0x1F, 0xD4, 0x3A, 0x10, // 1056=� � :8148 + 0x20, 0x0E, 0x3F, 0x11, // 1057=� �.:8206 + 0x20, 0x4D, 0x36, 0x0E, // 1058=� �.:8269 + 0x20, 0x83, 0x36, 0x0F, // 1059=� �.:8323 + 0x20, 0xB9, 0x43, 0x12, // 1060=� �.:8377 + 0x20, 0xFC, 0x3B, 0x0F, // 1061=� �.:8444 + 0x21, 0x37, 0x44, 0x12, // 1062=� �.:8503 + 0x21, 0x7B, 0x37, 0x10, // 1063=� �.:8571 + 0x21, 0xB2, 0x53, 0x16, // 1064=� �.:8626 + 0x22, 0x05, 0x5C, 0x17, // 1065=� ��:8709 + 0x22, 0x61, 0x47, 0x13, // 1066=� �.:8801 + 0x22, 0xA8, 0x4B, 0x15, // 1067=� �.:8872 + 0x22, 0xF3, 0x3B, 0x10, // 1068=� �.:8947 + 0x23, 0x2E, 0x3F, 0x11, // 1069=� �:9006 + 0x23, 0x6D, 0x5B, 0x18, // 1070=� �.:9069 + 0x23, 0xC8, 0x3B, 0x11, // 1071=� �.:9160 + 0x24, 0x03, 0x2F, 0x0D, // 1072=� ��:9219 + 0x24, 0x32, 0x33, 0x0E, // 1073=� �.:9266 + 0x24, 0x65, 0x2F, 0x0D, // 1074=� �.:9317 + 0x24, 0x94, 0x22, 0x09, // 1075=� �.:9364 + 0x24, 0xB6, 0x34, 0x0E, // 1076=� �.:9398 + 0x24, 0xEA, 0x2F, 0x0D, // 1077=� �.:9450 + 0x25, 0x19, 0x3B, 0x10, // 1078=� �.:9497 + 0x25, 0x54, 0x27, 0x0B, // 1079=� ��:9556 + 0x25, 0x7B, 0x2F, 0x0D, // 1080=� �.:9595 + 0x25, 0xAA, 0x2F, 0x0D, // 1081=� �..:9642 + 0x25, 0xD9, 0x2B, 0x0B, // 1082=� �.:9689 + 0x26, 0x04, 0x2F, 0x0E, // 1083=� �.:9732 + 0x26, 0x33, 0x3B, 0x11, // 1084=� �:9779 + 0x26, 0x6E, 0x2F, 0x0D, // 1085=� �.:9838 + 0x26, 0x9D, 0x2F, 0x0D, // 1086=� �.:9885 + 0x26, 0xCC, 0x2F, 0x0D, // 1087=� �.:9932 + 0x26, 0xFB, 0x33, 0x0E, // 1088=�.�.:9979 + 0x27, 0x2E, 0x2B, 0x0C, // 1089=�.�.:10030 + 0x27, 0x59, 0x26, 0x0B, // 1090=�.�..:10073 + 0x27, 0x7F, 0x2A, 0x0C, // 1091=�.�.:10111 + 0x27, 0xA9, 0x4B, 0x14, // 1092=�.�..:10153 + 0x27, 0xF4, 0x2B, 0x0B, // 1093=�.�..:10228 + 0x28, 0x1F, 0x34, 0x0E, // 1094=�.�. :10271 + 0x28, 0x53, 0x2B, 0x0D, // 1095=�.�..:10323 + 0x28, 0x7E, 0x47, 0x13, // 1096=�.�..:10366 + 0x28, 0xC5, 0x4C, 0x14, // 1097=�.�.�:10437 + 0x29, 0x11, 0x37, 0x0F, // 1098=�.�.:10513 + 0x29, 0x48, 0x3B, 0x11, // 1099=�.�..:10568 + 0x29, 0x83, 0x2F, 0x0D, // 1100=�.�.:10627 + 0x29, 0xB2, 0x2B, 0x0C, // 1101=�.�.:10674 + 0x29, 0xDD, 0x43, 0x12, // 1102=�.�.:10717 + 0x2A, 0x20, 0x2B, 0x0D, // 1103=�.�.:10784 + // Font Data: + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xCF, 0x00, 0x80, 0xFF, 0xCF, // 33 + 0x00, 0x00, 0x00, 0x00, 0x80, 0x1F, 0x00, 0x00, 0x80, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x1F, 0x00, 0x00, 0x80, 0x1F, // 34 + 0x00, 0x30, 0x0C, 0x00, 0x00, 0x30, 0xCC, 0x00, 0x00, 0x30, 0xFE, 0x00, 0x00, 0xF0, 0x3F, 0x00, 0x00, 0xFE, 0x0F, 0x00, 0x80, + 0x3F, 0x0C, 0x00, 0x80, 0x31, 0xCC, 0x00, 0x00, 0x30, 0xFE, 0x00, 0x00, 0xF0, 0x3F, 0x00, 0x00, 0xFE, 0x0D, 0x00, 0x80, 0x3F, + 0x0C, 0x00, 0x80, 0x31, 0x0C, 0x00, 0x00, 0x30, 0x0C, // 35 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x18, 0x00, 0x00, 0x3F, 0x78, 0x00, 0x00, 0x63, 0x70, 0x00, 0x80, 0x61, 0xE0, 0x00, 0x80, + 0xC1, 0xC0, 0x00, 0xC0, 0xFF, 0xFF, 0x03, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0x81, 0xC1, 0x00, 0x00, 0x83, 0x61, 0x00, 0x00, 0x07, + 0x7F, 0x00, 0x00, 0x04, 0x1E, // 36 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x80, 0xC1, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, + 0x80, 0x80, 0x00, 0x80, 0xC1, 0xE0, 0x00, 0x00, 0x7F, 0x78, 0x00, 0x00, 0x3E, 0x3E, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0xC0, + 0x03, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x3C, 0x3E, 0x00, 0x00, 0x0F, 0x7F, 0x00, 0x80, 0x83, 0xC1, 0x00, 0x80, 0x80, 0x80, + 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0xC1, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x3E, // 37 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x8E, 0x73, 0x00, 0x00, 0xDF, 0xE1, 0x00, 0x80, + 0xF3, 0xC0, 0x00, 0x80, 0xE1, 0xC0, 0x00, 0x80, 0xE1, 0xC1, 0x00, 0x80, 0xB3, 0xE3, 0x00, 0x00, 0x3F, 0x6E, 0x00, 0x00, 0x0E, + 0x7C, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0xE2, 0x00, 0x00, 0x00, 0x40, // 38 + 0x00, 0x00, 0x00, 0x00, 0x80, 0x1F, 0x00, 0x00, 0x80, 0x1F, // 39 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x3F, 0x00, 0x00, 0xF8, 0xFF, 0x01, 0x00, 0x3E, 0xC0, 0x07, 0x00, 0x07, 0x00, 0x0E, 0x80, + 0x01, 0x00, 0x18, 0x80, 0x00, 0x00, 0x10, // 40 + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x10, 0x80, 0x01, 0x00, 0x18, 0x00, 0x07, 0x00, 0x0E, 0x00, 0x3E, 0xC0, 0x07, 0x00, + 0xF8, 0xFF, 0x01, 0x00, 0xC0, 0x3F, // 41 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x00, 0x80, + 0x0F, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x02, // 42 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, + 0x80, 0x01, 0x00, 0x00, 0xFC, 0x3F, 0x00, 0x00, 0xFC, 0x3F, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, + 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, // 43 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x0C, 0x00, 0x00, 0xC0, 0x07, // 44 + 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, // 45 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, // 46 + 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x80, + 0x0F, 0x00, 0x00, 0x80, 0x01, // 47 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0x07, 0x70, 0x00, 0x80, 0x03, 0xE0, 0x00, 0x80, + 0x01, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x03, 0xE0, 0x00, 0x00, 0x07, 0x70, 0x00, 0x00, 0xFE, + 0x3F, 0x00, 0x00, 0xF8, 0x0F, // 48 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, + 0x0C, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, // 49 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0xC0, 0x00, 0x00, 0x0F, 0xE0, 0x00, 0x00, 0x03, 0xF0, 0x00, 0x80, 0x01, 0xD8, 0x00, 0x80, + 0x01, 0xCC, 0x00, 0x80, 0x01, 0xC6, 0x00, 0x80, 0x01, 0xC3, 0x00, 0x80, 0x81, 0xC1, 0x00, 0x00, 0xC3, 0xC0, 0x00, 0x00, 0x7F, + 0xC0, 0x00, 0x00, 0x3C, 0xC0, // 50 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x18, 0x00, 0x00, 0x07, 0x38, 0x00, 0x00, 0x03, 0x70, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, + 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x00, 0xE3, 0xC0, 0x00, 0x00, 0xBF, 0x61, 0x00, 0x00, 0x1E, + 0x3F, 0x00, 0x00, 0x00, 0x1E, // 51 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, 0xF0, 0x0C, 0x00, 0x00, + 0x38, 0x0C, 0x00, 0x00, 0x1E, 0x0C, 0x00, 0x00, 0x07, 0x0C, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x00, + 0x0C, 0x00, 0x00, 0x00, 0x0C, // 52 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x18, 0x00, 0x00, 0xFE, 0x38, 0x00, 0x80, 0x7F, 0x60, 0x00, 0x80, 0x21, 0xC0, 0x00, 0x80, + 0x31, 0xC0, 0x00, 0x80, 0x31, 0xC0, 0x00, 0x80, 0x31, 0xC0, 0x00, 0x80, 0x31, 0xC0, 0x00, 0x80, 0x61, 0x70, 0x00, 0x80, 0xC1, + 0x3F, 0x00, 0x00, 0x80, 0x0F, // 53 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x0F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0x8F, 0x71, 0x00, 0x00, 0xC3, 0xE0, 0x00, 0x80, + 0x61, 0xC0, 0x00, 0x80, 0x61, 0xC0, 0x00, 0x80, 0x61, 0xC0, 0x00, 0x80, 0x61, 0xC0, 0x00, 0x80, 0xC3, 0x60, 0x00, 0x00, 0xC7, + 0x3F, 0x00, 0x00, 0x06, 0x1F, // 54 + 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0xF0, 0x00, 0x80, + 0x01, 0xFE, 0x00, 0x80, 0xC1, 0x0F, 0x00, 0x80, 0xE1, 0x01, 0x00, 0x80, 0x39, 0x00, 0x00, 0x80, 0x0D, 0x00, 0x00, 0x80, 0x07, + 0x00, 0x00, 0x80, 0x01, // 55 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x1E, 0x7F, 0x00, 0x00, 0xBF, 0x61, 0x00, 0x80, 0xE3, 0xC0, 0x00, 0x80, + 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xE3, 0xC0, 0x00, 0x00, 0xBF, 0x61, 0x00, 0x00, 0x1E, + 0x7F, 0x00, 0x00, 0x00, 0x1E, // 56 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x30, 0x00, 0x00, 0xFE, 0x71, 0x00, 0x00, 0x87, 0xE1, 0x00, 0x80, 0x01, 0xC3, 0x00, 0x80, + 0x01, 0xC3, 0x00, 0x80, 0x01, 0xC3, 0x00, 0x80, 0x01, 0xC3, 0x00, 0x80, 0x81, 0x61, 0x00, 0x00, 0xC7, 0x78, 0x00, 0x00, 0xFE, + 0x3F, 0x00, 0x00, 0xF8, 0x07, // 57 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, // 58 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xC0, 0x0C, 0x00, 0x18, 0xC0, 0x07, // 59 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x60, 0x03, 0x00, 0x00, + 0x60, 0x03, 0x00, 0x00, 0x30, 0x06, 0x00, 0x00, 0x30, 0x06, 0x00, 0x00, 0x10, 0x04, 0x00, 0x00, 0x18, 0x0C, 0x00, 0x00, 0x18, + 0x0C, 0x00, 0x00, 0x0C, 0x18, // 60 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x06, 0x00, 0x00, 0x30, 0x06, 0x00, 0x00, 0x30, 0x06, 0x00, 0x00, 0x30, 0x06, 0x00, 0x00, + 0x30, 0x06, 0x00, 0x00, 0x30, 0x06, 0x00, 0x00, 0x30, 0x06, 0x00, 0x00, 0x30, 0x06, 0x00, 0x00, 0x30, 0x06, 0x00, 0x00, 0x30, + 0x06, 0x00, 0x00, 0x30, 0x06, // 61 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x18, 0x00, 0x00, 0x18, 0x0C, 0x00, 0x00, 0x18, 0x0C, 0x00, 0x00, 0x10, 0x04, 0x00, 0x00, + 0x30, 0x06, 0x00, 0x00, 0x30, 0x06, 0x00, 0x00, 0x60, 0x03, 0x00, 0x00, 0x60, 0x03, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0xC0, + 0x01, 0x00, 0x00, 0x80, // 62 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x80, + 0x01, 0xCE, 0x00, 0x80, 0x01, 0xCF, 0x00, 0x80, 0x81, 0x01, 0x00, 0x80, 0xC1, 0x00, 0x00, 0x00, 0xE3, 0x00, 0x00, 0x00, 0x7F, + 0x00, 0x00, 0x00, 0x1C, // 63 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0x78, 0xC0, 0x03, 0x00, 0x1C, 0x00, 0x07, 0x00, + 0x0E, 0x1F, 0x06, 0x00, 0xC7, 0x7F, 0x0E, 0x00, 0xE3, 0x60, 0x0C, 0x00, 0x33, 0xC0, 0x0C, 0x80, 0x39, 0xC0, 0x18, 0x80, 0x19, + 0xC0, 0x18, 0x80, 0x19, 0x60, 0x18, 0x80, 0x19, 0x30, 0x18, 0x80, 0x31, 0x78, 0x18, 0x80, 0xE1, 0xFF, 0x18, 0x80, 0xFB, 0xC7, + 0x18, 0x00, 0x3B, 0xC0, 0x18, 0x00, 0x07, 0x60, 0x0C, 0x00, 0x0E, 0x70, 0x0C, 0x00, 0x1C, 0x3C, 0x06, 0x00, 0xF8, 0x1F, 0x06, + 0x00, 0xE0, 0x07, 0x03, 0x00, 0x00, 0x00, 0x01, // 64 + 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, 0xF8, 0x07, 0x00, 0x00, + 0x3E, 0x06, 0x00, 0x80, 0x0F, 0x06, 0x00, 0x80, 0x01, 0x06, 0x00, 0x80, 0x0F, 0x06, 0x00, 0x00, 0x3E, 0x06, 0x00, 0x00, 0xF8, + 0x07, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0xC0, // 65 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, + 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, + 0xC0, 0x00, 0x00, 0xE3, 0xC1, 0x00, 0x00, 0xFF, 0x61, 0x00, 0x00, 0x1E, 0x7F, 0x00, 0x00, 0x00, 0x1E, // 66 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0x1E, 0x3C, 0x00, 0x00, 0x07, 0x70, 0x00, 0x00, + 0x03, 0x60, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, + 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x00, 0x03, 0x60, 0x00, 0x00, 0x07, 0x70, 0x00, 0x00, 0x0E, 0x3C, 0x00, 0x00, 0x08, + 0x0C, // 67 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, + 0x01, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, + 0xC0, 0x00, 0x80, 0x03, 0x60, 0x00, 0x00, 0x07, 0x70, 0x00, 0x00, 0x0E, 0x38, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xF0, + 0x07, // 68 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, + 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, + 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0x01, 0xC0, // 69 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xC1, 0x00, 0x00, 0x80, + 0xC1, 0x00, 0x00, 0x80, 0xC1, 0x00, 0x00, 0x80, 0xC1, 0x00, 0x00, 0x80, 0xC1, 0x00, 0x00, 0x80, 0xC1, 0x00, 0x00, 0x80, 0xC1, + 0x00, 0x00, 0x80, 0xC1, 0x00, 0x00, 0x80, 0xC1, 0x00, 0x00, 0x80, 0x01, // 70 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0x1E, 0x3C, 0x00, 0x00, 0x07, 0x70, 0x00, 0x00, + 0x03, 0x60, 0x00, 0x80, 0x03, 0x60, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x81, + 0xC1, 0x00, 0x80, 0x81, 0xC1, 0x00, 0x80, 0x83, 0xC1, 0x00, 0x00, 0x83, 0x61, 0x00, 0x00, 0x87, 0x61, 0x00, 0x00, 0x8E, 0x3F, + 0x00, 0x00, 0x88, 0x3F, // 71 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, + 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, + 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, // 72 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, // 73 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, + 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x80, 0xFF, 0x7F, 0x00, 0x80, 0xFF, 0x3F, // 74 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, + 0xC0, 0x01, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0xF0, 0x01, 0x00, 0x00, 0xF8, 0x03, 0x00, 0x00, 0x9C, 0x07, 0x00, 0x00, 0x0E, + 0x1E, 0x00, 0x00, 0x07, 0x3C, 0x00, 0x80, 0x03, 0x78, 0x00, 0x80, 0x01, 0xE0, 0x00, 0x80, 0x00, 0xC0, 0x00, 0x00, 0x00, + 0x80, // 75 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, + 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, + 0xC0, 0x00, 0x00, 0x00, 0xC0, // 76 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, + 0x3F, 0x00, 0x00, 0x00, 0xF8, 0x03, 0x00, 0x00, 0x80, 0x1F, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, + 0xFC, 0x00, 0x00, 0x80, 0x1F, 0x00, 0x00, 0xF8, 0x03, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x80, 0xFF, 0xFF, + 0x00, 0x80, 0xFF, 0xFF, // 77 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x0E, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, + 0x0E, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x70, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, // 78 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0x1E, 0x3C, 0x00, 0x00, 0x07, 0x70, 0x00, 0x00, + 0x03, 0x60, 0x00, 0x80, 0x03, 0xE0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, + 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x03, 0xE0, 0x00, 0x00, 0x03, 0x60, 0x00, 0x00, 0x07, 0x70, 0x00, 0x00, 0x1E, 0x3C, + 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xF0, 0x07, // 79 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0x81, 0x01, 0x00, 0x80, + 0x81, 0x01, 0x00, 0x80, 0x81, 0x01, 0x00, 0x80, 0x81, 0x01, 0x00, 0x80, 0x81, 0x01, 0x00, 0x80, 0x81, 0x01, 0x00, 0x80, 0x81, + 0x01, 0x00, 0x80, 0x81, 0x01, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x3C, // 80 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0x1E, 0x3C, 0x00, 0x00, 0x07, 0x30, 0x00, 0x00, + 0x03, 0x60, 0x00, 0x80, 0x03, 0x60, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, + 0xD8, 0x00, 0x80, 0x01, 0xD8, 0x00, 0x80, 0x03, 0xF0, 0x00, 0x00, 0x03, 0x70, 0x00, 0x00, 0x07, 0x70, 0x00, 0x00, 0x1E, 0xFC, + 0x00, 0x00, 0xFC, 0xDF, 0x01, 0x00, 0xF0, 0x87, 0x01, // 81 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xC1, 0x00, 0x00, 0x80, + 0xC1, 0x00, 0x00, 0x80, 0xC1, 0x00, 0x00, 0x80, 0xC1, 0x00, 0x00, 0x80, 0xC1, 0x01, 0x00, 0x80, 0xC1, 0x03, 0x00, 0x80, 0xC1, + 0x0F, 0x00, 0x80, 0xC1, 0x1E, 0x00, 0x80, 0x63, 0x7C, 0x00, 0x00, 0x7F, 0xF0, 0x00, 0x00, 0x3E, 0xC0, 0x00, 0x00, 0x00, + 0x80, // 82 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x1C, 0x3C, 0x00, 0x00, 0x7F, 0x70, 0x00, 0x00, 0x63, 0x60, 0x00, 0x80, + 0xE1, 0xE0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, + 0xC1, 0x00, 0x80, 0x83, 0xE1, 0x00, 0x00, 0x87, 0x63, 0x00, 0x00, 0x0E, 0x3F, 0x00, 0x00, 0x0C, 0x1E, // 83 + 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, + 0x01, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, + 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, // 84 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x0F, 0x00, 0x80, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0xE0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, + 0xC0, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x70, 0x00, 0x80, 0xFF, 0x3F, 0x00, 0x80, 0xFF, 0x0F, // 85 + 0x80, 0x00, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0xE0, 0x07, 0x00, 0x00, + 0x00, 0x3F, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0xE0, + 0x07, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x80, // 86 + 0x80, 0x01, 0x00, 0x00, 0x80, 0x1F, 0x00, 0x00, 0x00, 0xFE, 0x03, 0x00, 0x00, 0xE0, 0x3F, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, + 0x00, 0xC0, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x80, 0x0F, + 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0x80, 0x3F, + 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xE0, 0x3F, 0x00, 0x00, 0xFE, 0x03, 0x00, + 0x80, 0x1F, 0x00, 0x00, 0x80, 0x01, // 87 + 0x00, 0x00, 0x80, 0x00, 0x80, 0x00, 0xC0, 0x00, 0x80, 0x01, 0xF0, 0x00, 0x80, 0x07, 0x78, 0x00, 0x00, 0x0F, 0x1E, 0x00, 0x00, + 0x3C, 0x0F, 0x00, 0x00, 0xF8, 0x07, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0xF8, 0x07, 0x00, 0x00, 0x1E, 0x0F, 0x00, 0x00, 0x0F, + 0x1C, 0x00, 0x80, 0x07, 0x78, 0x00, 0x80, 0x01, 0xF0, 0x00, 0x80, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x80, // 88 + 0x80, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, + 0x78, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0x00, 0x00, 0xC0, 0xFF, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x78, + 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, // 89 + 0x00, 0x00, 0xC0, 0x00, 0x80, 0x01, 0xE0, 0x00, 0x80, 0x01, 0xF0, 0x00, 0x80, 0x01, 0xDC, 0x00, 0x80, 0x01, 0xCE, 0x00, 0x80, + 0x01, 0xC7, 0x00, 0x80, 0x81, 0xC3, 0x00, 0x80, 0xE1, 0xC0, 0x00, 0x80, 0x71, 0xC0, 0x00, 0x80, 0x39, 0xC0, 0x00, 0x80, 0x1D, + 0xC0, 0x00, 0x80, 0x07, 0xC0, 0x00, 0x80, 0x03, 0xC0, 0x00, 0x80, 0x01, 0xC0, // 90 + 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x1F, 0x80, 0xFF, 0xFF, 0x1F, 0x80, 0x01, 0x00, 0x18, 0x80, 0x01, 0x00, 0x18, // 91 + 0x80, 0x01, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, + 0x00, 0xF8, 0x00, 0x00, 0x00, 0xC0, // 92 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x18, 0x80, 0x01, 0x00, 0x18, 0x80, 0xFF, 0xFF, 0x1F, 0x80, + 0xFF, 0xFF, 0x1F, // 93 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x80, + 0x03, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, + 0x80, // 94 + 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, + 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, + 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, // 95 + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00, 0x02, // 96 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x38, 0x00, 0x00, 0x70, 0x7C, 0x00, 0x00, 0x30, 0xE6, 0x00, 0x00, 0x18, 0xC6, 0x00, 0x00, + 0x18, 0xC6, 0x00, 0x00, 0x18, 0xC3, 0x00, 0x00, 0x18, 0x63, 0x00, 0x00, 0x38, 0x63, 0x00, 0x00, 0xF0, 0x7F, 0x00, 0x00, 0xE0, + 0xFF, 0x00, 0x00, 0x00, 0x80, // 97 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x60, 0x30, 0x00, 0x00, + 0x30, 0x60, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x38, 0xE0, 0x00, 0x00, 0x70, + 0x70, 0x00, 0x00, 0xE0, 0x3F, 0x00, 0x00, 0x80, 0x0F, // 98 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x00, 0xE0, 0x3F, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0x38, 0xE0, 0x00, 0x00, + 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x38, 0xE0, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0x60, + 0x30, // 99 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x00, 0xE0, 0x3F, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0x38, 0xE0, 0x00, 0x00, + 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x30, 0x60, 0x00, 0x00, 0x70, 0x30, 0x00, 0x80, 0xFF, + 0xFF, 0x00, 0x80, 0xFF, 0xFF, // 100 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x1F, 0x00, 0x00, 0xE0, 0x3F, 0x00, 0x00, 0x70, 0x73, 0x00, 0x00, 0x38, 0xE3, 0x00, 0x00, + 0x18, 0xC3, 0x00, 0x00, 0x18, 0xC3, 0x00, 0x00, 0x18, 0xC3, 0x00, 0x00, 0x38, 0xE3, 0x00, 0x00, 0x70, 0x63, 0x00, 0x00, 0xE0, + 0x33, 0x00, 0x00, 0xC0, 0x13, // 101 + 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0x19, 0x00, 0x00, 0x80, + 0x19, 0x00, 0x00, 0x80, 0x19, // 102 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0F, 0x06, 0x00, 0xE0, 0x3F, 0x0E, 0x00, 0x70, 0x70, 0x1C, 0x00, 0x38, 0xE0, 0x18, 0x00, + 0x18, 0xC0, 0x18, 0x00, 0x18, 0xC0, 0x18, 0x00, 0x18, 0xC0, 0x18, 0x00, 0x30, 0x60, 0x1C, 0x00, 0x60, 0x30, 0x0E, 0x00, 0xF8, + 0xFF, 0x07, 0x00, 0xF8, 0xFF, 0x03, // 103 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0xF0, + 0xFF, 0x00, 0x00, 0xE0, 0xFF, // 104 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xF9, 0xFF, 0x00, 0x80, 0xF9, 0xFF, // 105 + 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x80, 0xF9, 0xFF, 0x1F, 0x80, 0xF9, 0xFF, 0x0F, // 106 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x80, 0x03, 0x00, 0x00, 0xC0, 0x07, 0x00, 0x00, 0x60, 0x1E, 0x00, 0x00, 0x30, 0x38, 0x00, 0x00, 0x18, 0xF0, 0x00, 0x00, 0x08, + 0xC0, 0x00, 0x00, 0x00, 0x80, // 107 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, // 108 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x00, 0x00, 0xE0, + 0xFF, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x38, 0x00, + 0x00, 0x00, 0xF0, 0xFF, 0x00, 0x00, 0xE0, 0xFF, // 109 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0xF0, + 0xFF, 0x00, 0x00, 0xE0, 0xFF, // 110 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x00, 0xE0, 0x3F, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0x38, 0xE0, 0x00, 0x00, + 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x38, 0xE0, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0xE0, + 0x3F, 0x00, 0x00, 0xC0, 0x1F, // 111 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x1F, 0x00, 0xF8, 0xFF, 0x1F, 0x00, 0x60, 0x30, 0x00, 0x00, + 0x30, 0x60, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x38, 0xE0, 0x00, 0x00, 0x70, + 0x70, 0x00, 0x00, 0xE0, 0x3F, 0x00, 0x00, 0xC0, 0x0F, // 112 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, 0xE0, 0x3F, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0x38, 0xE0, 0x00, 0x00, + 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x30, 0x60, 0x00, 0x00, 0x60, 0x30, 0x00, 0x00, 0xF8, + 0xFF, 0x1F, 0x00, 0xF8, 0xFF, 0x1F, // 113 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, // 114 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x30, 0x00, 0x00, 0xF0, 0x71, 0x00, 0x00, 0xB8, 0xE3, 0x00, 0x00, 0x18, 0xC3, 0x00, 0x00, + 0x18, 0xC3, 0x00, 0x00, 0x18, 0xC7, 0x00, 0x00, 0x18, 0xC7, 0x00, 0x00, 0x38, 0xE6, 0x00, 0x00, 0x70, 0x7E, 0x00, 0x00, 0x60, + 0x3C, // 115 + 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0xFF, 0x7F, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, + 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, // 116 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x3F, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, + 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0xF8, + 0xFF, 0x00, 0x00, 0xF8, 0xFF, // 117 + 0x00, 0x18, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0xE0, 0x03, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, + 0x00, 0xE0, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0xE0, 0x03, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, + 0x18, // 118 + 0x00, 0x38, 0x00, 0x00, 0x00, 0xF8, 0x01, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, + 0x00, 0x7E, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x00, 0xF0, 0x01, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0xF0, 0x01, 0x00, 0x00, 0x80, + 0x0F, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, 0xF8, 0x01, + 0x00, 0x00, 0x38, // 119 + 0x00, 0x08, 0x80, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x78, 0xF0, 0x00, 0x00, 0xE0, 0x38, 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x00, 0x80, 0x1F, 0x00, 0x00, 0xE0, 0x38, 0x00, 0x00, 0x70, 0xF0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x08, + 0x80, // 120 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0xF8, 0x01, 0x18, 0x00, 0xC0, 0x07, 0x18, 0x00, 0x00, 0x3E, 0x1C, 0x00, + 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xF0, 0x03, 0x00, 0x00, 0x7F, 0x00, 0x00, 0xE0, 0x0F, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, + 0x18, // 121 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x18, 0xF0, 0x00, 0x00, 0x18, 0xF8, 0x00, 0x00, 0x18, 0xDC, 0x00, 0x00, + 0x18, 0xCF, 0x00, 0x00, 0x98, 0xC3, 0x00, 0x00, 0xD8, 0xC1, 0x00, 0x00, 0xF8, 0xC0, 0x00, 0x00, 0x78, 0xC0, 0x00, 0x00, 0x18, + 0xC0, // 122 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0xFF, 0xF9, 0x0F, 0x80, 0xFF, 0xF0, 0x1F, 0x80, + 0x01, 0x00, 0x18, 0x80, 0x01, 0x00, 0x18, // 123 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x3F, 0x80, 0xFF, 0xFF, 0x3F, // 124 + 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x18, 0x80, 0x01, 0x00, 0x18, 0x80, 0xFF, 0xF0, 0x1F, 0x00, 0xFF, 0xFD, 0x0F, 0x00, + 0x00, 0x0F, 0x00, 0x00, 0x00, 0x06, // 125 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, + 0xC0, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x80, 0x01, // 126 + 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, + 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xC1, 0x00, 0x00, 0x80, 0xC1, + 0x00, 0x00, 0x80, 0x61, 0x00, 0x00, 0x80, 0x61, 0x60, 0x00, 0x80, 0x61, 0xC0, 0x00, 0x80, 0x61, 0xC0, 0x00, 0x00, 0x60, 0xC0, + 0x00, 0x00, 0xE0, 0xE0, 0x00, 0x00, 0xC0, 0x71, 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0x00, 0x1F, // 1026 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, + 0x01, 0x00, 0x00, 0xA0, 0x01, 0x00, 0x00, 0xB8, 0x01, 0x00, 0x00, 0x98, 0x01, 0x00, 0x00, 0x88, 0x01, 0x00, 0x00, 0x80, 0x01, + 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, // 1027 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x0C, 0x00, 0x00, 0xC0, 0x07, // 8218 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x80, + 0x1B, 0x00, 0x00, 0x80, 0x19, 0x00, 0x00, 0x80, 0x18, 0x00, 0x00, 0x00, 0x18, // 1107 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x0C, 0x00, 0x00, 0xC0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xC0, 0x0C, 0x00, 0x00, 0xC0, 0x07, // 8222 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, // 8230 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x0F, 0x80, 0xFF, 0xFF, 0x0F, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, + 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, // 8224 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, + 0x18, 0xC0, 0x00, 0x80, 0xFF, 0xFF, 0x0F, 0x80, 0xFF, 0xFF, 0x0F, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x18, + 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, // 8225 + 0x00, 0x30, 0x03, 0x00, 0x00, 0xF8, 0x07, 0x00, 0x00, 0xFE, 0x1F, 0x00, 0x00, 0x36, 0x3B, 0x00, 0x00, 0x33, 0x73, 0x00, 0x00, + 0x33, 0x63, 0x00, 0x80, 0x31, 0xC3, 0x00, 0x80, 0x31, 0xC3, 0x00, 0x80, 0x31, 0xC3, 0x00, 0x80, 0x31, 0xC3, 0x00, 0x80, 0x31, + 0xC0, 0x00, 0x00, 0x03, 0x60, // 8364 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x80, 0xC1, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, + 0xC1, 0xE0, 0x00, 0x00, 0x7F, 0xF8, 0x00, 0x00, 0x3E, 0x3E, 0x00, 0x00, 0xC0, 0x07, 0x00, 0x00, 0xF0, 0x01, 0x00, 0x00, 0x3E, + 0x3E, 0x00, 0x80, 0x0F, 0x7F, 0x00, 0x80, 0x81, 0xC1, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0xC1, 0x00, 0x00, 0x00, 0x7F, + 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x80, 0xC1, 0x00, + 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0xC1, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x3E, // 8240 + 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x80, 0xFF, 0x7F, 0x00, 0x80, 0xFF, 0x3F, 0x00, 0x80, + 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, + 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0xC0, 0xC0, + 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, + 0x00, 0x80, 0x61, 0x00, 0x00, 0x80, 0x7F, 0x00, 0x00, 0x00, 0x1E, // 1033 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x00, 0xE0, 0x3D, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, + 0x10, 0x40, // 8249 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, + 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, + 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0xC0, 0xC0, + 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0x80, 0x61, 0x00, + 0x00, 0x80, 0x7F, 0x00, 0x00, 0x00, 0x1E, // 1034 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, + 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x20, 0x60, 0x03, 0x00, 0x38, 0x78, 0x07, 0x00, 0x18, 0x1E, 0x0E, 0x00, 0x08, 0x07, + 0x38, 0x00, 0x80, 0x01, 0xF0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0x80, // 1036 + 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, + 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xC1, 0x00, 0x00, 0x80, 0xC1, + 0x00, 0x00, 0x80, 0x61, 0x00, 0x00, 0x80, 0x61, 0x00, 0x00, 0x80, 0x61, 0x00, 0x00, 0x80, 0x61, 0x00, 0x00, 0x00, 0x60, 0x00, + 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0xC0, 0xFF, 0x00, 0x00, 0x00, 0xFF, // 1035 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, + 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x00, + 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, // 1039 + 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, + 0x33, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x38, 0x00, 0x18, 0x00, 0xF0, + 0xFF, 0x1F, 0x00, 0xE0, 0xFF, 0x0F, // 1106 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x80, 0x19, // 8216 + 0x00, 0x00, 0x00, 0x00, 0x80, 0x19, 0x00, 0x00, 0x80, 0x0F, // 8217 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x80, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1F, 0x00, 0x00, 0x80, 0x19, // 8220 + 0x00, 0x00, 0x00, 0x00, 0x80, 0x19, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x19, 0x00, 0x00, 0x80, 0x0F, // 8221 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0xE0, 0x07, 0x00, 0x00, 0xE0, 0x07, 0x00, 0x00, 0xE0, 0x07, 0x00, 0x00, + 0xE0, 0x07, 0x00, 0x00, 0xC0, 0x03, // 8226 + 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, // 8211 + 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, + 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, // 8212 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, + 0x01, 0x00, 0x00, 0x80, 0xFF, 0x01, 0x00, 0x80, 0xFF, 0x01, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x01, 0x00, 0x80, 0xFF, 0x01, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00, 0x1E, 0x00, + 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, + 0x80, 0xFF, 0x01, 0x00, 0x80, 0xFF, 0x01, // 8482 + 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, + 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00, 0xC3, + 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00, 0xE7, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, + 0x3C, // 1113 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0xE0, 0x3D, 0x00, 0x00, + 0x80, 0x0F, 0x00, 0x00, 0x00, 0x02, // 8250 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, + 0xFF, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00, 0xC3, + 0x00, 0x00, 0x00, 0xE7, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x3C, // 1114 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x02, 0x02, 0x00, 0x80, + 0x03, 0x07, 0x00, 0x80, 0xC1, 0x0D, 0x00, 0x80, 0xF0, 0x38, 0x00, 0x00, 0x18, 0x70, 0x00, 0x00, 0x18, 0xE0, 0x00, 0x00, 0x00, + 0x80, // 1116 + 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, + 0x33, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0xF0, + 0xFF, 0x00, 0x00, 0xE0, 0xFF, // 1115 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, + 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0xF8, + 0xFF, 0x00, 0x00, 0xF8, 0xFF, // 1119 + 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x1E, 0xC0, 0x00, 0x18, 0x78, 0xC0, 0x00, 0x30, + 0xE0, 0xC1, 0x00, 0x20, 0x80, 0x77, 0x00, 0x20, 0x00, 0x3E, 0x00, 0x20, 0x80, 0x07, 0x00, 0x30, 0xE0, 0x01, 0x00, 0x18, 0x78, + 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x80, 0x01, // 1038 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0xF8, 0x01, 0x18, 0x80, 0xC1, 0x07, 0x18, 0x00, 0x03, 0x3E, 0x1C, 0x00, + 0x02, 0xF8, 0x0F, 0x00, 0x02, 0xF0, 0x03, 0x00, 0x02, 0x7F, 0x00, 0x00, 0xE3, 0x0F, 0x00, 0x80, 0xF9, 0x00, 0x00, 0x00, + 0x18, // 1118 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, + 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x80, 0xFF, 0x7F, 0x00, 0x80, 0xFF, 0x3F, // 1032 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0xDC, 0x3B, 0x00, 0x00, 0xF8, 0x1F, 0x00, 0x00, 0x30, 0x0C, 0x00, 0x00, + 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x30, 0x0C, 0x00, 0x00, 0xF8, + 0x1F, 0x00, 0x00, 0xDC, 0x3B, 0x00, 0x00, 0x08, 0x10, // 164 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, + 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xFC, 0x01, 0x00, 0x00, 0xFC, + 0x01, // 1168 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xE1, 0x3F, 0x80, 0xFF, 0xE1, 0x3F, // 166 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0xCE, 0x07, 0x03, 0x00, 0x7F, 0x0C, 0x0F, 0x80, 0x33, 0x1C, 0x0C, 0x80, + 0x71, 0x18, 0x18, 0x80, 0x61, 0x30, 0x18, 0x80, 0xC1, 0x70, 0x18, 0x80, 0xC3, 0xE1, 0x1C, 0x00, 0x87, 0xD3, 0x0F, 0x00, 0x06, + 0x9F, 0x07, 0x00, 0x00, 0x0E, // 167 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0xB0, + 0xC1, 0xC0, 0x00, 0xB0, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0xB0, 0xC1, 0xC0, 0x00, 0xB0, 0xC1, + 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0x01, 0xC0, // 1025 + 0x00, 0xE0, 0x03, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0x1C, 0x1C, 0x00, 0x00, 0x06, 0x30, 0x00, 0x00, 0xE7, 0x71, 0x00, 0x00, + 0xFB, 0x67, 0x00, 0x80, 0x19, 0xC6, 0x00, 0x80, 0x0D, 0xCC, 0x00, 0x80, 0x0D, 0xCC, 0x00, 0x80, 0x0D, 0xCC, 0x00, 0x80, 0x0D, + 0xCC, 0x00, 0x80, 0x1D, 0xCE, 0x00, 0x00, 0x1B, 0x66, 0x00, 0x00, 0x17, 0x72, 0x00, 0x00, 0x06, 0x30, 0x00, 0x00, 0x1C, 0x1C, + 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xE0, 0x03, // 169 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xCE, 0x3C, 0x00, 0x00, 0xC7, 0x70, 0x00, 0x00, + 0xC3, 0x60, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0x01, + 0xC0, 0x00, 0x80, 0x03, 0xE0, 0x00, 0x00, 0x03, 0x60, 0x00, 0x00, 0x0F, 0x78, 0x00, 0x00, 0x1E, 0x3C, 0x00, 0x00, 0x08, + 0x08, // 1028 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x00, 0xE0, 0x3D, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, + 0x10, 0x42, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x00, 0xE0, 0x3D, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0x10, 0x40, // 171 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0xF0, + 0x07, 0x00, 0x00, 0xF0, 0x07, // 172 + 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, // 173 + 0x00, 0xE0, 0x03, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0x1C, 0x1C, 0x00, 0x00, 0x06, 0x30, 0x00, 0x00, 0x07, 0x70, 0x00, 0x00, + 0xFB, 0x6F, 0x00, 0x80, 0xF9, 0xCF, 0x00, 0x80, 0x99, 0xC1, 0x00, 0x80, 0x99, 0xC1, 0x00, 0x80, 0x99, 0xC3, 0x00, 0x80, 0xF9, + 0xC7, 0x00, 0x80, 0xF1, 0xCC, 0x00, 0x00, 0x03, 0x68, 0x00, 0x00, 0x07, 0x70, 0x00, 0x00, 0x06, 0x30, 0x00, 0x00, 0x1C, 0x1C, + 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xE0, 0x03, // 174 + 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x30, // 1031 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x80, 0x20, 0x00, 0x00, 0x80, 0x20, 0x00, 0x00, 0x80, + 0x20, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x0E, // 176 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC1, 0x00, 0x00, 0x80, 0xC1, 0x00, 0x00, 0x80, 0xC1, 0x00, 0x00, 0x80, 0xC1, 0x00, 0x00, + 0x80, 0xC1, 0x00, 0x00, 0xFC, 0xFF, 0x00, 0x00, 0xFC, 0xFF, 0x00, 0x00, 0x80, 0xC1, 0x00, 0x00, 0x80, 0xC1, 0x00, 0x00, 0x80, + 0xC1, 0x00, 0x00, 0x80, 0xC1, 0x00, 0x00, 0x80, 0xC1, // 177 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, // 1030 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xF9, 0xFF, 0x00, 0x80, 0xF9, 0xFF, // 1110 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x80, 0x1F, 0x00, 0x00, 0x80, 0x1F, // 1169 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x1F, 0x00, 0xF8, 0xFF, 0x1F, 0x00, 0x00, 0x60, 0x00, 0x00, + 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0xF8, + 0xFF, 0x00, 0x00, 0xF8, 0xFF, // 181 + 0x00, 0x3C, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x80, 0xFF, 0x01, 0x00, 0x80, 0xFF, 0x01, 0x00, 0x80, + 0xFF, 0xFF, 0x1F, 0x80, 0xFF, 0xFF, 0x1F, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x1F, 0x80, 0xFF, + 0xFF, 0x1F, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, // 182 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, // 183 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x1F, 0x00, 0x00, 0xE0, 0x3F, 0x00, 0x00, 0x70, 0x73, 0x00, 0x00, 0x3B, 0xE3, 0x00, 0x00, + 0x1B, 0xC3, 0x00, 0x00, 0x18, 0xC3, 0x00, 0x00, 0x18, 0xC3, 0x00, 0x00, 0x3B, 0xE3, 0x00, 0x00, 0x73, 0x63, 0x00, 0x00, 0xE0, + 0x33, 0x00, 0x00, 0xC0, 0x13, // 1105 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, + 0x1C, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, + 0x0E, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x78, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x63, 0x00, 0x00, 0xF0, 0x67, 0x00, 0x00, 0x38, 0x6E, 0x00, 0x00, 0x18, 0x6C, 0x00, + 0x00, 0x18, 0x6C, 0x00, 0x00, 0x38, 0x6E, 0x00, 0x00, 0xF0, 0x67, 0x00, 0x00, 0xE0, 0x63, // 8470 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x00, 0xE0, 0x7F, 0x00, 0x00, 0x70, 0x73, 0x00, 0x00, 0x18, 0xC3, 0x00, 0x00, + 0x18, 0xC3, 0x00, 0x00, 0x18, 0xC3, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x38, 0x60, 0x00, 0x00, 0x70, 0x78, 0x00, 0x00, 0x60, + 0x18, // 1108 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, + 0xE0, 0x3D, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x00, 0x10, 0x42, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0xE0, 0x3D, 0x00, 0x00, 0x80, + 0x0F, 0x00, 0x00, 0x00, 0x02, // 187 + 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x80, 0xF9, 0xFF, 0x1F, 0x80, 0xF9, 0xFF, 0x0F, // 1112 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x1C, 0x3C, 0x00, 0x00, 0x7F, 0x70, 0x00, 0x00, 0x63, 0x60, 0x00, 0x80, + 0xE1, 0xE0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, + 0xC1, 0x00, 0x80, 0x83, 0xE1, 0x00, 0x00, 0x87, 0x63, 0x00, 0x00, 0x0E, 0x3F, 0x00, 0x00, 0x0C, 0x1E, // 1029 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x30, 0x00, 0x00, 0xF0, 0x71, 0x00, 0x00, 0xB8, 0xE3, 0x00, 0x00, 0x18, 0xC3, 0x00, 0x00, + 0x18, 0xC3, 0x00, 0x00, 0x18, 0xC7, 0x00, 0x00, 0x18, 0xC7, 0x00, 0x00, 0x38, 0xE6, 0x00, 0x00, 0x70, 0x7E, 0x00, 0x00, 0x60, + 0x3C, // 1109 + 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x03, // 1111 + 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, 0xF8, 0x07, 0x00, 0x00, + 0x3E, 0x06, 0x00, 0x80, 0x0F, 0x06, 0x00, 0x80, 0x01, 0x06, 0x00, 0x80, 0x0F, 0x06, 0x00, 0x00, 0x3E, 0x06, 0x00, 0x00, 0xF8, + 0x07, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0xC0, // 1040 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, + 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, + 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0x81, 0x61, 0x00, 0x00, 0x80, 0x7F, 0x00, 0x00, 0x00, 0x1E, // 1041 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, + 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, + 0xC0, 0x00, 0x00, 0xE3, 0xC1, 0x00, 0x00, 0xFF, 0x61, 0x00, 0x00, 0x1E, 0x7F, 0x00, 0x00, 0x00, 0x1E, // 1042 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, + 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, + 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, // 1043 + 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, 0xE0, 0x0F, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0xDF, 0x00, 0x80, 0xFF, 0xC7, 0x00, 0x80, + 0x7F, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, + 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, 0xC0, + 0x0F, // 1044 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, + 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, + 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0x01, 0xC0, // 1045 + 0x80, 0x01, 0x80, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0xF0, 0x00, 0x00, 0x07, 0x3C, 0x00, 0x00, 0x1E, 0x0E, 0x00, 0x00, + 0x38, 0x07, 0x00, 0x00, 0xE0, 0x03, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x80, 0xFF, + 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0xE0, 0x03, + 0x00, 0x00, 0x38, 0x07, 0x00, 0x00, 0x1E, 0x0E, 0x00, 0x00, 0x07, 0x3C, 0x00, 0x80, 0x01, 0xF0, 0x00, 0x80, 0x01, 0xC0, 0x00, + 0x80, 0x01, 0x80, // 1046 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x08, 0x00, 0x00, 0x1E, 0x3C, 0x00, 0x00, 0x07, 0x78, 0x00, 0x80, 0x03, 0x60, 0x00, 0x80, + 0x01, 0xE0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x00, 0xE3, + 0xE1, 0x00, 0x00, 0xBF, 0x73, 0x00, 0x00, 0x1C, 0x3F, 0x00, 0x00, 0x00, 0x1E, // 1047 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x3C, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x38, + 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, // 1048 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x70, 0x00, 0x18, + 0x00, 0x3C, 0x00, 0x30, 0x00, 0x0E, 0x00, 0x20, 0x80, 0x07, 0x00, 0x20, 0xC0, 0x01, 0x00, 0x20, 0xF0, 0x00, 0x00, 0x30, 0x38, + 0x00, 0x00, 0x18, 0x1E, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, // 1049 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, + 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x60, 0x03, 0x00, 0x00, 0x78, 0x07, 0x00, 0x00, 0x1E, 0x0E, 0x00, 0x00, 0x07, + 0x38, 0x00, 0x80, 0x01, 0xF0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0x80, // 1050 + 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x80, 0xFF, 0x7F, 0x00, 0x80, 0xFF, 0x3F, 0x00, 0x80, + 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, + 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, // 1051 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, + 0x3F, 0x00, 0x00, 0x00, 0xF8, 0x03, 0x00, 0x00, 0x80, 0x1F, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, + 0xFC, 0x00, 0x00, 0x80, 0x1F, 0x00, 0x00, 0xF8, 0x03, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x80, 0xFF, 0xFF, + 0x00, 0x80, 0xFF, 0xFF, // 1052 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, + 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, + 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, // 1053 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0x1E, 0x3C, 0x00, 0x00, 0x07, 0x70, 0x00, 0x00, + 0x03, 0x60, 0x00, 0x80, 0x03, 0xE0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, + 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x03, 0xE0, 0x00, 0x00, 0x03, 0x60, 0x00, 0x00, 0x07, 0x70, 0x00, 0x00, 0x1E, 0x3C, + 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xF0, 0x07, // 1054 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, + 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, + 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, // 1055 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0x81, 0x01, 0x00, 0x80, + 0x81, 0x01, 0x00, 0x80, 0x81, 0x01, 0x00, 0x80, 0x81, 0x01, 0x00, 0x80, 0x81, 0x01, 0x00, 0x80, 0x81, 0x01, 0x00, 0x80, 0x81, + 0x01, 0x00, 0x80, 0x81, 0x01, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x3C, // 1056 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0x1E, 0x3C, 0x00, 0x00, 0x07, 0x70, 0x00, 0x00, + 0x03, 0x60, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, + 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x00, 0x03, 0x60, 0x00, 0x00, 0x07, 0x70, 0x00, 0x00, 0x0E, 0x3C, 0x00, 0x00, 0x08, + 0x0C, // 1057 + 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, + 0x01, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, + 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, // 1058 + 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x1E, 0xC0, 0x00, 0x00, 0x78, 0xC0, 0x00, 0x00, + 0xE0, 0xC1, 0x00, 0x00, 0x80, 0x77, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0x78, + 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x80, 0x01, // 1059 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x03, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0x1C, 0x1C, 0x00, 0x00, 0x0C, 0x18, 0x00, 0x00, + 0x0E, 0x38, 0x00, 0x00, 0x06, 0x30, 0x00, 0x00, 0x06, 0x30, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x06, + 0x30, 0x00, 0x00, 0x06, 0x30, 0x00, 0x00, 0x0E, 0x38, 0x00, 0x00, 0x0C, 0x18, 0x00, 0x00, 0x1C, 0x1C, 0x00, 0x00, 0xF8, 0x0F, + 0x00, 0x00, 0xE0, 0x03, // 1060 + 0x00, 0x00, 0x80, 0x00, 0x80, 0x00, 0xC0, 0x00, 0x80, 0x01, 0xF0, 0x00, 0x80, 0x07, 0x78, 0x00, 0x00, 0x0F, 0x1E, 0x00, 0x00, + 0x3C, 0x0F, 0x00, 0x00, 0xF8, 0x07, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0xF8, 0x07, 0x00, 0x00, 0x1E, 0x0F, 0x00, 0x00, 0x0F, + 0x1C, 0x00, 0x80, 0x07, 0x78, 0x00, 0x80, 0x01, 0xF0, 0x00, 0x80, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x80, // 1061 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, + 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, + 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xC0, + 0x1F, 0x00, 0x00, 0xC0, 0x1F, // 1062 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x7F, 0x00, 0x00, 0x80, 0xFF, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x80, + 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, // 1063 + 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, + 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x80, 0xFF, + 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, + 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, + 0xFF, // 1064 + 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, + 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x80, 0xFF, + 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, + 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, + 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x00, 0xC0, 0x1F, // 1065 + 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, + 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0xC0, + 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0x80, 0x61, + 0x00, 0x00, 0x80, 0x7F, 0x00, 0x00, 0x00, 0x1E, // 1066 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, + 0xC0, 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0xC0, + 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0x80, 0x61, 0x00, 0x00, 0x80, 0x7F, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, // 1067 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, + 0xC0, 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0xC0, + 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0x80, 0x61, 0x00, 0x00, 0x80, 0x7F, 0x00, 0x00, 0x00, 0x1E, // 1068 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x1E, 0x3C, 0x00, 0x00, 0x0F, 0x78, 0x00, 0x00, 0x03, 0x60, 0x00, 0x80, + 0x03, 0xE0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, + 0xC0, 0x00, 0x00, 0xC3, 0x60, 0x00, 0x00, 0xC7, 0x70, 0x00, 0x00, 0xCE, 0x38, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xF0, + 0x07, // 1069 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, + 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0x1E, 0x3C, 0x00, 0x00, 0x07, + 0x70, 0x00, 0x00, 0x03, 0x60, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0xC0, + 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x00, 0x03, 0x60, 0x00, 0x00, 0x07, 0x70, 0x00, 0x00, 0x1E, 0x3C, 0x00, + 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xF0, 0x07, // 1070 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x3E, 0xC0, 0x00, 0x00, 0x7F, 0xF0, 0x00, 0x80, 0x63, 0x7C, 0x00, 0x80, + 0xC1, 0x1E, 0x00, 0x80, 0xC1, 0x0F, 0x00, 0x80, 0xC1, 0x03, 0x00, 0x80, 0xC1, 0x01, 0x00, 0x80, 0xC1, 0x00, 0x00, 0x80, 0xC1, + 0x00, 0x00, 0x80, 0xC1, 0x00, 0x00, 0x80, 0xC1, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, // 1071 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x38, 0x00, 0x00, 0x70, 0x7C, 0x00, 0x00, 0x30, 0xE6, 0x00, 0x00, 0x18, 0xC6, 0x00, 0x00, + 0x18, 0xC6, 0x00, 0x00, 0x18, 0xC3, 0x00, 0x00, 0x18, 0x63, 0x00, 0x00, 0x38, 0x63, 0x00, 0x00, 0xF0, 0x7F, 0x00, 0x00, 0xE0, + 0xFF, 0x00, 0x00, 0x00, 0x80, // 1072 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0x73, 0x70, 0x00, 0x00, 0x31, 0xE0, 0x00, 0x80, + 0x19, 0xC0, 0x00, 0x80, 0x19, 0xC0, 0x00, 0x80, 0x19, 0xC0, 0x00, 0x80, 0x19, 0xC0, 0x00, 0x80, 0x39, 0xE0, 0x00, 0x80, 0x71, + 0x70, 0x00, 0x80, 0xE1, 0x3F, 0x00, 0x80, 0x80, 0x0F, // 1073 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x18, 0xC3, 0x00, 0x00, + 0x18, 0xC3, 0x00, 0x00, 0x18, 0xC3, 0x00, 0x00, 0x18, 0xC3, 0x00, 0x00, 0x18, 0xC3, 0x00, 0x00, 0xF0, 0xE7, 0x00, 0x00, 0xF0, + 0x7E, 0x00, 0x00, 0x00, 0x3C, // 1074 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, // 1075 + 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, 0xE0, 0x0F, 0x00, 0x00, 0xFC, 0x00, 0x00, 0xF8, 0xDF, 0x00, 0x00, 0xF8, 0xC3, 0x00, 0x00, + 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, + 0xFF, 0x00, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, 0xC0, 0x0F, // 1076 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x1F, 0x00, 0x00, 0xE0, 0x3F, 0x00, 0x00, 0x70, 0x73, 0x00, 0x00, 0x38, 0xE3, 0x00, 0x00, + 0x18, 0xC3, 0x00, 0x00, 0x18, 0xC3, 0x00, 0x00, 0x18, 0xC3, 0x00, 0x00, 0x38, 0xE3, 0x00, 0x00, 0x70, 0x63, 0x00, 0x00, 0xE0, + 0x33, 0x00, 0x00, 0xC0, 0x13, // 1077 + 0x00, 0x18, 0xE0, 0x00, 0x00, 0x18, 0x70, 0x00, 0x00, 0xF8, 0x38, 0x00, 0x00, 0xE0, 0x0D, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0xE0, + 0x0D, 0x00, 0x00, 0xF8, 0x38, 0x00, 0x00, 0x18, 0x70, 0x00, 0x00, 0x18, 0xE0, 0x00, 0x00, 0x00, 0x80, // 1078 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x30, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0x38, 0xE0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, + 0x18, 0xC3, 0x00, 0x00, 0x18, 0xC3, 0x00, 0x00, 0x38, 0xE7, 0x00, 0x00, 0xF0, 0x7F, 0x00, 0x00, 0xE0, 0x3C, // 1079 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, + 0x00, 0x3C, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0xF8, + 0xFF, 0x00, 0x00, 0xF8, 0xFF, // 1080 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x80, 0x01, 0xF0, 0x00, 0x00, + 0x03, 0x3C, 0x00, 0x00, 0x02, 0x0F, 0x00, 0x00, 0x82, 0x07, 0x00, 0x00, 0xE2, 0x01, 0x00, 0x00, 0x7B, 0x00, 0x00, 0x80, 0xF9, + 0xFF, 0x00, 0x00, 0xF8, 0xFF, // 1081 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x00, 0xC0, 0x0D, 0x00, 0x00, 0xF0, 0x38, 0x00, 0x00, 0x18, 0x70, 0x00, 0x00, 0x18, 0xE0, 0x00, 0x00, 0x00, + 0x80, // 1082 + 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0xF8, + 0xFF, 0x00, 0x00, 0xF8, 0xFF, // 1083 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, + 0xF0, 0x03, 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x80, + 0x1F, 0x00, 0x00, 0xF0, 0x03, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, // 1084 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0xF8, + 0xFF, 0x00, 0x00, 0xF8, 0xFF, // 1085 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x00, 0xE0, 0x3F, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0x38, 0xE0, 0x00, 0x00, + 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x38, 0xE0, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0xE0, + 0x3F, 0x00, 0x00, 0xC0, 0x1F, // 1086 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0xF8, + 0xFF, 0x00, 0x00, 0xF8, 0xFF, // 1087 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x1F, 0x00, 0xF8, 0xFF, 0x1F, 0x00, 0x60, 0x30, 0x00, 0x00, + 0x30, 0x60, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x38, 0xE0, 0x00, 0x00, 0x70, + 0x70, 0x00, 0x00, 0xE0, 0x3F, 0x00, 0x00, 0xC0, 0x0F, // 1088 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x00, 0xE0, 0x3F, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0x38, 0xE0, 0x00, 0x00, + 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x38, 0xE0, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0x60, + 0x30, // 1089 + 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, + 0xF8, 0xFF, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, // 1090 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0xF8, 0x01, 0x18, 0x00, 0xC0, 0x07, 0x18, 0x00, 0x00, 0x3E, 0x1C, 0x00, + 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xF0, 0x03, 0x00, 0x00, 0x7F, 0x00, 0x00, 0xE0, 0x0F, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, + 0x18, // 1091 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x00, 0xE0, 0x3F, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0x38, 0xE0, 0x00, 0x00, + 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x70, 0x60, 0x00, 0x80, 0xFF, 0xFF, 0x1F, 0x80, 0xFF, + 0xFF, 0x1F, 0x00, 0x70, 0x60, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x18, 0xE0, + 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0xE0, 0x3F, 0x00, 0x00, 0xC0, 0x1F, // 1092 + 0x00, 0x08, 0x80, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x78, 0xF0, 0x00, 0x00, 0xE0, 0x38, 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x00, 0x80, 0x1F, 0x00, 0x00, 0xE0, 0x38, 0x00, 0x00, 0x70, 0xF0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x08, + 0x80, // 1093 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, + 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0xF8, + 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x1F, 0x00, 0x00, 0xC0, 0x1F, // 1094 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x01, 0x00, 0x00, 0xF8, 0x07, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, + 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, + 0xFF, // 1095 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, + 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, + 0xFF, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, + 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, // 1096 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, + 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, + 0xFF, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, + 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x1F, 0x00, 0x00, 0xC0, 0x1F, // 1097 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, + 0xF8, 0xFF, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00, + 0xC3, 0x00, 0x00, 0x00, 0xE7, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x3C, // 1098 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, + 0x00, 0xC3, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00, 0xE7, 0x00, 0x00, 0x00, + 0x7E, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, // 1099 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, + 0x00, 0xC3, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00, 0xE7, 0x00, 0x00, 0x00, + 0x7E, 0x00, 0x00, 0x00, 0x3C, // 1100 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x18, 0x00, 0x00, 0x70, 0x78, 0x00, 0x00, 0x38, 0x60, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, + 0x18, 0xC3, 0x00, 0x00, 0x18, 0xC3, 0x00, 0x00, 0x18, 0xC3, 0x00, 0x00, 0x70, 0x73, 0x00, 0x00, 0xE0, 0x7F, 0x00, 0x00, 0xC0, + 0x1F, // 1101 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x00, 0xE0, 0x3F, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0x38, 0xE0, 0x00, 0x00, 0x18, + 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x38, 0xE0, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0xE0, 0x3F, + 0x00, 0x00, 0xC0, 0x1F, // 1102 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xC1, 0x00, 0x00, 0xF0, 0xE3, 0x00, 0x00, 0x38, 0x7B, 0x00, 0x00, 0x18, 0x1A, 0x00, 0x00, + 0x18, 0x0E, 0x00, 0x00, 0x18, 0x06, 0x00, 0x00, 0x18, 0x06, 0x00, 0x00, 0x18, 0x06, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, + 0xFF, // 1103 }; \ No newline at end of file diff --git a/src/graphics/fonts/OLEDDisplayFontsUA.h b/src/graphics/fonts/OLEDDisplayFontsUA.h index 3bd9bb4ca..dc313aed2 100644 --- a/src/graphics/fonts/OLEDDisplayFontsUA.h +++ b/src/graphics/fonts/OLEDDisplayFontsUA.h @@ -8,4 +8,6 @@ #endif extern const uint8_t ArialMT_Plain_10_UA[] PROGMEM; +extern const uint8_t ArialMT_Plain_16_UA[] PROGMEM; +extern const uint8_t ArialMT_Plain_24_UA[] PROGMEM; #endif \ No newline at end of file diff --git a/src/input/MPR121Keyboard.cpp b/src/input/MPR121Keyboard.cpp index 078d80272..9bca6801d 100644 --- a/src/input/MPR121Keyboard.cpp +++ b/src/input/MPR121Keyboard.cpp @@ -29,6 +29,8 @@ #define _MPR121_REG_CONFIG1 0x5C #define _MPR121_REG_CONFIG2 0x5D #define _MPR121_REG_ELECTRODE_CONFIG 0x5E +#define _MPR121_REG_AUTOCONF_CTRL0 0x7B +#define _MPR121_REG_AUTOCONF_CTRL1 0x7C #define _MPR121_REG_SOFT_RESET 0x80 #define _KEY_MASK 0x0FFF // Key mask for the first 12 bits @@ -87,7 +89,7 @@ uint8_t MPR121_KeyMap[12] = {2, 5, 8, 11, 1, 4, 7, 10, 0, 3, 6, 9}; MPR121Keyboard::MPR121Keyboard() : m_wire(nullptr), m_addr(0), readCallback(nullptr), writeCallback(nullptr) { - // LOG_DEBUG("MPR121 @ %02x\n", m_addr); + // LOG_DEBUG("MPR121 @ %02x", m_addr); state = Init; last_key = -1; last_tap = 0L; @@ -132,18 +134,18 @@ void MPR121Keyboard::reset() writeRegister(_MPR121_REG_ELECTRODE_CONFIG, 0x00); delay(100); - LOG_DEBUG("MPR121 Configure"); + LOG_DEBUG("MPR121 Configuring"); // Set touch release thresholds for (uint8_t i = 0; i < 12; i++) { // Set touch threshold - writeRegister(_MPR121_REG_TOUCH_THRESHOLD + (i * 2), 15); + writeRegister(_MPR121_REG_TOUCH_THRESHOLD + (i * 2), 10); delay(20); // Set release threshold - writeRegister(_MPR121_REG_RELEASE_THRESHOLD + (i * 2), 7); + writeRegister(_MPR121_REG_RELEASE_THRESHOLD + (i * 2), 5); delay(20); } // Configure filtering and baseline registers - writeRegister(_MPR121_REG_MAX_HALF_DELTA_RISING, 0x01); + writeRegister(_MPR121_REG_MAX_HALF_DELTA_RISING, 0x05); delay(20); writeRegister(_MPR121_REG_MAX_HALF_DELTA_FALLING, 0x01); delay(20); @@ -153,7 +155,7 @@ void MPR121Keyboard::reset() delay(20); writeRegister(_MPR121_REG_NOISE_HALF_DELTA_TOUCHED, 0x00); delay(20); - writeRegister(_MPR121_REG_NOISE_COUNT_LIMIT_RISING, 0x0e); + writeRegister(_MPR121_REG_NOISE_COUNT_LIMIT_RISING, 0x05); delay(20); writeRegister(_MPR121_REG_NOISE_COUNT_LIMIT_FALLING, 0x01); delay(20); @@ -165,18 +167,19 @@ void MPR121Keyboard::reset() delay(20); writeRegister(_MPR121_REG_FILTER_DELAY_COUNT_TOUCHED, 0x00); delay(20); - // Set Debounce to 0x02 - writeRegister(_MPR121_REG_DEBOUNCE, 0x00); + writeRegister(_MPR121_REG_AUTOCONF_CTRL0, 0x04); // Auto-config enable delay(20); - // Set Filter1 itterations and discharge current 6x and 16uA respectively (0x10) - writeRegister(_MPR121_REG_CONFIG1, 0x10); + writeRegister(_MPR121_REG_AUTOCONF_CTRL1, 0x00); // Ensure no auto-config interrupt delay(20); - // Set CDT to 0.5us, Filter2 itterations to 4x, and Sample interval = 0 (0x20) - writeRegister(_MPR121_REG_CONFIG2, 0x20); + writeRegister(_MPR121_REG_DEBOUNCE, 0x02); + delay(20); + writeRegister(_MPR121_REG_CONFIG1, 0x20); + delay(20); + writeRegister(_MPR121_REG_CONFIG2, 0x21); delay(20); // Enter run mode by Seting partial filter calibration tracking, disable proximity detection, enable 12 channels writeRegister(_MPR121_REG_ELECTRODE_CONFIG, - ECR_CALIBRATION_TRACK_FROM_PARTIAL_FILTER | ECR_PROXIMITY_DETECTION_OFF | ECR_TOUCH_DETECTION_12CH); + ECR_CALIBRATION_TRACK_FROM_FULL_FILTER | ECR_PROXIMITY_DETECTION_OFF | ECR_TOUCH_DETECTION_12CH); delay(100); LOG_DEBUG("MPR121 Run"); state = Idle; @@ -427,4 +430,4 @@ void MPR121Keyboard::writeRegister(uint8_t reg, uint8_t value) if (writeCallback) { writeCallback(m_addr, data[0], &(data[1]), 1); } -} +} \ No newline at end of file diff --git a/src/input/TouchScreenBase.cpp b/src/input/TouchScreenBase.cpp index a63203362..d2f7b54f8 100644 --- a/src/input/TouchScreenBase.cpp +++ b/src/input/TouchScreenBase.cpp @@ -113,13 +113,13 @@ int32_t TouchScreenBase::runOnce() if (_tapped) { _tapped = false; e.touchEvent = static_cast(TOUCH_ACTION_TAP); - LOG_DEBUG("action TAP(%d/%d)\n", _last_x, _last_y); + LOG_DEBUG("action TAP(%d/%d)", _last_x, _last_y); } } else { if (_tapped && (time_t(millis()) - _start) > TIME_LONG_PRESS - 50) { _tapped = false; e.touchEvent = static_cast(TOUCH_ACTION_TAP); - LOG_DEBUG("action TAP(%d/%d)\n", _last_x, _last_y); + LOG_DEBUG("action TAP(%d/%d)", _last_x, _last_y); } } #else @@ -156,4 +156,4 @@ void TouchScreenBase::hapticFeedback() drv.setWaveform(1, 0); // end waveform drv.go(); #endif -} \ No newline at end of file +} diff --git a/src/input/cardKbI2cImpl.cpp b/src/input/cardKbI2cImpl.cpp index 41c17bc3a..4db0fe070 100644 --- a/src/input/cardKbI2cImpl.cpp +++ b/src/input/cardKbI2cImpl.cpp @@ -53,10 +53,11 @@ void CardKbI2cImpl::init() kb_model = 0x00; } } - LOG_DEBUG("Keyboard Type: 0x%02x Model: 0x%02x Address: 0x%02x", kb_info.type, kb_model, cardkb_found.address); if (cardkb_found.address == 0x00) { disable(); return; + } else { + LOG_DEBUG("Keyboard Type: 0x%02x Model: 0x%02x Address: 0x%02x", kb_info.type, kb_model, cardkb_found.address); } } #else diff --git a/src/main.cpp b/src/main.cpp index 7b866f331..55aea1710 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,4 +1,3 @@ -#include "../userPrefs.h" #include "configuration.h" #if !MESHTASTIC_EXCLUDE_GPS #include "GPS.h" @@ -41,6 +40,7 @@ #include #ifdef ARCH_ESP32 +#include "freertosinc.h" #if !MESHTASTIC_EXCLUDE_WEBSERVER #include "mesh/http/WebServer.h" #endif @@ -83,7 +83,7 @@ NRF52Bluetooth *nrf52Bluetooth = nullptr; #include "STM32WLE5JCInterface.h" #endif -#if !HAS_RADIO && defined(ARCH_PORTDUINO) +#if defined(ARCH_PORTDUINO) #include "platform/portduino/SimRadio.h" #endif @@ -91,6 +91,7 @@ NRF52Bluetooth *nrf52Bluetooth = nullptr; #include "linux/LinuxHardwareI2C.h" #include "mesh/raspihttp/PiWebServer.h" #include "platform/portduino/PortduinoGlue.h" +#include "platform/portduino/USBHal.h" #include #include #include @@ -150,10 +151,6 @@ ScanI2C::DeviceAddress accelerometer_found = ScanI2C::ADDRESS_NONE; // The I2C address of the RGB LED (if found) ScanI2C::FoundDevice rgb_found = ScanI2C::FoundDevice(ScanI2C::DeviceType::NONE, ScanI2C::ADDRESS_NONE); -#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) -ATECCX08A atecc; -#endif - #ifdef T_WATCH_S3 Adafruit_DRV2605 drv; #endif @@ -177,6 +174,8 @@ std::pair nodeTelemetrySensorsMap[_meshtastic_TelemetrySenso Router *router = NULL; // Users of router don't care what sort of subclass implements that API +const char *firmware_version = optstr(APP_VERSION_SHORT); + const char *getDeviceName() { uint8_t dmac[6]; @@ -218,6 +217,9 @@ static OSThread *powerFSMthread; static OSThread *ambientLightingThread; RadioInterface *rIf = NULL; +#ifdef ARCH_PORTDUINO +RadioLibHal *RadioLibHAL = NULL; +#endif /** * Some platforms (nrf52) might provide an alterate version that suppresses calling delay from sleep. @@ -242,6 +244,17 @@ void printInfo() #ifndef PIO_UNIT_TESTING void setup() { +#if defined(T_DECK) + // GPIO10 manages all peripheral power supplies + // Turn on peripheral power immediately after MUC starts. + // If some boards are turned on late, ESP32 will reset due to low voltage. + // ESP32-C3(Keyboard) , MAX98357A(Audio Power Amplifier) , + // TF Card , Display backlight(AW9364DNR) , AN48841B(Trackball) , ES7210(Decoder) + pinMode(KB_POWERON, OUTPUT); + digitalWrite(KB_POWERON, HIGH); + delay(100); +#endif + concurrency::hasBeenSetup = true; #if ARCH_PORTDUINO SPISettings spiSettings(settingsMap[spiSpeed], MSBFIRST, SPI_MODE0); @@ -414,15 +427,6 @@ void setup() digitalWrite(AQ_SET_PIN, HIGH); #endif -#ifdef T_DECK - // enable keyboard - pinMode(KB_POWERON, OUTPUT); - digitalWrite(KB_POWERON, HIGH); - // There needs to be a delay after power on, give LILYGO-KEYBOARD some startup time - // otherwise keyboard and touch screen will not work - delay(800); -#endif - // Currently only the tbeam has a PMU // PMU initialization needs to be placed before i2c scanning power = new Power(); @@ -575,49 +579,37 @@ void setup() LOG_DEBUG("acc_info = %i", acc_info.type); #endif -#define STRING(S) #S - -#define SCANNER_TO_SENSORS_MAP(SCANNER_T, PB_T) \ - { \ - auto found = i2cScanner->find(SCANNER_T); \ - if (found.type != ScanI2C::DeviceType::NONE) { \ - nodeTelemetrySensorsMap[PB_T].first = found.address.address; \ - nodeTelemetrySensorsMap[PB_T].second = i2cScanner->fetchI2CBus(found.address); \ - LOG_DEBUG("found i2c sensor %s", STRING(PB_T)); \ - } \ - } - - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::BME_680, meshtastic_TelemetrySensorType_BME680) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::BME_280, meshtastic_TelemetrySensorType_BME280) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::BMP_280, meshtastic_TelemetrySensorType_BMP280) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::BMP_3XX, meshtastic_TelemetrySensorType_BMP3XX) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::BMP_085, meshtastic_TelemetrySensorType_BMP085) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::INA260, meshtastic_TelemetrySensorType_INA260) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::INA219, meshtastic_TelemetrySensorType_INA219) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::INA3221, meshtastic_TelemetrySensorType_INA3221) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::MAX17048, meshtastic_TelemetrySensorType_MAX17048) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::MCP9808, meshtastic_TelemetrySensorType_MCP9808) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::MCP9808, meshtastic_TelemetrySensorType_MCP9808) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::SHT31, meshtastic_TelemetrySensorType_SHT31) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::SHTC3, meshtastic_TelemetrySensorType_SHTC3) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::LPS22HB, meshtastic_TelemetrySensorType_LPS22) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::QMC6310, meshtastic_TelemetrySensorType_QMC6310) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::QMI8658, meshtastic_TelemetrySensorType_QMI8658) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::QMC5883L, meshtastic_TelemetrySensorType_QMC5883L) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::HMC5883L, meshtastic_TelemetrySensorType_QMC5883L) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::PMSA0031, meshtastic_TelemetrySensorType_PMSA003I) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::RCWL9620, meshtastic_TelemetrySensorType_RCWL9620) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::VEML7700, meshtastic_TelemetrySensorType_VEML7700) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::TSL2591, meshtastic_TelemetrySensorType_TSL25911FN) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::OPT3001, meshtastic_TelemetrySensorType_OPT3001) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::MLX90632, meshtastic_TelemetrySensorType_MLX90632) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::MLX90614, meshtastic_TelemetrySensorType_MLX90614) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::SHT4X, meshtastic_TelemetrySensorType_SHT4X) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::AHT10, meshtastic_TelemetrySensorType_AHT10) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::DFROBOT_LARK, meshtastic_TelemetrySensorType_DFROBOT_LARK) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::ICM20948, meshtastic_TelemetrySensorType_ICM20948) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::MAX30102, meshtastic_TelemetrySensorType_MAX30102) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::CGRADSENS, meshtastic_TelemetrySensorType_RADSENS) + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::BME_680, meshtastic_TelemetrySensorType_BME680); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::BME_280, meshtastic_TelemetrySensorType_BME280); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::BMP_280, meshtastic_TelemetrySensorType_BMP280); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::BMP_3XX, meshtastic_TelemetrySensorType_BMP3XX); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::BMP_085, meshtastic_TelemetrySensorType_BMP085); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::INA260, meshtastic_TelemetrySensorType_INA260); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::INA226, meshtastic_TelemetrySensorType_INA226); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::INA219, meshtastic_TelemetrySensorType_INA219); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::INA3221, meshtastic_TelemetrySensorType_INA3221); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::MAX17048, meshtastic_TelemetrySensorType_MAX17048); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::MCP9808, meshtastic_TelemetrySensorType_MCP9808); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::SHT31, meshtastic_TelemetrySensorType_SHT31); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::SHTC3, meshtastic_TelemetrySensorType_SHTC3); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::LPS22HB, meshtastic_TelemetrySensorType_LPS22); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::QMC6310, meshtastic_TelemetrySensorType_QMC6310); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::QMI8658, meshtastic_TelemetrySensorType_QMI8658); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::QMC5883L, meshtastic_TelemetrySensorType_QMC5883L); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::HMC5883L, meshtastic_TelemetrySensorType_QMC5883L); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::PMSA0031, meshtastic_TelemetrySensorType_PMSA003I); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::RCWL9620, meshtastic_TelemetrySensorType_RCWL9620); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::VEML7700, meshtastic_TelemetrySensorType_VEML7700); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::TSL2591, meshtastic_TelemetrySensorType_TSL25911FN); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::OPT3001, meshtastic_TelemetrySensorType_OPT3001); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::MLX90632, meshtastic_TelemetrySensorType_MLX90632); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::MLX90614, meshtastic_TelemetrySensorType_MLX90614); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::SHT4X, meshtastic_TelemetrySensorType_SHT4X); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::AHT10, meshtastic_TelemetrySensorType_AHT10); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::DFROBOT_LARK, meshtastic_TelemetrySensorType_DFROBOT_LARK); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::ICM20948, meshtastic_TelemetrySensorType_ICM20948); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::MAX30102, meshtastic_TelemetrySensorType_MAX30102); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::CGRADSENS, meshtastic_TelemetrySensorType_RADSENS); i2cScanner.reset(); #endif @@ -724,12 +716,16 @@ void setup() pinMode(LORA_CS, OUTPUT); digitalWrite(LORA_CS, HIGH); SPI1.begin(false); -#else // HW_SPI1_DEVICE +#else // HW_SPI1_DEVICE SPI.setSCK(LORA_SCK); SPI.setTX(LORA_MOSI); SPI.setRX(LORA_MISO); SPI.begin(false); -#endif // HW_SPI1_DEVICE +#endif // HW_SPI1_DEVICE +#elif ARCH_PORTDUINO + if (settingsStrings[spidev] != "ch341") { + SPI.begin(); + } #elif !defined(ARCH_ESP32) // ARCH_RP2040 SPI.begin(); #else @@ -835,8 +831,11 @@ void setup() if (settingsMap[use_sx1262]) { if (!rIf) { LOG_DEBUG("Activate sx1262 radio on SPI port %s", settingsStrings[spidev].c_str()); - LockingArduinoHal *RadioLibHAL = - new LockingArduinoHal(SPI, spiSettings, (settingsMap[ch341Quirk] ? settingsMap[busy] : RADIOLIB_NC)); + if (settingsStrings[spidev] == "ch341") { + RadioLibHAL = ch341Hal; + } else { + RadioLibHAL = new LockingArduinoHal(SPI, spiSettings); + } rIf = new SX1262Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset], settingsMap[busy]); if (!rIf->init()) { @@ -850,8 +849,7 @@ void setup() } else if (settingsMap[use_rf95]) { if (!rIf) { LOG_DEBUG("Activate rf95 radio on SPI port %s", settingsStrings[spidev].c_str()); - LockingArduinoHal *RadioLibHAL = - new LockingArduinoHal(SPI, spiSettings, (settingsMap[ch341Quirk] ? settingsMap[busy] : RADIOLIB_NC)); + RadioLibHAL = new LockingArduinoHal(SPI, spiSettings); rIf = new RF95Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset], settingsMap[busy]); if (!rIf->init()) { @@ -866,7 +864,7 @@ void setup() } else if (settingsMap[use_sx1280]) { if (!rIf) { LOG_DEBUG("Activate sx1280 radio on SPI port %s", settingsStrings[spidev].c_str()); - LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI, spiSettings); + RadioLibHAL = new LockingArduinoHal(SPI, spiSettings); rIf = new SX1280Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset], settingsMap[busy]); if (!rIf->init()) { @@ -878,10 +876,55 @@ void setup() LOG_INFO("SX1280 init success"); } } + } else if (settingsMap[use_lr1110]) { + if (!rIf) { + LOG_DEBUG("Activate lr1110 radio on SPI port %s", settingsStrings[spidev].c_str()); + LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI, spiSettings); + rIf = new LR1110Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset], + settingsMap[busy]); + if (!rIf->init()) { + LOG_WARN("No LR1110 radio"); + delete rIf; + rIf = NULL; + exit(EXIT_FAILURE); + } else { + LOG_INFO("LR1110 init success"); + } + } + } else if (settingsMap[use_lr1120]) { + if (!rIf) { + LOG_DEBUG("Activate lr1120 radio on SPI port %s", settingsStrings[spidev].c_str()); + LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI, spiSettings); + rIf = new LR1120Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset], + settingsMap[busy]); + if (!rIf->init()) { + LOG_WARN("No LR1120 radio"); + delete rIf; + rIf = NULL; + exit(EXIT_FAILURE); + } else { + LOG_INFO("LR1120 init success"); + } + } + } else if (settingsMap[use_lr1121]) { + if (!rIf) { + LOG_DEBUG("Activate lr1121 radio on SPI port %s", settingsStrings[spidev].c_str()); + LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI, spiSettings); + rIf = new LR1121Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset], + settingsMap[busy]); + if (!rIf->init()) { + LOG_WARN("No LR1121 radio"); + delete rIf; + rIf = NULL; + exit(EXIT_FAILURE); + } else { + LOG_INFO("LR1121 init success"); + } + } } else if (settingsMap[use_sx1268]) { if (!rIf) { LOG_DEBUG("Activate sx1268 radio on SPI port %s", settingsStrings[spidev].c_str()); - LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI, spiSettings); + RadioLibHAL = new LockingArduinoHal(SPI, spiSettings); rIf = new SX1268Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset], settingsMap[busy]); if (!rIf->init()) { @@ -916,7 +959,7 @@ void setup() } #endif -#if !HAS_RADIO && defined(ARCH_PORTDUINO) +#if defined(ARCH_PORTDUINO) if (!rIf) { rIf = new SimRadio; if (!rIf->init()) { @@ -1195,6 +1238,19 @@ extern meshtastic_DeviceMetadata getDeviceMetadata() #endif return deviceMetadata; } + +#if !MESHTASTIC_EXCLUDE_I2C +void scannerToSensorsMap(const std::unique_ptr &i2cScanner, ScanI2C::DeviceType deviceType, + meshtastic_TelemetrySensorType sensorType) +{ + auto found = i2cScanner->find(deviceType); + if (found.type != ScanI2C::DeviceType::NONE) { + nodeTelemetrySensorsMap[sensorType].first = found.address.address; + nodeTelemetrySensorsMap[sensorType].second = i2cScanner->fetchI2CBus(found.address); + } +} +#endif + #ifndef PIO_UNIT_TESTING void loop() { @@ -1225,4 +1281,4 @@ void loop() mainDelay.delay(delayMsec); } } -#endif \ No newline at end of file +#endif diff --git a/src/main.h b/src/main.h index 5722f7cf0..b3f58ae4b 100644 --- a/src/main.h +++ b/src/main.h @@ -10,9 +10,6 @@ #include "mesh/generated/meshtastic/telemetry.pb.h" #include #include -#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) -#include -#endif #if defined(ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2) #include "nimble/NimbleBluetooth.h" extern NimbleBluetooth *nimbleBluetooth; @@ -21,6 +18,9 @@ extern NimbleBluetooth *nimbleBluetooth; #include "NRF52Bluetooth.h" extern NRF52Bluetooth *nrf52Bluetooth; #endif +#if !MESHTASTIC_EXCLUDE_I2C +#include "detect/ScanI2CTwoWire.h" +#endif #if ARCH_PORTDUINO extern HardwareSPI *DisplaySPI; @@ -39,10 +39,6 @@ extern bool pmu_found; extern bool isCharging; extern bool isUSBPowered; -#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) -extern ATECCX08A atecc; -#endif - #ifdef T_WATCH_S3 #include extern Adafruit_DRV2605 drv; @@ -84,6 +80,10 @@ extern bool pauseBluetoothLogging; void nrf52Setup(), esp32Setup(), nrf52Loop(), esp32Loop(), rp2040Setup(), clearBonds(), enterDfuMode(); meshtastic_DeviceMetadata getDeviceMetadata(); +#if !MESHTASTIC_EXCLUDE_I2C +void scannerToSensorsMap(const std::unique_ptr &i2cScanner, ScanI2C::DeviceType deviceType, + meshtastic_TelemetrySensorType sensorType); +#endif // We default to 4MHz SPI, SPI mode 0 extern SPISettings spiSettings; \ No newline at end of file diff --git a/src/mesh/Channels.cpp b/src/mesh/Channels.cpp index a516268eb..4bc91ce4e 100644 --- a/src/mesh/Channels.cpp +++ b/src/mesh/Channels.cpp @@ -1,5 +1,5 @@ #include "Channels.h" -#include "../userPrefs.h" + #include "CryptoEngine.h" #include "Default.h" #include "DisplayFormatters.h" @@ -178,12 +178,11 @@ CryptoKey Channels::getKey(ChannelIndex chIndex) { meshtastic_Channel &ch = getByIndex(chIndex); const meshtastic_ChannelSettings &channelSettings = ch.settings; - assert(ch.has_settings); CryptoKey k; memset(k.bytes, 0, sizeof(k.bytes)); // In case the user provided a short key, we want to pad the rest with zeros - if (ch.role == meshtastic_Channel_Role_DISABLED) { + if (!ch.has_settings || ch.role == meshtastic_Channel_Role_DISABLED) { k.length = -1; // invalid } else { memcpy(k.bytes, channelSettings.psk.bytes, channelSettings.psk.size); @@ -319,7 +318,7 @@ bool Channels::anyMqttEnabled() { #if USERPREFS_EVENT_MODE // Don't publish messages on the public MQTT broker if we are in event mode - if (strcmp(moduleConfig.mqtt.address, default_mqtt_address) == 0) { + if (mqtt && mqtt.isUsingDefaultServer()) { return false; } #endif diff --git a/src/mesh/CryptoEngine.cpp b/src/mesh/CryptoEngine.cpp index 94b9b6543..1624ab0d5 100644 --- a/src/mesh/CryptoEngine.cpp +++ b/src/mesh/CryptoEngine.cpp @@ -58,10 +58,16 @@ void CryptoEngine::clearKeys() * Encrypt a packet's payload using a key generated with Curve25519 and SHA256 * for a specific node. * - * @param bytes is updated in place + * @param toNode The MeshPacket `to` field. + * @param fromNode The MeshPacket `from` field. + * @param remotePublic The remote node's Curve25519 public key. + * @param packetId The MeshPacket `id` field. + * @param numBytes Number of bytes of plaintext in the bytes buffer. + * @param bytes Buffer containing plaintext input. + * @param bytesOut Output buffer to be populated with encrypted ciphertext. */ bool CryptoEngine::encryptCurve25519(uint32_t toNode, uint32_t fromNode, meshtastic_UserLite_public_key_t remotePublic, - uint64_t packetNum, size_t numBytes, uint8_t *bytes, uint8_t *bytesOut) + uint64_t packetNum, size_t numBytes, const uint8_t *bytes, uint8_t *bytesOut) { uint8_t *auth; long extraNonceTmp = random(); @@ -93,14 +99,18 @@ bool CryptoEngine::encryptCurve25519(uint32_t toNode, uint32_t fromNode, meshtas * Decrypt a packet's payload using a key generated with Curve25519 and SHA256 * for a specific node. * - * @param bytes is updated in place + * @param fromNode The MeshPacket `from` field. + * @param remotePublic The remote node's Curve25519 public key. + * @param packetId The MeshPacket `id` field. + * @param numBytes Number of bytes of ciphertext in the bytes buffer. + * @param bytes Buffer containing ciphertext input. + * @param bytesOut Output buffer to be populated with decrypted plaintext. */ bool CryptoEngine::decryptCurve25519(uint32_t fromNode, meshtastic_UserLite_public_key_t remotePublic, uint64_t packetNum, - size_t numBytes, uint8_t *bytes, uint8_t *bytesOut) + size_t numBytes, const uint8_t *bytes, uint8_t *bytesOut) { - uint8_t *auth; // set to last 8 bytes of text? - uint32_t extraNonce; // pointer was not really used - auth = bytes + numBytes - 12; + const uint8_t *auth = bytes + numBytes - 12; // set to last 8 bytes of text? + uint32_t extraNonce; // pointer was not really used memcpy(&extraNonce, auth + 8, sizeof(uint32_t)); // do not use dereference on potential non aligned pointers : (uint32_t *)(auth + 8); LOG_INFO("Random nonce value: %d", extraNonce); diff --git a/src/mesh/CryptoEngine.h b/src/mesh/CryptoEngine.h index 32862d95c..6bbcb3b8a 100644 --- a/src/mesh/CryptoEngine.h +++ b/src/mesh/CryptoEngine.h @@ -40,9 +40,9 @@ class CryptoEngine void clearKeys(); void setDHPrivateKey(uint8_t *_private_key); virtual bool encryptCurve25519(uint32_t toNode, uint32_t fromNode, meshtastic_UserLite_public_key_t remotePublic, - uint64_t packetNum, size_t numBytes, uint8_t *bytes, uint8_t *bytesOut); + uint64_t packetNum, size_t numBytes, const uint8_t *bytes, uint8_t *bytesOut); virtual bool decryptCurve25519(uint32_t fromNode, meshtastic_UserLite_public_key_t remotePublic, uint64_t packetNum, - size_t numBytes, uint8_t *bytes, uint8_t *bytesOut); + size_t numBytes, const uint8_t *bytes, uint8_t *bytesOut); virtual bool setDHPublicKey(uint8_t *publicKey); virtual void hash(uint8_t *bytes, size_t numBytes); diff --git a/src/mesh/Default.cpp b/src/mesh/Default.cpp index ba1dafe70..1bd0340f8 100644 --- a/src/mesh/Default.cpp +++ b/src/mesh/Default.cpp @@ -1,5 +1,5 @@ #include "Default.h" -#include "../userPrefs.h" + #include "meshUtils.h" uint32_t Default::getConfiguredOrDefaultMs(uint32_t configuredInterval, uint32_t defaultInterval) diff --git a/src/mesh/FloodingRouter.cpp b/src/mesh/FloodingRouter.cpp index 81ea72381..f94540905 100644 --- a/src/mesh/FloodingRouter.cpp +++ b/src/mesh/FloodingRouter.cpp @@ -1,5 +1,5 @@ #include "FloodingRouter.h" -#include "../userPrefs.h" + #include "configuration.h" #include "mesh-pb-constants.h" @@ -24,11 +24,15 @@ bool FloodingRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) printPacket("Ignore dupe incoming msg", p); rxDupe++; if (config.device.role != meshtastic_Config_DeviceConfig_Role_ROUTER && - config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER) { + config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER && + config.device.role != meshtastic_Config_DeviceConfig_Role_ROUTER_LATE) { // cancel rebroadcast of this message *if* there was already one, unless we're a router/repeater! if (Router::cancelSending(p->from, p->id)) txRelayCanceled++; } + if (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER_LATE && iface) { + iface->clampToLateRebroadcastWindow(getFrom(p), p->id); + } /* If the original transmitter is doing retransmissions (hopStart equals hopLimit) for a reliable transmission, e.g., when the ACK got lost, we will handle the packet again to make sure it gets an ACK to its packet. */ @@ -36,7 +40,8 @@ bool FloodingRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) if (isRepeated) { LOG_DEBUG("Repeated reliable tx"); if (!perhapsRebroadcast(p) && isToUs(p) && p->want_ack) { - sendAckNak(meshtastic_Routing_Error_NONE, getFrom(p), p->id, p->channel, 0); + // FIXME - channel index should be used, but the packet is still encrypted here + sendAckNak(meshtastic_Routing_Error_NONE, getFrom(p), p->id, 0, 0); } } diff --git a/src/mesh/LR11x0Interface.cpp b/src/mesh/LR11x0Interface.cpp index 30ef8f9af..ce4f912ba 100644 --- a/src/mesh/LR11x0Interface.cpp +++ b/src/mesh/LR11x0Interface.cpp @@ -48,8 +48,10 @@ template bool LR11x0Interface::init() digitalWrite(LR11X0_POWER_EN, HIGH); #endif +#if ARCH_PORTDUINO + float tcxoVoltage = (float)settingsMap[dio3_tcxo_voltage] / 1000; // FIXME: correct logic to default to not using TCXO if no voltage is specified for LR11x0_DIO3_TCXO_VOLTAGE -#if !defined(LR11X0_DIO3_TCXO_VOLTAGE) +#elif !defined(LR11X0_DIO3_TCXO_VOLTAGE) float tcxoVoltage = 0; // "TCXO reference voltage to be set on DIO3. Defaults to 1.6 V, set to 0 to skip." per // https://github.com/jgromes/RadioLib/blob/690a050ebb46e6097c5d00c371e961c1caa3b52e/src/modules/LR11x0/LR11x0.h#L471C26-L471C104 diff --git a/src/mesh/MemoryPool.h b/src/mesh/MemoryPool.h index d30404b9f..c4af3c4ac 100644 --- a/src/mesh/MemoryPool.h +++ b/src/mesh/MemoryPool.h @@ -2,6 +2,8 @@ #include #include +#include +#include #include "PointerQueue.h" @@ -9,6 +11,7 @@ template class Allocator { public: + Allocator() : deleter([this](T *p) { this->release(p); }) {} virtual ~Allocator() {} /// Return a queable object which has been prefilled with zeros. Panic if no buffer is available @@ -43,12 +46,32 @@ template class Allocator return p; } + /// Variations of the above methods that return std::unique_ptr instead of raw pointers. + using UniqueAllocation = std::unique_ptr &>; + /// Return a queable object which has been prefilled with zeros. + /// std::unique_ptr wrapped variant of allocZeroed(). + UniqueAllocation allocUniqueZeroed() { return UniqueAllocation(allocZeroed(), deleter); } + /// Return a queable object which has been prefilled with zeros - allow timeout to wait for available buffers (you probably + /// don't want this version). + /// std::unique_ptr wrapped variant of allocZeroed(TickType_t maxWait). + UniqueAllocation allocUniqueZeroed(TickType_t maxWait) { return UniqueAllocation(allocZeroed(maxWait), deleter); } + /// Return a queable object which is a copy of some other object + /// std::unique_ptr wrapped variant of allocCopy(const T &src, TickType_t maxWait). + UniqueAllocation allocUniqueCopy(const T &src, TickType_t maxWait = portMAX_DELAY) + { + return UniqueAllocation(allocCopy(src, maxWait), deleter); + } + /// Return a buffer for use by others virtual void release(T *p) = 0; protected: // Alloc some storage virtual T *alloc(TickType_t maxWait) = 0; + + private: + // std::unique_ptr Deleter function; calls release(). + const std::function deleter; }; /** diff --git a/src/mesh/MeshPacketQueue.cpp b/src/mesh/MeshPacketQueue.cpp index 99ef41c1e..d7ee65800 100644 --- a/src/mesh/MeshPacketQueue.cpp +++ b/src/mesh/MeshPacketQueue.cpp @@ -16,6 +16,12 @@ inline uint32_t getPriority(const meshtastic_MeshPacket *p) bool CompareMeshPacketFunc(const meshtastic_MeshPacket *p1, const meshtastic_MeshPacket *p2) { assert(p1 && p2); + + // If one packet is in the late transmit window, prefer the other one + if ((bool)p1->tx_after != (bool)p2->tx_after) { + return !p1->tx_after; + } + auto p1p = getPriority(p1), p2p = getPriority(p2); // If priorities differ, use that // for equal priorities, prefer packets already on mesh. @@ -94,11 +100,11 @@ meshtastic_MeshPacket *MeshPacketQueue::getFront() } /** Attempt to find and remove a packet from this queue. Returns a pointer to the removed packet, or NULL if not found */ -meshtastic_MeshPacket *MeshPacketQueue::remove(NodeNum from, PacketId id) +meshtastic_MeshPacket *MeshPacketQueue::remove(NodeNum from, PacketId id, bool tx_normal, bool tx_late) { for (auto it = queue.begin(); it != queue.end(); it++) { auto p = (*it); - if (getFrom(p) == from && p->id == id) { + if (getFrom(p) == from && p->id == id && ((tx_normal && !p->tx_after) || (tx_late && p->tx_after))) { queue.erase(it); return p; } @@ -114,9 +120,10 @@ bool MeshPacketQueue::replaceLowerPriorityPacket(meshtastic_MeshPacket *p) if (queue.empty()) { return false; // No packets to replace } + // Check if the packet at the back has a lower priority than the new packet auto &backPacket = queue.back(); - if (backPacket->priority < p->priority) { + if (!backPacket->tx_after && backPacket->priority < p->priority) { // Remove the back packet packetPool.release(backPacket); queue.pop_back(); @@ -125,6 +132,19 @@ bool MeshPacketQueue::replaceLowerPriorityPacket(meshtastic_MeshPacket *p) return true; } + if (backPacket->tx_after) { + // Check if there's a non-late packet with lower priority + auto it = queue.end(); + auto refPacket = *--it; + for (; refPacket->tx_after && it != queue.begin(); refPacket = *--it) + ; + if (!refPacket->tx_after && refPacket->priority < p->priority) { + packetPool.release(refPacket); + enqueue(refPacket); + return true; + } + } + // If the back packet's priority is not lower, no replacement occurs return false; } \ No newline at end of file diff --git a/src/mesh/MeshPacketQueue.h b/src/mesh/MeshPacketQueue.h index 3c28fc5ce..b41a214b9 100644 --- a/src/mesh/MeshPacketQueue.h +++ b/src/mesh/MeshPacketQueue.h @@ -36,5 +36,5 @@ class MeshPacketQueue meshtastic_MeshPacket *getFront(); /** Attempt to find and remove a packet from this queue. Returns the packet which was removed from the queue */ - meshtastic_MeshPacket *remove(NodeNum from, PacketId id); -}; + meshtastic_MeshPacket *remove(NodeNum from, PacketId id, bool tx_normal = true, bool tx_late = true); +}; \ No newline at end of file diff --git a/src/mesh/MeshService.cpp b/src/mesh/MeshService.cpp index 50a13da6a..773ab7053 100644 --- a/src/mesh/MeshService.cpp +++ b/src/mesh/MeshService.cpp @@ -166,27 +166,10 @@ NodeNum MeshService::getNodenumFromRequestId(uint32_t request_id) */ void MeshService::handleToRadio(meshtastic_MeshPacket &p) { -#if defined(ARCH_PORTDUINO) && !HAS_RADIO - // Simulates device received a packet via the LoRa chip - if (p.decoded.portnum == meshtastic_PortNum_SIMULATOR_APP) { - // Simulator packet (=Compressed packet) is encapsulated in a MeshPacket, so need to unwrap first - meshtastic_Compressed scratch; - meshtastic_Compressed *decoded = NULL; - if (p.which_payload_variant == meshtastic_MeshPacket_decoded_tag) { - memset(&scratch, 0, sizeof(scratch)); - p.decoded.payload.size = - pb_decode_from_bytes(p.decoded.payload.bytes, p.decoded.payload.size, &meshtastic_Compressed_msg, &scratch); - if (p.decoded.payload.size) { - decoded = &scratch; - // Extract the original payload and replace - memcpy(&p.decoded.payload, &decoded->data, sizeof(decoded->data)); - // Switch the port from PortNum_SIMULATOR_APP back to the original PortNum - p.decoded.portnum = decoded->portnum; - } else - LOG_ERROR("Error decoding proto for simulator message!"); - } - // Let SimRadio receive as if it did via its LoRa chip - SimRadio::instance->startReceive(&p); +#if defined(ARCH_PORTDUINO) + if (SimRadio::instance && p.decoded.portnum == meshtastic_PortNum_SIMULATOR_APP) { + // Simulates device received a packet via the LoRa chip + SimRadio::instance->unpackAndReceive(p); return; } #endif @@ -271,7 +254,7 @@ bool MeshService::trySendPosition(NodeNum dest, bool wantReplies) assert(node); - if (hasValidPosition(node)) { + if (nodeDB->hasValidPosition(node)) { #if HAS_GPS && !MESHTASTIC_EXCLUDE_GPS if (positionModule) { LOG_INFO("Send position ping to 0x%x, wantReplies=%d, channel=%d", dest, wantReplies, node->channel); diff --git a/src/mesh/MeshService.h b/src/mesh/MeshService.h index 1ccca4e6d..268c4308f 100644 --- a/src/mesh/MeshService.h +++ b/src/mesh/MeshService.h @@ -10,7 +10,7 @@ #include "MeshTypes.h" #include "Observer.h" #include "PointerQueue.h" -#if defined(ARCH_PORTDUINO) && !HAS_RADIO +#if defined(ARCH_PORTDUINO) #include "../platform/portduino/SimRadio.h" #endif #if defined(ARCH_ESP32) || defined(ARCH_PORTDUINO) @@ -165,4 +165,4 @@ class MeshService friend class RoutingModule; }; -extern MeshService *service; +extern MeshService *service; \ No newline at end of file diff --git a/src/mesh/MeshTypes.h b/src/mesh/MeshTypes.h index cf1b54c78..1d6bd342d 100644 --- a/src/mesh/MeshTypes.h +++ b/src/mesh/MeshTypes.h @@ -44,6 +44,7 @@ typedef int ErrorCode; /// Alloc and free packets to our global, ISR safe pool extern Allocator &packetPool; +using UniquePacketPoolPacket = Allocator::UniqueAllocation; /** * Most (but not always) of the time we want to treat packets 'from' the local phone (where from == 0), as if they originated on diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 44a28eea2..9dbe92b7c 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -1,4 +1,3 @@ -#include "../userPrefs.h" #include "configuration.h" #if !MESHTASTIC_EXCLUDE_GPS #include "GPS.h" @@ -58,6 +57,7 @@ NodeDB *nodeDB = nullptr; EXT_RAM_BSS_ATTR meshtastic_DeviceState devicestate; meshtastic_MyNodeInfo &myNodeInfo = devicestate.my_node; meshtastic_LocalConfig config; +meshtastic_DeviceUIConfig uiconfig{.screen_brightness = 153, .screen_timeout = 30}; meshtastic_LocalModuleConfig moduleConfig; meshtastic_ChannelFile channelFile; @@ -71,6 +71,78 @@ static unsigned char userprefs_admin_key_1[] = USERPREFS_USE_ADMIN_KEY_1; static unsigned char userprefs_admin_key_2[] = USERPREFS_USE_ADMIN_KEY_2; #endif +#ifdef HELTEC_MESH_NODE_T114 + +uint32_t read8(uint8_t bits, uint8_t dummy, uint8_t cs, uint8_t sck, uint8_t mosi, uint8_t dc, uint8_t rst) +{ + uint32_t ret = 0; + uint8_t SDAPIN = mosi; + pinMode(SDAPIN, INPUT_PULLUP); + digitalWrite(dc, HIGH); + for (int i = 0; i < dummy; i++) { // any dummy clocks + digitalWrite(sck, HIGH); + delay(1); + digitalWrite(sck, LOW); + delay(1); + } + for (int i = 0; i < bits; i++) { // read results + ret <<= 1; + delay(1); + if (digitalRead(SDAPIN)) + ret |= 1; + ; + digitalWrite(sck, HIGH); + delay(1); + digitalWrite(sck, LOW); + } + return ret; +} + +void write9(uint8_t val, uint8_t dc_val, uint8_t cs, uint8_t sck, uint8_t mosi, uint8_t dc, uint8_t rst) +{ + pinMode(mosi, OUTPUT); + digitalWrite(dc, dc_val); + for (int i = 0; i < 8; i++) { // send command + digitalWrite(mosi, (val & 0x80) != 0); + delay(1); + digitalWrite(sck, HIGH); + delay(1); + digitalWrite(sck, LOW); + val <<= 1; + } +} + +uint32_t readwrite8(uint8_t cmd, uint8_t bits, uint8_t dummy, uint8_t cs, uint8_t sck, uint8_t mosi, uint8_t dc, uint8_t rst) +{ + digitalWrite(cs, LOW); + write9(cmd, 0, cs, sck, mosi, dc, rst); + uint32_t ret = read8(bits, dummy, cs, sck, mosi, dc, rst); + digitalWrite(cs, HIGH); + return ret; +} + +uint32_t get_st7789_id(uint8_t cs, uint8_t sck, uint8_t mosi, uint8_t dc, uint8_t rst) +{ + pinMode(cs, OUTPUT); + digitalWrite(cs, HIGH); + pinMode(cs, OUTPUT); + pinMode(sck, OUTPUT); + pinMode(mosi, OUTPUT); + pinMode(dc, OUTPUT); + pinMode(rst, OUTPUT); + digitalWrite(rst, LOW); // Hardware Reset + delay(10); + digitalWrite(rst, HIGH); + delay(10); + + uint32_t ID = 0; + ID = readwrite8(0x04, 24, 1, cs, sck, mosi, dc, rst); + ID = readwrite8(0x04, 24, 1, cs, sck, mosi, dc, rst); // ST7789 needs twice + return ID; +} + +#endif + bool meshtastic_DeviceState_callback(pb_istream_t *istream, pb_ostream_t *ostream, const pb_field_iter_t *field) { if (ostream) { @@ -465,7 +537,7 @@ void NodeDB::installDefaultConfig(bool preserveKey = false) #endif #if defined(USERPREFS_CONFIG_GPS_MODE) config.position.gps_mode = USERPREFS_CONFIG_GPS_MODE; -#elif !HAS_GPS || defined(T_DECK) || defined(TLORA_T3S3_EPAPER) +#elif !HAS_GPS || GPS_DEFAULT_NOT_PRESENT config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_NOT_PRESENT; #elif !defined(GPS_RX_PIN) if (config.position.rx_gpio == 0) @@ -490,6 +562,12 @@ void NodeDB::installDefaultConfig(bool preserveKey = false) #if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7789_CS) || \ defined(HX8357_CS) || defined(USE_ST7789) bool hasScreen = true; +#ifdef HELTEC_MESH_NODE_T114 + uint32_t st7789_id = get_st7789_id(ST7789_NSS, ST7789_SCK, ST7789_SDA, ST7789_RS, ST7789_RESET); + if (st7789_id == 0xFFFFFF) { + hasScreen = false; + } +#endif #elif ARCH_PORTDUINO bool hasScreen = false; if (settingsMap[displayPanel]) @@ -542,7 +620,7 @@ void NodeDB::initConfigIntervals() config.display.screen_on_secs = default_screen_on_secs; -#if defined(T_WATCH_S3) || defined(T_DECK) || defined(RAK14014) || defined(SENSECAP_INDICATOR) +#if defined(T_WATCH_S3) || defined(T_DECK) || defined(MESH_TAB) || defined(RAK14014) config.power.is_power_saving = true; config.display.screen_on_secs = 30; config.power.wait_bluetooth_secs = 30; @@ -775,12 +853,12 @@ void NodeDB::installDefaultDeviceState() #ifdef USERPREFS_CONFIG_OWNER_LONG_NAME snprintf(owner.long_name, sizeof(owner.long_name), USERPREFS_CONFIG_OWNER_LONG_NAME); #else - snprintf(owner.long_name, sizeof(owner.long_name), "Meshtastic %02x%02x", ourMacAddr[4], ourMacAddr[5]); + snprintf(owner.long_name, sizeof(owner.long_name), "Meshtastic %04x", getNodeNum() & 0x0ffff); #endif #ifdef USERPREFS_CONFIG_OWNER_SHORT_NAME snprintf(owner.short_name, sizeof(owner.short_name), USERPREFS_CONFIG_OWNER_SHORT_NAME); #else - snprintf(owner.short_name, sizeof(owner.short_name), "%02x%02x", ourMacAddr[4], ourMacAddr[5]); + snprintf(owner.short_name, sizeof(owner.short_name), "%04x", getNodeNum() & 0x0ffff); #endif snprintf(owner.id, sizeof(owner.id), "!%08x", getNodeNum()); // Default node ID now based on nodenum memcpy(owner.macaddr, ourMacAddr, sizeof(owner.macaddr)); @@ -818,6 +896,7 @@ void NodeDB::pickNewNodeNum() static const char *prefFileName = "/prefs/db.proto"; static const char *configFileName = "/prefs/config.proto"; +static const char *uiconfigFileName = "/prefs/uiconfig.proto"; static const char *moduleConfigFileName = "/prefs/module.proto"; static const char *channelFileName = "/prefs/channels.proto"; @@ -977,6 +1056,12 @@ void NodeDB::loadFromDisk() } } + state = loadProto(uiconfigFileName, meshtastic_DeviceUIConfig_size, sizeof(meshtastic_DeviceUIConfig), + &meshtastic_DeviceUIConfig_msg, &uiconfig); + if (state == LoadFileResult::LOAD_SUCCESS) { + LOG_INFO("Loaded UIConfig"); + } + // 2.4.X - configuration migration to update new default intervals if (moduleConfig.version < 23) { LOG_DEBUG("ModuleConfig version %d is stale, upgrading to new default intervals", moduleConfig.version); @@ -1243,7 +1328,6 @@ bool NodeDB::updateUser(uint32_t nodeId, meshtastic_User &p, uint8_t channelInde return false; } - LOG_DEBUG("old user %s/%s, channel=%d", info->user.long_name, info->user.short_name, info->channel); #if !(MESHTASTIC_EXCLUDE_PKI) if (p.public_key.size > 0) { printBytes("Incoming Pubkey: ", p.public_key.bytes, 32); @@ -1267,7 +1351,8 @@ bool NodeDB::updateUser(uint32_t nodeId, meshtastic_User &p, uint8_t channelInde } if (nodeId != getNodeNum()) info->channel = channelIndex; // Set channel we need to use to reach this node (but don't set our own channel) - LOG_DEBUG("Update changed=%d user %s/%s, channel=%d", changed, info->user.long_name, info->user.short_name, info->channel); + LOG_DEBUG("Update changed=%d user %s/%s, id=0x%08x, channel=%d", changed, info->user.long_name, info->user.short_name, nodeId, + info->channel); info->has_user = true; if (changed) { @@ -1275,10 +1360,14 @@ bool NodeDB::updateUser(uint32_t nodeId, meshtastic_User &p, uint8_t channelInde powerFSM.trigger(EVENT_NODEDB_UPDATED); notifyObservers(true); // Force an update whether or not our node counts have changed - // We just changed something about the user, store our DB - Throttle::execute( - &lastNodeDbSave, ONE_MINUTE_MS, []() { nodeDB->saveToDisk(SEGMENT_DEVICESTATE); }, - []() { LOG_DEBUG("Defer NodeDB saveToDisk for now"); }); // since we saved less than a minute ago + // We just changed something about a User, + // store our DB unless we just did so less than a minute ago + if (!Throttle::isWithinTimespanMs(lastNodeDbSave, ONE_MINUTE_MS)) { + saveToDisk(SEGMENT_DEVICESTATE); + lastNodeDbSave = millis(); + } else { + LOG_DEBUG("Defer NodeDB saveToDisk for now"); + } } return changed; @@ -1345,7 +1434,7 @@ meshtastic_NodeInfoLite *NodeDB::getOrCreateMeshNode(NodeNum n) if (!lite) { if (isFull()) { - LOG_INFO("Node database full with %i nodes and %i bytes free. Erasing oldest entry", numMeshNodes, + LOG_INFO("Node database full with %i nodes and %u bytes free. Erasing oldest entry", numMeshNodes, memGet.getFreeHeap()); // look for oldest node and erase it uint32_t oldest = UINT32_MAX; @@ -1369,11 +1458,14 @@ meshtastic_NodeInfoLite *NodeDB::getOrCreateMeshNode(NodeNum n) if (oldestBoringIndex != -1) { oldestIndex = oldestBoringIndex; } - // Shove the remaining nodes down the chain - for (int i = oldestIndex; i < numMeshNodes - 1; i++) { - meshNodes->at(i) = meshNodes->at(i + 1); + + if (oldestIndex != -1) { + // Shove the remaining nodes down the chain + for (int i = oldestIndex; i < numMeshNodes - 1; i++) { + meshNodes->at(i) = meshNodes->at(i + 1); + } + (numMeshNodes)--; } - (numMeshNodes)--; } // add the node at the end lite = &meshNodes->at((numMeshNodes)++); @@ -1381,12 +1473,19 @@ meshtastic_NodeInfoLite *NodeDB::getOrCreateMeshNode(NodeNum n) // everything is missing except the nodenum memset(lite, 0, sizeof(*lite)); lite->num = n; - LOG_INFO("Adding node to database with %i nodes and %i bytes free!", numMeshNodes, memGet.getFreeHeap()); + LOG_INFO("Adding node to database with %i nodes and %u bytes free!", numMeshNodes, memGet.getFreeHeap()); } return lite; } +/// Sometimes we will have Position objects that only have a time, so check for +/// valid lat/lon +bool NodeDB::hasValidPosition(const meshtastic_NodeInfoLite *n) +{ + return n->has_position && (n->position.latitude_i != 0 || n->position.longitude_i != 0); +} + /// Record an error that should be reported via analytics void recordCriticalError(meshtastic_CriticalErrorCode code, uint32_t address, const char *filename) { @@ -1409,4 +1508,4 @@ void recordCriticalError(meshtastic_CriticalErrorCode code, uint32_t address, co LOG_ERROR("A critical failure occurred, portduino is exiting"); exit(2); #endif -} \ No newline at end of file +} diff --git a/src/mesh/NodeDB.h b/src/mesh/NodeDB.h index 2f9980f14..c8c0d3170 100644 --- a/src/mesh/NodeDB.h +++ b/src/mesh/NodeDB.h @@ -29,6 +29,7 @@ extern meshtastic_DeviceState devicestate; extern meshtastic_ChannelFile channelFile; extern meshtastic_MyNodeInfo &myNodeInfo; extern meshtastic_LocalConfig config; +extern meshtastic_DeviceUIConfig uiconfig; extern meshtastic_LocalModuleConfig moduleConfig; extern meshtastic_User &owner; extern meshtastic_Position localPosition; @@ -165,6 +166,8 @@ class NodeDB localPosition = position; } + bool hasValidPosition(const meshtastic_NodeInfoLite *n); + private: uint32_t lastNodeDbSave = 0; // when we last saved our db to flash /// Find a node in our DB, create an empty NodeInfoLite if missing @@ -217,13 +220,6 @@ extern NodeDB *nodeDB; prefs.is_power_saving = True */ -/// Sometimes we will have Position objects that only have a time, so check for -/// valid lat/lon -static inline bool hasValidPosition(const meshtastic_NodeInfoLite *n) -{ - return n->has_position && (n->position.latitude_i != 0 || n->position.longitude_i != 0); -} - /** The current change # for radio settings. Starts at 0 on boot and any time the radio settings * might have changed is incremented. Allows others to detect they might now be on a new channel. */ diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp index 20421e73e..8c1ba74c7 100644 --- a/src/mesh/PhoneAPI.cpp +++ b/src/mesh/PhoneAPI.cpp @@ -164,6 +164,7 @@ bool PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength) * * Our sending states progress in the following sequence (the client apps ASSUME THIS SEQUENCE, DO NOT CHANGE IT): STATE_SEND_MY_INFO, // send our my info record + STATE_SEND_UIDATA, STATE_SEND_OWN_NODEINFO, STATE_SEND_METADATA, STATE_SEND_CHANNELS @@ -188,7 +189,6 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf) case STATE_SEND_NOTHING: LOG_DEBUG("FromRadio=STATE_SEND_NOTHING"); break; - case STATE_SEND_MY_INFO: LOG_DEBUG("FromRadio=STATE_SEND_MY_INFO"); // If the user has specified they don't want our node to share its location, make sure to tell the phone @@ -196,11 +196,18 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf) fromRadioScratch.which_payload_variant = meshtastic_FromRadio_my_info_tag; strncpy(myNodeInfo.pio_env, optstr(APP_ENV), sizeof(myNodeInfo.pio_env)); fromRadioScratch.my_info = myNodeInfo; - state = STATE_SEND_OWN_NODEINFO; + state = STATE_SEND_UIDATA; service->refreshLocalMeshNode(); // Update my NodeInfo because the client will be asking for it soon. break; + case STATE_SEND_UIDATA: + LOG_INFO("getFromRadio=STATE_SEND_UIDATA"); + fromRadioScratch.which_payload_variant = meshtastic_FromRadio_deviceuiConfig_tag; + fromRadioScratch.deviceuiConfig = uiconfig; + state = STATE_SEND_OWN_NODEINFO; + break; + case STATE_SEND_OWN_NODEINFO: { LOG_DEBUG("Send My NodeInfo"); auto us = nodeDB->readNextMeshNode(readIndex); @@ -284,6 +291,9 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf) LOG_DEBUG("Send config: sessionkey"); fromRadioScratch.config.which_payload_variant = meshtastic_Config_sessionkey_tag; break; + case meshtastic_Config_device_ui_tag: // NOOP! + fromRadioScratch.config.which_payload_variant = meshtastic_Config_device_ui_tag; + break; default: LOG_ERROR("Unknown config type %d", config_state); } @@ -518,6 +528,7 @@ bool PhoneAPI::available() case STATE_SEND_NOTHING: return false; case STATE_SEND_MY_INFO: + case STATE_SEND_UIDATA: case STATE_SEND_CHANNELS: case STATE_SEND_CONFIG: case STATE_SEND_MODULECONFIG: @@ -613,13 +624,14 @@ bool PhoneAPI::handleToRadioPacket(meshtastic_MeshPacket &p) { printPacket("PACKET FROM PHONE", &p); -// For use with the simulator, we should not ignore duplicate packets -#if !(defined(ARCH_PORTDUINO) && !HAS_RADIO) - if (p.id > 0 && wasSeenRecently(p.id)) { - LOG_DEBUG("Ignore packet from phone, already seen recently"); - return false; - } +#if defined(ARCH_PORTDUINO) + // For use with the simulator, we should not ignore duplicate packets from the phone + if (SimRadio::instance == nullptr) #endif + if (p.id > 0 && wasSeenRecently(p.id)) { + LOG_DEBUG("Ignore packet from phone, already seen recently"); + return false; + } if (p.decoded.portnum == meshtastic_PortNum_TRACEROUTE_APP && lastPortNumToRadio[p.decoded.portnum] && Throttle::isWithinTimespanMs(lastPortNumToRadio[p.decoded.portnum], THIRTY_SECONDS_MS)) { diff --git a/src/mesh/PhoneAPI.h b/src/mesh/PhoneAPI.h index 3247fee5c..681b244c8 100644 --- a/src/mesh/PhoneAPI.h +++ b/src/mesh/PhoneAPI.h @@ -34,6 +34,7 @@ class PhoneAPI { enum State { STATE_SEND_NOTHING, // Initial state, don't send anything until the client starts asking for config + STATE_SEND_UIDATA, // send stored data for device-ui STATE_SEND_MY_INFO, // send our my info record STATE_SEND_OWN_NODEINFO, STATE_SEND_METADATA, @@ -148,6 +149,9 @@ class PhoneAPI */ virtual void onNowHasData(uint32_t fromRadioNum) {} + /// begin a new connection + void handleStartConfig(); + private: void releasePhonePacket(); @@ -157,9 +161,6 @@ class PhoneAPI void releaseClientNotification(); - /// begin a new connection - void handleStartConfig(); - bool wasSeenRecently(uint32_t packetId); /** @@ -170,4 +171,4 @@ class PhoneAPI /// If the mesh service tells us fromNum has changed, tell the phone virtual int onNotify(uint32_t newValue) override; -}; \ No newline at end of file +}; diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp index 53b66ff0a..b1403f3b6 100644 --- a/src/mesh/RadioInterface.cpp +++ b/src/mesh/RadioInterface.cpp @@ -254,8 +254,8 @@ uint32_t RadioInterface::getTxDelayMsec() return random(0, pow(2, CWsize)) * slotTimeMsec; } -/** The delay to use when we want to flood a message */ -uint32_t RadioInterface::getTxDelayMsecWeighted(float snr) +/** The CW size to use when calculating SNR_based delays */ +uint8_t RadioInterface::getCWsize(float snr) { // The minimum value for a LoRa SNR const uint32_t SNR_MIN = -20; @@ -263,10 +263,24 @@ uint32_t RadioInterface::getTxDelayMsecWeighted(float snr) // The maximum value for a LoRa SNR const uint32_t SNR_MAX = 15; + return map(snr, SNR_MIN, SNR_MAX, CWmin, CWmax); +} + +/** The worst-case SNR_based packet delay */ +uint32_t RadioInterface::getTxDelayMsecWeightedWorst(float snr) +{ + uint8_t CWsize = getCWsize(snr); + // offset the maximum delay for routers: (2 * CWmax * slotTimeMsec) + return (2 * CWmax * slotTimeMsec) + pow(2, CWsize) * slotTimeMsec; +} + +/** The delay to use when we want to flood a message */ +uint32_t RadioInterface::getTxDelayMsecWeighted(float snr) +{ // high SNR = large CW size (Long Delay) // low SNR = small CW size (Short Delay) uint32_t delay = 0; - uint8_t CWsize = map(snr, SNR_MIN, SNR_MAX, CWmin, CWmax); + uint8_t CWsize = getCWsize(snr); // LOG_DEBUG("rx_snr of %f so setting CWsize to:%d", snr, CWsize); if (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER || config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER) { @@ -284,8 +298,8 @@ uint32_t RadioInterface::getTxDelayMsecWeighted(float snr) void printPacket(const char *prefix, const meshtastic_MeshPacket *p) { #ifdef DEBUG_PORT - std::string out = DEBUG_PORT.mt_sprintf("%s (id=0x%08x fr=0x%02x to=0x%02x, WantAck=%d, HopLim=%d Ch=0x%x", prefix, p->id, - p->from & 0xff, p->to & 0xff, p->want_ack, p->hop_limit, p->channel); + std::string out = DEBUG_PORT.mt_sprintf("%s (id=0x%08x fr=0x%08x to=0x%08x, WantAck=%d, HopLim=%d Ch=0x%x", prefix, p->id, + p->from, p->to, p->want_ack, p->hop_limit, p->channel); if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) { auto &s = p->decoded; @@ -313,6 +327,7 @@ void printPacket(const char *prefix, const meshtastic_MeshPacket *p) out += DEBUG_PORT.mt_sprintf(" failId=%08x", s.ackVariant.fail_id); */ } else { out += " encrypted"; + out += DEBUG_PORT.mt_sprintf(" len=%d", p->encrypted.size + sizeof(PacketHeader)); } if (p->rx_time != 0) diff --git a/src/mesh/RadioInterface.h b/src/mesh/RadioInterface.h index 89a4c7087..652b2269c 100644 --- a/src/mesh/RadioInterface.h +++ b/src/mesh/RadioInterface.h @@ -173,9 +173,18 @@ class RadioInterface /** The delay to use when we want to send something */ uint32_t getTxDelayMsec(); + /** The CW to use when calculating SNR_based delays */ + uint8_t getCWsize(float snr); + + /** The worst-case SNR_based packet delay */ + uint32_t getTxDelayMsecWeightedWorst(float snr); + /** The delay to use when we want to flood a message. Use a weighted scale based on SNR */ uint32_t getTxDelayMsecWeighted(float snr); + /** If the packet is not already in the late rebroadcast window, move it there */ + virtual void clampToLateRebroadcastWindow(NodeNum from, PacketId id) { return; } + /** * Calculate airtime per * https://www.rs-online.com/designspark/rel-assets/ds-assets/uploads/knowledge-items/application-notes-for-the-internet-of-things/LoRa%20Design%20Guide.pdf diff --git a/src/mesh/RadioLibInterface.cpp b/src/mesh/RadioLibInterface.cpp index 5f82a41ce..997b1d6fe 100644 --- a/src/mesh/RadioLibInterface.cpp +++ b/src/mesh/RadioLibInterface.cpp @@ -31,31 +31,7 @@ void LockingArduinoHal::spiEndTransaction() #if ARCH_PORTDUINO void LockingArduinoHal::spiTransfer(uint8_t *out, size_t len, uint8_t *in) { - if (busy == RADIOLIB_NC) { - spi->transfer(out, in, len); - } else { - uint16_t offset = 0; - - while (len) { - uint8_t block_size = (len < 20 ? len : 20); - spi->transfer((out != NULL ? out + offset : NULL), (in != NULL ? in + offset : NULL), block_size); - if (block_size == len) - return; - - // ensure GPIO is low - - uint32_t start = millis(); - while (digitalRead(busy)) { - if (!Throttle::isWithinTimespanMs(start, 2000)) { - LOG_ERROR("GPIO mid-transfer timeout, is it connected?"); - return; - } - } - - offset += block_size; - len -= block_size; - } - } + spi->transfer(out, in, len); } #endif @@ -259,12 +235,12 @@ void RadioLibInterface::onNotify(uint32_t notification) case ISR_TX: handleTransmitInterrupt(); startReceive(); - startTransmitTimer(); + setTransmitDelay(); break; case ISR_RX: handleReceiveInterrupt(); startReceive(); - startTransmitTimer(); + setTransmitDelay(); break; case TRANSMIT_DELAY_COMPLETED: @@ -274,23 +250,32 @@ void RadioLibInterface::onNotify(uint32_t notification) if (!canSendImmediately()) { setTransmitDelay(); // currently Rx/Tx-ing: reset random delay } else { - if (isChannelActive()) { // check if there is currently a LoRa packet on the channel - startReceive(); // try receiving this packet, afterwards we'll be trying to transmit again - setTransmitDelay(); + meshtastic_MeshPacket *txp = txQueue.getFront(); + assert(txp); + long delay_remaining = txp->tx_after ? txp->tx_after - millis() : 0; + if (delay_remaining > 0) { + // There's still some delay pending on this packet, so resume waiting for it to elapse + notifyLater(delay_remaining, TRANSMIT_DELAY_COMPLETED, false); } else { - // Send any outgoing packets we have ready as fast as possible to keep the time between channel scan and - // actual transmission as short as possible - meshtastic_MeshPacket *txp = txQueue.dequeue(); - assert(txp); - bool sent = startSend(txp); - if (sent) { - // Packet has been sent, count it toward our TX airtime utilization. - uint32_t xmitMsec = getPacketTime(txp); - airTime->logAirtime(TX_LOG, xmitMsec); + if (isChannelActive()) { // check if there is currently a LoRa packet on the channel + startReceive(); // try receiving this packet, afterwards we'll be trying to transmit again + setTransmitDelay(); + } else { + // Send any outgoing packets we have ready as fast as possible to keep the time between channel scan and + // actual transmission as short as possible + txp = txQueue.dequeue(); + assert(txp); + bool sent = startSend(txp); + if (sent) { + // Packet has been sent, count it toward our TX airtime utilization. + uint32_t xmitMsec = getPacketTime(txp); + airTime->logAirtime(TX_LOG, xmitMsec); + } } } } } else { + // Do nothing, because the queue is empty } break; default: @@ -301,15 +286,24 @@ void RadioLibInterface::onNotify(uint32_t notification) void RadioLibInterface::setTransmitDelay() { meshtastic_MeshPacket *p = txQueue.getFront(); + if (!p) { + return; // noop if there's nothing in the queue + } + // We want all sending/receiving to be done by our daemon thread. // We use a delay here because this packet might have been sent in response to a packet we just received. // So we want to make sure the other side has had a chance to reconfigure its radio. - /* We assume if rx_snr = 0 and rx_rssi = 0, the packet was generated locally. - * This assumption is valid because of the offset generated by the radio to account for the noise - * floor. - */ - if (p->rx_snr == 0 && p->rx_rssi == 0) { + if (p->tx_after) { + unsigned long add_delay = p->rx_rssi ? getTxDelayMsecWeighted(p->rx_snr) : getTxDelayMsec(); + unsigned long now = millis(); + p->tx_after = max(p->tx_after + add_delay, now + add_delay); + notifyLater(now - p->tx_after, TRANSMIT_DELAY_COMPLETED, false); + } else if (p->rx_snr == 0 && p->rx_rssi == 0) { + /* We assume if rx_snr = 0 and rx_rssi = 0, the packet was generated locally. + * This assumption is valid because of the offset generated by the radio to account for the noise + * floor. + */ startTransmitTimer(true); } else { // If there is a SNR, start a timer scaled based on that SNR. @@ -336,6 +330,20 @@ void RadioLibInterface::startTransmitTimerSNR(float snr) } } +/** + * If the packet is not already in the late rebroadcast window, move it there + */ +void RadioLibInterface::clampToLateRebroadcastWindow(NodeNum from, PacketId id) +{ + // Look for non-late packets only, so we don't do this twice! + meshtastic_MeshPacket *p = txQueue.remove(from, id, true, false); + if (p) { + p->tx_after = millis() + getTxDelayMsecWeightedWorst(p->rx_snr); + txQueue.enqueue(p); + LOG_DEBUG("Move existing queued packet to the late rebroadcast window %dms from now", p->tx_after - millis()); + } +} + void RadioLibInterface::handleTransmitInterrupt() { // This can be null if we forced the device to enter standby mode. In that case diff --git a/src/mesh/RadioLibInterface.h b/src/mesh/RadioLibInterface.h index a5c2e30dd..dff58c9ad 100644 --- a/src/mesh/RadioLibInterface.h +++ b/src/mesh/RadioLibInterface.h @@ -22,18 +22,11 @@ class LockingArduinoHal : public ArduinoHal { public: - LockingArduinoHal(SPIClass &spi, SPISettings spiSettings, RADIOLIB_PIN_TYPE _busy = RADIOLIB_NC) - : ArduinoHal(spi, spiSettings) - { -#if ARCH_PORTDUINO - busy = _busy; -#endif - }; + LockingArduinoHal(SPIClass &spi, SPISettings spiSettings) : ArduinoHal(spi, spiSettings){}; void spiBeginTransaction() override; void spiEndTransaction() override; #if ARCH_PORTDUINO - RADIOLIB_PIN_TYPE busy; void spiTransfer(uint8_t *out, size_t len, uint8_t *in) override; #endif @@ -147,10 +140,16 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified * doing the transmit */ void setTransmitDelay(); - /** random timer with certain min. and max. settings */ + /** + * random timer with certain min. and max. settings + * @return Timestamp after which the packet may be sent + */ void startTransmitTimer(bool withDelay = true); - /** timer scaled to SNR of to be flooded packet */ + /** + * timer scaled to SNR of to be flooded packet + * @return Timestamp after which the packet may be sent + */ void startTransmitTimerSNR(float snr); void handleTransmitInterrupt(); @@ -200,4 +199,9 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified virtual void setStandby(); const char *radioLibErr = "RadioLib err="; + + /** + * If the packet is not already in the late rebroadcast window, move it there + */ + void clampToLateRebroadcastWindow(NodeNum from, PacketId id); }; \ No newline at end of file diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 7b792db30..f55e7cc5a 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -6,6 +6,7 @@ #include "NodeDB.h" #include "RTC.h" #include "configuration.h" +#include "detect/LoRaRadioType.h" #include "main.h" #include "mesh-pb-constants.h" #include "meshUtils.h" @@ -20,7 +21,6 @@ #if ENABLE_JSON_LOGGING || ARCH_PORTDUINO #include "serialization/MeshPacketSerializer.h" #endif -#include "../userPrefs.h" #define MAX_RX_FROMRADIO \ 4 // max number of packets destined to our queue, we dispatch packets quickly so it doesn't need to be big @@ -37,7 +37,6 @@ static MemoryDynamic staticPool; Allocator &packetPool = staticPool; static uint8_t bytes[MAX_LORA_PAYLOAD_LEN + 1] __attribute__((__aligned__)); -static uint8_t ScratchEncrypted[MAX_LORA_PAYLOAD_LEN + 1] __attribute__((__aligned__)); /** * Constructor @@ -271,6 +270,7 @@ ErrorCode Router::send(meshtastic_MeshPacket *p) auto encodeResult = perhapsEncode(p); if (encodeResult != meshtastic_Routing_Error_NONE) { packetPool.release(p_decoded); + p->channel = 0; // Reset the channel to 0, so we don't use the failing hash again abortSendAndNak(encodeResult, p); return encodeResult; // FIXME - this isn't a valid ErrorCode } @@ -326,9 +326,6 @@ bool perhapsDecode(meshtastic_MeshPacket *p) } bool decrypted = false; ChannelIndex chIndex = 0; - memcpy(bytes, p->encrypted.bytes, - rawSize); // we have to copy into a scratch buffer, because these bytes are a union with the decoded protobuf - memcpy(ScratchEncrypted, p->encrypted.bytes, rawSize); #if !(MESHTASTIC_EXCLUDE_PKI) // Attempt PKI decryption first if (p->channel == 0 && isToUs(p) && p->to > 0 && !isBroadcast(p->to) && nodeDB->getMeshNode(p->from) != nullptr && @@ -336,7 +333,7 @@ bool perhapsDecode(meshtastic_MeshPacket *p) rawSize > MESHTASTIC_PKC_OVERHEAD) { LOG_DEBUG("Attempt PKI decryption"); - if (crypto->decryptCurve25519(p->from, nodeDB->getMeshNode(p->from)->user.public_key, p->id, rawSize, ScratchEncrypted, + if (crypto->decryptCurve25519(p->from, nodeDB->getMeshNode(p->from)->user.public_key, p->id, rawSize, p->encrypted.bytes, bytes)) { LOG_INFO("PKI Decryption worked!"); memset(&p->decoded, 0, sizeof(p->decoded)); @@ -348,8 +345,6 @@ bool perhapsDecode(meshtastic_MeshPacket *p) p->pki_encrypted = true; memcpy(&p->public_key.bytes, nodeDB->getMeshNode(p->from)->user.public_key.bytes, 32); p->public_key.size = 32; - // memcpy(bytes, ScratchEncrypted, rawSize); // TODO: Rename the bytes buffers - // chIndex = 8; } else { LOG_ERROR("PKC Decrypted, but pb_decode failed!"); return false; @@ -366,6 +361,9 @@ bool perhapsDecode(meshtastic_MeshPacket *p) for (chIndex = 0; chIndex < channels.getNumChannels(); chIndex++) { // Try to use this hash/channel pair if (channels.decryptForHash(chIndex, p->channel)) { + // we have to copy into a scratch buffer, because these bytes are a union with the decoded protobuf. Create a + // fresh copy for each decrypt attempt. + memcpy(bytes, p->encrypted.bytes, rawSize); // Try to decrypt the packet if we can crypto->decrypt(p->from, p->id, rawSize, bytes); @@ -492,6 +490,8 @@ meshtastic_Routing_Error perhapsEncode(meshtastic_MeshPacket *p) // is not in the local nodedb // First, only PKC encrypt packets we are originating if (isFromUs(p) && + // Don't use PKC with simulator + radioType != SIM_RADIO && // Don't use PKC with Ham mode !owner.is_licensed && // Don't use PKC if it's not explicitly requested and a non-primary channel is requested @@ -512,9 +512,8 @@ meshtastic_Routing_Error perhapsEncode(meshtastic_MeshPacket *p) *node->user.public_key.bytes); return meshtastic_Routing_Error_PKI_FAILED; } - crypto->encryptCurve25519(p->to, getFrom(p), node->user.public_key, p->id, numbytes, bytes, ScratchEncrypted); + crypto->encryptCurve25519(p->to, getFrom(p), node->user.public_key, p->id, numbytes, bytes, p->encrypted.bytes); numbytes += MESHTASTIC_PKC_OVERHEAD; - memcpy(p->encrypted.bytes, ScratchEncrypted, numbytes); p->channel = 0; p->pki_encrypted = true; } else { diff --git a/src/mesh/SX126xInterface.cpp b/src/mesh/SX126xInterface.cpp index 002fb41ca..ed0267c5b 100644 --- a/src/mesh/SX126xInterface.cpp +++ b/src/mesh/SX126xInterface.cpp @@ -50,9 +50,7 @@ template bool SX126xInterface::init() #endif #if ARCH_PORTDUINO - float tcxoVoltage = 0; - if (settingsMap[dio3_tcxo_voltage]) - tcxoVoltage = 1.8; + float tcxoVoltage = (float)settingsMap[dio3_tcxo_voltage] / 1000; if (settingsMap[sx126x_ant_sw] != RADIOLIB_NC) { digitalWrite(settingsMap[sx126x_ant_sw], HIGH); pinMode(settingsMap[sx126x_ant_sw], OUTPUT); diff --git a/src/mesh/aes-ccm.cpp b/src/mesh/aes-ccm.cpp index b9af14fdb..a650ba2fc 100644 --- a/src/mesh/aes-ccm.cpp +++ b/src/mesh/aes-ccm.cpp @@ -10,7 +10,7 @@ #include "aes-ccm.h" #if !MESHTASTIC_EXCLUDE_PKI -static inline void WPA_PUT_BE16(uint8_t *a, uint16_t val) +static void WPA_PUT_BE16(uint8_t *a, uint16_t val) { a[0] = val >> 8; a[1] = val & 0xff; @@ -18,12 +18,9 @@ static inline void WPA_PUT_BE16(uint8_t *a, uint16_t val) static void xor_aes_block(uint8_t *dst, const uint8_t *src) { - uint32_t *d = (uint32_t *)dst; - uint32_t *s = (uint32_t *)src; - *d++ ^= *s++; - *d++ ^= *s++; - *d++ ^= *s++; - *d++ ^= *s++; + for (uint8_t i = 0; i < AES_BLOCK_SIZE; i++) { + dst[i] ^= src[i]; + } } static void aes_ccm_auth_start(size_t M, size_t L, const uint8_t *nonce, const uint8_t *aad, size_t aad_len, size_t plain_len, uint8_t *x) diff --git a/src/mesh/api/ServerAPI.h b/src/mesh/api/ServerAPI.h index 5b84fddd7..fe6a733a7 100644 --- a/src/mesh/api/ServerAPI.h +++ b/src/mesh/api/ServerAPI.h @@ -2,6 +2,8 @@ #include "StreamAPI.h" +#define SERVER_API_DEFAULT_PORT 4403 + /** * Provides both debug printing and, if the client starts sending protobufs to us, switches to send/receive protobufs * (and starts dropping debug printing - FIXME, eventually those prints should be encapsulated in protobufs). diff --git a/src/mesh/api/WiFiServerAPI.h b/src/mesh/api/WiFiServerAPI.h index 7a3d2967f..6e60bb678 100644 --- a/src/mesh/api/WiFiServerAPI.h +++ b/src/mesh/api/WiFiServerAPI.h @@ -22,5 +22,5 @@ class WiFiServerPort : public APIServerPort explicit WiFiServerPort(int port); }; -void initApiServer(int port = 4403); +void initApiServer(int port = SERVER_API_DEFAULT_PORT); void deInitApiServer(); \ No newline at end of file diff --git a/src/mesh/api/ethServerAPI.h b/src/mesh/api/ethServerAPI.h index 6f214c75a..9d25a2fc1 100644 --- a/src/mesh/api/ethServerAPI.h +++ b/src/mesh/api/ethServerAPI.h @@ -22,4 +22,4 @@ class ethServerPort : public APIServerPort explicit ethServerPort(int port); }; -void initApiServer(int port = 4403); +void initApiServer(int port = SERVER_API_DEFAULT_PORT); diff --git a/src/mesh/generated/meshtastic/admin.pb.cpp b/src/mesh/generated/meshtastic/admin.pb.cpp index 8b3fd3d1b..7ce3c74ce 100644 --- a/src/mesh/generated/meshtastic/admin.pb.cpp +++ b/src/mesh/generated/meshtastic/admin.pb.cpp @@ -1,5 +1,5 @@ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.4.9 */ +/* Generated by nanopb-0.4.9.1 */ #include "meshtastic/admin.pb.h" #if PB_PROTO_HEADER_VERSION != 40 diff --git a/src/mesh/generated/meshtastic/admin.pb.h b/src/mesh/generated/meshtastic/admin.pb.h index bbf633ef5..d9b8de384 100644 --- a/src/mesh/generated/meshtastic/admin.pb.h +++ b/src/mesh/generated/meshtastic/admin.pb.h @@ -1,5 +1,5 @@ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.4.9 */ +/* Generated by nanopb-0.4.9.1 */ #ifndef PB_MESHTASTIC_MESHTASTIC_ADMIN_PB_H_INCLUDED #define PB_MESHTASTIC_MESHTASTIC_ADMIN_PB_H_INCLUDED diff --git a/src/mesh/generated/meshtastic/apponly.pb.cpp b/src/mesh/generated/meshtastic/apponly.pb.cpp index 64d43b7ee..8b1b3da19 100644 --- a/src/mesh/generated/meshtastic/apponly.pb.cpp +++ b/src/mesh/generated/meshtastic/apponly.pb.cpp @@ -1,5 +1,5 @@ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.4.9 */ +/* Generated by nanopb-0.4.9.1 */ #include "meshtastic/apponly.pb.h" #if PB_PROTO_HEADER_VERSION != 40 diff --git a/src/mesh/generated/meshtastic/apponly.pb.h b/src/mesh/generated/meshtastic/apponly.pb.h index dc08d9ff3..f4c33bd79 100644 --- a/src/mesh/generated/meshtastic/apponly.pb.h +++ b/src/mesh/generated/meshtastic/apponly.pb.h @@ -1,5 +1,5 @@ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.4.9 */ +/* Generated by nanopb-0.4.9.1 */ #ifndef PB_MESHTASTIC_MESHTASTIC_APPONLY_PB_H_INCLUDED #define PB_MESHTASTIC_MESHTASTIC_APPONLY_PB_H_INCLUDED diff --git a/src/mesh/generated/meshtastic/atak.pb.cpp b/src/mesh/generated/meshtastic/atak.pb.cpp index 6dbc69fb4..a0368cf6b 100644 --- a/src/mesh/generated/meshtastic/atak.pb.cpp +++ b/src/mesh/generated/meshtastic/atak.pb.cpp @@ -1,5 +1,5 @@ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.4.9 */ +/* Generated by nanopb-0.4.9.1 */ #include "meshtastic/atak.pb.h" #if PB_PROTO_HEADER_VERSION != 40 diff --git a/src/mesh/generated/meshtastic/atak.pb.h b/src/mesh/generated/meshtastic/atak.pb.h index 15a86788b..8533bcbf9 100644 --- a/src/mesh/generated/meshtastic/atak.pb.h +++ b/src/mesh/generated/meshtastic/atak.pb.h @@ -1,5 +1,5 @@ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.4.9 */ +/* Generated by nanopb-0.4.9.1 */ #ifndef PB_MESHTASTIC_MESHTASTIC_ATAK_PB_H_INCLUDED #define PB_MESHTASTIC_MESHTASTIC_ATAK_PB_H_INCLUDED diff --git a/src/mesh/generated/meshtastic/cannedmessages.pb.cpp b/src/mesh/generated/meshtastic/cannedmessages.pb.cpp index 9f51e9634..1f4ebc927 100644 --- a/src/mesh/generated/meshtastic/cannedmessages.pb.cpp +++ b/src/mesh/generated/meshtastic/cannedmessages.pb.cpp @@ -1,5 +1,5 @@ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.4.9 */ +/* Generated by nanopb-0.4.9.1 */ #include "meshtastic/cannedmessages.pb.h" #if PB_PROTO_HEADER_VERSION != 40 diff --git a/src/mesh/generated/meshtastic/cannedmessages.pb.h b/src/mesh/generated/meshtastic/cannedmessages.pb.h index 06d14b98f..8343c4d6e 100644 --- a/src/mesh/generated/meshtastic/cannedmessages.pb.h +++ b/src/mesh/generated/meshtastic/cannedmessages.pb.h @@ -1,5 +1,5 @@ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.4.9 */ +/* Generated by nanopb-0.4.9.1 */ #ifndef PB_MESHTASTIC_MESHTASTIC_CANNEDMESSAGES_PB_H_INCLUDED #define PB_MESHTASTIC_MESHTASTIC_CANNEDMESSAGES_PB_H_INCLUDED diff --git a/src/mesh/generated/meshtastic/channel.pb.cpp b/src/mesh/generated/meshtastic/channel.pb.cpp index 52f923b13..6670a40fc 100644 --- a/src/mesh/generated/meshtastic/channel.pb.cpp +++ b/src/mesh/generated/meshtastic/channel.pb.cpp @@ -1,5 +1,5 @@ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.4.9 */ +/* Generated by nanopb-0.4.9.1 */ #include "meshtastic/channel.pb.h" #if PB_PROTO_HEADER_VERSION != 40 diff --git a/src/mesh/generated/meshtastic/channel.pb.h b/src/mesh/generated/meshtastic/channel.pb.h index 3d617ae39..ca4310bf1 100644 --- a/src/mesh/generated/meshtastic/channel.pb.h +++ b/src/mesh/generated/meshtastic/channel.pb.h @@ -1,5 +1,5 @@ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.4.9 */ +/* Generated by nanopb-0.4.9.1 */ #ifndef PB_MESHTASTIC_MESHTASTIC_CHANNEL_PB_H_INCLUDED #define PB_MESHTASTIC_MESHTASTIC_CHANNEL_PB_H_INCLUDED diff --git a/src/mesh/generated/meshtastic/clientonly.pb.cpp b/src/mesh/generated/meshtastic/clientonly.pb.cpp index d99af8cf5..8f380a972 100644 --- a/src/mesh/generated/meshtastic/clientonly.pb.cpp +++ b/src/mesh/generated/meshtastic/clientonly.pb.cpp @@ -1,5 +1,5 @@ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.4.9 */ +/* Generated by nanopb-0.4.9.1 */ #include "meshtastic/clientonly.pb.h" #if PB_PROTO_HEADER_VERSION != 40 diff --git a/src/mesh/generated/meshtastic/clientonly.pb.h b/src/mesh/generated/meshtastic/clientonly.pb.h index bf32d7875..5109e20b2 100644 --- a/src/mesh/generated/meshtastic/clientonly.pb.h +++ b/src/mesh/generated/meshtastic/clientonly.pb.h @@ -1,5 +1,5 @@ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.4.9 */ +/* Generated by nanopb-0.4.9.1 */ #ifndef PB_MESHTASTIC_MESHTASTIC_CLIENTONLY_PB_H_INCLUDED #define PB_MESHTASTIC_MESHTASTIC_CLIENTONLY_PB_H_INCLUDED diff --git a/src/mesh/generated/meshtastic/config.pb.cpp b/src/mesh/generated/meshtastic/config.pb.cpp index 23f4d542b..6fd2161ae 100644 --- a/src/mesh/generated/meshtastic/config.pb.cpp +++ b/src/mesh/generated/meshtastic/config.pb.cpp @@ -1,5 +1,5 @@ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.4.9 */ +/* Generated by nanopb-0.4.9.1 */ #include "meshtastic/config.pb.h" #if PB_PROTO_HEADER_VERSION != 40 diff --git a/src/mesh/generated/meshtastic/config.pb.h b/src/mesh/generated/meshtastic/config.pb.h index fab23ae34..5e105ab17 100644 --- a/src/mesh/generated/meshtastic/config.pb.h +++ b/src/mesh/generated/meshtastic/config.pb.h @@ -1,5 +1,5 @@ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.4.9 */ +/* Generated by nanopb-0.4.9.1 */ #ifndef PB_MESHTASTIC_MESHTASTIC_CONFIG_PB_H_INCLUDED #define PB_MESHTASTIC_MESHTASTIC_CONFIG_PB_H_INCLUDED @@ -58,7 +58,13 @@ typedef enum _meshtastic_Config_DeviceConfig_Role { Technical Details: Turns off many of the routine broadcasts to favor ATAK CoT packet stream and automatic TAK PLI (position location information) broadcasts. Uses position module configuration to determine TAK PLI broadcast interval. */ - meshtastic_Config_DeviceConfig_Role_TAK_TRACKER = 10 + meshtastic_Config_DeviceConfig_Role_TAK_TRACKER = 10, + /* Description: Will always rebroadcast packets, but will do so after all other modes. + Technical Details: Used for router nodes that are intended to provide additional coverage + in areas not already covered by other routers, or to bridge around problematic terrain, + but should not be given priority over other routers in order to avoid unnecessaraily + consuming hops. */ + meshtastic_Config_DeviceConfig_Role_ROUTER_LATE = 11 } meshtastic_Config_DeviceConfig_Role; /* Defines the device's behavior for how messages are rebroadcast */ @@ -588,8 +594,8 @@ extern "C" { /* Helper constants for enums */ #define _meshtastic_Config_DeviceConfig_Role_MIN meshtastic_Config_DeviceConfig_Role_CLIENT -#define _meshtastic_Config_DeviceConfig_Role_MAX meshtastic_Config_DeviceConfig_Role_TAK_TRACKER -#define _meshtastic_Config_DeviceConfig_Role_ARRAYSIZE ((meshtastic_Config_DeviceConfig_Role)(meshtastic_Config_DeviceConfig_Role_TAK_TRACKER+1)) +#define _meshtastic_Config_DeviceConfig_Role_MAX meshtastic_Config_DeviceConfig_Role_ROUTER_LATE +#define _meshtastic_Config_DeviceConfig_Role_ARRAYSIZE ((meshtastic_Config_DeviceConfig_Role)(meshtastic_Config_DeviceConfig_Role_ROUTER_LATE+1)) #define _meshtastic_Config_DeviceConfig_RebroadcastMode_MIN meshtastic_Config_DeviceConfig_RebroadcastMode_ALL #define _meshtastic_Config_DeviceConfig_RebroadcastMode_MAX meshtastic_Config_DeviceConfig_RebroadcastMode_CORE_PORTNUMS_ONLY diff --git a/src/mesh/generated/meshtastic/connection_status.pb.cpp b/src/mesh/generated/meshtastic/connection_status.pb.cpp index d1495bb83..b0df459ad 100644 --- a/src/mesh/generated/meshtastic/connection_status.pb.cpp +++ b/src/mesh/generated/meshtastic/connection_status.pb.cpp @@ -1,5 +1,5 @@ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.4.9 */ +/* Generated by nanopb-0.4.9.1 */ #include "meshtastic/connection_status.pb.h" #if PB_PROTO_HEADER_VERSION != 40 diff --git a/src/mesh/generated/meshtastic/connection_status.pb.h b/src/mesh/generated/meshtastic/connection_status.pb.h index c433e370b..55559dcef 100644 --- a/src/mesh/generated/meshtastic/connection_status.pb.h +++ b/src/mesh/generated/meshtastic/connection_status.pb.h @@ -1,5 +1,5 @@ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.4.9 */ +/* Generated by nanopb-0.4.9.1 */ #ifndef PB_MESHTASTIC_MESHTASTIC_CONNECTION_STATUS_PB_H_INCLUDED #define PB_MESHTASTIC_MESHTASTIC_CONNECTION_STATUS_PB_H_INCLUDED diff --git a/src/mesh/generated/meshtastic/device_ui.pb.cpp b/src/mesh/generated/meshtastic/device_ui.pb.cpp index 6e0cf0cc8..3a9e28725 100644 --- a/src/mesh/generated/meshtastic/device_ui.pb.cpp +++ b/src/mesh/generated/meshtastic/device_ui.pb.cpp @@ -1,5 +1,5 @@ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.4.9 */ +/* Generated by nanopb-0.4.9.1 */ #include "meshtastic/device_ui.pb.h" #if PB_PROTO_HEADER_VERSION != 40 diff --git a/src/mesh/generated/meshtastic/device_ui.pb.h b/src/mesh/generated/meshtastic/device_ui.pb.h index 107aa8846..0c4f5384e 100644 --- a/src/mesh/generated/meshtastic/device_ui.pb.h +++ b/src/mesh/generated/meshtastic/device_ui.pb.h @@ -1,5 +1,5 @@ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.4.9 */ +/* Generated by nanopb-0.4.9.1 */ #ifndef PB_MESHTASTIC_MESHTASTIC_DEVICE_UI_PB_H_INCLUDED #define PB_MESHTASTIC_MESHTASTIC_DEVICE_UI_PB_H_INCLUDED diff --git a/src/mesh/generated/meshtastic/deviceonly.pb.cpp b/src/mesh/generated/meshtastic/deviceonly.pb.cpp index 92853f00d..aa020467a 100644 --- a/src/mesh/generated/meshtastic/deviceonly.pb.cpp +++ b/src/mesh/generated/meshtastic/deviceonly.pb.cpp @@ -1,5 +1,5 @@ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.4.9 */ +/* Generated by nanopb-0.4.9.1 */ #include "meshtastic/deviceonly.pb.h" #if PB_PROTO_HEADER_VERSION != 40 diff --git a/src/mesh/generated/meshtastic/deviceonly.pb.h b/src/mesh/generated/meshtastic/deviceonly.pb.h index e52a914e0..c0a0fee91 100644 --- a/src/mesh/generated/meshtastic/deviceonly.pb.h +++ b/src/mesh/generated/meshtastic/deviceonly.pb.h @@ -1,5 +1,5 @@ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.4.9 */ +/* Generated by nanopb-0.4.9.1 */ #ifndef PB_MESHTASTIC_MESHTASTIC_DEVICEONLY_PB_H_INCLUDED #define PB_MESHTASTIC_MESHTASTIC_DEVICEONLY_PB_H_INCLUDED diff --git a/src/mesh/generated/meshtastic/localonly.pb.cpp b/src/mesh/generated/meshtastic/localonly.pb.cpp index 0a752a5a8..34391df73 100644 --- a/src/mesh/generated/meshtastic/localonly.pb.cpp +++ b/src/mesh/generated/meshtastic/localonly.pb.cpp @@ -1,5 +1,5 @@ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.4.9 */ +/* Generated by nanopb-0.4.9.1 */ #include "meshtastic/localonly.pb.h" #if PB_PROTO_HEADER_VERSION != 40 diff --git a/src/mesh/generated/meshtastic/localonly.pb.h b/src/mesh/generated/meshtastic/localonly.pb.h index 8f92b2a77..30f70ed90 100644 --- a/src/mesh/generated/meshtastic/localonly.pb.h +++ b/src/mesh/generated/meshtastic/localonly.pb.h @@ -1,5 +1,5 @@ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.4.9 */ +/* Generated by nanopb-0.4.9.1 */ #ifndef PB_MESHTASTIC_MESHTASTIC_LOCALONLY_PB_H_INCLUDED #define PB_MESHTASTIC_MESHTASTIC_LOCALONLY_PB_H_INCLUDED diff --git a/src/mesh/generated/meshtastic/mesh.pb.cpp b/src/mesh/generated/meshtastic/mesh.pb.cpp index a9f42f979..6c5c7a4be 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.cpp +++ b/src/mesh/generated/meshtastic/mesh.pb.cpp @@ -1,5 +1,5 @@ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.4.9 */ +/* Generated by nanopb-0.4.9.1 */ #include "meshtastic/mesh.pb.h" #if PB_PROTO_HEADER_VERSION != 40 diff --git a/src/mesh/generated/meshtastic/mesh.pb.h b/src/mesh/generated/meshtastic/mesh.pb.h index 3e195e7f5..5cd23c8e3 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.h +++ b/src/mesh/generated/meshtastic/mesh.pb.h @@ -1,5 +1,5 @@ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.4.9 */ +/* Generated by nanopb-0.4.9.1 */ #ifndef PB_MESHTASTIC_MESHTASTIC_MESH_PB_H_INCLUDED #define PB_MESHTASTIC_MESHTASTIC_MESH_PB_H_INCLUDED @@ -215,6 +215,14 @@ typedef enum _meshtastic_HardwareModel { /* WisMesh Tap RAK-4631 w/ TFT in injection modled case */ meshtastic_HardwareModel_WISMESH_TAP = 84, + /* Similar to PORTDUINO but used by Routastic devices, this is not any + particular device and does not run Meshtastic's code but supports + the same frame format. + Runs on linux, see https://github.com/Jorropo/routastic */ + meshtastic_HardwareModel_ROUTASTIC = 85, + /* Mesh-Tab, esp32 based + https://github.com/valzzu/Mesh-Tab */ + meshtastic_HardwareModel_MESH_TAB = 86, /* ------------------------------------------------------------------------------------------------------------------------------------------ Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits. ------------------------------------------------------------------------------------------------------------------------------------------ */ @@ -229,7 +237,7 @@ typedef enum _meshtastic_Constants { /* From mesh.options note: this payload length is ONLY the bytes that are sent inside of the Data protobuf (excluding protobuf overhead). The 16 byte header is outside of this envelope */ - meshtastic_Constants_DATA_PAYLOAD_LEN = 237 + meshtastic_Constants_DATA_PAYLOAD_LEN = 233 } meshtastic_Constants; /* Error codes for critical errors @@ -409,6 +417,8 @@ typedef enum _meshtastic_MeshPacket_Priority { meshtastic_MeshPacket_Priority_RESPONSE = 80, /* Higher priority for specific message types (portnums) to distinguish between other reliable packets. */ meshtastic_MeshPacket_Priority_HIGH = 100, + /* Higher priority alert message used for critical alerts which take priority over other reliable packets. */ + meshtastic_MeshPacket_Priority_ALERT = 110, /* Ack/naks are sent with very high priority to ensure that retransmission stops as soon as possible */ meshtastic_MeshPacket_Priority_ACK = 120, @@ -603,7 +613,7 @@ typedef struct _meshtastic_Routing { }; } meshtastic_Routing; -typedef PB_BYTES_ARRAY_T(237) meshtastic_Data_payload_t; +typedef PB_BYTES_ARRAY_T(233) meshtastic_Data_payload_t; /* (Formerly called SubPacket) The payload portion fo a packet, this is the actual bytes that are sent inside a radio packet (because from/to are broken out by the comms library) */ @@ -760,6 +770,10 @@ typedef struct _meshtastic_MeshPacket { /* Last byte of the node number of the node that will relay/relayed this packet. Set by the firmware internally, clients are not supposed to set this. */ uint8_t relay_node; + /* *Never* sent over the radio links. + Timestamp after which this packet may be sent. + Set by the firmware internally, clients are not supposed to set this. */ + uint32_t tx_after; } meshtastic_MeshPacket; /* The bluetooth to device link: @@ -882,7 +896,7 @@ typedef struct _meshtastic_FileInfo { uint32_t size_bytes; } meshtastic_FileInfo; -typedef PB_BYTES_ARRAY_T(237) meshtastic_Compressed_data_t; +typedef PB_BYTES_ARRAY_T(233) meshtastic_Compressed_data_t; /* Compressed message payload */ typedef struct _meshtastic_Compressed { /* PortNum to determine the how to handle the compressed payload. */ @@ -1168,7 +1182,7 @@ extern "C" { #define meshtastic_Data_init_default {_meshtastic_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0, false, 0} #define meshtastic_Waypoint_init_default {0, false, 0, false, 0, 0, 0, "", "", 0} #define meshtastic_MqttClientProxyMessage_init_default {"", 0, {{0, {0}}}, 0} -#define meshtastic_MeshPacket_init_default {0, 0, 0, 0, {meshtastic_Data_init_default}, 0, 0, 0, 0, 0, _meshtastic_MeshPacket_Priority_MIN, 0, _meshtastic_MeshPacket_Delayed_MIN, 0, 0, {0, {0}}, 0, 0, 0} +#define meshtastic_MeshPacket_init_default {0, 0, 0, 0, {meshtastic_Data_init_default}, 0, 0, 0, 0, 0, _meshtastic_MeshPacket_Priority_MIN, 0, _meshtastic_MeshPacket_Delayed_MIN, 0, 0, {0, {0}}, 0, 0, 0, 0} #define meshtastic_NodeInfo_init_default {0, false, meshtastic_User_init_default, false, meshtastic_Position_init_default, 0, 0, false, meshtastic_DeviceMetrics_init_default, 0, 0, false, 0, 0, 0} #define meshtastic_MyNodeInfo_init_default {0, 0, 0, {0, {0}}, ""} #define meshtastic_LogRecord_init_default {"", 0, "", _meshtastic_LogRecord_Level_MIN} @@ -1193,7 +1207,7 @@ extern "C" { #define meshtastic_Data_init_zero {_meshtastic_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0, false, 0} #define meshtastic_Waypoint_init_zero {0, false, 0, false, 0, 0, 0, "", "", 0} #define meshtastic_MqttClientProxyMessage_init_zero {"", 0, {{0, {0}}}, 0} -#define meshtastic_MeshPacket_init_zero {0, 0, 0, 0, {meshtastic_Data_init_zero}, 0, 0, 0, 0, 0, _meshtastic_MeshPacket_Priority_MIN, 0, _meshtastic_MeshPacket_Delayed_MIN, 0, 0, {0, {0}}, 0, 0, 0} +#define meshtastic_MeshPacket_init_zero {0, 0, 0, 0, {meshtastic_Data_init_zero}, 0, 0, 0, 0, 0, _meshtastic_MeshPacket_Priority_MIN, 0, _meshtastic_MeshPacket_Delayed_MIN, 0, 0, {0, {0}}, 0, 0, 0, 0} #define meshtastic_NodeInfo_init_zero {0, false, meshtastic_User_init_zero, false, meshtastic_Position_init_zero, 0, 0, false, meshtastic_DeviceMetrics_init_zero, 0, 0, false, 0, 0, 0} #define meshtastic_MyNodeInfo_init_zero {0, 0, 0, {0, {0}}, ""} #define meshtastic_LogRecord_init_zero {"", 0, "", _meshtastic_LogRecord_Level_MIN} @@ -1291,6 +1305,7 @@ extern "C" { #define meshtastic_MeshPacket_pki_encrypted_tag 17 #define meshtastic_MeshPacket_next_hop_tag 18 #define meshtastic_MeshPacket_relay_node_tag 19 +#define meshtastic_MeshPacket_tx_after_tag 20 #define meshtastic_NodeInfo_num_tag 1 #define meshtastic_NodeInfo_user_tag 2 #define meshtastic_NodeInfo_position_tag 3 @@ -1487,7 +1502,8 @@ X(a, STATIC, SINGULAR, UINT32, hop_start, 15) \ X(a, STATIC, SINGULAR, BYTES, public_key, 16) \ X(a, STATIC, SINGULAR, BOOL, pki_encrypted, 17) \ X(a, STATIC, SINGULAR, UINT32, next_hop, 18) \ -X(a, STATIC, SINGULAR, UINT32, relay_node, 19) +X(a, STATIC, SINGULAR, UINT32, relay_node, 19) \ +X(a, STATIC, SINGULAR, UINT32, tx_after, 20) #define meshtastic_MeshPacket_CALLBACK NULL #define meshtastic_MeshPacket_DEFAULT NULL #define meshtastic_MeshPacket_payload_variant_decoded_MSGTYPE meshtastic_Data @@ -1730,14 +1746,14 @@ extern const pb_msgdesc_t meshtastic_ChunkedPayloadResponse_msg; #define MESHTASTIC_MESHTASTIC_MESH_PB_H_MAX_SIZE meshtastic_FromRadio_size #define meshtastic_ChunkedPayload_size 245 #define meshtastic_ClientNotification_size 415 -#define meshtastic_Compressed_size 243 -#define meshtastic_Data_size 273 +#define meshtastic_Compressed_size 239 +#define meshtastic_Data_size 269 #define meshtastic_DeviceMetadata_size 54 #define meshtastic_FileInfo_size 236 #define meshtastic_FromRadio_size 510 #define meshtastic_Heartbeat_size 0 #define meshtastic_LogRecord_size 426 -#define meshtastic_MeshPacket_size 375 +#define meshtastic_MeshPacket_size 378 #define meshtastic_MqttClientProxyMessage_size 501 #define meshtastic_MyNodeInfo_size 77 #define meshtastic_NeighborInfo_size 258 diff --git a/src/mesh/generated/meshtastic/module_config.pb.cpp b/src/mesh/generated/meshtastic/module_config.pb.cpp index c40041eab..9843f0e91 100644 --- a/src/mesh/generated/meshtastic/module_config.pb.cpp +++ b/src/mesh/generated/meshtastic/module_config.pb.cpp @@ -1,5 +1,5 @@ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.4.9 */ +/* Generated by nanopb-0.4.9.1 */ #include "meshtastic/module_config.pb.h" #if PB_PROTO_HEADER_VERSION != 40 diff --git a/src/mesh/generated/meshtastic/module_config.pb.h b/src/mesh/generated/meshtastic/module_config.pb.h index 8f7bb701d..697b965c5 100644 --- a/src/mesh/generated/meshtastic/module_config.pb.h +++ b/src/mesh/generated/meshtastic/module_config.pb.h @@ -1,5 +1,5 @@ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.4.9 */ +/* Generated by nanopb-0.4.9.1 */ #ifndef PB_MESHTASTIC_MESHTASTIC_MODULE_CONFIG_PB_H_INCLUDED #define PB_MESHTASTIC_MESHTASTIC_MODULE_CONFIG_PB_H_INCLUDED diff --git a/src/mesh/generated/meshtastic/mqtt.pb.cpp b/src/mesh/generated/meshtastic/mqtt.pb.cpp index 74536cb79..2c32ef2e4 100644 --- a/src/mesh/generated/meshtastic/mqtt.pb.cpp +++ b/src/mesh/generated/meshtastic/mqtt.pb.cpp @@ -1,5 +1,5 @@ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.4.9 */ +/* Generated by nanopb-0.4.9.1 */ #include "meshtastic/mqtt.pb.h" #if PB_PROTO_HEADER_VERSION != 40 diff --git a/src/mesh/generated/meshtastic/mqtt.pb.h b/src/mesh/generated/meshtastic/mqtt.pb.h index 4d1027374..1726bc470 100644 --- a/src/mesh/generated/meshtastic/mqtt.pb.h +++ b/src/mesh/generated/meshtastic/mqtt.pb.h @@ -1,5 +1,5 @@ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.4.9 */ +/* Generated by nanopb-0.4.9.1 */ #ifndef PB_MESHTASTIC_MESHTASTIC_MQTT_PB_H_INCLUDED #define PB_MESHTASTIC_MESHTASTIC_MQTT_PB_H_INCLUDED diff --git a/src/mesh/generated/meshtastic/paxcount.pb.cpp b/src/mesh/generated/meshtastic/paxcount.pb.cpp index 403288147..ff738bde9 100644 --- a/src/mesh/generated/meshtastic/paxcount.pb.cpp +++ b/src/mesh/generated/meshtastic/paxcount.pb.cpp @@ -1,5 +1,5 @@ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.4.9 */ +/* Generated by nanopb-0.4.9.1 */ #include "meshtastic/paxcount.pb.h" #if PB_PROTO_HEADER_VERSION != 40 diff --git a/src/mesh/generated/meshtastic/paxcount.pb.h b/src/mesh/generated/meshtastic/paxcount.pb.h index b6b51fdd5..06078aef7 100644 --- a/src/mesh/generated/meshtastic/paxcount.pb.h +++ b/src/mesh/generated/meshtastic/paxcount.pb.h @@ -1,5 +1,5 @@ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.4.9 */ +/* Generated by nanopb-0.4.9.1 */ #ifndef PB_MESHTASTIC_MESHTASTIC_PAXCOUNT_PB_H_INCLUDED #define PB_MESHTASTIC_MESHTASTIC_PAXCOUNT_PB_H_INCLUDED diff --git a/src/mesh/generated/meshtastic/portnums.pb.cpp b/src/mesh/generated/meshtastic/portnums.pb.cpp index 8fca9af79..15a6ba372 100644 --- a/src/mesh/generated/meshtastic/portnums.pb.cpp +++ b/src/mesh/generated/meshtastic/portnums.pb.cpp @@ -1,5 +1,5 @@ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.4.9 */ +/* Generated by nanopb-0.4.9.1 */ #include "meshtastic/portnums.pb.h" #if PB_PROTO_HEADER_VERSION != 40 diff --git a/src/mesh/generated/meshtastic/portnums.pb.h b/src/mesh/generated/meshtastic/portnums.pb.h index df6cf32c2..d7dc47785 100644 --- a/src/mesh/generated/meshtastic/portnums.pb.h +++ b/src/mesh/generated/meshtastic/portnums.pb.h @@ -1,5 +1,5 @@ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.4.9 */ +/* Generated by nanopb-0.4.9.1 */ #ifndef PB_MESHTASTIC_MESHTASTIC_PORTNUMS_PB_H_INCLUDED #define PB_MESHTASTIC_MESHTASTIC_PORTNUMS_PB_H_INCLUDED @@ -72,6 +72,8 @@ typedef enum _meshtastic_PortNum { /* Same as Text Message but originating from Detection Sensor Module. NOTE: This portnum traffic is not sent to the public MQTT starting at firmware version 2.2.9 */ meshtastic_PortNum_DETECTION_SENSOR_APP = 10, + /* Same as Text Message but used for critical alerts. */ + meshtastic_PortNum_ALERT_APP = 11, /* Provides a 'ping' service that replies to any packet it receives. Also serves as a small example module. ENCODING: ASCII Plaintext */ diff --git a/src/mesh/generated/meshtastic/powermon.pb.cpp b/src/mesh/generated/meshtastic/powermon.pb.cpp index 6a9b7551a..8838e165f 100644 --- a/src/mesh/generated/meshtastic/powermon.pb.cpp +++ b/src/mesh/generated/meshtastic/powermon.pb.cpp @@ -1,5 +1,5 @@ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.4.9 */ +/* Generated by nanopb-0.4.9.1 */ #include "meshtastic/powermon.pb.h" #if PB_PROTO_HEADER_VERSION != 40 diff --git a/src/mesh/generated/meshtastic/powermon.pb.h b/src/mesh/generated/meshtastic/powermon.pb.h index 5add85b85..9d4d94193 100644 --- a/src/mesh/generated/meshtastic/powermon.pb.h +++ b/src/mesh/generated/meshtastic/powermon.pb.h @@ -1,5 +1,5 @@ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.4.9 */ +/* Generated by nanopb-0.4.9.1 */ #ifndef PB_MESHTASTIC_MESHTASTIC_POWERMON_PB_H_INCLUDED #define PB_MESHTASTIC_MESHTASTIC_POWERMON_PB_H_INCLUDED diff --git a/src/mesh/generated/meshtastic/remote_hardware.pb.cpp b/src/mesh/generated/meshtastic/remote_hardware.pb.cpp index 239950e7e..8942104b5 100644 --- a/src/mesh/generated/meshtastic/remote_hardware.pb.cpp +++ b/src/mesh/generated/meshtastic/remote_hardware.pb.cpp @@ -1,5 +1,5 @@ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.4.9 */ +/* Generated by nanopb-0.4.9.1 */ #include "meshtastic/remote_hardware.pb.h" #if PB_PROTO_HEADER_VERSION != 40 diff --git a/src/mesh/generated/meshtastic/remote_hardware.pb.h b/src/mesh/generated/meshtastic/remote_hardware.pb.h index ade250e93..9ab3413c3 100644 --- a/src/mesh/generated/meshtastic/remote_hardware.pb.h +++ b/src/mesh/generated/meshtastic/remote_hardware.pb.h @@ -1,5 +1,5 @@ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.4.9 */ +/* Generated by nanopb-0.4.9.1 */ #ifndef PB_MESHTASTIC_MESHTASTIC_REMOTE_HARDWARE_PB_H_INCLUDED #define PB_MESHTASTIC_MESHTASTIC_REMOTE_HARDWARE_PB_H_INCLUDED diff --git a/src/mesh/generated/meshtastic/rtttl.pb.cpp b/src/mesh/generated/meshtastic/rtttl.pb.cpp index 61ad8b73f..c994741f3 100644 --- a/src/mesh/generated/meshtastic/rtttl.pb.cpp +++ b/src/mesh/generated/meshtastic/rtttl.pb.cpp @@ -1,5 +1,5 @@ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.4.9 */ +/* Generated by nanopb-0.4.9.1 */ #include "meshtastic/rtttl.pb.h" #if PB_PROTO_HEADER_VERSION != 40 diff --git a/src/mesh/generated/meshtastic/rtttl.pb.h b/src/mesh/generated/meshtastic/rtttl.pb.h index 0572265f7..b6e152dbf 100644 --- a/src/mesh/generated/meshtastic/rtttl.pb.h +++ b/src/mesh/generated/meshtastic/rtttl.pb.h @@ -1,5 +1,5 @@ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.4.9 */ +/* Generated by nanopb-0.4.9.1 */ #ifndef PB_MESHTASTIC_MESHTASTIC_RTTTL_PB_H_INCLUDED #define PB_MESHTASTIC_MESHTASTIC_RTTTL_PB_H_INCLUDED diff --git a/src/mesh/generated/meshtastic/storeforward.pb.cpp b/src/mesh/generated/meshtastic/storeforward.pb.cpp index 71a232bf6..82db566a1 100644 --- a/src/mesh/generated/meshtastic/storeforward.pb.cpp +++ b/src/mesh/generated/meshtastic/storeforward.pb.cpp @@ -1,5 +1,5 @@ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.4.9 */ +/* Generated by nanopb-0.4.9.1 */ #include "meshtastic/storeforward.pb.h" #if PB_PROTO_HEADER_VERSION != 40 diff --git a/src/mesh/generated/meshtastic/storeforward.pb.h b/src/mesh/generated/meshtastic/storeforward.pb.h index 71f2fcad5..75cff5205 100644 --- a/src/mesh/generated/meshtastic/storeforward.pb.h +++ b/src/mesh/generated/meshtastic/storeforward.pb.h @@ -1,5 +1,5 @@ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.4.9 */ +/* Generated by nanopb-0.4.9.1 */ #ifndef PB_MESHTASTIC_MESHTASTIC_STOREFORWARD_PB_H_INCLUDED #define PB_MESHTASTIC_MESHTASTIC_STOREFORWARD_PB_H_INCLUDED @@ -91,7 +91,7 @@ typedef struct _meshtastic_StoreAndForward_Heartbeat { uint32_t secondary; } meshtastic_StoreAndForward_Heartbeat; -typedef PB_BYTES_ARRAY_T(237) meshtastic_StoreAndForward_text_t; +typedef PB_BYTES_ARRAY_T(233) meshtastic_StoreAndForward_text_t; /* TODO: REPLACE */ typedef struct _meshtastic_StoreAndForward { /* TODO: REPLACE */ @@ -211,7 +211,7 @@ extern const pb_msgdesc_t meshtastic_StoreAndForward_Heartbeat_msg; #define meshtastic_StoreAndForward_Heartbeat_size 12 #define meshtastic_StoreAndForward_History_size 18 #define meshtastic_StoreAndForward_Statistics_size 50 -#define meshtastic_StoreAndForward_size 242 +#define meshtastic_StoreAndForward_size 238 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/meshtastic/telemetry.pb.cpp b/src/mesh/generated/meshtastic/telemetry.pb.cpp index f6d39da6e..c79941fa5 100644 --- a/src/mesh/generated/meshtastic/telemetry.pb.cpp +++ b/src/mesh/generated/meshtastic/telemetry.pb.cpp @@ -1,5 +1,5 @@ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.4.9 */ +/* Generated by nanopb-0.4.9.1 */ #include "meshtastic/telemetry.pb.h" #if PB_PROTO_HEADER_VERSION != 40 diff --git a/src/mesh/generated/meshtastic/telemetry.pb.h b/src/mesh/generated/meshtastic/telemetry.pb.h index 874eef60f..85fe4bdc1 100644 --- a/src/mesh/generated/meshtastic/telemetry.pb.h +++ b/src/mesh/generated/meshtastic/telemetry.pb.h @@ -1,5 +1,5 @@ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.4.9 */ +/* Generated by nanopb-0.4.9.1 */ #ifndef PB_MESHTASTIC_MESHTASTIC_TELEMETRY_PB_H_INCLUDED #define PB_MESHTASTIC_MESHTASTIC_TELEMETRY_PB_H_INCLUDED @@ -79,7 +79,9 @@ typedef enum _meshtastic_TelemetrySensorType { /* SCD40/SCD41 CO2, humidity, temperature sensor */ meshtastic_TelemetrySensorType_SCD4X = 32, /* ClimateGuard RadSens, radiation, Geiger-Muller Tube */ - meshtastic_TelemetrySensorType_RADSENS = 33 + meshtastic_TelemetrySensorType_RADSENS = 33, + /* High accuracy current and voltage */ + meshtastic_TelemetrySensorType_INA226 = 34 } meshtastic_TelemetrySensorType; /* Struct definitions */ @@ -304,8 +306,8 @@ extern "C" { /* Helper constants for enums */ #define _meshtastic_TelemetrySensorType_MIN meshtastic_TelemetrySensorType_SENSOR_UNSET -#define _meshtastic_TelemetrySensorType_MAX meshtastic_TelemetrySensorType_RADSENS -#define _meshtastic_TelemetrySensorType_ARRAYSIZE ((meshtastic_TelemetrySensorType)(meshtastic_TelemetrySensorType_RADSENS+1)) +#define _meshtastic_TelemetrySensorType_MAX meshtastic_TelemetrySensorType_INA226 +#define _meshtastic_TelemetrySensorType_ARRAYSIZE ((meshtastic_TelemetrySensorType)(meshtastic_TelemetrySensorType_INA226+1)) diff --git a/src/mesh/generated/meshtastic/xmodem.pb.cpp b/src/mesh/generated/meshtastic/xmodem.pb.cpp index 3960ccdaa..09ae41d35 100644 --- a/src/mesh/generated/meshtastic/xmodem.pb.cpp +++ b/src/mesh/generated/meshtastic/xmodem.pb.cpp @@ -1,5 +1,5 @@ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.4.9 */ +/* Generated by nanopb-0.4.9.1 */ #include "meshtastic/xmodem.pb.h" #if PB_PROTO_HEADER_VERSION != 40 diff --git a/src/mesh/generated/meshtastic/xmodem.pb.h b/src/mesh/generated/meshtastic/xmodem.pb.h index 76edc0df6..3410fda0f 100644 --- a/src/mesh/generated/meshtastic/xmodem.pb.h +++ b/src/mesh/generated/meshtastic/xmodem.pb.h @@ -1,5 +1,5 @@ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.4.9 */ +/* Generated by nanopb-0.4.9.1 */ #ifndef PB_MESHTASTIC_MESHTASTIC_XMODEM_PB_H_INCLUDED #define PB_MESHTASTIC_MESHTASTIC_XMODEM_PB_H_INCLUDED diff --git a/src/mesh/http/ContentHandler.cpp b/src/mesh/http/ContentHandler.cpp index 64f7164c9..aa8a68f91 100644 --- a/src/mesh/http/ContentHandler.cpp +++ b/src/mesh/http/ContentHandler.cpp @@ -93,6 +93,7 @@ void registerHandlers(HTTPServer *insecureServer, HTTPSServer *secureServer) ResourceNode *nodeJsonScanNetworks = new ResourceNode("/json/scanNetworks", "GET", &handleScanNetworks); ResourceNode *nodeJsonBlinkLED = new ResourceNode("/json/blink", "POST", &handleBlinkLED); ResourceNode *nodeJsonReport = new ResourceNode("/json/report", "GET", &handleReport); + ResourceNode *nodeJsonNodes = new ResourceNode("/json/nodes", "GET", &handleNodes); ResourceNode *nodeJsonFsBrowseStatic = new ResourceNode("/json/fs/browse/static", "GET", &handleFsBrowseStatic); ResourceNode *nodeJsonDelete = new ResourceNode("/json/fs/delete/static", "DELETE", &handleFsDeleteStatic); @@ -112,6 +113,7 @@ void registerHandlers(HTTPServer *insecureServer, HTTPSServer *secureServer) secureServer->registerNode(nodeJsonFsBrowseStatic); secureServer->registerNode(nodeJsonDelete); secureServer->registerNode(nodeJsonReport); + secureServer->registerNode(nodeJsonNodes); // secureServer->registerNode(nodeUpdateFs); // secureServer->registerNode(nodeDeleteFs); secureServer->registerNode(nodeAdmin); @@ -680,6 +682,77 @@ void handleReport(HTTPRequest *req, HTTPResponse *res) delete value; } +void handleNodes(HTTPRequest *req, HTTPResponse *res) +{ + ResourceParameters *params = req->getParams(); + std::string content; + + if (!params->getQueryParameter("content", content)) { + content = "json"; + } + + if (content == "json") { + res->setHeader("Content-Type", "application/json"); + res->setHeader("Access-Control-Allow-Origin", "*"); + res->setHeader("Access-Control-Allow-Methods", "GET"); + } else { + res->setHeader("Content-Type", "text/html"); + res->println("
");
+    }
+
+    JSONArray nodesArray;
+
+    uint32_t readIndex = 0;
+    const meshtastic_NodeInfoLite *tempNodeInfo = nodeDB->readNextMeshNode(readIndex);
+    while (tempNodeInfo != NULL) {
+        if (tempNodeInfo->has_user) {
+            JSONObject node;
+
+            char id[16];
+            snprintf(id, sizeof(id), "!%08x", tempNodeInfo->num);
+
+            node["id"] = new JSONValue(id);
+            node["snr"] = new JSONValue(tempNodeInfo->snr);
+            node["via_mqtt"] = new JSONValue(BoolToString(tempNodeInfo->via_mqtt));
+            node["last_heard"] = new JSONValue((int)tempNodeInfo->last_heard);
+            node["position"] = new JSONValue();
+
+            if (nodeDB->hasValidPosition(tempNodeInfo)) {
+                JSONObject position;
+                position["latitude"] = new JSONValue((float)tempNodeInfo->position.latitude_i * 1e-7);
+                position["longitude"] = new JSONValue((float)tempNodeInfo->position.longitude_i * 1e-7);
+                position["altitude"] = new JSONValue((int)tempNodeInfo->position.altitude);
+                node["position"] = new JSONValue(position);
+            }
+
+            node["long_name"] = new JSONValue(tempNodeInfo->user.long_name);
+            node["short_name"] = new JSONValue(tempNodeInfo->user.short_name);
+            char macStr[18];
+            snprintf(macStr, sizeof(macStr), "%02X:%02X:%02X:%02X:%02X:%02X", tempNodeInfo->user.macaddr[0],
+                     tempNodeInfo->user.macaddr[1], tempNodeInfo->user.macaddr[2], tempNodeInfo->user.macaddr[3],
+                     tempNodeInfo->user.macaddr[4], tempNodeInfo->user.macaddr[5]);
+            node["mac_address"] = new JSONValue(macStr);
+            node["hw_model"] = new JSONValue(tempNodeInfo->user.hw_model);
+
+            nodesArray.push_back(new JSONValue(node));
+        }
+        tempNodeInfo = nodeDB->readNextMeshNode(readIndex);
+    }
+
+    // collect data to inner data object
+    JSONObject jsonObjInner;
+    jsonObjInner["nodes"] = new JSONValue(nodesArray);
+
+    // create json output structure
+    JSONObject jsonObjOuter;
+    jsonObjOuter["data"] = new JSONValue(jsonObjInner);
+    jsonObjOuter["status"] = new JSONValue("ok");
+    // serialize and write it to the stream
+    JSONValue *value = new JSONValue(jsonObjOuter);
+    res->print(value->Stringify().c_str());
+    delete value;
+}
+
 /*
     This supports the Apple Captive Network Assistant (CNA) Portal
 */
diff --git a/src/mesh/http/ContentHandler.h b/src/mesh/http/ContentHandler.h
index 987e3ffef..2066a6d57 100644
--- a/src/mesh/http/ContentHandler.h
+++ b/src/mesh/http/ContentHandler.h
@@ -13,6 +13,7 @@ void handleFsBrowseStatic(HTTPRequest *req, HTTPResponse *res);
 void handleFsDeleteStatic(HTTPRequest *req, HTTPResponse *res);
 void handleBlinkLED(HTTPRequest *req, HTTPResponse *res);
 void handleReport(HTTPRequest *req, HTTPResponse *res);
+void handleNodes(HTTPRequest *req, HTTPResponse *res);
 void handleUpdateFs(HTTPRequest *req, HTTPResponse *res);
 void handleDeleteFsContent(HTTPRequest *req, HTTPResponse *res);
 void handleFs(HTTPRequest *req, HTTPResponse *res);
diff --git a/src/mesh/http/ContentHelper.h b/src/mesh/http/ContentHelper.h
index a80c39f47..e5d3a2f57 100644
--- a/src/mesh/http/ContentHelper.h
+++ b/src/mesh/http/ContentHelper.h
@@ -1,5 +1,6 @@
 #include 
 #include 
+#include 
 
 #define BoolToString(x) ((x) ? "true" : "false")
 
diff --git a/src/mesh/raspihttp/PiWebServer.cpp b/src/mesh/raspihttp/PiWebServer.cpp
index f9ba9c235..846d70723 100644
--- a/src/mesh/raspihttp/PiWebServer.cpp
+++ b/src/mesh/raspihttp/PiWebServer.cpp
@@ -232,9 +232,9 @@ int handleAPIv1ToRadio(const struct _u_request *req, struct _u_response *res, vo
     ulfius_add_header_to_response(res, "X-Protobuf-Schema",
                                   "https://raw.githubusercontent.com/meshtastic/protobufs/master/meshtastic/mesh.proto");
 
-    if (req->http_verb == "OPTIONS") {
+    if (strcmp(req->http_verb, "OPTIONS") == 0) {
         ulfius_set_response_properties(res, U_OPT_STATUS, 204);
-        return U_CALLBACK_CONTINUE;
+        return U_CALLBACK_COMPLETE;
     }
 
     byte buffer[MAX_TO_FROM_RADIO_SIZE];
@@ -269,6 +269,11 @@ int handleAPIv1FromRadio(const struct _u_request *req, struct _u_response *res,
     ulfius_add_header_to_response(res, "X-Protobuf-Schema",
                                   "https://raw.githubusercontent.com/meshtastic/protobufs/master/meshtastic/mesh.proto");
 
+    if (strcmp(req->http_verb, "OPTIONS") == 0) {
+        ulfius_set_response_properties(res, U_OPT_STATUS, 204);
+        return U_CALLBACK_COMPLETE;
+    }
+
     uint8_t txBuf[MAX_STREAM_BUF_SIZE];
     uint32_t len = 1;
 
@@ -493,7 +498,9 @@ PiWebServerThread::PiWebServerThread()
         // Maximum body size sent by the client is 1 Kb
         instanceWeb.max_post_body_size = 1024;
         ulfius_add_endpoint_by_val(&instanceWeb, "GET", PREFIX, "/api/v1/fromradio/*", 1, &handleAPIv1FromRadio, NULL);
+        ulfius_add_endpoint_by_val(&instanceWeb, "OPTIONS", PREFIX, "/api/v1/fromradio/*", 1, &handleAPIv1FromRadio, NULL);
         ulfius_add_endpoint_by_val(&instanceWeb, "PUT", PREFIX, "/api/v1/toradio/*", 1, &handleAPIv1ToRadio, configWeb.rootPath);
+        ulfius_add_endpoint_by_val(&instanceWeb, "OPTIONS", PREFIX, "/api/v1/toradio/*", 1, &handleAPIv1ToRadio, NULL);
 
         // Add callback function to all endpoints for the Web Server
         ulfius_add_endpoint_by_val(&instanceWeb, "GET", NULL, "/*", 2, &callback_static_file, &configWeb);
diff --git a/src/mesh/wifi/WiFiAPClient.cpp b/src/mesh/wifi/WiFiAPClient.cpp
index 779576d64..38aa2e2a2 100644
--- a/src/mesh/wifi/WiFiAPClient.cpp
+++ b/src/mesh/wifi/WiFiAPClient.cpp
@@ -62,21 +62,17 @@ static void onNetworkConnected()
         LOG_INFO("Start WiFi network services");
 
         // start mdns
-        if (
-#ifdef ARCH_RP2040
-            !moduleConfig.mqtt.enabled && // MDNS is not supported when MQTT is enabled on ARCH_RP2040
-#endif
-            !MDNS.begin("Meshtastic")) {
+        if (!MDNS.begin("Meshtastic")) {
             LOG_ERROR("Error setting up MDNS responder!");
         } else {
             LOG_INFO("mDNS Host: Meshtastic.local");
+            MDNS.addService("meshtastic", "tcp", SERVER_API_DEFAULT_PORT);
 #ifdef ARCH_ESP32
             MDNS.addService("http", "tcp", 80);
             MDNS.addService("https", "tcp", 443);
+            // ESP32 prints obtained IP address in WiFiEvent
 #elif defined(ARCH_RP2040)
-            // ARCH_RP2040 does not support HTTPS, create a "meshtastic" service
-            MDNS.addService("meshtastic", "tcp", 4403);
-            // ESP32 handles this in WiFiEvent
+            // ARCH_RP2040 does not support HTTPS
             LOG_INFO("Obtained IP address: %s", WiFi.localIP().toString().c_str());
 #endif
         }
@@ -434,4 +430,4 @@ uint8_t getWifiDisconnectReason()
 {
     return wifiDisconnectReason;
 }
-#endif
\ No newline at end of file
+#endif
diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp
index c81b6ede4..fc3b914e5 100644
--- a/src/modules/AdminModule.cpp
+++ b/src/modules/AdminModule.cpp
@@ -18,7 +18,7 @@
 #ifdef ARCH_PORTDUINO
 #include "unistd.h"
 #endif
-#include "../userPrefs.h"
+
 #include "Default.h"
 #include "TypeConversions.h"
 
@@ -175,6 +175,12 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta
         LOG_INFO("Client set ham mode");
         handleSetHamMode(r->set_ham_mode);
         break;
+    case meshtastic_AdminMessage_get_ui_config_request_tag: {
+        LOG_INFO("Client is getting device-ui config");
+        handleGetDeviceUIConfig(mp);
+        handled = true;
+        break;
+    }
 
     /**
      * Other
@@ -234,6 +240,12 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta
         reboot(DEFAULT_REBOOT_SECONDS);
         break;
     }
+    case meshtastic_AdminMessage_store_ui_config_tag: {
+        LOG_INFO("Storing device-ui config");
+        handleStoreDeviceUIConfig(r->store_ui_config);
+        handled = true;
+        break;
+    }
     case meshtastic_AdminMessage_begin_edit_settings_tag: {
         LOG_INFO("Begin transaction for editing settings");
         hasOpenEditTransaction = true;
@@ -358,7 +370,7 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta
 #ifdef ARCH_PORTDUINO
     case meshtastic_AdminMessage_exit_simulator_tag:
         LOG_INFO("Exiting simulator");
-        _exit(0);
+        exit(0);
         break;
 #endif
 
@@ -477,7 +489,7 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c)
             IS_ONE_OF(config.device.role, meshtastic_Config_DeviceConfig_Role_ROUTER,
                       meshtastic_Config_DeviceConfig_Role_REPEATER)) {
             config.device.rebroadcast_mode = meshtastic_Config_DeviceConfig_RebroadcastMode_ALL;
-            const char *warning = "Rebroadcast mode can't be set to NONE for a router or repeater\n";
+            const char *warning = "Rebroadcast mode can't be set to NONE for a router or repeater";
             LOG_WARN(warning);
             sendWarning(warning);
         }
@@ -621,6 +633,9 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c)
             requiresReboot = false;
 
         break;
+    case meshtastic_Config_device_ui_tag:
+        // NOOP! This is handled by handleStoreDeviceUIConfig
+        break;
     }
     if (requiresReboot && !hasOpenEditTransaction) {
         disableBluetooth();
@@ -783,6 +798,10 @@ void AdminModule::handleGetConfig(const meshtastic_MeshPacket &req, const uint32
             LOG_INFO("Get config: Sessionkey");
             res.get_config_response.which_payload_variant = meshtastic_Config_sessionkey_tag;
             break;
+        case meshtastic_AdminMessage_ConfigType_DEVICEUI_CONFIG:
+            // NOOP! This is handled by handleGetDeviceUIConfig
+            res.get_config_response.which_payload_variant = meshtastic_Config_device_ui_tag;
+            break;
         }
         // NOTE: The phone app needs to know the ls_secs value so it can properly expect sleep behavior.
         // So even if we internally use 0 to represent 'use default' we still need to send the value we are
@@ -995,6 +1014,14 @@ void AdminModule::handleGetChannel(const meshtastic_MeshPacket &req, uint32_t ch
     }
 }
 
+void AdminModule::handleGetDeviceUIConfig(const meshtastic_MeshPacket &req)
+{
+    meshtastic_AdminMessage r = meshtastic_AdminMessage_init_default;
+    r.which_payload_variant = meshtastic_AdminMessage_get_ui_config_response_tag;
+    r.get_ui_config_response = uiconfig;
+    myReply = allocDataProtobuf(r);
+}
+
 void AdminModule::reboot(int32_t seconds)
 {
     LOG_INFO("Reboot in %d seconds", seconds);
@@ -1015,6 +1042,11 @@ void AdminModule::saveChanges(int saveWhat, bool shouldReboot)
     }
 }
 
+void AdminModule::handleStoreDeviceUIConfig(const meshtastic_DeviceUIConfig &uicfg)
+{
+    nodeDB->saveProto("/prefs/uiconfig.proto", meshtastic_DeviceUIConfig_size, &meshtastic_DeviceUIConfig_msg, &uicfg);
+}
+
 void AdminModule::handleSetHamMode(const meshtastic_HamParameters &p)
 {
     // Set call sign and override lora limitations for licensed use
@@ -1081,7 +1113,7 @@ bool AdminModule::messageIsResponse(const meshtastic_AdminMessage *r)
         r->which_payload_variant == meshtastic_AdminMessage_get_ringtone_response_tag ||
         r->which_payload_variant == meshtastic_AdminMessage_get_device_connection_status_response_tag ||
         r->which_payload_variant == meshtastic_AdminMessage_get_node_remote_hardware_pins_response_tag ||
-        r->which_payload_variant == meshtastic_NodeRemoteHardwarePinsResponse_node_remote_hardware_pins_tag)
+        r->which_payload_variant == meshtastic_AdminMessage_get_ui_config_response_tag)
         return true;
     else
         return false;
@@ -1097,7 +1129,8 @@ bool AdminModule::messageIsRequest(const meshtastic_AdminMessage *r)
         r->which_payload_variant == meshtastic_AdminMessage_get_device_metadata_request_tag ||
         r->which_payload_variant == meshtastic_AdminMessage_get_ringtone_request_tag ||
         r->which_payload_variant == meshtastic_AdminMessage_get_device_connection_status_request_tag ||
-        r->which_payload_variant == meshtastic_AdminMessage_get_node_remote_hardware_pins_request_tag)
+        r->which_payload_variant == meshtastic_AdminMessage_get_node_remote_hardware_pins_request_tag ||
+        r->which_payload_variant == meshtastic_AdminMessage_get_ui_config_request_tag)
         return true;
     else
         return false;
diff --git a/src/modules/AdminModule.h b/src/modules/AdminModule.h
index b99e86707..ee2ebfd96 100644
--- a/src/modules/AdminModule.h
+++ b/src/modules/AdminModule.h
@@ -43,6 +43,7 @@ class AdminModule : public ProtobufModule, public Obser
     void handleGetDeviceMetadata(const meshtastic_MeshPacket &req);
     void handleGetDeviceConnectionStatus(const meshtastic_MeshPacket &req);
     void handleGetNodeRemoteHardwarePins(const meshtastic_MeshPacket &req);
+    void handleGetDeviceUIConfig(const meshtastic_MeshPacket &req);
     /**
      * Setters
      */
@@ -52,6 +53,7 @@ class AdminModule : public ProtobufModule, public Obser
     void handleSetModuleConfig(const meshtastic_ModuleConfig &c);
     void handleSetChannel();
     void handleSetHamMode(const meshtastic_HamParameters &req);
+    void handleStoreDeviceUIConfig(const meshtastic_DeviceUIConfig &uicfg);
     void reboot(int32_t seconds);
 
     void setPassKey(meshtastic_AdminMessage *res);
diff --git a/src/modules/CannedMessageModule.h b/src/modules/CannedMessageModule.h
index fd9ffc9b6..a91933a0f 100644
--- a/src/modules/CannedMessageModule.h
+++ b/src/modules/CannedMessageModule.h
@@ -117,8 +117,10 @@ class CannedMessageModule : public SinglePortModule, public ObservableshouldDraw(); }
     virtual Observable *getUIFrameObservable() override { return this; }
-    virtual void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) override;
     virtual bool interceptingKeyboardInput() override;
+#if !HAS_TFT
+    virtual void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) override;
+#endif
     virtual AdminMessageHandleResult handleAdminMessageForModule(const meshtastic_MeshPacket &mp,
                                                                  meshtastic_AdminMessage *request,
                                                                  meshtastic_AdminMessage *response) override;
@@ -228,4 +230,4 @@ class CannedMessageModule : public SinglePortModule, public Observableinit();
 #endif
@@ -201,11 +201,13 @@ void setupModules()
         if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_PMSA003I].first > 0) {
             new AirQualityTelemetryModule();
         }
+#if !MESHTASTIC_EXCLUDE_HEALTH_TELEMETRY
         if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_MAX30102].first > 0 ||
             nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_MLX90614].first > 0) {
             new HealthTelemetryModule();
         }
 #endif
+#endif
 #if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_POWER_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
         new PowerTelemetryModule();
 #endif
@@ -229,7 +231,7 @@ void setupModules()
         storeForwardModule = new StoreForwardModule();
 #endif
 #endif
-#if defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040)
+#if defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040) || defined(ARCH_PORTDUINO)
 #if !MESHTASTIC_EXCLUDE_EXTERNALNOTIFICATION
         externalNotificationModule = new ExternalNotificationModule();
 #endif
diff --git a/src/modules/PositionModule.cpp b/src/modules/PositionModule.cpp
index d977cfdec..6285d7aa5 100644
--- a/src/modules/PositionModule.cpp
+++ b/src/modules/PositionModule.cpp
@@ -389,7 +389,7 @@ int32_t PositionModule::runOnce()
     }
 
     if (lastGpsSend == 0 || msSinceLastSend >= intervalMs) {
-        if (hasValidPosition(node)) {
+        if (nodeDB->hasValidPosition(node)) {
             lastGpsSend = now;
 
             lastGpsLatitude = node->position.latitude_i;
@@ -403,7 +403,7 @@ int32_t PositionModule::runOnce()
     } else if (config.position.position_broadcast_smart_enabled) {
         const meshtastic_NodeInfoLite *node2 = service->refreshLocalMeshNode(); // should guarantee there is now a position
 
-        if (hasValidPosition(node2)) {
+        if (nodeDB->hasValidPosition(node2)) {
             // The minimum time (in seconds) that would pass before we are able to send a new position packet.
 
             auto smartPosition = getDistanceTraveledSinceLastSend(node->position);
@@ -464,7 +464,7 @@ void PositionModule::handleNewPosition()
     meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(nodeDB->getNodeNum());
     const meshtastic_NodeInfoLite *node2 = service->refreshLocalMeshNode(); // should guarantee there is now a position
     // We limit our GPS broadcasts to a max rate
-    if (hasValidPosition(node2)) {
+    if (nodeDB->hasValidPosition(node2)) {
         auto smartPosition = getDistanceTraveledSinceLastSend(node->position);
         uint32_t msSinceLastSend = millis() - lastGpsSend;
         if (smartPosition.hasTraveledOverThreshold &&
@@ -483,4 +483,4 @@ void PositionModule::handleNewPosition()
     }
 }
 
-#endif
+#endif
\ No newline at end of file
diff --git a/src/modules/RangeTestModule.cpp b/src/modules/RangeTestModule.cpp
index bf842ce55..c42839d97 100644
--- a/src/modules/RangeTestModule.cpp
+++ b/src/modules/RangeTestModule.cpp
@@ -155,8 +155,6 @@ ProcessMessage RangeTestModuleRadio::handleReceived(const meshtastic_MeshPacket
             LOG_DEBUG("mp.from          %d", mp.from);
             LOG_DEBUG("mp.rx_snr        %f", mp.rx_snr);
             LOG_DEBUG("mp.hop_limit     %d", mp.hop_limit);
-            // LOG_DEBUG("mp.decoded.position.latitude_i     %d", mp.decoded.position.latitude_i); // Deprecated
-            // LOG_DEBUG("mp.decoded.position.longitude_i    %d", mp.decoded.position.longitude_i); // Deprecated
             LOG_DEBUG("---- Node Information of Received Packet (mp.from):");
             LOG_DEBUG("n->user.long_name         %s", n->user.long_name);
             LOG_DEBUG("n->user.short_name        %s", n->user.short_name);
@@ -194,8 +192,6 @@ bool RangeTestModuleRadio::appendFile(const meshtastic_MeshPacket &mp)
         LOG_DEBUG("mp.from          %d", mp.from);
         LOG_DEBUG("mp.rx_snr        %f", mp.rx_snr);
         LOG_DEBUG("mp.hop_limit     %d", mp.hop_limit);
-        // LOG_DEBUG("mp.decoded.position.latitude_i     %d", mp.decoded.position.latitude_i);  // Deprecated
-        // LOG_DEBUG("mp.decoded.position.longitude_i    %d", mp.decoded.position.longitude_i); // Deprecated
         LOG_DEBUG("---- Node Information of Received Packet (mp.from):");
         LOG_DEBUG("n->user.long_name         %s", n->user.long_name);
         LOG_DEBUG("n->user.short_name        %s", n->user.short_name);
@@ -265,13 +261,21 @@ bool RangeTestModuleRadio::appendFile(const meshtastic_MeshPacket &mp)
         fileToAppend.printf("??:??:??,"); // Time
     }
 
-    fileToAppend.printf("%d,", getFrom(&mp));                     // From
-    fileToAppend.printf("%s,", n->user.long_name);                // Long Name
-    fileToAppend.printf("%f,", n->position.latitude_i * 1e-7);    // Sender Lat
-    fileToAppend.printf("%f,", n->position.longitude_i * 1e-7);   // Sender Long
-    fileToAppend.printf("%f,", gpsStatus->getLatitude() * 1e-7);  // RX Lat
-    fileToAppend.printf("%f,", gpsStatus->getLongitude() * 1e-7); // RX Long
-    fileToAppend.printf("%d,", gpsStatus->getAltitude());         // RX Altitude
+    fileToAppend.printf("%d,", getFrom(&mp));                   // From
+    fileToAppend.printf("%s,", n->user.long_name);              // Long Name
+    fileToAppend.printf("%f,", n->position.latitude_i * 1e-7);  // Sender Lat
+    fileToAppend.printf("%f,", n->position.longitude_i * 1e-7); // Sender Long
+    if (gpsStatus->getIsConnected() || config.position.fixed_position) {
+        fileToAppend.printf("%f,", gpsStatus->getLatitude() * 1e-7);  // RX Lat
+        fileToAppend.printf("%f,", gpsStatus->getLongitude() * 1e-7); // RX Long
+        fileToAppend.printf("%d,", gpsStatus->getAltitude());         // RX Altitude
+    } else {
+        // When the phone API is in use, the node info will be updated with position
+        meshtastic_NodeInfoLite *us = nodeDB->getMeshNode(nodeDB->getNodeNum());
+        fileToAppend.printf("%f,", us->position.latitude_i * 1e-7);  // RX Lat
+        fileToAppend.printf("%f,", us->position.longitude_i * 1e-7); // RX Long
+        fileToAppend.printf("%d,", us->position.altitude);           // RX Altitude
+    }
 
     fileToAppend.printf("%f,", mp.rx_snr); // RX SNR
 
@@ -292,4 +296,4 @@ bool RangeTestModuleRadio::appendFile(const meshtastic_MeshPacket &mp)
 #endif
 
     return 1;
-}
+}
\ No newline at end of file
diff --git a/src/modules/SerialModule.cpp b/src/modules/SerialModule.cpp
index 531be274e..bf53b1748 100644
--- a/src/modules/SerialModule.cpp
+++ b/src/modules/SerialModule.cpp
@@ -205,7 +205,7 @@ int32_t SerialModule::runOnce()
                     uint32_t readIndex = 0;
                     const meshtastic_NodeInfoLite *tempNodeInfo = nodeDB->readNextMeshNode(readIndex);
                     while (tempNodeInfo != NULL) {
-                        if (tempNodeInfo->has_user && hasValidPosition(tempNodeInfo)) {
+                        if (tempNodeInfo->has_user && nodeDB->hasValidPosition(tempNodeInfo)) {
                             printWPL(outbuf, sizeof(outbuf), tempNodeInfo->position, tempNodeInfo->user.long_name, true);
                             serialPrint->printf("%s", outbuf);
                         }
@@ -474,7 +474,7 @@ void SerialModule::processWXSerial()
                         if (windDirPos != NULL) {
                             // Extract data after "=" for WindDir
                             strcpy(windDir, windDirPos + 15); // Add 15 to skip "WindDir = "
-                            double radians = toRadians(strtof(windDir, nullptr));
+                            double radians = GeoCoord::toRadians(strtof(windDir, nullptr));
                             dir_sum_sin += sin(radians);
                             dir_sum_cos += cos(radians);
                             dirCount++;
@@ -541,7 +541,7 @@ void SerialModule::processWXSerial()
         double avgCos = dir_sum_cos / dirCount;
 
         double avgRadians = atan2(avgSin, avgCos);
-        float dirAvg = toDegrees(avgRadians);
+        float dirAvg = GeoCoord::toDegrees(avgRadians);
 
         if (dirAvg < 0) {
             dirAvg += 360.0;
diff --git a/src/modules/StoreForwardModule.cpp b/src/modules/StoreForwardModule.cpp
index 4cf06f5d2..0a6e1b4c4 100644
--- a/src/modules/StoreForwardModule.cpp
+++ b/src/modules/StoreForwardModule.cpp
@@ -73,11 +73,11 @@ void StoreForwardModule::populatePSRAM()
     LOG_DEBUG("Before PSRAM init: heap %d/%d PSRAM %d/%d", memGet.getFreeHeap(), memGet.getHeapSize(), memGet.getFreePsram(),
               memGet.getPsramSize());
 
-    /* Use a maximum of 2/3 the available PSRAM unless otherwise specified.
+    /* Use a maximum of 3/4 the available PSRAM unless otherwise specified.
         Note: This needs to be done after every thing that would use PSRAM
     */
     uint32_t numberOfPackets =
-        (this->records ? this->records : (((memGet.getFreePsram() / 3) * 2) / sizeof(PacketHistoryStruct)));
+        (this->records ? this->records : (((memGet.getFreePsram() / 4) * 3) / sizeof(PacketHistoryStruct)));
     this->records = numberOfPackets;
 #if defined(ARCH_ESP32)
     this->packetHistory = static_cast(ps_calloc(numberOfPackets, sizeof(PacketHistoryStruct)));
@@ -198,6 +198,9 @@ void StoreForwardModule::historyAdd(const meshtastic_MeshPacket &mp)
     this->packetHistory[this->packetHistoryTotalCount].to = mp.to;
     this->packetHistory[this->packetHistoryTotalCount].channel = mp.channel;
     this->packetHistory[this->packetHistoryTotalCount].from = getFrom(&mp);
+    this->packetHistory[this->packetHistoryTotalCount].id = mp.id;
+    this->packetHistory[this->packetHistoryTotalCount].reply_id = p.reply_id;
+    this->packetHistory[this->packetHistoryTotalCount].emoji = (bool)p.emoji;
     this->packetHistory[this->packetHistoryTotalCount].payload_size = p.payload.size;
     memcpy(this->packetHistory[this->packetHistoryTotalCount].payload, p.payload.bytes, meshtastic_Constants_DATA_PAYLOAD_LEN);
 
@@ -244,8 +247,11 @@ meshtastic_MeshPacket *StoreForwardModule::preparePayload(NodeNum dest, uint32_t
 
                 p->to = local ? this->packetHistory[i].to : dest; // PhoneAPI can handle original `to`
                 p->from = this->packetHistory[i].from;
+                p->id = this->packetHistory[i].id;
                 p->channel = this->packetHistory[i].channel;
+                p->decoded.reply_id = this->packetHistory[i].reply_id;
                 p->rx_time = this->packetHistory[i].time;
+                p->decoded.emoji = (uint32_t)this->packetHistory[i].emoji;
 
                 // Let's assume that if the server received the S&F request that the client is in range.
                 //   TODO: Make this configurable.
@@ -617,4 +623,4 @@ StoreForwardModule::StoreForwardModule()
         disable();
     }
 #endif
-}
+}
\ No newline at end of file
diff --git a/src/modules/StoreForwardModule.h b/src/modules/StoreForwardModule.h
index e3273470b..30db1625c 100644
--- a/src/modules/StoreForwardModule.h
+++ b/src/modules/StoreForwardModule.h
@@ -13,7 +13,10 @@ struct PacketHistoryStruct {
     uint32_t time;
     uint32_t to;
     uint32_t from;
+    uint32_t id;
     uint8_t channel;
+    uint32_t reply_id;
+    bool emoji;
     uint8_t payload[meshtastic_Constants_DATA_PAYLOAD_LEN];
     pb_size_t payload_size;
 };
diff --git a/src/modules/Telemetry/AirQualityTelemetry.cpp b/src/modules/Telemetry/AirQualityTelemetry.cpp
index 362d60252..6a8077f03 100644
--- a/src/modules/Telemetry/AirQualityTelemetry.cpp
+++ b/src/modules/Telemetry/AirQualityTelemetry.cpp
@@ -113,12 +113,18 @@ bool AirQualityTelemetryModule::getAirQualityTelemetry(meshtastic_Telemetry *m)
 
     m->time = getTime();
     m->which_variant = meshtastic_Telemetry_air_quality_metrics_tag;
+    m->variant.air_quality_metrics.has_pm10_standard = true;
     m->variant.air_quality_metrics.pm10_standard = data.pm10_standard;
+    m->variant.air_quality_metrics.has_pm25_standard = true;
     m->variant.air_quality_metrics.pm25_standard = data.pm25_standard;
+    m->variant.air_quality_metrics.has_pm100_standard = true;
     m->variant.air_quality_metrics.pm100_standard = data.pm100_standard;
 
+    m->variant.air_quality_metrics.has_pm10_environmental = true;
     m->variant.air_quality_metrics.pm10_environmental = data.pm10_env;
+    m->variant.air_quality_metrics.has_pm25_environmental = true;
     m->variant.air_quality_metrics.pm25_environmental = data.pm25_env;
+    m->variant.air_quality_metrics.has_pm100_environmental = true;
     m->variant.air_quality_metrics.pm100_environmental = data.pm100_env;
 
     LOG_INFO("Send: PM1.0(Standard)=%i, PM2.5(Standard)=%i, PM10.0(Standard)=%i", m->variant.air_quality_metrics.pm10_standard,
diff --git a/src/modules/Telemetry/DeviceTelemetry.cpp b/src/modules/Telemetry/DeviceTelemetry.cpp
index 4989b88e2..192754e09 100644
--- a/src/modules/Telemetry/DeviceTelemetry.cpp
+++ b/src/modules/Telemetry/DeviceTelemetry.cpp
@@ -130,6 +130,14 @@ meshtastic_Telemetry DeviceTelemetryModule::getLocalStatsTelemetry()
         telemetry.variant.local_stats.num_packets_rx_bad = RadioLibInterface::instance->rxBad;
         telemetry.variant.local_stats.num_tx_relay = RadioLibInterface::instance->txRelay;
     }
+#ifdef ARCH_PORTDUINO
+    if (SimRadio::instance) {
+        telemetry.variant.local_stats.num_packets_tx = SimRadio::instance->txGood;
+        telemetry.variant.local_stats.num_packets_rx = SimRadio::instance->rxGood + SimRadio::instance->rxBad;
+        telemetry.variant.local_stats.num_packets_rx_bad = SimRadio::instance->rxBad;
+        telemetry.variant.local_stats.num_tx_relay = SimRadio::instance->txRelay;
+    }
+#endif
     if (router) {
         telemetry.variant.local_stats.num_rx_dupe = router->rxDupe;
         telemetry.variant.local_stats.num_tx_relay_canceled = router->txRelayCanceled;
diff --git a/src/modules/Telemetry/EnvironmentTelemetry.cpp b/src/modules/Telemetry/EnvironmentTelemetry.cpp
index 92d964f7d..008da5c71 100644
--- a/src/modules/Telemetry/EnvironmentTelemetry.cpp
+++ b/src/modules/Telemetry/EnvironmentTelemetry.cpp
@@ -18,6 +18,7 @@
 #include 
 #include 
 
+#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR_EXTERNAL
 // Sensors
 #include "Sensor/AHT10.h"
 #include "Sensor/BME280Sensor.h"
@@ -36,7 +37,6 @@
 #include "Sensor/SHT31Sensor.h"
 #include "Sensor/SHT4XSensor.h"
 #include "Sensor/SHTC3Sensor.h"
-#include "Sensor/T1000xSensor.h"
 #include "Sensor/TSL2591Sensor.h"
 #include "Sensor/VEML7700Sensor.h"
 
@@ -58,11 +58,12 @@ MLX90632Sensor mlx90632Sensor;
 DFRobotLarkSensor dfRobotLarkSensor;
 NAU7802Sensor nau7802Sensor;
 BMP3XXSensor bmp3xxSensor;
+CGRadSensSensor cgRadSens;
+#endif
 #ifdef T1000X_SENSOR_EN
+#include "Sensor/T1000xSensor.h"
 T1000xSensor t1000xSensor;
 #endif
-CGRadSensSensor cgRadSens;
-
 #define FAILED_STATE_SENSOR_READ_MULTIPLIER 10
 #define DISPLAY_RECEIVEID_MEASUREMENTS_ON_SCREEN true
 
@@ -104,7 +105,7 @@ int32_t EnvironmentTelemetryModule::runOnce()
             // therefore, we should only enable the sensor loop if measurement is also enabled
 #ifdef T1000X_SENSOR_EN
             result = t1000xSensor.runOnce();
-#else
+#elif !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR_EXTERNAL
             if (dfRobotLarkSensor.hasSensor())
                 result = dfRobotLarkSensor.runOnce();
             if (bmp085Sensor.hasSensor())
@@ -159,8 +160,10 @@ int32_t EnvironmentTelemetryModule::runOnce()
         if (!moduleConfig.telemetry.environment_measurement_enabled) {
             return disable();
         } else {
+#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR_EXTERNAL
             if (bme680Sensor.hasSensor())
                 result = bme680Sensor.runTrigger();
+#endif
         }
 
         if (((lastSentToMesh == 0) ||
@@ -499,6 +502,7 @@ AdminMessageHandleResult EnvironmentTelemetryModule::handleAdminMessageForModule
                                                                                  meshtastic_AdminMessage *response)
 {
     AdminMessageHandleResult result = AdminMessageHandleResult::NOT_HANDLED;
+#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR_EXTERNAL
     if (dfRobotLarkSensor.hasSensor()) {
         result = dfRobotLarkSensor.handleAdminMessage(mp, request, response);
         if (result != AdminMessageHandleResult::NOT_HANDLED)
@@ -609,7 +613,8 @@ AdminMessageHandleResult EnvironmentTelemetryModule::handleAdminMessageForModule
         if (result != AdminMessageHandleResult::NOT_HANDLED)
             return result;
     }
+#endif
     return result;
 }
 
-#endif
+#endif
\ No newline at end of file
diff --git a/src/modules/Telemetry/HealthTelemetry.cpp b/src/modules/Telemetry/HealthTelemetry.cpp
index 22534e9f5..1b9b49813 100644
--- a/src/modules/Telemetry/HealthTelemetry.cpp
+++ b/src/modules/Telemetry/HealthTelemetry.cpp
@@ -1,6 +1,6 @@
 #include "configuration.h"
 
-#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && !defined(ARCH_PORTDUINO)
+#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && !MESHTASTIC_EXCLUDE_HEALTH_TELEMETRY && !defined(ARCH_PORTDUINO)
 
 #include "../mesh/generated/meshtastic/telemetry.pb.h"
 #include "Default.h"
@@ -246,4 +246,4 @@ bool HealthTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
     return false;
 }
 
-#endif
+#endif
\ No newline at end of file
diff --git a/src/modules/Telemetry/HealthTelemetry.h b/src/modules/Telemetry/HealthTelemetry.h
index fe84f2d27..01e4c2372 100644
--- a/src/modules/Telemetry/HealthTelemetry.h
+++ b/src/modules/Telemetry/HealthTelemetry.h
@@ -1,6 +1,6 @@
 #include "configuration.h"
 
-#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && !defined(ARCH_PORTDUINO)
+#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && !MESHTASTIC_EXCLUDE_HEALTH_TELEMETRY && !defined(ARCH_PORTDUINO)
 
 #pragma once
 #include "../mesh/generated/meshtastic/telemetry.pb.h"
@@ -57,4 +57,4 @@ class HealthTelemetryModule : private concurrency::OSThread, public ProtobufModu
     uint32_t sensor_read_error_count = 0;
 };
 
-#endif
+#endif
\ No newline at end of file
diff --git a/src/modules/Telemetry/PowerTelemetry.cpp b/src/modules/Telemetry/PowerTelemetry.cpp
index 367643849..10133fca5 100644
--- a/src/modules/Telemetry/PowerTelemetry.cpp
+++ b/src/modules/Telemetry/PowerTelemetry.cpp
@@ -56,6 +56,8 @@ int32_t PowerTelemetryModule::runOnce()
             // therefore, we should only enable the sensor loop if measurement is also enabled
             if (ina219Sensor.hasSensor() && !ina219Sensor.isInitialized())
                 result = ina219Sensor.runOnce();
+            if (ina226Sensor.hasSensor() && !ina226Sensor.isInitialized())
+                result = ina226Sensor.runOnce();
             if (ina260Sensor.hasSensor() && !ina260Sensor.isInitialized())
                 result = ina260Sensor.runOnce();
             if (ina3221Sensor.hasSensor() && !ina3221Sensor.isInitialized())
@@ -170,6 +172,8 @@ bool PowerTelemetryModule::getPowerTelemetry(meshtastic_Telemetry *m)
 #if HAS_TELEMETRY && !defined(ARCH_PORTDUINO)
     if (ina219Sensor.hasSensor())
         valid = ina219Sensor.getMetrics(m);
+    if (ina226Sensor.hasSensor())
+        valid = ina226Sensor.getMetrics(m);
     if (ina260Sensor.hasSensor())
         valid = ina260Sensor.getMetrics(m);
     if (ina3221Sensor.hasSensor())
@@ -253,4 +257,4 @@ bool PowerTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
     return false;
 }
 
-#endif
+#endif
\ No newline at end of file
diff --git a/src/modules/Telemetry/Sensor/CurrentSensor.h b/src/modules/Telemetry/Sensor/CurrentSensor.h
new file mode 100644
index 000000000..9827a9aa4
--- /dev/null
+++ b/src/modules/Telemetry/Sensor/CurrentSensor.h
@@ -0,0 +1,13 @@
+#include "configuration.h"
+
+#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
+
+#pragma once
+
+class CurrentSensor
+{
+  public:
+    virtual int16_t getCurrentMa() = 0;
+};
+
+#endif
\ No newline at end of file
diff --git a/src/modules/Telemetry/Sensor/INA219Sensor.cpp b/src/modules/Telemetry/Sensor/INA219Sensor.cpp
index de69163b4..ea47e265d 100644
--- a/src/modules/Telemetry/Sensor/INA219Sensor.cpp
+++ b/src/modules/Telemetry/Sensor/INA219Sensor.cpp
@@ -45,4 +45,9 @@ uint16_t INA219Sensor::getBusVoltageMv()
     return lround(ina219.getBusVoltage_V() * 1000);
 }
 
+int16_t INA219Sensor::getCurrentMa()
+{
+    return lround(ina219.getCurrent_mA());
+}
+
 #endif
\ No newline at end of file
diff --git a/src/modules/Telemetry/Sensor/INA219Sensor.h b/src/modules/Telemetry/Sensor/INA219Sensor.h
index 9dded067b..9b6a2fcca 100644
--- a/src/modules/Telemetry/Sensor/INA219Sensor.h
+++ b/src/modules/Telemetry/Sensor/INA219Sensor.h
@@ -3,11 +3,12 @@
 #if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
 
 #include "../mesh/generated/meshtastic/telemetry.pb.h"
+#include "CurrentSensor.h"
 #include "TelemetrySensor.h"
 #include "VoltageSensor.h"
 #include 
 
-class INA219Sensor : public TelemetrySensor, VoltageSensor
+class INA219Sensor : public TelemetrySensor, VoltageSensor, CurrentSensor
 {
   private:
     Adafruit_INA219 ina219;
@@ -20,6 +21,7 @@ class INA219Sensor : public TelemetrySensor, VoltageSensor
     virtual int32_t runOnce() override;
     virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
     virtual uint16_t getBusVoltageMv() override;
+    virtual int16_t getCurrentMa() override;
 };
 
 #endif
\ No newline at end of file
diff --git a/src/modules/Telemetry/Sensor/INA226Sensor.cpp b/src/modules/Telemetry/Sensor/INA226Sensor.cpp
new file mode 100644
index 000000000..1ee7cd92e
--- /dev/null
+++ b/src/modules/Telemetry/Sensor/INA226Sensor.cpp
@@ -0,0 +1,58 @@
+#include "configuration.h"
+
+#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
+
+#include "../mesh/generated/meshtastic/telemetry.pb.h"
+#include "INA226.h"
+#include "INA226Sensor.h"
+#include "TelemetrySensor.h"
+
+INA226Sensor::INA226Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_INA226, "INA226") {}
+
+int32_t INA226Sensor::runOnce()
+{
+    LOG_INFO("Init sensor: %s", sensorName);
+    if (!hasSensor()) {
+        return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
+    }
+
+    begin(nodeTelemetrySensorsMap[sensorType].second, nodeTelemetrySensorsMap[sensorType].first);
+
+    if (!status) {
+        status = ina226.begin();
+    }
+    return initI2CSensor();
+}
+
+void INA226Sensor::setup() {}
+
+void INA226Sensor::begin(TwoWire *wire, uint8_t addr)
+{
+    _wire = wire;
+    _addr = addr;
+    ina226 = INA226(_addr, _wire);
+    _wire->begin();
+}
+
+bool INA226Sensor::getMetrics(meshtastic_Telemetry *measurement)
+{
+    measurement->variant.environment_metrics.has_voltage = true;
+    measurement->variant.environment_metrics.has_current = true;
+
+    // mV conversion to V
+    measurement->variant.environment_metrics.voltage = ina226.getBusVoltage() / 1000;
+    measurement->variant.environment_metrics.current = ina226.getCurrent_mA();
+    return true;
+}
+
+uint16_t INA226Sensor::getBusVoltageMv()
+{
+    return lround(ina226.getBusVoltage());
+}
+
+int16_t INA226Sensor::getCurrentMa()
+{
+    return lround(ina226.getCurrent_mA());
+}
+
+#endif
\ No newline at end of file
diff --git a/src/modules/Telemetry/Sensor/INA226Sensor.h b/src/modules/Telemetry/Sensor/INA226Sensor.h
new file mode 100644
index 000000000..2f71c5b86
--- /dev/null
+++ b/src/modules/Telemetry/Sensor/INA226Sensor.h
@@ -0,0 +1,30 @@
+#include "configuration.h"
+
+#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
+
+#include "../mesh/generated/meshtastic/telemetry.pb.h"
+#include "CurrentSensor.h"
+#include "TelemetrySensor.h"
+#include "VoltageSensor.h"
+#include 
+
+class INA226Sensor : public TelemetrySensor, VoltageSensor, CurrentSensor
+{
+  private:
+    uint8_t _addr = INA_ADDR;
+    TwoWire *_wire = &Wire;
+    INA226 ina226 = INA226(_addr, _wire);
+
+  protected:
+    virtual void setup() override;
+    void begin(TwoWire *wire = &Wire, uint8_t addr = INA_ADDR);
+
+  public:
+    INA226Sensor();
+    virtual int32_t runOnce() override;
+    virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
+    virtual uint16_t getBusVoltageMv() override;
+    virtual int16_t getCurrentMa() override;
+};
+
+#endif
\ No newline at end of file
diff --git a/src/modules/Telemetry/Sensor/INA3221Sensor.cpp b/src/modules/Telemetry/Sensor/INA3221Sensor.cpp
index ed09856e2..7ac11dfde 100644
--- a/src/modules/Telemetry/Sensor/INA3221Sensor.cpp
+++ b/src/modules/Telemetry/Sensor/INA3221Sensor.cpp
@@ -102,4 +102,9 @@ uint16_t INA3221Sensor::getBusVoltageMv()
     return lround(ina3221.getVoltage(BAT_CH) * 1000);
 }
 
+int16_t INA3221Sensor::getCurrentMa()
+{
+    return lround(ina3221.getCurrent(BAT_CH));
+}
+
 #endif
\ No newline at end of file
diff --git a/src/modules/Telemetry/Sensor/INA3221Sensor.h b/src/modules/Telemetry/Sensor/INA3221Sensor.h
index d5121aab6..8eeda3e02 100644
--- a/src/modules/Telemetry/Sensor/INA3221Sensor.h
+++ b/src/modules/Telemetry/Sensor/INA3221Sensor.h
@@ -3,11 +3,12 @@
 #if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
 
 #include "../mesh/generated/meshtastic/telemetry.pb.h"
+#include "CurrentSensor.h"
 #include "TelemetrySensor.h"
 #include "VoltageSensor.h"
 #include 
 
-class INA3221Sensor : public TelemetrySensor, VoltageSensor
+class INA3221Sensor : public TelemetrySensor, VoltageSensor, CurrentSensor
 {
   private:
     INA3221 ina3221 = INA3221(INA3221_ADDR42_SDA);
@@ -35,6 +36,7 @@ class INA3221Sensor : public TelemetrySensor, VoltageSensor
     int32_t runOnce() override;
     bool getMetrics(meshtastic_Telemetry *measurement) override;
     virtual uint16_t getBusVoltageMv() override;
+    virtual int16_t getCurrentMa() override;
 };
 
 struct _INA3221Measurement {
diff --git a/src/modules/Telemetry/Sensor/MAX30102Sensor.cpp b/src/modules/Telemetry/Sensor/MAX30102Sensor.cpp
index 88128a6db..f99956925 100644
--- a/src/modules/Telemetry/Sensor/MAX30102Sensor.cpp
+++ b/src/modules/Telemetry/Sensor/MAX30102Sensor.cpp
@@ -1,6 +1,6 @@
 #include "configuration.h"
 
-#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && !defined(ARCH_PORTDUINO)
+#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && !MESHTASTIC_EXCLUDE_HEALTH_TELEMETRY && !defined(ARCH_PORTDUINO)
 
 #include "../mesh/generated/meshtastic/telemetry.pb.h"
 #include "MAX30102Sensor.h"
@@ -80,4 +80,4 @@ bool MAX30102Sensor::getMetrics(meshtastic_Telemetry *measurement)
     return true;
 }
 
-#endif
+#endif
\ No newline at end of file
diff --git a/src/modules/Telemetry/Sensor/MAX30102Sensor.h b/src/modules/Telemetry/Sensor/MAX30102Sensor.h
index 426d9d365..026e30ed0 100644
--- a/src/modules/Telemetry/Sensor/MAX30102Sensor.h
+++ b/src/modules/Telemetry/Sensor/MAX30102Sensor.h
@@ -1,6 +1,6 @@
 #include "configuration.h"
 
-#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && !defined(ARCH_PORTDUINO)
+#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && !MESHTASTIC_EXCLUDE_HEALTH_TELEMETRY && !defined(ARCH_PORTDUINO)
 
 #include "../mesh/generated/meshtastic/telemetry.pb.h"
 #include "TelemetrySensor.h"
@@ -23,4 +23,4 @@ class MAX30102Sensor : public TelemetrySensor
     virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
 };
 
-#endif
+#endif
\ No newline at end of file
diff --git a/src/modules/WaypointModule.cpp b/src/modules/WaypointModule.cpp
index 48e0c4242..b8b738309 100644
--- a/src/modules/WaypointModule.cpp
+++ b/src/modules/WaypointModule.cpp
@@ -126,7 +126,7 @@ void WaypointModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state,
     }
 
     // If our node has a position:
-    if (ourNode && (hasValidPosition(ourNode) || screen->hasHeading())) {
+    if (ourNode && (nodeDB->hasValidPosition(ourNode) || screen->hasHeading())) {
         const meshtastic_PositionLite &op = ourNode->position;
         float myHeading;
         if (screen->hasHeading())
diff --git a/src/motion/LIS3DHSensor.cpp b/src/motion/LIS3DHSensor.cpp
index f3f5a62d1..995f74abe 100755
--- a/src/motion/LIS3DHSensor.cpp
+++ b/src/motion/LIS3DHSensor.cpp
@@ -22,7 +22,7 @@ int32_t LIS3DHSensor::runOnce()
 {
     if (sensor.getClick() > 0) {
         uint8_t click = sensor.getClick();
-        if (!config.device.double_tap_as_button_press) {
+        if (!config.device.double_tap_as_button_press && config.display.wake_on_tap_or_motion) {
             wakeScreen();
         }
 
@@ -34,4 +34,4 @@ int32_t LIS3DHSensor::runOnce()
     return MOTION_SENSOR_CHECK_INTERVAL_MS;
 }
 
-#endif
\ No newline at end of file
+#endif
diff --git a/src/motion/QMA6100PSensor.cpp b/src/motion/QMA6100PSensor.cpp
index 4c5bc14d2..eb81e16c7 100644
--- a/src/motion/QMA6100PSensor.cpp
+++ b/src/motion/QMA6100PSensor.cpp
@@ -88,13 +88,13 @@ bool QMA6100PSingleton::init(ScanI2C::FoundDevice device)
     bool status = begin(device.address.address, &Wire);
 #endif
     if (status != true) {
-        LOG_WARN("QMA6100P init begin failed\n");
+        LOG_WARN("QMA6100P init begin failed");
         return false;
     }
     delay(20);
     // SW reset to make sure the device starts in a known state
     if (softwareReset() != true) {
-        LOG_WARN("QMA6100P init reset failed\n");
+        LOG_WARN("QMA6100P init reset failed");
         return false;
     }
     delay(20);
@@ -180,4 +180,4 @@ bool QMA6100PSingleton::setWakeOnMotion()
     return true;
 }
 
-#endif
\ No newline at end of file
+#endif
diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp
index 3d5948976..4260ae201 100644
--- a/src/mqtt/MQTT.cpp
+++ b/src/mqtt/MQTT.cpp
@@ -19,24 +19,240 @@
 #include 
 #endif
 #include "Default.h"
+#if !defined(ARCH_NRF52) || NRF52_USE_JSON
 #include "serialization/JSON.h"
 #include "serialization/MeshPacketSerializer.h"
+#endif
 #include 
 #include 
+#include 
+#include 
 
-const int reconnectMax = 5;
+#include 
+#if defined(ARCH_PORTDUINO)
+#include 
+#elif !defined(ntohl)
+#include 
+#define ntohl __ntohl
+#endif
 
 MQTT *mqtt;
 
-static MemoryDynamic staticMqttPool;
-
-Allocator &mqttPool = staticMqttPool;
+namespace
+{
+constexpr int reconnectMax = 5;
 
 // FIXME - this size calculation is super sloppy, but it will go away once we dynamically alloc meshpackets
 static uint8_t bytes[meshtastic_MqttClientProxyMessage_size + 30]; // 12 for channel name and 16 for nodeid
 
 static bool isMqttServerAddressPrivate = false;
 
+// meshtastic_ServiceEnvelope that automatically releases dynamically allocated memory when it goes out of scope.
+struct DecodedServiceEnvelope : public meshtastic_ServiceEnvelope {
+    DecodedServiceEnvelope() = delete;
+    DecodedServiceEnvelope(const uint8_t *payload, size_t length)
+        : meshtastic_ServiceEnvelope(meshtastic_ServiceEnvelope_init_default),
+          validDecode(pb_decode_from_bytes(payload, length, &meshtastic_ServiceEnvelope_msg, this))
+    {
+    }
+    ~DecodedServiceEnvelope()
+    {
+        if (validDecode)
+            pb_release(&meshtastic_ServiceEnvelope_msg, this);
+    }
+    // Clients must check that this is true before using.
+    const bool validDecode;
+};
+
+inline void onReceiveProto(char *topic, byte *payload, size_t length)
+{
+    const DecodedServiceEnvelope e(payload, length);
+    if (!e.validDecode || e.channel_id == NULL || e.gateway_id == NULL || e.packet == NULL) {
+        LOG_ERROR("Invalid MQTT service envelope, topic %s, len %u!", topic, length);
+        return;
+    }
+    const meshtastic_Channel &ch = channels.getByName(e.channel_id);
+    if (strcmp(e.gateway_id, owner.id) == 0) {
+        // Generate an implicit ACK towards ourselves (handled and processed only locally!) for this message.
+        // We do this because packets are not rebroadcasted back into MQTT anymore and we assume that at least one node
+        // receives it when we get our own packet back. Then we'll stop our retransmissions.
+        if (isFromUs(e.packet))
+            routingModule->sendAckNak(meshtastic_Routing_Error_NONE, getFrom(e.packet), e.packet->id, ch.index);
+        else
+            LOG_INFO("Ignore downlink message we originally sent");
+        return;
+    }
+    if (isFromUs(e.packet)) {
+        LOG_INFO("Ignore downlink message we originally sent");
+        return;
+    }
+
+    // Find channel by channel_id and check downlink_enabled
+    if (!(strcmp(e.channel_id, "PKI") == 0 ||
+          (strcmp(e.channel_id, channels.getGlobalId(ch.index)) == 0 && ch.settings.downlink_enabled))) {
+        return;
+    }
+    LOG_INFO("Received MQTT topic %s, len=%u", topic, length);
+
+    UniquePacketPoolPacket p = packetPool.allocUniqueCopy(*e.packet);
+    p->via_mqtt = true; // Mark that the packet was received via MQTT
+    // Unset received SNR/RSSI which might have been added by the MQTT gateway
+    p->rx_snr = 0;
+    p->rx_rssi = 0;
+
+    if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
+        if (moduleConfig.mqtt.encryption_enabled) {
+            LOG_INFO("Ignore decoded message on MQTT, encryption is enabled");
+            return;
+        }
+        if (p->decoded.portnum == meshtastic_PortNum_ADMIN_APP) {
+            LOG_INFO("Ignore decoded admin packet");
+            return;
+        }
+        p->channel = ch.index;
+    }
+
+    // PKI messages get accepted even if we can't decrypt
+    if (router && p->which_payload_variant == meshtastic_MeshPacket_encrypted_tag && strcmp(e.channel_id, "PKI") == 0) {
+        const meshtastic_NodeInfoLite *tx = nodeDB->getMeshNode(getFrom(p.get()));
+        const meshtastic_NodeInfoLite *rx = nodeDB->getMeshNode(p->to);
+        // Only accept PKI messages to us, or if we have both the sender and receiver in our nodeDB, as then it's
+        // likely they discovered each other via a channel we have downlink enabled for
+        if (isToUs(p.get()) || (tx && tx->has_user && rx && rx->has_user))
+            router->enqueueReceivedMessage(p.release());
+    } else if (router && perhapsDecode(p.get())) // ignore messages if we don't have the channel key
+        router->enqueueReceivedMessage(p.release());
+}
+
+#if !defined(ARCH_NRF52) || NRF52_USE_JSON
+// returns true if this is a valid JSON envelope which we accept on downlink
+inline bool isValidJsonEnvelope(JSONObject &json)
+{
+    // if "sender" is provided, avoid processing packets we uplinked
+    return (json.find("sender") != json.end() ? (json["sender"]->AsString().compare(owner.id) != 0) : true) &&
+           (json.find("hopLimit") != json.end() ? json["hopLimit"]->IsNumber() : true) && // hop limit should be a number
+           (json.find("from") != json.end()) && json["from"]->IsNumber() &&
+           (json["from"]->AsNumber() == nodeDB->getNodeNum()) &&            // only accept message if the "from" is us
+           (json.find("type") != json.end()) && json["type"]->IsString() && // should specify a type
+           (json.find("payload") != json.end());                            // should have a payload
+}
+
+inline void onReceiveJson(byte *payload, size_t length)
+{
+    char payloadStr[length + 1];
+    memcpy(payloadStr, payload, length);
+    payloadStr[length] = 0; // null terminated string
+    std::unique_ptr json_value(JSON::Parse(payloadStr));
+    if (json_value == nullptr) {
+        LOG_ERROR("JSON received payload on MQTT but not a valid JSON");
+        return;
+    }
+
+    JSONObject json;
+    json = json_value->AsObject();
+
+    if (!isValidJsonEnvelope(json)) {
+        LOG_ERROR("JSON received payload on MQTT but not a valid envelope");
+        return;
+    }
+
+    // this is a valid envelope
+    if (json["type"]->AsString().compare("sendtext") == 0 && json["payload"]->IsString()) {
+        std::string jsonPayloadStr = json["payload"]->AsString();
+        LOG_INFO("JSON payload %s, length %u", jsonPayloadStr.c_str(), jsonPayloadStr.length());
+
+        // construct protobuf data packet using TEXT_MESSAGE, send it to the mesh
+        meshtastic_MeshPacket *p = router->allocForSending();
+        p->decoded.portnum = meshtastic_PortNum_TEXT_MESSAGE_APP;
+        if (json.find("channel") != json.end() && json["channel"]->IsNumber() &&
+            (json["channel"]->AsNumber() < channels.getNumChannels()))
+            p->channel = json["channel"]->AsNumber();
+        if (json.find("to") != json.end() && json["to"]->IsNumber())
+            p->to = json["to"]->AsNumber();
+        if (json.find("hopLimit") != json.end() && json["hopLimit"]->IsNumber())
+            p->hop_limit = json["hopLimit"]->AsNumber();
+        if (jsonPayloadStr.length() <= sizeof(p->decoded.payload.bytes)) {
+            memcpy(p->decoded.payload.bytes, jsonPayloadStr.c_str(), jsonPayloadStr.length());
+            p->decoded.payload.size = jsonPayloadStr.length();
+            service->sendToMesh(p, RX_SRC_LOCAL);
+        } else {
+            LOG_WARN("Received MQTT json payload too long, drop");
+        }
+    } else if (json["type"]->AsString().compare("sendposition") == 0 && json["payload"]->IsObject()) {
+        // invent the "sendposition" type for a valid envelope
+        JSONObject posit;
+        posit = json["payload"]->AsObject(); // get nested JSON Position
+        meshtastic_Position pos = meshtastic_Position_init_default;
+        if (posit.find("latitude_i") != posit.end() && posit["latitude_i"]->IsNumber())
+            pos.latitude_i = posit["latitude_i"]->AsNumber();
+        if (posit.find("longitude_i") != posit.end() && posit["longitude_i"]->IsNumber())
+            pos.longitude_i = posit["longitude_i"]->AsNumber();
+        if (posit.find("altitude") != posit.end() && posit["altitude"]->IsNumber())
+            pos.altitude = posit["altitude"]->AsNumber();
+        if (posit.find("time") != posit.end() && posit["time"]->IsNumber())
+            pos.time = posit["time"]->AsNumber();
+
+        // construct protobuf data packet using POSITION, send it to the mesh
+        meshtastic_MeshPacket *p = router->allocForSending();
+        p->decoded.portnum = meshtastic_PortNum_POSITION_APP;
+        if (json.find("channel") != json.end() && json["channel"]->IsNumber() &&
+            (json["channel"]->AsNumber() < channels.getNumChannels()))
+            p->channel = json["channel"]->AsNumber();
+        if (json.find("to") != json.end() && json["to"]->IsNumber())
+            p->to = json["to"]->AsNumber();
+        if (json.find("hopLimit") != json.end() && json["hopLimit"]->IsNumber())
+            p->hop_limit = json["hopLimit"]->AsNumber();
+        p->decoded.payload.size =
+            pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes), &meshtastic_Position_msg,
+                               &pos); // make the Data protobuf from position
+        service->sendToMesh(p, RX_SRC_LOCAL);
+    } else {
+        LOG_DEBUG("JSON ignore downlink message with unsupported type");
+    }
+}
+#endif
+
+/// Determines if the given IPAddress is a private IPv4 address, i.e. not routable on the public internet.
+bool isPrivateIpAddress(const IPAddress &ip)
+{
+    constexpr struct {
+        uint32_t network;
+        uint32_t mask;
+    } privateCidrRanges[] = {
+        {.network = 192u << 24 | 168 << 16, .mask = 0xffff0000}, // 192.168.0.0/16
+        {.network = 172u << 24 | 16 << 16, .mask = 0xfff00000},  // 172.16.0.0/12
+        {.network = 169u << 24 | 254 << 16, .mask = 0xffff0000}, // 169.254.0.0/16
+        {.network = 10u << 24, .mask = 0xff000000},              // 10.0.0.0/8
+        {.network = 127u << 24 | 1, .mask = 0xffffffff},         // 127.0.0.1/32
+    };
+    const uint32_t addr = ntohl(ip);
+    for (const auto &cidrRange : privateCidrRanges) {
+        if (cidrRange.network == (addr & cidrRange.mask)) {
+            LOG_INFO("MQTT server on a private IP");
+            return true;
+        }
+    }
+    return false;
+}
+
+// Separate a [:] string. Returns a pair containing the parsed host and port. If the port is
+// not present in the input string, or is invalid, the value of the `port` argument will be returned.
+std::pair parseHostAndPort(String server, uint16_t port = 0)
+{
+    const int delimIndex = server.indexOf(':');
+    if (delimIndex > 0) {
+        const long parsedPort = server.substring(delimIndex + 1, server.length()).toInt();
+        if (parsedPort < 1 || parsedPort > UINT16_MAX) {
+            LOG_WARN("Invalid MQTT port %d: %s", parsedPort, server.c_str());
+        } else {
+            port = parsedPort;
+        }
+        server[delimIndex] = 0;
+    }
+    return std::make_pair(std::move(server), port);
+}
+} // namespace
+
 void MQTT::mqttCallback(char *topic, byte *payload, unsigned int length)
 {
     mqtt->onReceive(topic, payload, length);
@@ -49,161 +265,32 @@ void MQTT::onClientProxyReceive(meshtastic_MqttClientProxyMessage msg)
 
 void MQTT::onReceive(char *topic, byte *payload, size_t length)
 {
-    meshtastic_ServiceEnvelope e = meshtastic_ServiceEnvelope_init_default;
-
-    if (moduleConfig.mqtt.json_enabled && (strncmp(topic, jsonTopic.c_str(), jsonTopic.length()) == 0)) {
-        // check if this is a json payload message by comparing the topic start
-        char payloadStr[length + 1];
-        memcpy(payloadStr, payload, length);
-        payloadStr[length] = 0; // null terminated string
-        JSONValue *json_value = JSON::Parse(payloadStr);
-        if (json_value != NULL) {
-            // check if it is a valid envelope
-            JSONObject json;
-            json = json_value->AsObject();
-
-            // parse the channel name from the topic string
-            // the topic has been checked above for having jsonTopic prefix, so just move past it
-            char *ptr = topic + jsonTopic.length();
-            ptr = strtok(ptr, "/") ? strtok(ptr, "/") : ptr; // if another "/" was added, parse string up to that character
-            meshtastic_Channel sendChannel = channels.getByName(ptr);
-            // We allow downlink JSON packets only on a channel named "mqtt"
-            if (strncasecmp(channels.getGlobalId(sendChannel.index), Channels::mqttChannel, strlen(Channels::mqttChannel)) == 0 &&
-                sendChannel.settings.downlink_enabled) {
-                if (isValidJsonEnvelope(json)) {
-                    // this is a valid envelope
-                    if (json["type"]->AsString().compare("sendtext") == 0 && json["payload"]->IsString()) {
-                        std::string jsonPayloadStr = json["payload"]->AsString();
-                        LOG_INFO("JSON payload %s, length %u", jsonPayloadStr.c_str(), jsonPayloadStr.length());
-
-                        // construct protobuf data packet using TEXT_MESSAGE, send it to the mesh
-                        meshtastic_MeshPacket *p = router->allocForSending();
-                        p->decoded.portnum = meshtastic_PortNum_TEXT_MESSAGE_APP;
-                        if (json.find("channel") != json.end() && json["channel"]->IsNumber() &&
-                            (json["channel"]->AsNumber() < channels.getNumChannels()))
-                            p->channel = json["channel"]->AsNumber();
-                        if (json.find("to") != json.end() && json["to"]->IsNumber())
-                            p->to = json["to"]->AsNumber();
-                        if (json.find("hopLimit") != json.end() && json["hopLimit"]->IsNumber())
-                            p->hop_limit = json["hopLimit"]->AsNumber();
-                        if (jsonPayloadStr.length() <= sizeof(p->decoded.payload.bytes)) {
-                            memcpy(p->decoded.payload.bytes, jsonPayloadStr.c_str(), jsonPayloadStr.length());
-                            p->decoded.payload.size = jsonPayloadStr.length();
-                            service->sendToMesh(p, RX_SRC_LOCAL);
-                        } else {
-                            LOG_WARN("Received MQTT json payload too long, drop");
-                        }
-                    } else if (json["type"]->AsString().compare("sendposition") == 0 && json["payload"]->IsObject()) {
-                        // invent the "sendposition" type for a valid envelope
-                        JSONObject posit;
-                        posit = json["payload"]->AsObject(); // get nested JSON Position
-                        meshtastic_Position pos = meshtastic_Position_init_default;
-                        if (posit.find("latitude_i") != posit.end() && posit["latitude_i"]->IsNumber())
-                            pos.latitude_i = posit["latitude_i"]->AsNumber();
-                        if (posit.find("longitude_i") != posit.end() && posit["longitude_i"]->IsNumber())
-                            pos.longitude_i = posit["longitude_i"]->AsNumber();
-                        if (posit.find("altitude") != posit.end() && posit["altitude"]->IsNumber())
-                            pos.altitude = posit["altitude"]->AsNumber();
-                        if (posit.find("time") != posit.end() && posit["time"]->IsNumber())
-                            pos.time = posit["time"]->AsNumber();
-
-                        // construct protobuf data packet using POSITION, send it to the mesh
-                        meshtastic_MeshPacket *p = router->allocForSending();
-                        p->decoded.portnum = meshtastic_PortNum_POSITION_APP;
-                        if (json.find("channel") != json.end() && json["channel"]->IsNumber() &&
-                            (json["channel"]->AsNumber() < channels.getNumChannels()))
-                            p->channel = json["channel"]->AsNumber();
-                        if (json.find("to") != json.end() && json["to"]->IsNumber())
-                            p->to = json["to"]->AsNumber();
-                        if (json.find("hopLimit") != json.end() && json["hopLimit"]->IsNumber())
-                            p->hop_limit = json["hopLimit"]->AsNumber();
-                        p->decoded.payload.size =
-                            pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes),
-                                               &meshtastic_Position_msg, &pos); // make the Data protobuf from position
-                        service->sendToMesh(p, RX_SRC_LOCAL);
-                    } else {
-                        LOG_DEBUG("JSON ignore downlink message with unsupported type");
-                    }
-                } else {
-                    LOG_ERROR("JSON received payload on MQTT but not a valid envelope");
-                }
-            } else {
-                LOG_WARN("JSON downlink received on channel not called 'mqtt' or without downlink enabled");
-            }
-        } else {
-            // no json, this is an invalid payload
-            LOG_ERROR("JSON received payload on MQTT but not a valid JSON");
-        }
-        delete json_value;
-    } else {
-        if (length == 0) {
-            LOG_WARN("Empty MQTT payload received, topic %s!", topic);
-            return;
-        } else if (!pb_decode_from_bytes(payload, length, &meshtastic_ServiceEnvelope_msg, &e)) {
-            LOG_ERROR("Invalid MQTT service envelope, topic %s, len %u!", topic, length);
-            return;
-        } else {
-            if (e.channel_id == NULL || e.gateway_id == NULL) {
-                LOG_ERROR("Invalid MQTT service envelope, topic %s, len %u!", topic, length);
-                return;
-            }
-            meshtastic_Channel ch = channels.getByName(e.channel_id);
-            if (strcmp(e.gateway_id, owner.id) == 0) {
-                // Generate an implicit ACK towards ourselves (handled and processed only locally!) for this message.
-                // We do this because packets are not rebroadcasted back into MQTT anymore and we assume that at least one node
-                // receives it when we get our own packet back. Then we'll stop our retransmissions.
-                if (e.packet && isFromUs(e.packet))
-                    routingModule->sendAckNak(meshtastic_Routing_Error_NONE, getFrom(e.packet), e.packet->id, ch.index);
-                else
-                    LOG_INFO("Ignore downlink message we originally sent");
-            } else {
-                // Find channel by channel_id and check downlink_enabled
-                if ((strcmp(e.channel_id, "PKI") == 0 && e.packet) ||
-                    (strcmp(e.channel_id, channels.getGlobalId(ch.index)) == 0 && e.packet && ch.settings.downlink_enabled)) {
-                    LOG_INFO("Received MQTT topic %s, len=%u", topic, length);
-                    meshtastic_MeshPacket *p = packetPool.allocCopy(*e.packet);
-                    p->via_mqtt = true; // Mark that the packet was received via MQTT
-
-                    if (isFromUs(p)) {
-                        LOG_INFO("Ignore downlink message we originally sent");
-                        packetPool.release(p);
-                        return;
-                    }
-                    if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
-                        if (moduleConfig.mqtt.encryption_enabled) {
-                            LOG_INFO("Ignore decoded message on MQTT, encryption is enabled");
-                            packetPool.release(p);
-                            return;
-                        }
-                        if (p->decoded.portnum == meshtastic_PortNum_ADMIN_APP) {
-                            LOG_INFO("Ignore decoded admin packet");
-                            packetPool.release(p);
-                            return;
-                        }
-                        p->channel = ch.index;
-                    }
-
-                    // PKI messages get accepted even if we can't decrypt
-                    if (router && p->which_payload_variant == meshtastic_MeshPacket_encrypted_tag &&
-                        strcmp(e.channel_id, "PKI") == 0) {
-                        const meshtastic_NodeInfoLite *tx = nodeDB->getMeshNode(getFrom(p));
-                        const meshtastic_NodeInfoLite *rx = nodeDB->getMeshNode(p->to);
-                        // Only accept PKI messages to us, or if we have both the sender and receiver in our nodeDB, as then it's
-                        // likely they discovered each other via a channel we have downlink enabled for
-                        if (isToUs(p) || (tx && tx->has_user && rx && rx->has_user))
-                            router->enqueueReceivedMessage(p);
-                    } else if (router && perhapsDecode(p)) // ignore messages if we don't have the channel key
-                        router->enqueueReceivedMessage(p);
-                    else
-                        packetPool.release(p);
-                }
-            }
-        }
-        // make sure to free both strings and the MeshPacket (passing in NULL is acceptable)
-        free(e.channel_id);
-        free(e.gateway_id);
-        free(e.packet);
+    if (length == 0) {
+        LOG_WARN("Empty MQTT payload received, topic %s!", topic);
+        return;
     }
+
+    // check if this is a json payload message by comparing the topic start
+    if (moduleConfig.mqtt.json_enabled && (strncmp(topic, jsonTopic.c_str(), jsonTopic.length()) == 0)) {
+#if !defined(ARCH_NRF52) || NRF52_USE_JSON
+        // parse the channel name from the topic string
+        // the topic has been checked above for having jsonTopic prefix, so just move past it
+        char *channelName = topic + jsonTopic.length();
+        // if another "/" was added, parse string up to that character
+        channelName = strtok(channelName, "/") ? strtok(channelName, "/") : channelName;
+        // We allow downlink JSON packets only on a channel named "mqtt"
+        meshtastic_Channel &sendChannel = channels.getByName(channelName);
+        if (!(strncasecmp(channels.getGlobalId(sendChannel.index), Channels::mqttChannel, strlen(Channels::mqttChannel)) == 0 &&
+              sendChannel.settings.downlink_enabled)) {
+            LOG_WARN("JSON downlink received on channel not called 'mqtt' or without downlink enabled");
+            return;
+        }
+        onReceiveJson(payload, length);
+#endif
+        return;
+    }
+
+    onReceiveProto(topic, payload, length);
 }
 
 void mqttInit()
@@ -240,10 +327,10 @@ MQTT::MQTT() : concurrency::OSThread("mqtt"), mqttQueue(MAX_MQTT_QUEUE)
                 moduleConfig.mqtt.map_report_settings.publish_interval_secs, default_map_publish_interval_secs);
         }
 
-        isMqttServerAddressPrivate = isPrivateIpAddress(moduleConfig.mqtt.address);
-        if (isMqttServerAddressPrivate) {
-            LOG_INFO("MQTT server on a private IP");
-        }
+        String host = parseHostAndPort(moduleConfig.mqtt.address).first;
+        isConfiguredForDefaultServer = host.length() == 0 || host == default_mqtt_address;
+        IPAddress ip;
+        isMqttServerAddressPrivate = ip.fromString(host.c_str()) && isPrivateIpAddress(ip);
 
 #if HAS_NETWORKING
         if (!moduleConfig.mqtt.proxy_to_client_enabled)
@@ -336,7 +423,7 @@ void MQTT::reconnect()
             mqttPassword = moduleConfig.mqtt.password;
         }
 #if HAS_WIFI && !defined(ARCH_PORTDUINO)
-#if !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(RPI_PICO)
+#if !defined(CONFIG_IDF_TARGET_ESP32C6)
         if (moduleConfig.mqtt.tls_enabled) {
             // change default for encrypted to 8883
             try {
@@ -359,14 +446,9 @@ void MQTT::reconnect()
         pubSub.setClient(mqttClient);
 #endif
 
-        String server = String(serverAddr);
-        int delimIndex = server.indexOf(':');
-        if (delimIndex > 0) {
-            String port = server.substring(delimIndex + 1, server.length());
-            server[delimIndex] = 0;
-            serverPort = port.toInt();
-            serverAddr = server.c_str();
-        }
+        std::pair hostAndPort = parseHostAndPort(serverAddr, serverPort);
+        serverAddr = hostAndPort.first.c_str();
+        serverPort = hostAndPort.second;
         pubSub.setServer(serverAddr, serverPort);
         pubSub.setBufferSize(512);
 
@@ -379,6 +461,7 @@ void MQTT::reconnect()
             enabled = true; // Start running background process again
             runASAP = true;
             reconnectCount = 0;
+            isMqttServerAddressPrivate = isPrivateIpAddress(mqttClient.remoteIP());
 
             publishNodeInfo();
             sendSubscriptions();
@@ -495,39 +578,37 @@ void MQTT::publishNodeInfo()
 }
 void MQTT::publishQueuedMessages()
 {
-    if (!mqttQueue.isEmpty()) {
-        LOG_DEBUG("Publish enqueued MQTT message");
-        meshtastic_ServiceEnvelope *env = mqttQueue.dequeuePtr(0);
-        size_t numBytes = pb_encode_to_bytes(bytes, sizeof(bytes), &meshtastic_ServiceEnvelope_msg, env);
-        std::string topic;
-        if (env->packet->pki_encrypted) {
-            topic = cryptTopic + "PKI/" + owner.id;
-        } else {
-            topic = cryptTopic + env->channel_id + "/" + owner.id;
-        }
-        LOG_INFO("publish %s, %u bytes from queue", topic.c_str(), numBytes);
+    if (mqttQueue.isEmpty())
+        return;
 
-        publish(topic.c_str(), bytes, numBytes, false);
+    LOG_DEBUG("Publish enqueued MQTT message");
+    const std::unique_ptr entry(mqttQueue.dequeuePtr(0));
+    LOG_INFO("publish %s, %u bytes from queue", entry->topic.c_str(), entry->envBytes.size());
+    publish(entry->topic.c_str(), entry->envBytes.data(), entry->envBytes.size(), false);
 
 #if !defined(ARCH_NRF52) ||                                                                                                      \
     defined(NRF52_USE_JSON) // JSON is not supported on nRF52, see issue #2804 ### Fixed by using ArduinoJson ###
-        if (moduleConfig.mqtt.json_enabled) {
-            // handle json topic
-            auto jsonString = MeshPacketSerializer::JsonSerialize(env->packet);
-            if (jsonString.length() != 0) {
-                std::string topicJson;
-                if (env->packet->pki_encrypted) {
-                    topicJson = jsonTopic + "PKI/" + owner.id;
-                } else {
-                    topicJson = jsonTopic + env->channel_id + "/" + owner.id;
-                }
-                LOG_INFO("JSON publish message to %s, %u bytes: %s", topicJson.c_str(), jsonString.length(), jsonString.c_str());
-                publish(topicJson.c_str(), jsonString.c_str(), false);
-            }
-        }
-#endif // ARCH_NRF52 NRF52_USE_JSON
-        mqttPool.release(env);
+    if (!moduleConfig.mqtt.json_enabled)
+        return;
+
+    // handle json topic
+    const DecodedServiceEnvelope env(entry->envBytes.data(), entry->envBytes.size());
+    if (!env.validDecode || env.packet == NULL || env.channel_id == NULL)
+        return;
+
+    auto jsonString = MeshPacketSerializer::JsonSerialize(env.packet);
+    if (jsonString.length() == 0)
+        return;
+
+    std::string topicJson;
+    if (env.packet->pki_encrypted) {
+        topicJson = jsonTopic + "PKI/" + owner.id;
+    } else {
+        topicJson = jsonTopic + env.channel_id + "/" + owner.id;
     }
+    LOG_INFO("JSON publish message to %s, %u bytes: %s", topicJson.c_str(), jsonString.length(), jsonString.c_str());
+    publish(topicJson.c_str(), jsonString.c_str(), false);
+#endif // ARCH_NRF52 NRF52_USE_JSON
 }
 
 void MQTT::onSend(const meshtastic_MeshPacket &mp_encrypted, const meshtastic_MeshPacket &mp_decoded, ChannelIndex chIndex)
@@ -546,8 +627,7 @@ void MQTT::onSend(const meshtastic_MeshPacket &mp_encrypted, const meshtastic_Me
     // mp_decoded will not be decoded when it's PKI encrypted and not directed to us
     if (mp_decoded.which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
         // For uplinking other's packets, check if it's not OK to MQTT or if it's an older packet without the bitfield
-        bool dontUplink = !mp_decoded.decoded.has_bitfield ||
-                          (mp_decoded.decoded.has_bitfield && !(mp_decoded.decoded.bitfield & BITFIELD_OK_TO_MQTT_MASK));
+        bool dontUplink = !mp_decoded.decoded.has_bitfield || !(mp_decoded.decoded.bitfield & BITFIELD_OK_TO_MQTT_MASK);
         // check for the lowest bit of the data bitfield set false, and the use of one of the default keys.
         if (!isFromUs(&mp_decoded) && !isMqttServerAddressPrivate && dontUplink &&
             (ch.settings.psk.size < 2 || (ch.settings.psk.size == 16 && memcmp(ch.settings.psk.bytes, defaultpsk, 16)) ||
@@ -556,9 +636,8 @@ void MQTT::onSend(const meshtastic_MeshPacket &mp_encrypted, const meshtastic_Me
             return;
         }
 
-        if (strcmp(moduleConfig.mqtt.address, default_mqtt_address) == 0 &&
-            (mp_decoded.decoded.portnum == meshtastic_PortNum_RANGE_TEST_APP ||
-             mp_decoded.decoded.portnum == meshtastic_PortNum_DETECTION_SENSOR_APP)) {
+        if (isConfiguredForDefaultServer && (mp_decoded.decoded.portnum == meshtastic_PortNum_RANGE_TEST_APP ||
+                                             mp_decoded.decoded.portnum == meshtastic_PortNum_DETECTION_SENSOR_APP)) {
             LOG_DEBUG("MQTT onSend - Ignoring range test or detection sensor message on public mqtt");
             return;
         }
@@ -566,59 +645,56 @@ void MQTT::onSend(const meshtastic_MeshPacket &mp_encrypted, const meshtastic_Me
     // Either encrypted packet (we couldn't decrypt) is marked as pki_encrypted, or we could decode the PKI encrypted packet
     bool isPKIEncrypted = mp_encrypted.pki_encrypted || mp_decoded.pki_encrypted;
     // If it was to a channel, check uplink enabled, else must be pki_encrypted
-    if ((ch.settings.uplink_enabled && !isPKIEncrypted) || isPKIEncrypted) {
-        const char *channelId = isPKIEncrypted ? "PKI" : channels.getGlobalId(chIndex);
+    if (!(ch.settings.uplink_enabled || isPKIEncrypted))
+        return;
+    const char *channelId = isPKIEncrypted ? "PKI" : channels.getGlobalId(chIndex);
 
-        meshtastic_ServiceEnvelope *env = mqttPool.allocZeroed();
-        env->channel_id = (char *)channelId;
-        env->gateway_id = owner.id;
+    LOG_DEBUG("MQTT onSend - Publish ");
+    const meshtastic_MeshPacket *p;
+    if (moduleConfig.mqtt.encryption_enabled) {
+        p = &mp_encrypted;
+        LOG_DEBUG("encrypted message");
+    } else if (mp_decoded.which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
+        p = &mp_decoded;
+        LOG_DEBUG("portnum %i message", mp_decoded.decoded.portnum);
+    } else {
+        LOG_DEBUG("nothing, pkt not decrypted");
+        return; // Don't upload a still-encrypted PKI packet if not encryption_enabled
+    }
 
-        LOG_DEBUG("MQTT onSend - Publish ");
-        if (moduleConfig.mqtt.encryption_enabled) {
-            env->packet = (meshtastic_MeshPacket *)&mp_encrypted;
-            LOG_DEBUG("encrypted message");
-        } else if (mp_decoded.which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
-            env->packet = (meshtastic_MeshPacket *)&mp_decoded;
-            LOG_DEBUG("portnum %i message", env->packet->decoded.portnum);
-        } else {
-            LOG_DEBUG("nothing, pkt not decrypted");
-            mqttPool.release(env);
-            return; // Don't upload a still-encrypted PKI packet if not encryption_enabled
-        }
+    const meshtastic_ServiceEnvelope env = {
+        .packet = const_cast(p), .channel_id = const_cast(channelId), .gateway_id = owner.id};
+    size_t numBytes = pb_encode_to_bytes(bytes, sizeof(bytes), &meshtastic_ServiceEnvelope_msg, &env);
+    std::string topic = cryptTopic + channelId + "/" + owner.id;
 
-        if (moduleConfig.mqtt.proxy_to_client_enabled || this->isConnectedDirectly()) {
-            size_t numBytes = pb_encode_to_bytes(bytes, sizeof(bytes), &meshtastic_ServiceEnvelope_msg, env);
-            std::string topic = cryptTopic + channelId + "/" + owner.id;
-            LOG_DEBUG("MQTT Publish %s, %u bytes", topic.c_str(), numBytes);
-
-            publish(topic.c_str(), bytes, numBytes, false);
+    if (moduleConfig.mqtt.proxy_to_client_enabled || this->isConnectedDirectly()) {
+        LOG_DEBUG("MQTT Publish %s, %u bytes", topic.c_str(), numBytes);
+        publish(topic.c_str(), bytes, numBytes, false);
 
 #if !defined(ARCH_NRF52) ||                                                                                                      \
     defined(NRF52_USE_JSON) // JSON is not supported on nRF52, see issue #2804 ### Fixed by using ArduinoJson ###
-            if (moduleConfig.mqtt.json_enabled) {
-                // handle json topic
-                auto jsonString = MeshPacketSerializer::JsonSerialize((meshtastic_MeshPacket *)&mp_decoded);
-                if (jsonString.length() != 0) {
-                    std::string topicJson = jsonTopic + channelId + "/" + owner.id;
-                    LOG_INFO("JSON publish message to %s, %u bytes: %s", topicJson.c_str(), jsonString.length(),
-                             jsonString.c_str());
-                    publish(topicJson.c_str(), jsonString.c_str(), false);
-                }
-            }
+        if (!moduleConfig.mqtt.json_enabled)
+            return;
+        // handle json topic
+        auto jsonString = MeshPacketSerializer::JsonSerialize(&mp_decoded);
+        if (jsonString.length() == 0)
+            return;
+        std::string topicJson = jsonTopic + channelId + "/" + owner.id;
+        LOG_INFO("JSON publish message to %s, %u bytes: %s", topicJson.c_str(), jsonString.length(), jsonString.c_str());
+        publish(topicJson.c_str(), jsonString.c_str(), false);
 #endif // ARCH_NRF52 NRF52_USE_JSON
+    } else {
+        LOG_INFO("MQTT not connected, queue packet");
+        QueueEntry *entry;
+        if (mqttQueue.numFree() == 0) {
+            LOG_WARN("MQTT queue is full, discard oldest");
+            entry = mqttQueue.dequeuePtr(0);
         } else {
-            LOG_INFO("MQTT not connected, queue packet");
-            if (mqttQueue.numFree() == 0) {
-                LOG_WARN("MQTT queue is full, discard oldest");
-                meshtastic_ServiceEnvelope *d = mqttQueue.dequeuePtr(0);
-                if (d)
-                    mqttPool.release(d);
-            }
-            // make a copy of serviceEnvelope and queue it
-            meshtastic_ServiceEnvelope *copied = mqttPool.allocCopy(*env);
-            assert(mqttQueue.enqueue(copied, 0));
+            entry = new QueueEntry;
         }
-        mqttPool.release(env);
+        entry->topic = std::move(topic);
+        entry->envBytes.assign(bytes, numBytes);
+        assert(mqttQueue.enqueue(entry, 0));
     }
 }
 
@@ -627,148 +703,68 @@ void MQTT::perhapsReportToMap()
     if (!moduleConfig.mqtt.map_reporting_enabled || !(moduleConfig.mqtt.proxy_to_client_enabled || isConnectedDirectly()))
         return;
 
-    if (Throttle::isWithinTimespanMs(last_report_to_map, map_publish_interval_msecs)) {
+    if (Throttle::isWithinTimespanMs(last_report_to_map, map_publish_interval_msecs))
         return;
-    } else {
-        if (map_position_precision == 0 || (localPosition.latitude_i == 0 && localPosition.longitude_i == 0)) {
-            last_report_to_map = millis();
-            if (map_position_precision == 0)
-                LOG_WARN("MQTT Map report enabled, but precision is 0");
-            if (localPosition.latitude_i == 0 && localPosition.longitude_i == 0)
-                LOG_WARN("MQTT Map report enabled, but no position available");
-            return;
-        }
 
-        // Allocate ServiceEnvelope and fill it
-        meshtastic_ServiceEnvelope *se = mqttPool.allocZeroed();
-        se->channel_id = (char *)channels.getGlobalId(channels.getPrimaryIndex()); // Use primary channel as the channel_id
-        se->gateway_id = owner.id;
-
-        // Allocate MeshPacket and fill it
-        meshtastic_MeshPacket *mp = packetPool.allocZeroed();
-        mp->which_payload_variant = meshtastic_MeshPacket_decoded_tag;
-        mp->from = nodeDB->getNodeNum();
-        mp->to = NODENUM_BROADCAST;
-        mp->decoded.portnum = meshtastic_PortNum_MAP_REPORT_APP;
-
-        // Fill MapReport message
-        meshtastic_MapReport mapReport = meshtastic_MapReport_init_default;
-        memcpy(mapReport.long_name, owner.long_name, sizeof(owner.long_name));
-        memcpy(mapReport.short_name, owner.short_name, sizeof(owner.short_name));
-        mapReport.role = config.device.role;
-        mapReport.hw_model = owner.hw_model;
-        strncpy(mapReport.firmware_version, optstr(APP_VERSION), sizeof(mapReport.firmware_version));
-        mapReport.region = config.lora.region;
-        mapReport.modem_preset = config.lora.modem_preset;
-        mapReport.has_default_channel = channels.hasDefaultChannel();
-
-        // Set position with precision (same as in PositionModule)
-        if (map_position_precision < 32 && map_position_precision > 0) {
-            mapReport.latitude_i = localPosition.latitude_i & (UINT32_MAX << (32 - map_position_precision));
-            mapReport.longitude_i = localPosition.longitude_i & (UINT32_MAX << (32 - map_position_precision));
-            mapReport.latitude_i += (1 << (31 - map_position_precision));
-            mapReport.longitude_i += (1 << (31 - map_position_precision));
-        } else {
-            mapReport.latitude_i = localPosition.latitude_i;
-            mapReport.longitude_i = localPosition.longitude_i;
-        }
-        mapReport.altitude = localPosition.altitude;
-        mapReport.position_precision = map_position_precision;
-
-        mapReport.num_online_local_nodes = nodeDB->getNumOnlineMeshNodes(true);
-
-        // Encode MapReport message and set it to MeshPacket in ServiceEnvelope
-        mp->decoded.payload.size = pb_encode_to_bytes(mp->decoded.payload.bytes, sizeof(mp->decoded.payload.bytes),
-                                                      &meshtastic_MapReport_msg, &mapReport);
-        se->packet = mp;
-
-        size_t numBytes = pb_encode_to_bytes(bytes, sizeof(bytes), &meshtastic_ServiceEnvelope_msg, se);
-
-        LOG_INFO("MQTT Publish map report to %s", mapTopic.c_str());
-        publish(mapTopic.c_str(), bytes, numBytes, false);
-
-        // Release the allocated memory for ServiceEnvelope and MeshPacket
-        mqttPool.release(se);
-        packetPool.release(mp);
-
-        // Update the last report time
+    if (map_position_precision == 0 || (localPosition.latitude_i == 0 && localPosition.longitude_i == 0)) {
         last_report_to_map = millis();
-    }
-}
-
-bool MQTT::isValidJsonEnvelope(JSONObject &json)
-{
-    // if "sender" is provided, avoid processing packets we uplinked
-    return (json.find("sender") != json.end() ? (json["sender"]->AsString().compare(owner.id) != 0) : true) &&
-           (json.find("hopLimit") != json.end() ? json["hopLimit"]->IsNumber() : true) && // hop limit should be a number
-           (json.find("from") != json.end()) && json["from"]->IsNumber() &&
-           (json["from"]->AsNumber() == nodeDB->getNodeNum()) &&            // only accept message if the "from" is us
-           (json.find("type") != json.end()) && json["type"]->IsString() && // should specify a type
-           (json.find("payload") != json.end());                            // should have a payload
-}
-
-bool MQTT::isPrivateIpAddress(const char address[])
-{
-    // Min. length like 10.0.0.0 (8), max like 192.168.255.255:65535 (21)
-    size_t length = strlen(address);
-    if (length < 8 || length > 21) {
-        return false;
+        if (map_position_precision == 0)
+            LOG_WARN("MQTT Map report enabled, but precision is 0");
+        if (localPosition.latitude_i == 0 && localPosition.longitude_i == 0)
+            LOG_WARN("MQTT Map report enabled, but no position available");
+        return;
     }
 
-    // Ensure the address contains only digits and dots and maybe a colon.
-    // Some limited validation is done.
-    // Even if it's not a valid IP address, we will know it's not a domain.
-    bool hasColon = false;
-    int numDots = 0;
-    for (size_t i = 0; i < length; i++) {
-        if (!isdigit(address[i]) && address[i] != '.' && address[i] != ':') {
-            return false;
-        }
+    // Allocate MeshPacket and fill it
+    meshtastic_MeshPacket *mp = packetPool.allocZeroed();
+    mp->which_payload_variant = meshtastic_MeshPacket_decoded_tag;
+    mp->from = nodeDB->getNodeNum();
+    mp->to = NODENUM_BROADCAST;
+    mp->decoded.portnum = meshtastic_PortNum_MAP_REPORT_APP;
 
-        // Dots can't be the first character, immediately follow another dot,
-        // occur more than 3 times, or occur after a colon.
-        if (address[i] == '.') {
-            if (++numDots > 3 || i == 0 || address[i - 1] == '.' || hasColon) {
-                return false;
-            }
-        }
-        // There can only be a single colon, and it can only occur after 3 dots
-        else if (address[i] == ':') {
-            if (hasColon || numDots < 3) {
-                return false;
-            }
+    // Fill MapReport message
+    meshtastic_MapReport mapReport = meshtastic_MapReport_init_default;
+    memcpy(mapReport.long_name, owner.long_name, sizeof(owner.long_name));
+    memcpy(mapReport.short_name, owner.short_name, sizeof(owner.short_name));
+    mapReport.role = config.device.role;
+    mapReport.hw_model = owner.hw_model;
+    strncpy(mapReport.firmware_version, optstr(APP_VERSION), sizeof(mapReport.firmware_version));
+    mapReport.region = config.lora.region;
+    mapReport.modem_preset = config.lora.modem_preset;
+    mapReport.has_default_channel = channels.hasDefaultChannel();
 
-            hasColon = true;
-        }
+    // Set position with precision (same as in PositionModule)
+    if (map_position_precision < 32 && map_position_precision > 0) {
+        mapReport.latitude_i = localPosition.latitude_i & (UINT32_MAX << (32 - map_position_precision));
+        mapReport.longitude_i = localPosition.longitude_i & (UINT32_MAX << (32 - map_position_precision));
+        mapReport.latitude_i += (1 << (31 - map_position_precision));
+        mapReport.longitude_i += (1 << (31 - map_position_precision));
+    } else {
+        mapReport.latitude_i = localPosition.latitude_i;
+        mapReport.longitude_i = localPosition.longitude_i;
     }
+    mapReport.altitude = localPosition.altitude;
+    mapReport.position_precision = map_position_precision;
 
-    // Final validation for IPv4 address and port format.
-    // Note that the values of octets haven't been tested, only the address format.
-    if (numDots != 3) {
-        return false;
-    }
+    mapReport.num_online_local_nodes = nodeDB->getNumOnlineMeshNodes(true);
 
-    // Check the easy ones first.
-    if (strcmp(address, "127.0.0.1") == 0 || strncmp(address, "10.", 3) == 0 || strncmp(address, "192.168", 7) == 0 ||
-        strncmp(address, "169.254", 7) == 0) {
-        return true;
-    }
+    // Encode MapReport message into the MeshPacket
+    mp->decoded.payload.size =
+        pb_encode_to_bytes(mp->decoded.payload.bytes, sizeof(mp->decoded.payload.bytes), &meshtastic_MapReport_msg, &mapReport);
 
-    // See if it's definitely not a 172 address.
-    if (strncmp(address, "172", 3) != 0) {
-        return false;
-    }
+    // Encode the MeshPacket into a binary ServiceEnvelope and publish
+    const meshtastic_ServiceEnvelope se = {
+        .packet = mp,
+        .channel_id = (char *)channels.getGlobalId(channels.getPrimaryIndex()), // Use primary channel as the channel_id
+        .gateway_id = owner.id};
+    size_t numBytes = pb_encode_to_bytes(bytes, sizeof(bytes), &meshtastic_ServiceEnvelope_msg, &se);
 
-    // We know it's a 172 address, now see if the second octet is 2 digits.
-    if (address[6] != '.') {
-        return false;
-    }
+    LOG_INFO("MQTT Publish map report to %s", mapTopic.c_str());
+    publish(mapTopic.c_str(), bytes, numBytes, false);
 
-    // Copy the second octet into a secondary buffer we can null-terminate and parse.
-    char octet2[3];
-    strncpy(octet2, address + 4, 2);
-    octet2[2] = 0;
+    // Release the allocated memory for MeshPacket
+    packetPool.release(mp);
 
-    int octet2Num = atoi(octet2);
-    return octet2Num >= 16 && octet2Num <= 31;
+    // Update the last report time
+    last_report_to_map = millis();
 }
\ No newline at end of file
diff --git a/src/mqtt/MQTT.h b/src/mqtt/MQTT.h
index fcefb94a2..cb1fffcc9 100644
--- a/src/mqtt/MQTT.h
+++ b/src/mqtt/MQTT.h
@@ -5,7 +5,9 @@
 #include "concurrency/OSThread.h"
 #include "mesh/Channels.h"
 #include "mesh/generated/meshtastic/mqtt.pb.h"
+#if !defined(ARCH_NRF52) || NRF52_USE_JSON
 #include "serialization/JSON.h"
+#endif
 #if HAS_WIFI
 #include 
 #if !defined(ARCH_PORTDUINO)
@@ -35,7 +37,7 @@ class MQTT : private concurrency::OSThread
 #if HAS_WIFI
     WiFiClient mqttClient;
 #if !defined(ARCH_PORTDUINO)
-#if defined(ESP_ARDUINO_VERSION_MAJOR) && ESP_ARDUINO_VERSION_MAJOR < 3
+#if (defined(ESP_ARDUINO_VERSION_MAJOR) && ESP_ARDUINO_VERSION_MAJOR < 3) || defined(RPI_PICO)
     WiFiClientSecure wifiSecureClient;
 #endif
 #endif
@@ -77,10 +79,17 @@ class MQTT : private concurrency::OSThread
 
     void start() { setIntervalFromNow(0); };
 
+    bool isUsingDefaultServer() { return isConfiguredForDefaultServer; }
+
   protected:
-    PointerQueue mqttQueue;
+    struct QueueEntry {
+        std::string topic;
+        std::basic_string envBytes; // binary/pb_encode_to_bytes ServiceEnvelope
+    };
+    PointerQueue mqttQueue;
 
     int reconnectCount = 0;
+    bool isConfiguredForDefaultServer = true;
 
     virtual int32_t runOnce() override;
 
@@ -117,13 +126,6 @@ class MQTT : private concurrency::OSThread
     // Check if we should report unencrypted information about our node for consumption by a map
     void perhapsReportToMap();
 
-    // returns true if this is a valid JSON envelope which we accept on downlink
-    bool isValidJsonEnvelope(JSONObject &json);
-
-    /// Determines if the given address is a private IPv4 address, i.e. not routable on the public internet.
-    /// These are the ranges: 127.0.0.1, 10.0.0.0-10.255.255.255, 172.16.0.0-172.31.255.255, 192.168.0.0-192.168.255.255.
-    bool isPrivateIpAddress(const char address[]);
-
     /// Return 0 if sleep is okay, veto sleep if we are connected to pubsub server
     // int preflightSleepCb(void *unused = NULL) { return pubSub.connected() ? 1 : 0; }
 };
diff --git a/src/platform/esp32/architecture.h b/src/platform/esp32/architecture.h
index 1a274aa28..742b295b5 100644
--- a/src/platform/esp32/architecture.h
+++ b/src/platform/esp32/architecture.h
@@ -174,6 +174,8 @@
 #define HW_VENDOR meshtastic_HardwareModel_SENSECAP_INDICATOR
 #elif defined(SEEED_XIAO_S3)
 #define HW_VENDOR meshtastic_HardwareModel_SEEED_XIAO_S3
+#elif defined(MESH_TAB)
+#define HW_VENDOR meshtastic_HardwareModel_MESH_TAB
 #endif
 
 // -----------------------------------------------------------------------------
diff --git a/src/platform/portduino/PortduinoGlue.cpp b/src/platform/portduino/PortduinoGlue.cpp
index 686564cc1..0c981bf16 100644
--- a/src/platform/portduino/PortduinoGlue.cpp
+++ b/src/platform/portduino/PortduinoGlue.cpp
@@ -5,21 +5,30 @@
 #include "sleep.h"
 #include "target_specific.h"
 
+#include "PortduinoGlue.h"
+#include "api/ServerAPI.h"
+#include "linux/gpio/LinuxGPIOPin.h"
+#include "meshUtils.h"
+#include "yaml-cpp/yaml.h"
 #include 
 #include 
-
-#include "PortduinoGlue.h"
-#include "linux/gpio/LinuxGPIOPin.h"
-#include "yaml-cpp/yaml.h"
+#include 
+#include 
 #include 
+#include 
 #include 
 #include 
+#include 
 #include 
 
+#include "platform/portduino/USBHal.h"
+
 std::map settingsMap;
 std::map settingsStrings;
 std::ofstream traceFile;
+Ch341Hal *ch341Hal = nullptr;
 char *configPath = nullptr;
+char *optionMac = nullptr;
 
 // FIXME - move setBluetoothEnable into a HALPlatform class
 void setBluetoothEnable(bool enable)
@@ -34,7 +43,7 @@ void cpuDeepSleep(uint32_t msecs)
 
 void updateBatteryLevel(uint8_t level) NOT_IMPLEMENTED("updateBatteryLevel");
 
-int TCPPort = 4403;
+int TCPPort = SERVER_API_DEFAULT_PORT;
 
 static error_t parse_opt(int key, char *arg, struct argp_state *state)
 {
@@ -48,6 +57,10 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state)
     case 'c':
         configPath = arg;
         break;
+    case 'h':
+        optionMac = arg;
+        break;
+
     case ARGP_KEY_ARG:
         return 0;
     default:
@@ -60,6 +73,7 @@ void portduinoCustomInit()
 {
     static struct argp_option options[] = {{"port", 'p', "PORT", 0, "The TCP port to use."},
                                            {"config", 'c', "CONFIG_PATH", 0, "Full path of the .yaml config file to use."},
+                                           {"hwid", 'h', "HWID", 0, "The mac address to assign to this virtual machine"},
                                            {0}};
     static void *childArguments;
     static char doc[] = "Meshtastic native build.";
@@ -69,6 +83,49 @@ void portduinoCustomInit()
     portduinoAddArguments(child, childArguments);
 }
 
+void getMacAddr(uint8_t *dmac)
+{
+    // We should store this value, and short-circuit all this if it's already been set.
+    if (optionMac != nullptr && strlen(optionMac) > 0) {
+        if (strlen(optionMac) >= 12) {
+            MAC_from_string(optionMac, dmac);
+        } else {
+            uint32_t hwId = {0};
+            sscanf(optionMac, "%u", &hwId);
+            dmac[0] = 0x80;
+            dmac[1] = 0;
+            dmac[2] = hwId >> 24;
+            dmac[3] = hwId >> 16;
+            dmac[4] = hwId >> 8;
+            dmac[5] = hwId & 0xff;
+        }
+    } else if (settingsStrings[mac_address].length() > 11) {
+        MAC_from_string(settingsStrings[mac_address], dmac);
+        exit;
+    } else {
+
+        struct hci_dev_info di = {0};
+        di.dev_id = 0;
+        bdaddr_t bdaddr;
+        int btsock;
+        btsock = socket(AF_BLUETOOTH, SOCK_RAW, 1);
+        if (btsock < 0) { // If anything fails, just return with the default value
+            return;
+        }
+
+        if (ioctl(btsock, HCIGETDEVINFO, (void *)&di)) {
+            return;
+        }
+
+        dmac[0] = di.bdaddr.b[5];
+        dmac[1] = di.bdaddr.b[4];
+        dmac[2] = di.bdaddr.b[3];
+        dmac[3] = di.bdaddr.b[2];
+        dmac[4] = di.bdaddr.b[1];
+        dmac[5] = di.bdaddr.b[0];
+    }
+}
+
 /** apps run under portduino can optionally define a portduinoSetup() to
  * use portduino specific init code (such as gpioBind) to setup portduino on their host machine,
  * before running 'arduino' code.
@@ -96,6 +153,7 @@ void portduinoSetup()
     std::string gpioChipName = "gpiochip";
     settingsStrings[i2cdev] = "";
     settingsStrings[keyboardDevice] = "";
+    settingsStrings[pointerDevice] = "";
     settingsStrings[webserverrootpath] = "";
     settingsStrings[spidev] = "";
     settingsStrings[displayspidev] = "";
@@ -113,10 +171,20 @@ void portduinoSetup()
             std::cout << "Unable to use " << configPath << " as config file" << std::endl;
             exit(EXIT_FAILURE);
         }
-    } else if (access("config.yaml", R_OK) == 0 && loadConfig("config.yaml")) {
-        std::cout << "Using local config.yaml as config file" << std::endl;
-    } else if (access("/etc/meshtasticd/config.yaml", R_OK) == 0 && loadConfig("/etc/meshtasticd/config.yaml")) {
-        std::cout << "Using /etc/meshtasticd/config.yaml as config file" << std::endl;
+    } else if (access("config.yaml", R_OK) == 0) {
+        if (loadConfig("config.yaml")) {
+            std::cout << "Using local config.yaml as config file" << std::endl;
+        } else {
+            std::cout << "Unable to use local config.yaml as config file" << std::endl;
+            exit(EXIT_FAILURE);
+        }
+    } else if (access("/etc/meshtasticd/config.yaml", R_OK) == 0) {
+        if (loadConfig("/etc/meshtasticd/config.yaml")) {
+            std::cout << "Using /etc/meshtasticd/config.yaml as config file" << std::endl;
+        } else {
+            std::cout << "Unable to use /etc/meshtasticd/config.yaml as config file" << std::endl;
+            exit(EXIT_FAILURE);
+        }
     } else {
         std::cout << "No 'config.yaml' found, running simulated." << std::endl;
         settingsMap[maxnodes] = 200;               // Default to 200 nodes
@@ -136,7 +204,43 @@ void portduinoSetup()
             }
         }
     }
+    // if we're using a usermode driver, we need to initialize it here, to get a serial number back for mac address
+    uint8_t dmac[6] = {0};
+    if (settingsStrings[spidev] == "ch341") {
+        ch341Hal = new Ch341Hal(0);
+        if (settingsStrings[lora_usb_serial_num] != "") {
+            ch341Hal->serial = settingsStrings[lora_usb_serial_num];
+        }
+        ch341Hal->vid = settingsMap[lora_usb_vid];
+        ch341Hal->pid = settingsMap[lora_usb_pid];
+        ch341Hal->init();
+        if (!ch341Hal->isInit()) {
+            std::cout << "Could not initialize CH341 device!" << std::endl;
+            exit(EXIT_FAILURE);
+        }
+        char serial[9] = {0};
+        ch341Hal->getSerialString(serial, 8);
+        std::cout << "Serial " << serial << std::endl;
+        if (strlen(serial) == 8 && settingsStrings[mac_address].length() < 12) {
+            uint8_t hash[32] = {0};
+            memcpy(hash, serial, 8);
+            crypto->hash(hash, 8);
+            dmac[0] = (hash[0] << 4) | 2;
+            dmac[1] = hash[1];
+            dmac[2] = hash[2];
+            dmac[3] = hash[3];
+            dmac[4] = hash[4];
+            dmac[5] = hash[5];
+        }
+    }
 
+    getMacAddr(dmac);
+    if (dmac[0] == 0 && dmac[1] == 0 && dmac[2] == 0 && dmac[3] == 0 && dmac[4] == 0 && dmac[5] == 0) {
+        std::cout << "*** Blank MAC Address not allowed!" << std::endl;
+        std::cout << "Please set a MAC Address in config.yaml using either MACAddress or MACAddressSource." << std::endl;
+        exit(EXIT_FAILURE);
+    }
+    std::cout << "MAC Address: " << std::hex << +dmac[0] << +dmac[1] << +dmac[2] << +dmac[3] << +dmac[4] << +dmac[5] << std::endl;
     // Rather important to set this, if not running simulated.
     randomSeed(time(NULL));
 
@@ -152,47 +256,11 @@ void portduinoSetup()
     // Need to bind all the configured GPIO pins so they're not simulated
     // TODO: Can we do this in the for loop above?
     // TODO: If one of these fails, we should log and terminate
-    if (settingsMap.count(cs) > 0 && settingsMap[cs] != RADIOLIB_NC) {
-        if (initGPIOPin(settingsMap[cs], gpioChipName) != ERRNO_OK) {
-            settingsMap[cs] = RADIOLIB_NC;
-        }
-    }
-    if (settingsMap.count(irq) > 0 && settingsMap[irq] != RADIOLIB_NC) {
-        if (initGPIOPin(settingsMap[irq], gpioChipName) != ERRNO_OK) {
-            settingsMap[irq] = RADIOLIB_NC;
-        }
-    }
-    if (settingsMap.count(busy) > 0 && settingsMap[busy] != RADIOLIB_NC) {
-        if (initGPIOPin(settingsMap[busy], gpioChipName) != ERRNO_OK) {
-            settingsMap[busy] = RADIOLIB_NC;
-        }
-    }
-    if (settingsMap.count(reset) > 0 && settingsMap[reset] != RADIOLIB_NC) {
-        if (initGPIOPin(settingsMap[reset], gpioChipName) != ERRNO_OK) {
-            settingsMap[reset] = RADIOLIB_NC;
-        }
-    }
-    if (settingsMap.count(sx126x_ant_sw) > 0 && settingsMap[sx126x_ant_sw] != RADIOLIB_NC) {
-        if (initGPIOPin(settingsMap[sx126x_ant_sw], gpioChipName) != ERRNO_OK) {
-            settingsMap[sx126x_ant_sw] = RADIOLIB_NC;
-        }
-    }
     if (settingsMap.count(user) > 0 && settingsMap[user] != RADIOLIB_NC) {
         if (initGPIOPin(settingsMap[user], gpioChipName) != ERRNO_OK) {
             settingsMap[user] = RADIOLIB_NC;
         }
     }
-    if (settingsMap.count(rxen) > 0 && settingsMap[rxen] != RADIOLIB_NC) {
-        if (initGPIOPin(settingsMap[rxen], gpioChipName) != ERRNO_OK) {
-            settingsMap[rxen] = RADIOLIB_NC;
-        }
-    }
-    if (settingsMap.count(txen) > 0 && settingsMap[txen] != RADIOLIB_NC) {
-        if (initGPIOPin(settingsMap[txen], gpioChipName) != ERRNO_OK) {
-            settingsMap[txen] = RADIOLIB_NC;
-        }
-    }
-
     if (settingsMap[displayPanel] != no_screen) {
         if (settingsMap[displayCS] > 0)
             initGPIOPin(settingsMap[displayCS], gpioChipName);
@@ -210,7 +278,43 @@ void portduinoSetup()
             initGPIOPin(settingsMap[touchscreenIRQ], gpioChipName);
     }
 
-    if (settingsStrings[spidev] != "") {
+    // Only initialize the radio pins when dealing with real, kernel controlled SPI hardware
+    if (settingsStrings[spidev] != "" && settingsStrings[spidev] != "ch341") {
+        if (settingsMap.count(cs) > 0 && settingsMap[cs] != RADIOLIB_NC) {
+            if (initGPIOPin(settingsMap[cs], gpioChipName) != ERRNO_OK) {
+                settingsMap[cs] = RADIOLIB_NC;
+            }
+        }
+        if (settingsMap.count(irq) > 0 && settingsMap[irq] != RADIOLIB_NC) {
+            if (initGPIOPin(settingsMap[irq], gpioChipName) != ERRNO_OK) {
+                settingsMap[irq] = RADIOLIB_NC;
+            }
+        }
+        if (settingsMap.count(busy) > 0 && settingsMap[busy] != RADIOLIB_NC) {
+            if (initGPIOPin(settingsMap[busy], gpioChipName) != ERRNO_OK) {
+                settingsMap[busy] = RADIOLIB_NC;
+            }
+        }
+        if (settingsMap.count(reset) > 0 && settingsMap[reset] != RADIOLIB_NC) {
+            if (initGPIOPin(settingsMap[reset], gpioChipName) != ERRNO_OK) {
+                settingsMap[reset] = RADIOLIB_NC;
+            }
+        }
+        if (settingsMap.count(sx126x_ant_sw) > 0 && settingsMap[sx126x_ant_sw] != RADIOLIB_NC) {
+            if (initGPIOPin(settingsMap[sx126x_ant_sw], gpioChipName) != ERRNO_OK) {
+                settingsMap[sx126x_ant_sw] = RADIOLIB_NC;
+            }
+        }
+        if (settingsMap.count(rxen) > 0 && settingsMap[rxen] != RADIOLIB_NC) {
+            if (initGPIOPin(settingsMap[rxen], gpioChipName) != ERRNO_OK) {
+                settingsMap[rxen] = RADIOLIB_NC;
+            }
+        }
+        if (settingsMap.count(txen) > 0 && settingsMap[txen] != RADIOLIB_NC) {
+            if (initGPIOPin(settingsMap[txen], gpioChipName) != ERRNO_OK) {
+                settingsMap[txen] = RADIOLIB_NC;
+            }
+        }
         SPI.begin(settingsStrings[spidev].c_str());
     }
     if (settingsStrings[traceFilename] != "") {
@@ -272,6 +376,9 @@ bool loadConfig(const char *configPath)
             settingsMap[use_sx1262] = false;
             settingsMap[use_rf95] = false;
             settingsMap[use_sx1280] = false;
+            settingsMap[use_lr1110] = false;
+            settingsMap[use_lr1120] = false;
+            settingsMap[use_lr1121] = false;
             settingsMap[use_sx1268] = false;
 
             if (yamlConfig["Lora"]["Module"] && yamlConfig["Lora"]["Module"].as("") == "sx1262") {
@@ -280,11 +387,20 @@ bool loadConfig(const char *configPath)
                 settingsMap[use_rf95] = true;
             } else if (yamlConfig["Lora"]["Module"] && yamlConfig["Lora"]["Module"].as("") == "sx1280") {
                 settingsMap[use_sx1280] = true;
+            } else if (yamlConfig["Lora"]["Module"] && yamlConfig["Lora"]["Module"].as("") == "lr1110") {
+                settingsMap[use_lr1110] = true;
+            } else if (yamlConfig["Lora"]["Module"] && yamlConfig["Lora"]["Module"].as("") == "lr1120") {
+                settingsMap[use_lr1120] = true;
+            } else if (yamlConfig["Lora"]["Module"] && yamlConfig["Lora"]["Module"].as("") == "lr1121") {
+                settingsMap[use_lr1121] = true;
             } else if (yamlConfig["Lora"]["Module"] && yamlConfig["Lora"]["Module"].as("") == "sx1268") {
                 settingsMap[use_sx1268] = true;
             }
             settingsMap[dio2_as_rf_switch] = yamlConfig["Lora"]["DIO2_AS_RF_SWITCH"].as(false);
-            settingsMap[dio3_tcxo_voltage] = yamlConfig["Lora"]["DIO3_TCXO_VOLTAGE"].as(false);
+            settingsMap[dio3_tcxo_voltage] = yamlConfig["Lora"]["DIO3_TCXO_VOLTAGE"].as(0) * 1000;
+            if (settingsMap[dio3_tcxo_voltage] == 0 && yamlConfig["Lora"]["DIO3_TCXO_VOLTAGE"].as(false)) {
+                settingsMap[dio3_tcxo_voltage] = 1800; // default millivolts for "true"
+            }
             settingsMap[cs] = yamlConfig["Lora"]["CS"].as(RADIOLIB_NC);
             settingsMap[irq] = yamlConfig["Lora"]["IRQ"].as(RADIOLIB_NC);
             settingsMap[busy] = yamlConfig["Lora"]["Busy"].as(RADIOLIB_NC);
@@ -293,17 +409,24 @@ bool loadConfig(const char *configPath)
             settingsMap[rxen] = yamlConfig["Lora"]["RXen"].as(RADIOLIB_NC);
             settingsMap[sx126x_ant_sw] = yamlConfig["Lora"]["SX126X_ANT_SW"].as(RADIOLIB_NC);
             settingsMap[gpiochip] = yamlConfig["Lora"]["gpiochip"].as(0);
-            settingsMap[ch341Quirk] = yamlConfig["Lora"]["ch341_quirk"].as(false);
             settingsMap[spiSpeed] = yamlConfig["Lora"]["spiSpeed"].as(2000000);
+            settingsStrings[lora_usb_serial_num] = yamlConfig["Lora"]["USB_Serialnum"].as("");
+            settingsMap[lora_usb_pid] = yamlConfig["Lora"]["USB_PID"].as(0x5512);
+            settingsMap[lora_usb_vid] = yamlConfig["Lora"]["USB_VID"].as(0x1A86);
 
-            settingsStrings[spidev] = "/dev/" + yamlConfig["Lora"]["spidev"].as("spidev0.0");
-            if (settingsStrings[spidev].length() == 14) {
-                int x = settingsStrings[spidev].at(11) - '0';
-                int y = settingsStrings[spidev].at(13) - '0';
-                if (x >= 0 && x < 10 && y >= 0 && y < 10) {
-                    settingsMap[spidev] = x + y << 4;
-                    settingsMap[displayspidev] = settingsMap[spidev];
-                    settingsMap[touchscreenspidev] = settingsMap[spidev];
+            settingsStrings[spidev] = yamlConfig["Lora"]["spidev"].as("spidev0.0");
+            if (settingsStrings[spidev] != "ch341") {
+                settingsStrings[spidev] = "/dev/" + settingsStrings[spidev];
+                if (settingsStrings[spidev].length() == 14) {
+                    int x = settingsStrings[spidev].at(11) - '0';
+                    int y = settingsStrings[spidev].at(13) - '0';
+                    // Pretty sure this is always true
+                    if (x >= 0 && x < 10 && y >= 0 && y < 10) {
+                        // I believe this bit of weirdness is specifically for the new GUI
+                        settingsMap[spidev] = x + y << 4;
+                        settingsMap[displayspidev] = settingsMap[spidev];
+                        settingsMap[touchscreenspidev] = settingsMap[spidev];
+                    }
                 }
             }
         }
@@ -333,6 +456,8 @@ bool loadConfig(const char *configPath)
                 settingsMap[displayPanel] = ili9341;
             else if (yamlConfig["Display"]["Panel"].as("") == "ILI9342")
                 settingsMap[displayPanel] = ili9342;
+            else if (yamlConfig["Display"]["Panel"].as("") == "ILI9486")
+                settingsMap[displayPanel] = ili9486;
             else if (yamlConfig["Display"]["Panel"].as("") == "ILI9488")
                 settingsMap[displayPanel] = ili9488;
             else if (yamlConfig["Display"]["Panel"].as("") == "HX8357D")
@@ -393,6 +518,7 @@ bool loadConfig(const char *configPath)
         }
         if (yamlConfig["Input"]) {
             settingsStrings[keyboardDevice] = (yamlConfig["Input"]["KeyboardDevice"]).as("");
+            settingsStrings[pointerDevice] = (yamlConfig["Input"]["PointerDevice"]).as("");
         }
 
         if (yamlConfig["Webserver"]) {
@@ -404,8 +530,23 @@ bool loadConfig(const char *configPath)
             settingsMap[maxnodes] = (yamlConfig["General"]["MaxNodes"]).as(200);
             settingsMap[maxtophone] = (yamlConfig["General"]["MaxMessageQueue"]).as(100);
             settingsStrings[config_directory] = (yamlConfig["General"]["ConfigDirectory"]).as("");
-        }
+            if ((yamlConfig["General"]["MACAddress"]).as("") != "" &&
+                (yamlConfig["General"]["MACAddressSource"]).as("") != "") {
+                std::cout << "Cannot set both MACAddress and MACAddressSource!" << std::endl;
+                exit(EXIT_FAILURE);
+            }
+            settingsStrings[mac_address] = (yamlConfig["General"]["MACAddress"]).as("");
+            if ((yamlConfig["General"]["MACAddressSource"]).as("") != "") {
+                std::ifstream infile("/sys/class/net/" + (yamlConfig["General"]["MACAddressSource"]).as("") +
+                                     "/address");
+                std::getline(infile, settingsStrings[mac_address]);
+            }
 
+            // https://stackoverflow.com/a/20326454
+            settingsStrings[mac_address].erase(
+                std::remove(settingsStrings[mac_address].begin(), settingsStrings[mac_address].end(), ':'),
+                settingsStrings[mac_address].end());
+        }
     } catch (YAML::Exception &e) {
         std::cout << "*** Exception " << e.what() << std::endl;
         return false;
@@ -417,4 +558,20 @@ bool loadConfig(const char *configPath)
 static bool ends_with(std::string_view str, std::string_view suffix)
 {
     return str.size() >= suffix.size() && str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;
-}
\ No newline at end of file
+}
+
+bool MAC_from_string(std::string mac_str, uint8_t *dmac)
+{
+    mac_str.erase(std::remove(mac_str.begin(), mac_str.end(), ':'), mac_str.end());
+    if (mac_str.length() == 12) {
+        dmac[0] = std::stoi(settingsStrings[mac_address].substr(0, 2), nullptr, 16);
+        dmac[1] = std::stoi(settingsStrings[mac_address].substr(2, 2), nullptr, 16);
+        dmac[2] = std::stoi(settingsStrings[mac_address].substr(4, 2), nullptr, 16);
+        dmac[3] = std::stoi(settingsStrings[mac_address].substr(6, 2), nullptr, 16);
+        dmac[4] = std::stoi(settingsStrings[mac_address].substr(8, 2), nullptr, 16);
+        dmac[5] = std::stoi(settingsStrings[mac_address].substr(10, 2), nullptr, 16);
+        return true;
+    } else {
+        return false;
+    }
+}
diff --git a/src/platform/portduino/PortduinoGlue.h b/src/platform/portduino/PortduinoGlue.h
index 95d82c1a2..5bc07df6a 100644
--- a/src/platform/portduino/PortduinoGlue.h
+++ b/src/platform/portduino/PortduinoGlue.h
@@ -2,6 +2,8 @@
 #include 
 #include 
 
+#include "platform/portduino/USBHal.h"
+
 enum configNames {
     use_sx1262,
     cs,
@@ -13,10 +15,15 @@ enum configNames {
     rxen,
     dio2_as_rf_switch,
     dio3_tcxo_voltage,
-    ch341Quirk,
     use_rf95,
     use_sx1280,
+    use_lr1110,
+    use_lr1120,
+    use_lr1121,
     use_sx1268,
+    lora_usb_serial_num,
+    lora_usb_pid,
+    lora_usb_vid,
     user,
     gpiochip,
     spidev,
@@ -48,6 +55,7 @@ enum configNames {
     displayOffsetY,
     displayInvert,
     keyboardDevice,
+    pointerDevice,
     logoutputlevel,
     traceFilename,
     webserver,
@@ -56,15 +64,19 @@ enum configNames {
     maxtophone,
     maxnodes,
     ascii_logs,
-    config_directory
+    config_directory,
+    mac_address
 };
-enum { no_screen, x11, st7789, st7735, st7735s, st7796, ili9341, ili9342, ili9488, hx8357d };
+enum { no_screen, x11, st7789, st7735, st7735s, st7796, ili9341, ili9342, ili9486, ili9488, hx8357d };
 enum { no_touchscreen, xpt2046, stmpe610, gt911, ft5x06 };
 enum { level_error, level_warn, level_info, level_debug, level_trace };
 
 extern std::map settingsMap;
 extern std::map settingsStrings;
 extern std::ofstream traceFile;
+extern Ch341Hal *ch341Hal;
 int initGPIOPin(int pinNum, std::string gpioChipname);
 bool loadConfig(const char *configPath);
-static bool ends_with(std::string_view str, std::string_view suffix);
\ No newline at end of file
+static bool ends_with(std::string_view str, std::string_view suffix);
+void getMacAddr(uint8_t *dmac);
+bool MAC_from_string(std::string mac_str, uint8_t *dmac);
diff --git a/src/platform/portduino/SimRadio.cpp b/src/platform/portduino/SimRadio.cpp
index 0a77b6088..7e63b995e 100644
--- a/src/platform/portduino/SimRadio.cpp
+++ b/src/platform/portduino/SimRadio.cpp
@@ -73,6 +73,10 @@ void SimRadio::handleTransmitInterrupt()
     // ignore the transmit interrupt
     if (sendingPacket)
         completeSending();
+
+    isReceiving = true;
+    if (receivingPacket) // This happens when we don't consider something a collision if we weren't sending long enough
+        handleReceiveInterrupt();
 }
 
 void SimRadio::completeSending()
@@ -84,6 +88,8 @@ void SimRadio::completeSending()
 
     if (p) {
         txGood++;
+        if (!isFromUs(p))
+            txRelay++;
         printPacket("Completed sending", p);
 
         // We are done sending that packet, release it
@@ -113,12 +119,12 @@ bool SimRadio::canSendImmediately()
 
 bool SimRadio::isActivelyReceiving()
 {
-    return false; // TODO check how this should be simulated
+    return receivingPacket != nullptr;
 }
 
 bool SimRadio::isChannelActive()
 {
-    return false; // TODO ask simulator
+    return receivingPacket != nullptr;
 }
 
 /** Attempt to cancel a previously sent packet.  Returns true if a packet was found we could cancel */
@@ -142,10 +148,16 @@ void SimRadio::onNotify(uint32_t notification)
         startTransmitTimer();
         break;
     case ISR_RX:
+        handleReceiveInterrupt();
         //  LOG_DEBUG("rx complete - starting timer");
         startTransmitTimer();
         break;
     case TRANSMIT_DELAY_COMPLETED:
+        if (receivingPacket) { // This happens when we had a timer pending and we started receiving
+            handleReceiveInterrupt();
+            startTransmitTimer();
+            break;
+        }
         LOG_DEBUG("delay done");
 
         // If we are not currently in receive mode, then restart the random delay (this can happen if the main thread
@@ -183,6 +195,7 @@ void SimRadio::onNotify(uint32_t notification)
 void SimRadio::startSend(meshtastic_MeshPacket *txp)
 {
     printPacket("Start low level send", txp);
+    isReceiving = false;
     size_t numbytes = beginSending(txp);
     meshtastic_MeshPacket *p = packetPool.allocCopy(*txp);
     perhapsDecode(p);
@@ -201,15 +214,64 @@ void SimRadio::startSend(meshtastic_MeshPacket *txp)
 
     service->sendQueueStatusToPhone(router->getQueueStatus(), 0, p->id);
     service->sendToPhone(p); // Sending back to simulator
+    service->loop();         // Process the send immediately
+}
+
+// Simulates device received a packet via the LoRa chip
+void SimRadio::unpackAndReceive(meshtastic_MeshPacket &p)
+{
+    // Simulator packet (=Compressed packet) is encapsulated in a MeshPacket, so need to unwrap first
+    meshtastic_Compressed scratch;
+    meshtastic_Compressed *decoded = NULL;
+    if (p.which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
+        memset(&scratch, 0, sizeof(scratch));
+        p.decoded.payload.size =
+            pb_decode_from_bytes(p.decoded.payload.bytes, p.decoded.payload.size, &meshtastic_Compressed_msg, &scratch);
+        if (p.decoded.payload.size) {
+            decoded = &scratch;
+            // Extract the original payload and replace
+            memcpy(&p.decoded.payload, &decoded->data, sizeof(decoded->data));
+            // Switch the port from PortNum_SIMULATOR_APP back to the original PortNum
+            p.decoded.portnum = decoded->portnum;
+        } else
+            LOG_ERROR("Error decoding proto for simulator message!");
+    }
+    // Let SimRadio receive as if it did via its LoRa chip
+    startReceive(&p);
 }
 
 void SimRadio::startReceive(meshtastic_MeshPacket *p)
 {
+#ifdef USERPREFS_SIMRADIO_EMULATE_COLLISIONS
+    if (isActivelyReceiving()) {
+        LOG_WARN("Collision detected, dropping current and previous packet!");
+        rxBad++;
+        airTime->logAirtime(RX_ALL_LOG, getPacketTime(receivingPacket));
+        packetPool.release(receivingPacket);
+        receivingPacket = nullptr;
+        return;
+    } else if (sendingPacket) {
+        uint32_t airtimeLeft = tillRun(millis());
+        if (airtimeLeft <= 0) {
+            LOG_WARN("Transmitting packet was already done");
+            handleTransmitInterrupt(); // Finish sending first
+        } else if ((interval - airtimeLeft) > preambleTimeMsec) {
+            // Only if transmitting for longer than preamble there is a collision
+            // (channel should actually be detected as active otherwise)
+            LOG_WARN("Collision detected during transmission!");
+            return;
+        }
+    }
     isReceiving = true;
-    size_t length = getPacketLength(p);
-    uint32_t xmitMsec = getPacketTime(length);
-    delay(xmitMsec); // Model the time it is busy receiving
-    handleReceiveInterrupt(p);
+    receivingPacket = packetPool.allocCopy(*p);
+    uint32_t airtimeMsec = getPacketTime(p);
+    notifyLater(airtimeMsec, ISR_RX, false); // Model the time it is busy receiving
+#else
+    isReceiving = true;
+    receivingPacket = packetPool.allocCopy(*p);
+    handleReceiveInterrupt(); // Simulate receiving the packet immediately
+    startTransmitTimer();
+#endif
 }
 
 meshtastic_QueueStatus SimRadio::getQueueStatus()
@@ -223,28 +285,27 @@ meshtastic_QueueStatus SimRadio::getQueueStatus()
     return qs;
 }
 
-void SimRadio::handleReceiveInterrupt(meshtastic_MeshPacket *p)
+void SimRadio::handleReceiveInterrupt()
 {
-    LOG_DEBUG("HANDLE RECEIVE INTERRUPT");
-    uint32_t xmitMsec;
+    if (receivingPacket == nullptr) {
+        return;
+    }
 
     if (!isReceiving) {
         LOG_DEBUG("*** WAS_ASSERT *** handleReceiveInterrupt called when not in receive mode");
         return;
     }
 
-    isReceiving = false;
+    LOG_DEBUG("HANDLE RECEIVE INTERRUPT");
+    rxGood++;
 
-    // read the number of actually received bytes
-    size_t length = getPacketLength(p);
-    xmitMsec = getPacketTime(length);
-    // LOG_DEBUG("Payload size %d vs length (includes header) %d", p->decoded.payload.size, length);
-
-    meshtastic_MeshPacket *mp = packetPool.allocCopy(*p); // keep a copy in packetPool
+    meshtastic_MeshPacket *mp = packetPool.allocCopy(*receivingPacket); // keep a copy in packetPool
+    packetPool.release(receivingPacket);                                // release the original
+    receivingPacket = nullptr;
 
     printPacket("Lora RX", mp);
 
-    airTime->logAirtime(RX_LOG, xmitMsec);
+    airTime->logAirtime(RX_LOG, getPacketTime(mp));
 
     deliverToReceiver(mp);
 }
@@ -265,4 +326,4 @@ int16_t SimRadio::readData(uint8_t *data, size_t len)
     }
 
     return state;
-}
+}
\ No newline at end of file
diff --git a/src/platform/portduino/SimRadio.h b/src/platform/portduino/SimRadio.h
index 1edb4963b..c082444e5 100644
--- a/src/platform/portduino/SimRadio.h
+++ b/src/platform/portduino/SimRadio.h
@@ -11,11 +11,6 @@ class SimRadio : public RadioInterface, protected concurrency::NotifiedWorkerThr
 {
     enum PendingISR { ISR_NONE = 0, ISR_RX, ISR_TX, TRANSMIT_DELAY_COMPLETED };
 
-    /**
-     * Debugging counts
-     */
-    uint32_t rxBad = 0, rxGood = 0, txGood = 0;
-
     MeshPacketQueue txQueue = MeshPacketQueue(MAX_TX_QUEUE);
 
   public:
@@ -47,9 +42,17 @@ class SimRadio : public RadioInterface, protected concurrency::NotifiedWorkerThr
 
     meshtastic_QueueStatus getQueueStatus() override;
 
+    // Convert Compressed_msg to normal msg and receive it
+    void unpackAndReceive(meshtastic_MeshPacket &p);
+
+    /**
+     * Debugging counts
+     */
+    uint32_t rxBad = 0, rxGood = 0, txGood = 0, txRelay = 0;
+
   protected:
     /// are _trying_ to receive a packet currently (note - we might just be waiting for one)
-    bool isReceiving = false;
+    bool isReceiving = true;
 
   private:
     void setTransmitDelay();
@@ -61,7 +64,7 @@ class SimRadio : public RadioInterface, protected concurrency::NotifiedWorkerThr
     void startTransmitTimerSNR(float snr);
 
     void handleTransmitInterrupt();
-    void handleReceiveInterrupt(meshtastic_MeshPacket *p);
+    void handleReceiveInterrupt();
 
     void onNotify(uint32_t notification);
 
@@ -73,6 +76,8 @@ class SimRadio : public RadioInterface, protected concurrency::NotifiedWorkerThr
 
     int16_t readData(uint8_t *str, size_t len);
 
+    meshtastic_MeshPacket *receivingPacket = nullptr; // The packet we are currently receiving
+
   protected:
     /** Could we send right now (i.e. either not actively receiving or transmitting)? */
     virtual bool canSendImmediately();
diff --git a/src/platform/portduino/USBHal.h b/src/platform/portduino/USBHal.h
new file mode 100644
index 000000000..2b0302ced
--- /dev/null
+++ b/src/platform/portduino/USBHal.h
@@ -0,0 +1,194 @@
+#ifndef PI_HAL_LGPIO_H
+#define PI_HAL_LGPIO_H
+
+// include RadioLib
+#include "platform/portduino/PortduinoGlue.h"
+#include 
+#include 
+#include 
+#include 
+
+// include the library for Raspberry GPIO pins
+
+#define PI_RISING (PINEDIO_INT_MODE_RISING)
+#define PI_FALLING (PINEDIO_INT_MODE_FALLING)
+#define PI_INPUT (0)
+#define PI_OUTPUT (1)
+#define PI_LOW (0)
+#define PI_HIGH (1)
+
+#define CH341_PIN_CS (101)
+#define CH341_PIN_IRQ (0)
+
+// the HAL must inherit from the base RadioLibHal class
+// and implement all of its virtual methods
+class Ch341Hal : public RadioLibHal
+{
+  public:
+    // default constructor - initializes the base HAL and any needed private members
+    Ch341Hal(uint8_t spiChannel, uint32_t spiSpeed = 2000000, uint8_t spiDevice = 0, uint8_t gpioDevice = 0)
+        : RadioLibHal(PI_INPUT, PI_OUTPUT, PI_LOW, PI_HIGH, PI_RISING, PI_FALLING)
+    {
+    }
+
+    void getSerialString(char *_serial, size_t len)
+    {
+        if (!pinedio_is_init) {
+            return;
+        }
+        strncpy(_serial, pinedio.serial_number, len);
+    }
+
+    void init() override
+    {
+        // now the SPI
+        spiBegin();
+    }
+
+    void term() override
+    {
+        // stop the SPI
+        spiEnd();
+    }
+
+    // GPIO-related methods (pinMode, digitalWrite etc.) should check
+    // RADIOLIB_NC as an alias for non-connected pins
+    void pinMode(uint32_t pin, uint32_t mode) override
+    {
+        if (pin == RADIOLIB_NC) {
+            return;
+        }
+        pinedio_set_pin_mode(&pinedio, pin, mode);
+    }
+
+    void digitalWrite(uint32_t pin, uint32_t value) override
+    {
+        if (pin == RADIOLIB_NC) {
+            return;
+        }
+        pinedio_digital_write(&pinedio, pin, value);
+    }
+
+    uint32_t digitalRead(uint32_t pin) override
+    {
+        if (pin == RADIOLIB_NC) {
+            return 0;
+        }
+        return pinedio_digital_read(&pinedio, pin);
+    }
+
+    void attachInterrupt(uint32_t interruptNum, void (*interruptCb)(void), uint32_t mode) override
+    {
+        if ((interruptNum == RADIOLIB_NC)) {
+            return;
+        }
+        // LOG_DEBUG("Attach interrupt to pin %d", interruptNum);
+        pinedio_attach_interrupt(&this->pinedio, (pinedio_int_pin)interruptNum, (pinedio_int_mode)mode, interruptCb);
+    }
+
+    void detachInterrupt(uint32_t interruptNum) override
+    {
+        if ((interruptNum == RADIOLIB_NC)) {
+            return;
+        }
+        // LOG_DEBUG("Detach interrupt from pin %d", interruptNum);
+
+        pinedio_deattach_interrupt(&this->pinedio, (pinedio_int_pin)interruptNum);
+    }
+
+    void delay(unsigned long ms) override
+    {
+        if (ms == 0) {
+            sched_yield();
+            return;
+        }
+
+        usleep(ms * 1000);
+    }
+
+    void delayMicroseconds(unsigned long us) override
+    {
+        if (us == 0) {
+            sched_yield();
+            return;
+        }
+        usleep(us);
+    }
+
+    void yield() override { sched_yield(); }
+
+    unsigned long millis() override
+    {
+        struct timeval tv;
+        gettimeofday(&tv, NULL);
+        return (tv.tv_sec * 1000ULL) + (tv.tv_usec / 1000ULL);
+    }
+
+    unsigned long micros() override
+    {
+        struct timeval tv;
+        gettimeofday(&tv, NULL);
+        return (tv.tv_sec * 1000000ULL) + tv.tv_usec;
+    }
+
+    long pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) override
+    {
+        fprintf(stderr, "pulseIn for pin %u is not supported!\n", pin);
+        return 0;
+    }
+
+    void spiBegin()
+    {
+        if (!pinedio_is_init) {
+            if (serial != "") {
+                strncpy(pinedio.serial_number, serial.c_str(), 8);
+                pinedio_set_option(&pinedio, PINEDIO_OPTION_SEARCH_SERIAL, 1);
+            }
+            pinedio_set_option(&pinedio, PINEDIO_OPTION_PID, pid);
+            pinedio_set_option(&pinedio, PINEDIO_OPTION_VID, vid);
+            int32_t ret = pinedio_init(&pinedio, NULL);
+            if (ret != 0) {
+                fprintf(stderr, "Could not open SPI: %d\n", ret);
+            } else {
+                pinedio_is_init = true;
+                // LOG_INFO("USB Serial: %s", pinedio.serial_number);
+                pinedio_set_option(&pinedio, PINEDIO_OPTION_AUTO_CS, 0);
+                pinedio_set_pin_mode(&pinedio, 3, true);
+                pinedio_set_pin_mode(&pinedio, 5, true);
+            }
+        }
+    }
+
+    void spiBeginTransaction() {}
+
+    void spiTransfer(uint8_t *out, size_t len, uint8_t *in)
+    {
+        int32_t result = pinedio_transceive(&this->pinedio, out, in, len);
+        if (result < 0) {
+            fprintf(stderr, "Could not perform SPI transfer: %d\n", result);
+        }
+    }
+
+    void spiEndTransaction() {}
+
+    void spiEnd()
+    {
+        if (pinedio_is_init) {
+            pinedio_deinit(&pinedio);
+            pinedio_is_init = false;
+        }
+    }
+
+    bool isInit() { return pinedio_is_init; }
+
+    std::string serial = "";
+    uint32_t pid = 0x5512;
+    uint32_t vid = 0x1A86;
+
+  private:
+    // the HAL can contain any additional private members
+    pinedio_inst pinedio = {0};
+    bool pinedio_is_init = false;
+};
+
+#endif
\ No newline at end of file
diff --git a/src/platform/portduino/architecture.h b/src/platform/portduino/architecture.h
index 321949226..3dde87199 100644
--- a/src/platform/portduino/architecture.h
+++ b/src/platform/portduino/architecture.h
@@ -11,6 +11,9 @@
 #ifndef HAS_WIFI
 #define HAS_WIFI 1
 #endif
+#ifndef HAS_RADIO
+#define HAS_RADIO 1
+#endif
 #ifndef HAS_RTC
 #define HAS_RTC 1
 #endif
diff --git a/src/platform/rp2xx0/architecture.h b/src/platform/rp2xx0/architecture.h
index 8c7dfc0cd..506c19c83 100644
--- a/src/platform/rp2xx0/architecture.h
+++ b/src/platform/rp2xx0/architecture.h
@@ -33,4 +33,6 @@
 #define HW_VENDOR meshtastic_HardwareModel_RP2040_LORA
 #elif defined(RP2040_FEATHER_RFM95)
 #define HW_VENDOR meshtastic_HardwareModel_RP2040_FEATHER_RFM95
+#elif defined(PRIVATE_HW)
+#define HW_VENDOR meshtastic_HardwareModel_PRIVATE_HW
 #endif
\ No newline at end of file
diff --git a/src/power.h b/src/power.h
index 63335104b..ab55fc7e1 100644
--- a/src/power.h
+++ b/src/power.h
@@ -42,10 +42,12 @@ extern RTC_NOINIT_ATTR uint64_t RTC_reg_b;
 
 #if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && !defined(ARCH_PORTDUINO)
 #include "modules/Telemetry/Sensor/INA219Sensor.h"
+#include "modules/Telemetry/Sensor/INA226Sensor.h"
 #include "modules/Telemetry/Sensor/INA260Sensor.h"
 #include "modules/Telemetry/Sensor/INA3221Sensor.h"
-extern INA260Sensor ina260Sensor;
 extern INA219Sensor ina219Sensor;
+extern INA226Sensor ina226Sensor;
+extern INA260Sensor ina260Sensor;
 extern INA3221Sensor ina3221Sensor;
 #endif
 
@@ -99,4 +101,4 @@ class Power : private concurrency::OSThread
 #endif
 };
 
-extern Power *power;
\ No newline at end of file
+extern Power *power;
diff --git a/src/sleep.cpp b/src/sleep.cpp
index 05597cdfa..69eb0349a 100644
--- a/src/sleep.cpp
+++ b/src/sleep.cpp
@@ -336,6 +336,12 @@ esp_sleep_wakeup_cause_t doLightSleep(uint64_t sleepMsec) // FIXME, use a more r
 {
     // LOG_DEBUG("Enter light sleep");
 
+    // LORA_DIO1 is an extended IO pin. Setting it as a wake-up pin will cause problems, such as the indicator device not entering
+    // LightSleep.
+#if defined(SENSECAP_INDICATOR)
+    return ESP_SLEEP_WAKEUP_TIMER;
+#endif
+
     waitEnterSleep(false);
 
     uint64_t sleepUsec = sleepMsec * 1000LL;
diff --git a/test/TestUtil.cpp b/test/TestUtil.cpp
new file mode 100644
index 000000000..b470b8ce8
--- /dev/null
+++ b/test/TestUtil.cpp
@@ -0,0 +1,18 @@
+#include "SerialConsole.h"
+#include "concurrency/OSThread.h"
+#include "gps/RTC.h"
+
+#include "TestUtil.h"
+
+void initializeTestEnvironment()
+{
+    concurrency::hasBeenSetup = true;
+    consoleInit();
+#if ARCH_PORTDUINO
+    struct timeval tv;
+    tv.tv_sec = time(NULL);
+    tv.tv_usec = 0;
+    perhapsSetRTC(RTCQualityNTP, &tv);
+#endif
+    concurrency::OSThread::setup();
+}
\ No newline at end of file
diff --git a/test/TestUtil.h b/test/TestUtil.h
new file mode 100644
index 000000000..ce021e459
--- /dev/null
+++ b/test/TestUtil.h
@@ -0,0 +1,4 @@
+#pragma once
+
+// Initialize testing environment.
+void initializeTestEnvironment();
\ No newline at end of file
diff --git a/test/test_crypto/test_main.cpp b/test/test_crypto/test_main.cpp
index 652d5dbcb..fd7706e6e 100644
--- a/test/test_crypto/test_main.cpp
+++ b/test/test_crypto/test_main.cpp
@@ -1,5 +1,6 @@
 #include "CryptoEngine.h"
 
+#include "TestUtil.h"
 #include 
 
 void HexToBytes(uint8_t *result, const std::string hex, size_t len = 0)
@@ -170,15 +171,14 @@ void setup()
     delay(10);
     delay(2000);
 
+    initializeTestEnvironment();
     UNITY_BEGIN(); // IMPORTANT LINE!
     RUN_TEST(test_SHA256);
     RUN_TEST(test_ECB_AES256);
     RUN_TEST(test_DH25519);
     RUN_TEST(test_AES_CTR);
     RUN_TEST(test_PKC_Decrypt);
+    exit(UNITY_END()); // stop unit testing
 }
 
-void loop()
-{
-    UNITY_END(); // stop unit testing
-}
\ No newline at end of file
+void loop() {}
\ No newline at end of file
diff --git a/userPrefs.h b/userPrefs.h
deleted file mode 100644
index 00f04149a..000000000
--- a/userPrefs.h
+++ /dev/null
@@ -1,107 +0,0 @@
-#ifndef _USERPREFS_
-#define _USERPREFS_
-
-// Slipstream values:
-
-#define USERPREFS_TZ_STRING "tzplaceholder                                         "
-
-// Uncomment and modify to set device defaults
-
-// #define USERPREFS_EVENT_MODE 1
-
-// #define USERPREFS_CONFIG_LORA_REGION meshtastic_Config_LoRaConfig_RegionCode_US
-// #define USERPREFS_LORACONFIG_MODEM_PRESET meshtastic_Config_LoRaConfig_ModemPreset_SHORT_FAST
-// #define USERPREFS_LORACONFIG_CHANNEL_NUM 31
-// #define USERPREFS_CONFIG_LORA_IGNORE_MQTT true
-
-// #define USERPREFS_CONFIG_GPS_MODE meshtastic_Config_PositionConfig_GpsMode_ENABLED
-
-// #define USERPREFS_CHANNELS_TO_WRITE 3
-/*
-#define USERPREFS_CHANNEL_0_PSK \
-    {                                                                                                                            \
-        0x38, 0x4b, 0xbc, 0xc0, 0x1d, 0xc0, 0x22, 0xd1, 0x81, 0xbf, 0x36, 0xb8, 0x61, 0x21, 0xe1, 0xfb, 0x96, 0xb7, 0x2e, 0x55,  \
-            0xbf, 0x74, 0x22, 0x7e, 0x9d, 0x6a, 0xfb, 0x48, 0xd6, 0x4c, 0xb1, 0xa1                                               \
-    }
-*/
-// #define USERPREFS_CHANNEL_0_NAME "DEFCONnect"
-// #define USERPREFS_CHANNEL_0_PRECISION 14
-// #define USERPREFS_CHANNEL_0_UPLINK_ENABLED true
-// #define USERPREFS_CHANNEL_0_DOWNLINK_ENABLED true
-/*
-#define USERPREFS_CHANNEL_1_PSK \
-    {                                                                                                                            \
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  \
-            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00                                               \
-    }
-*/
-// #define USERPREFS_CHANNEL_1_NAME "REPLACEME"
-// #define USERPREFS_CHANNEL_1_PRECISION 14
-// #define USERPREFS_CHANNEL_1_UPLINK_ENABLED true
-// #define USERPREFS_CHANNEL_1_DOWNLINK_ENABLED true
-/*
-#define USERPREFS_CHANNEL_2_PSK \
-    {                                                                                                                            \
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  \
-            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00                                              \
-    }
-*/
-// #define USERPREFS_CHANNEL_2_NAME "REPLACEME"
-// #define USERPREFS_CHANNEL_2_PRECISION 14
-// #define USERPREFS_CHANNEL_2_UPLINK_ENABLED true
-// #define USERPREFS_CHANNEL_2_DOWNLINK_ENABLED true
-
-// #define USERPREFS_CONFIG_OWNER_LONG_NAME "My Long Name"
-// #define USERPREFS_CONFIG_OWNER_SHORT_NAME "MLN"
-
-// #define USERPREFS_SPLASH_TITLE "DEFCONtastic"
-// #define icon_width 34
-// #define icon_height 29
-// #define USERPREFS_HAS_SPLASH
-/*
-static unsigned char icon_bits[] = {
-    0x00, 0xC0, 0x0F, 0x00, 0x00, 0x00, 0xF0, 0x3F, 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0x00, 0x00, 0x00,
-    0x9E, 0xE7, 0x00, 0x00, 0x00, 0x0E, 0xC7, 0x01, 0x00, 0x1C, 0x0F, 0xC7, 0x01, 0x00, 0x1C, 0xDF, 0xE7, 0x63, 0x00, 0x1C, 0xFF,
-    0xBF, 0xE1, 0x00, 0x3C, 0xF3, 0xBF, 0xE3, 0x00, 0x7F, 0xF7, 0xBF, 0xF1, 0x00, 0xFF, 0xF7, 0xBF, 0xF9, 0x03, 0xFF, 0xE7, 0x9F,
-    0xFF, 0x03, 0xC0, 0xCF, 0xEF, 0xDF, 0x03, 0x00, 0xDF, 0xE3, 0x8F, 0x00, 0x00, 0x7C, 0xFB, 0x03, 0x00, 0x00, 0xF8, 0xFF, 0x00,
-    0x00, 0x00, 0xE0, 0x0F, 0x00, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, 0x00, 0x78, 0x3F, 0x00, 0x00, 0x00, 0xFC, 0xFC, 0x00, 0x00,
-    0x98, 0x3F, 0xF0, 0x23, 0x00, 0xFC, 0x0F, 0xE0, 0x7F, 0x00, 0xFC, 0x03, 0x80, 0xFF, 0x01, 0xFC, 0x00, 0x00, 0x3E, 0x00, 0x70,
-    0x00, 0x00, 0x1C, 0x00, 0x70, 0x00, 0x00, 0x1C, 0x00, 0x70, 0x00, 0x00, 0x1C, 0x00, 0x70, 0x00, 0x00, 0x1C, 0x00};
-*/
-
-/*
- * PKI Admin keys.
- * If a Admin key is set with '{};'
- * then it will be ignored, a PKI key must have a size of 32 byte.
- */
-/*
-#define USERPREFS_USE_ADMIN_KEY_0 \
-    {                                                                                                                           \
-        0xcd, 0xc0, 0xb4, 0x3c, 0x53, 0x24, 0xdf, 0x13, 0xca, 0x5a, 0xa6, 0x0c, 0x0d, 0xec, 0x85, 0x5a, 0x4c, 0xf6, 0x1a, 0x96, \
-        0x04, 0x1a, 0x3e, 0xfc, 0xbb, 0x8e, 0x33, 0x71, 0xe5, 0xfc, 0xff, 0x3c                                                  \
-    };
-*/
-// #define USERPREFS_USE_ADMIN_KEY_1 {};
-// #define USERPREFS_USE_ADMIN_KEY_2 {};
-
-/*
- * USERPREF_FIXED_GPS_LAT and USERPREF_FIXED_GPS_LON must be set, USERPREF_FIXED_GPS_ALT is optional
- *
- * Fixed GPS is Eiffel Tower, Paris, France
- */
-// #define USERPREFS_FIXED_GPS
-// #define USERPREFS_FIXED_GPS_LAT 48.85873920
-// #define USERPREFS_FIXED_GPS_LON 2.294508368
-// #define USERPREFS_FIXED_GPS_ALT 0
-
-/*
- * Set Fixed Bluetooth paring code
- */
-// #define USERPREFS_FIXED_BLUETOOTH 121212
-
-/*
- * Will overwrite BUTTON_PIN if set
- */
-// #define USERPREFS_BUTTON_PIN 36
-
-#endif
\ No newline at end of file
diff --git a/userPrefs.json b/userPrefs.json
deleted file mode 100644
index bc62602be..000000000
--- a/userPrefs.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
-  "USERPREFS_CHANNEL_0_NAME": "\"DEFCONnect\"",
-  "USERPREFS_CHANNEL_0_PRECISION": "14",
-  "USERPREFS_CHANNEL_0_PSK": "{ 0x38, 0x4b, 0xbc, 0xc0, 0x1d, 0xc0, 0x22, 0xd1, 0x81, 0xbf, 0x36, 0xb8, 0x61, 0x21, 0xe1, 0xfb, 0x96, 0xb7, 0x2e, 0x55, 0xbf, 0x74, 0x22, 0x7e, 0x9d, 0x6a, 0xfb, 0x48, 0xd6, 0x4c, 0xb1, 0xa1 }",
-  "USERPREFS_CONFIG_LORA_IGNORE_MQTT": "true",
-  "USERPREFS_CONFIG_LORA_REGION": "meshtastic_Config_LoRaConfig_RegionCode_US",
-  "USERPREFS_CONFIG_OWNER_LONG_NAME": "\"My Long Name\"",
-  "USERPREFS_CONFIG_OWNER_SHORT_NAME": "\"MLN\"",
-  "USERPREFS_EVENT_MODE": "1",
-  "USERPREFS_HAS_SPLASH": "",
-  "USERPREFS_LORACONFIG_CHANNEL_NUM": "31",
-  "USERPREFS_LORACONFIG_MODEM_PRESET": "meshtastic_Config_LoRaConfig_ModemPreset_SHORT_FAST",
-  "USERPREFS_SPLASH_TITLE": "\"DEFCONtastic\"",
-  "USERPREFS_TZ_STRING": "\"tzplaceholder                                         \"",
-  "USERPREFS_USE_ADMIN_KEY": "1"
-}
diff --git a/userPrefs.jsonc b/userPrefs.jsonc
new file mode 100644
index 000000000..055f59273
--- /dev/null
+++ b/userPrefs.jsonc
@@ -0,0 +1,37 @@
+{
+  // "USERPREFS_BUTTON_PIN": "36",
+  // "USERPREFS_CHANNELS_TO_WRITE": "3",
+  // "USERPREFS_CHANNEL_0_DOWNLINK_ENABLED": "true",
+  // "USERPREFS_CHANNEL_0_NAME": "DEFCONnect",
+  // "USERPREFS_CHANNEL_0_PRECISION": "14",
+  // "USERPREFS_CHANNEL_0_PSK": "{ 0x38, 0x4b, 0xbc, 0xc0, 0x1d, 0xc0, 0x22, 0xd1, 0x81, 0xbf, 0x36, 0xb8, 0x61, 0x21, 0xe1, 0xfb, 0x96, 0xb7, 0x2e, 0x55, 0xbf, 0x74, 0x22, 0x7e, 0x9d, 0x6a, 0xfb, 0x48, 0xd6, 0x4c, 0xb1, 0xa1 }",
+  // "USERPREFS_CHANNEL_0_UPLINK_ENABLED": "true",
+  // "USERPREFS_CHANNEL_1_DOWNLINK_ENABLED": "true",
+  // "USERPREFS_CHANNEL_1_NAME": "REPLACEME",
+  // "USERPREFS_CHANNEL_1_PRECISION": "14",
+  // "USERPREFS_CHANNEL_1_PSK": "{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }",
+  // "USERPREFS_CHANNEL_1_UPLINK_ENABLED": "true",
+  // "USERPREFS_CHANNEL_2_DOWNLINK_ENABLED": "true",
+  // "USERPREFS_CHANNEL_2_NAME": "REPLACEME",
+  // "USERPREFS_CHANNEL_2_PRECISION": "14",
+  // "USERPREFS_CHANNEL_2_PSK": "{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }",
+  // "USERPREFS_CHANNEL_2_UPLINK_ENABLED": "true",
+  // "USERPREFS_CONFIG_GPS_MODE": "meshtastic_Config_PositionConfig_GpsMode_ENABLED",
+  // "USERPREFS_CONFIG_LORA_IGNORE_MQTT": "true",
+  // "USERPREFS_CONFIG_LORA_REGION": "meshtastic_Config_LoRaConfig_RegionCode_US",
+  // "USERPREFS_CONFIG_OWNER_LONG_NAME": "My Long Name",
+  // "USERPREFS_CONFIG_OWNER_SHORT_NAME": "MLN",
+  // "USERPREFS_EVENT_MODE": "1",
+  // "USERPREFS_FIXED_BLUETOOTH": "121212",
+  // "USERPREFS_FIXED_GPS": "",
+  // "USERPREFS_FIXED_GPS_ALT": "0",
+  // "USERPREFS_FIXED_GPS_LAT": "48.85873920",
+  // "USERPREFS_FIXED_GPS_LON": "2.294508368",
+  // "USERPREFS_LORACONFIG_CHANNEL_NUM": "31",
+  // "USERPREFS_LORACONFIG_MODEM_PRESET": "meshtastic_Config_LoRaConfig_ModemPreset_SHORT_FAST",
+  // "USERPREFS_SPLASH_TITLE": "DEFCONtastic",
+  "USERPREFS_TZ_STRING": "tzplaceholder                                         "
+  // "USERPREFS_USE_ADMIN_KEY_0": "{ 0xcd, 0xc0, 0xb4, 0x3c, 0x53, 0x24, 0xdf, 0x13, 0xca, 0x5a, 0xa6, 0x0c, 0x0d, 0xec, 0x85, 0x5a, 0x4c, 0xf6, 0x1a, 0x96, 0x04, 0x1a, 0x3e, 0xfc, 0xbb, 0x8e, 0x33, 0x71, 0xe5, 0xfc, 0xff, 0x3c }",
+  // "USERPREFS_USE_ADMIN_KEY_1": "{}",
+  // "USERPREFS_USE_ADMIN_KEY_2": "{}"
+}
\ No newline at end of file
diff --git a/variants/diy/nrf52_promicro_diy_tcxo/Schematic_Pro-Micro_Pinouts 2024-12-14.pdf b/variants/diy/nrf52_promicro_diy_tcxo/Schematic_Pro-Micro_Pinouts 2024-12-14.pdf
new file mode 100644
index 000000000..de87af141
--- /dev/null
+++ b/variants/diy/nrf52_promicro_diy_tcxo/Schematic_Pro-Micro_Pinouts 2024-12-14.pdf	
@@ -0,0 +1,9836 @@
+%PDF-1.4
+%߬
+3 0 obj
+<>
+endobj
+4 0 obj
+<<
+/Length 102720
+>>
+stream
+0.20 w
+0 G
+2 J
+0 j
+100 M
+1.00 g
+[] 0 d
+0.00 826.80 1169.00 -826.80 re
+f
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+216.000 806.000 m 
+216.000 816.000 l
+216.000 20.000 m 
+216.000 10.000 l
+412.000 806.000 m 
+412.000 816.000 l
+412.000 20.000 m 
+412.000 10.000 l
+608.000 806.000 m 
+608.000 816.000 l
+608.000 20.000 m 
+608.000 10.000 l
+804.000 806.000 m 
+804.000 816.000 l
+804.000 20.000 m 
+804.000 10.000 l
+1000.000 806.000 m 
+1000.000 816.000 l
+1000.000 20.000 m 
+1000.000 10.000 l
+20.000 610.000 m 
+10.000 610.000 l
+1149.000 610.000 m 
+1159.000 610.000 l
+20.000 414.000 m 
+10.000 414.000 l
+1149.000 414.000 m 
+1159.000 414.000 l
+20.000 218.000 m 
+10.000 218.000 l
+1149.000 218.000 m 
+1159.000 218.000 l
+20.000 22.000 m 
+10.000 22.000 l
+1149.000 22.000 m 
+1159.000 22.000 l
+S
+10.00 w
+BT
+/F1 9 Tf
+9.00 TL
+0.533 0.000 0.000 rg
+11.50 708.00 Td
+(A) Tj
+ET
+10.00 w
+BT
+/F1 9 Tf
+9.00 TL
+0.533 0.000 0.000 rg
+1150.50 708.00 Td
+(A) Tj
+ET
+10.00 w
+BT
+/F1 9 Tf
+9.00 TL
+0.533 0.000 0.000 rg
+11.50 512.00 Td
+(B) Tj
+ET
+10.00 w
+BT
+/F1 9 Tf
+9.00 TL
+0.533 0.000 0.000 rg
+1150.50 512.00 Td
+(B) Tj
+ET
+10.00 w
+BT
+/F1 9 Tf
+9.00 TL
+0.533 0.000 0.000 rg
+11.50 316.00 Td
+(C) Tj
+ET
+10.00 w
+BT
+/F1 9 Tf
+9.00 TL
+0.533 0.000 0.000 rg
+1150.50 316.00 Td
+(C) Tj
+ET
+10.00 w
+BT
+/F1 9 Tf
+9.00 TL
+0.533 0.000 0.000 rg
+11.50 120.00 Td
+(D) Tj
+ET
+10.00 w
+BT
+/F1 9 Tf
+9.00 TL
+0.533 0.000 0.000 rg
+1150.50 120.00 Td
+(D) Tj
+ET
+10.00 w
+BT
+/F1 9 Tf
+9.00 TL
+0.533 0.000 0.000 rg
+118.00 807.50 Td
+(1) Tj
+ET
+10.00 w
+BT
+/F1 9 Tf
+9.00 TL
+0.533 0.000 0.000 rg
+118.00 11.50 Td
+(1) Tj
+ET
+10.00 w
+BT
+/F1 9 Tf
+9.00 TL
+0.533 0.000 0.000 rg
+314.00 807.50 Td
+(2) Tj
+ET
+10.00 w
+BT
+/F1 9 Tf
+9.00 TL
+0.533 0.000 0.000 rg
+314.00 11.50 Td
+(2) Tj
+ET
+10.00 w
+BT
+/F1 9 Tf
+9.00 TL
+0.533 0.000 0.000 rg
+510.00 807.50 Td
+(3) Tj
+ET
+10.00 w
+BT
+/F1 9 Tf
+9.00 TL
+0.533 0.000 0.000 rg
+510.00 11.50 Td
+(3) Tj
+ET
+10.00 w
+BT
+/F1 9 Tf
+9.00 TL
+0.533 0.000 0.000 rg
+706.00 807.50 Td
+(4) Tj
+ET
+10.00 w
+BT
+/F1 9 Tf
+9.00 TL
+0.533 0.000 0.000 rg
+706.00 11.50 Td
+(4) Tj
+ET
+10.00 w
+BT
+/F1 9 Tf
+9.00 TL
+0.533 0.000 0.000 rg
+902.00 807.50 Td
+(5) Tj
+ET
+10.00 w
+BT
+/F1 9 Tf
+9.00 TL
+0.533 0.000 0.000 rg
+902.00 11.50 Td
+(5) Tj
+ET
+2 J
+0 j
+100 M
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+20.00 806.00 1129.00 -786.00 re
+S
+2 J
+0 j
+100 M
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+10.00 816.00 1149.00 -806.00 re
+S
+2 J
+0 j
+100 M
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+705.00 100.00 444.00 -80.00 re
+S
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+0.00 g
+[] 0 d
+705.100 60.750 m 
+1148.630 60.750 l
+S
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+0.00 g
+[] 0 d
+809.630 40.750 m 
+1148.630 40.750 l
+S
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+0.00 g
+[] 0 d
+1069.610 99.930 m 
+1069.630 60.750 l
+S
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+0.00 g
+[] 0 d
+1069.630 60.750 m 
+1069.630 40.750 l
+S
+10.00 w
+BT
+/F1 11 Tf
+11.00 TL
+0.533 0.000 0.000 rg
+710.00 87.00 Td
+(TITLE:) Tj
+ET
+10.00 w
+BT
+/F1 13 Tf
+13.00 TL
+0.000 0.000 1.000 rg
+767.62 74.41 Td
+(Pro-Micro Pinouts) Tj
+ET
+10.00 w
+BT
+/F1 11 Tf
+11.00 TL
+0.533 0.000 0.000 rg
+1074.62 73.75 Td
+(REV:) Tj
+ET
+10.00 w
+BT
+/F1 12 Tf
+12.00 TL
+0.000 0.000 1.000 rg
+1112.62 73.75 Td
+(1.0) Tj
+ET
+10.00 w
+BT
+/F1 11 Tf
+11.00 TL
+0.533 0.000 0.000 rg
+814.62 25.00 Td
+(Date:) Tj
+ET
+10.00 w
+BT
+/F1 12 Tf
+12.00 TL
+0.000 0.000 1.000 rg
+861.62 24.52 Td
+(2024-12-17) Tj
+ET
+10.00 w
+BT
+/F1 11 Tf
+11.00 TL
+0.533 0.000 0.000 rg
+1073.62 45.00 Td
+(Sheet:) Tj
+ET
+10.00 w
+BT
+/F1 12 Tf
+12.00 TL
+0.000 0.000 1.000 rg
+1118.62 44.52 Td
+(1/1) Tj
+ET
+10.00 w
+BT
+/F1 11 Tf
+11.00 TL
+0.533 0.000 0.000 rg
+953.62 24.75 Td
+(Drawn By:) Tj
+ET
+10.00 w
+BT
+/F1 11 Tf
+11.00 TL
+0.533 0.000 0.000 rg
+814.62 46.75 Td
+(Company:) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+0.00 g
+[] 0 d
+809.630 60.750 m 
+809.630 20.750 l
+S
+1 J
+1 j
+1.00 w
+0.20 0.80 0.20 RG
+[] 0 d
+541.000 684.000 m 
+549.000 676.000 l
+549.000 684.000 m 
+541.000 676.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 0.53 0.00 RG
+0.00 g
+[] 0 d
+665.000 680.000 m 
+635.000 680.000 l
+S
+1 J
+1 j
+1.00 w
+0.20 0.80 0.20 RG
+[] 0 d
+986.000 649.000 m 
+994.000 641.000 l
+994.000 649.000 m 
+986.000 641.000 l
+S
+1 J
+1 j
+1.00 w
+0.20 0.80 0.20 RG
+[] 0 d
+541.000 614.000 m 
+549.000 606.000 l
+549.000 614.000 m 
+541.000 606.000 l
+S
+1 J
+1 j
+1.00 w
+0.20 0.80 0.20 RG
+[] 0 d
+541.000 624.000 m 
+549.000 616.000 l
+549.000 624.000 m 
+541.000 616.000 l
+S
+1 J
+1 j
+1.00 w
+0.20 0.80 0.20 RG
+[] 0 d
+541.000 644.000 m 
+549.000 636.000 l
+549.000 644.000 m 
+541.000 636.000 l
+S
+1 J
+1 j
+1.00 w
+0.20 0.80 0.20 RG
+[] 0 d
+631.000 634.000 m 
+639.000 626.000 l
+639.000 634.000 m 
+631.000 626.000 l
+S
+BT
+/F2 12 Tf
+12.00 TL
+0.000 g
+1.00 -0.00 0.00 1.00 804.82 611.00 Tm
+(VCC) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+830.000 615.000 m 
+840.000 615.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+830.000 610.000 m 
+830.000 620.000 l
+S
+BT
+/F2 12 Tf
+12.00 TL
+0.000 g
+1.00 -0.00 0.00 1.00 797.50 621.00 Tm
+(GND) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+830.000 625.000 m 
+840.000 625.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+830.000 634.000 m 
+830.000 616.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+828.000 631.000 m 
+828.000 619.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+826.000 628.000 m 
+826.000 622.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+824.000 626.000 m 
+824.000 624.000 l
+S
+BT
+/F2 12 Tf
+12.00 TL
+0.000 g
+1.00 -0.00 0.00 1.00 1006.50 651.00 Tm
+(GND) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+1000.000 655.000 m 
+990.000 655.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+1000.000 646.000 m 
+1000.000 664.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+1002.000 649.000 m 
+1002.000 661.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+1004.000 652.000 m 
+1004.000 658.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+1006.000 654.000 m 
+1006.000 656.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 1011.94 671.15 Tm
+(IRQ) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+990.000 675.000 m 
+995.000 680.000 l
+1010.000 680.000 l
+1010.000 670.000 l
+995.000 670.000 l
+990.000 675.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 797.25 651.75 Tm
+(SCK) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+840.000 655.000 m 
+835.000 650.000 l
+820.000 650.000 l
+820.000 660.000 l
+835.000 660.000 l
+840.000 655.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 804.69 631.45 Tm
+(CS) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+840.000 635.000 m 
+835.000 630.000 l
+820.000 630.000 l
+820.000 640.000 l
+835.000 640.000 l
+840.000 635.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 791.48 661.75 Tm
+(MOSI) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+840.000 665.000 m 
+835.000 660.000 l
+820.000 660.000 l
+820.000 670.000 l
+835.000 670.000 l
+840.000 665.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 791.41 671.75 Tm
+(MISO) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+840.000 675.000 m 
+835.000 670.000 l
+820.000 670.000 l
+820.000 680.000 l
+835.000 680.000 l
+840.000 675.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 790.06 641.57 Tm
+(NRST) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+840.000 645.000 m 
+835.000 640.000 l
+820.000 640.000 l
+820.000 650.000 l
+835.000 650.000 l
+840.000 645.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 1011.92 661.15 Tm
+(BUSY) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+990.000 665.000 m 
+995.000 670.000 l
+1010.000 670.000 l
+1010.000 660.000 l
+995.000 660.000 l
+990.000 665.000 l
+S
+10.00 w
+BT
+/F3 9 Tf
+9.00 TL
+0.000 0.000 0.502 rg
+908.96 708.00 Td
+(Seeed-wio-SX1262) Tj
+ET
+10.00 w
+BT
+/F3 9 Tf
+9.00 TL
+0.000 0.000 0.502 rg
+908.96 717.00 Td
+(SEEED_WIO-SX1262) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+862.00 682.00 Td
+(RF_SW) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+849.28 686.00 Td
+(1) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+840.000 685.000 m 
+860.000 685.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+862.00 672.00 Td
+(MISO) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+849.28 676.00 Td
+(2) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+840.000 675.000 m 
+860.000 675.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+862.00 662.00 Td
+(MOSI) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+849.28 666.00 Td
+(3) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+840.000 665.000 m 
+860.000 665.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+862.00 652.00 Td
+(CLK) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+849.28 656.00 Td
+(4) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+840.000 655.000 m 
+860.000 655.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+862.00 642.00 Td
+(RST) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+849.28 646.00 Td
+(5) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+840.000 645.000 m 
+860.000 645.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+862.00 632.00 Td
+(NSS) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+849.28 636.00 Td
+(6) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+840.000 635.000 m 
+860.000 635.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+862.00 622.00 Td
+(GND) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+849.28 626.00 Td
+(7) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+840.000 625.000 m 
+860.000 625.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+862.00 612.00 Td
+(VCC) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+849.28 616.00 Td
+(8) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+840.000 615.000 m 
+860.000 615.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+949.58 642.00 Td
+(ANT) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+975.00 646.00 Td
+(9) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+990.000 645.000 m 
+970.000 645.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+947.36 652.00 Td
+(GND) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+975.00 656.00 Td
+(10) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+990.000 655.000 m 
+970.000 655.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+943.57 662.00 Td
+(BUSY) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+975.00 666.00 Td
+(11) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+990.000 665.000 m 
+970.000 665.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+944.49 672.00 Td
+(DIO1) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+975.00 676.00 Td
+(12) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+990.000 675.000 m 
+970.000 675.000 l
+S
+2 J
+0 j
+100 M
+1.00 w
+0.00 G
+[] 0 d
+860.00 705.00 110.00 -110.00 re
+S
+1.00 w
+0.00 G
+[] 0 d
+965.00 615.00 m 965.00 623.28 958.28 630.00 950.00 630.00 c
+941.72 630.00 935.00 623.28 935.00 615.00 c
+935.00 606.72 941.72 600.00 950.00 600.00 c
+958.28 600.00 965.00 606.72 965.00 615.00 c
+S
+2 J
+0 j
+100 M
+1.00 w
+0.00 G
+[] 0 d
+930.00 635.00 40.00 -40.00 re
+S
+1 J
+1 j
+1.00 w
+0.00 0.53 0.00 RG
+0.00 g
+[] 0 d
+535.000 660.000 m 
+545.000 660.000 l
+S
+BT
+/F2 12 Tf
+12.00 TL
+0.000 g
+1.00 -0.00 0.00 1.00 499.82 655.93 Tm
+(VCC) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+525.000 660.000 m 
+535.000 660.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+525.000 655.000 m 
+525.000 665.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 0.53 0.00 RG
+0.00 g
+[] 0 d
+520.000 670.000 m 
+545.000 670.000 l
+S
+BT
+/F2 12 Tf
+12.00 TL
+0.000 g
+1.00 -0.00 0.00 1.00 652.00 699.09 Tm
+(GND) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+665.000 690.000 m 
+665.000 680.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+674.000 690.000 m 
+656.000 690.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+671.000 692.000 m 
+659.000 692.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+668.000 694.000 m 
+662.000 694.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+666.000 696.000 m 
+664.000 696.000 l
+S
+BT
+/F2 12 Tf
+12.00 TL
+0.000 g
+1.00 -0.00 0.00 1.00 507.00 689.09 Tm
+(GND) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+520.000 680.000 m 
+520.000 670.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+529.000 680.000 m 
+511.000 680.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+526.000 682.000 m 
+514.000 682.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+523.000 684.000 m 
+517.000 684.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+521.000 686.000 m 
+519.000 686.000 l
+S
+BT
+/F2 12 Tf
+12.00 TL
+0.000 g
+1.00 -0.00 0.00 1.00 622.00 582.76 Tm
+(GND) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+635.000 600.000 m 
+635.000 610.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+626.000 600.000 m 
+644.000 600.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+629.000 598.000 m 
+641.000 598.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+632.000 596.000 m 
+638.000 596.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+634.000 594.000 m 
+636.000 594.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 656.92 616.15 Tm
+(BUSY) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+635.000 620.000 m 
+640.000 625.000 l
+655.000 625.000 l
+655.000 615.000 l
+640.000 615.000 l
+635.000 620.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 656.55 636.15 Tm
+(SCK) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+635.000 640.000 m 
+640.000 645.000 l
+655.000 645.000 l
+655.000 635.000 l
+640.000 635.000 l
+635.000 640.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 656.92 646.15 Tm
+(MISO) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+635.000 650.000 m 
+640.000 655.000 l
+655.000 655.000 l
+655.000 645.000 l
+640.000 645.000 l
+635.000 650.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 656.85 656.15 Tm
+(MOSI) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+635.000 660.000 m 
+640.000 665.000 l
+655.000 665.000 l
+655.000 655.000 l
+640.000 655.000 l
+635.000 660.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 657.00 666.45 Tm
+(CS) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+635.000 670.000 m 
+640.000 675.000 l
+655.000 675.000 l
+655.000 665.000 l
+640.000 665.000 l
+635.000 670.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 504.19 626.40 Tm
+(IRQ) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+545.000 630.000 m 
+540.000 625.000 l
+525.000 625.000 l
+525.000 635.000 l
+540.000 635.000 l
+545.000 630.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 495.06 646.57 Tm
+(NRST) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+545.000 650.000 m 
+540.000 645.000 l
+525.000 645.000 l
+525.000 655.000 l
+540.000 655.000 l
+545.000 650.000 l
+S
+10.00 w
+BT
+/F3 9 Tf
+9.00 TL
+0.000 0.000 0.502 rg
+584.95 693.33 Td
+(RA-01SH) Tj
+ET
+10.00 w
+BT
+/F3 9 Tf
+9.00 TL
+0.000 0.000 0.502 rg
+584.95 702.33 Td
+(HT-RA62) Tj
+ET
+2 J
+0 j
+100 M
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+557.000 690.000 m 
+623.000 690.000 l
+624.105 690.000 625.000 689.105 625.000 688.000 c
+625.000 602.000 l
+625.000 600.895 623.895 600.000 623.000 600.000 c
+557.000 600.000 l
+555.895 600.000 555.000 601.105 555.000 602.000 c
+555.000 688.000 l
+555.000 689.105 556.105 690.000 557.000 690.000 c
+S
+1.00 w
+0.53 0.00 0.00 RG
+0.53 0.00 0.00 rg
+[] 0 d
+561.50 685.00 m 561.50 685.83 560.83 686.50 560.00 686.50 c
+559.17 686.50 558.50 685.83 558.50 685.00 c
+558.50 684.17 559.17 683.50 560.00 683.50 c
+560.83 683.50 561.50 684.17 561.50 685.00 c
+B
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+558.70 676.00 Td
+(ANT) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+548.78 681.00 Td
+(1) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+545.000 680.000 m 
+555.000 680.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 g
+558.70 666.00 Td
+(GND) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 g
+548.78 671.00 Td
+(2) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+[] 0 d
+545.000 670.000 m 
+555.000 670.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+558.70 656.00 Td
+(3.3V) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+548.78 661.00 Td
+(3) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+545.000 660.000 m 
+555.000 660.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+558.70 646.00 Td
+(RESET) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+548.78 651.00 Td
+(4) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+545.000 650.000 m 
+555.000 650.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+558.70 636.00 Td
+(TXEN) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+548.78 641.00 Td
+(5) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+545.000 640.000 m 
+555.000 640.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+558.70 626.00 Td
+(DIO1) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+548.78 631.00 Td
+(6) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+545.000 630.000 m 
+555.000 630.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+558.70 616.00 Td
+(DIO2) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+548.78 621.00 Td
+(7) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+545.000 620.000 m 
+555.000 620.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+558.70 606.00 Td
+(DIO3) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+548.78 611.00 Td
+(8) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+545.000 610.000 m 
+555.000 610.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 g
+600.66 606.00 Td
+(GND) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 g
+625.50 611.00 Td
+(9) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+[] 0 d
+635.000 610.000 m 
+625.000 610.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+596.87 616.00 Td
+(BUSY) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+625.50 621.00 Td
+(10) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+635.000 620.000 m 
+625.000 620.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+596.46 626.00 Td
+(RXEN) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+625.50 631.00 Td
+(11) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+635.000 630.000 m 
+625.000 630.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+602.64 636.00 Td
+(SCK) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+625.50 641.00 Td
+(12) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+635.000 640.000 m 
+625.000 640.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+596.71 646.00 Td
+(MISO) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+625.50 651.00 Td
+(13) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+635.000 650.000 m 
+625.000 650.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+596.71 656.00 Td
+(MOSI) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+625.50 661.00 Td
+(14) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+635.000 660.000 m 
+625.000 660.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+602.27 666.00 Td
+(NSS) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+625.50 671.00 Td
+(15) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+635.000 670.000 m 
+625.000 670.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 g
+600.66 676.00 Td
+(GND) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 g
+625.50 681.00 Td
+(16) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+[] 0 d
+635.000 680.000 m 
+625.000 680.000 l
+S
+10.00 w
+BT
+/F3 9 Tf
+9.00 TL
+0.000 0.000 0.502 rg
+153.95 479.05 Td
+(AMC-U_FL) Tj
+ET
+10.00 w
+BT
+/F3 9 Tf
+9.00 TL
+0.000 0.000 0.502 rg
+153.95 488.16 Td
+(U6) Tj
+ET
+2 J
+0 j
+100 M
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+165.00 465.00 20.00 -20.00 re
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+0.00 1.00 -1.00 0.00 174.00 434.29 Tm
+(1) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+175.000 425.000 m 
+175.000 445.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+159.28 456.00 Td
+(2) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+155.000 455.000 m 
+165.000 455.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+185.00 456.00 Td
+(3) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+195.000 455.000 m 
+185.000 455.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+0.00 1.00 -1.00 0.00 174.00 465.00 Tm
+(4) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+175.000 475.000 m 
+175.000 465.000 l
+S
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+177.00 455.00 m 177.00 456.10 176.10 457.00 175.00 457.00 c
+173.90 457.00 173.00 456.10 173.00 455.00 c
+173.00 453.90 173.90 453.00 175.00 453.00 c
+176.10 453.00 177.00 453.90 177.00 455.00 c
+S
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+0.00 g
+[] 0 d
+175.000 453.000 m 
+175.000 445.000 l
+S
+1 J
+1 j
+1.00 w
+0.20 0.80 0.20 RG
+[] 0 d
+506.000 394.000 m 
+514.000 386.000 l
+514.000 394.000 m 
+506.000 386.000 l
+S
+1 J
+1 j
+1.00 w
+0.20 0.80 0.20 RG
+[] 0 d
+646.000 394.000 m 
+654.000 386.000 l
+654.000 394.000 m 
+646.000 386.000 l
+S
+BT
+/F2 12 Tf
+12.00 TL
+0.000 g
+1.00 -0.00 0.00 1.00 666.50 415.93 Tm
+(GND) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+660.000 420.000 m 
+650.000 420.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+660.000 411.000 m 
+660.000 429.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+662.000 414.000 m 
+662.000 426.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+664.000 417.000 m 
+664.000 423.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+666.000 419.000 m 
+666.000 421.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 0.53 0.00 RG
+0.00 g
+[] 0 d
+650.000 430.000 m 
+650.000 400.000 l
+S
+1 J
+1 j
+1.00 w
+0.20 0.80 0.20 RG
+[] 0 d
+796.000 389.000 m 
+804.000 381.000 l
+804.000 389.000 m 
+796.000 381.000 l
+S
+10.00 w
+BT
+/F3 9 Tf
+9.00 TL
+0.000 0.000 0.502 rg
+573.96 503.33 Td
+(E22-900M22S) Tj
+ET
+10.00 w
+BT
+/F3 9 Tf
+9.00 TL
+0.000 0.000 0.502 rg
+573.96 512.33 Td
+(E22-900M22S) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+532.00 377.00 Td
+(GND) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+513.57 381.00 Td
+(22) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+510.000 380.000 m 
+530.000 380.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+532.00 387.00 Td
+(ANT) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+513.57 391.00 Td
+(21) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+510.000 390.000 m 
+530.000 390.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+532.00 397.00 Td
+(GND) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+513.57 401.00 Td
+(20) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+510.000 400.000 m 
+530.000 400.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+532.00 417.00 Td
+(NSS) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+513.57 421.00 Td
+(19) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+510.000 420.000 m 
+530.000 420.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+532.00 427.00 Td
+(SCK) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+513.57 431.00 Td
+(18) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+510.000 430.000 m 
+530.000 430.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+532.00 437.00 Td
+(MOSI) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+513.57 441.00 Td
+(17) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+510.000 440.000 m 
+530.000 440.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+532.00 447.00 Td
+(MISO) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+513.57 451.00 Td
+(16) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+510.000 450.000 m 
+530.000 450.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+532.00 457.00 Td
+(NRST) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+513.57 461.00 Td
+(15) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+510.000 460.000 m 
+530.000 460.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+532.00 467.00 Td
+(BUSY) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+513.57 471.00 Td
+(14) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+510.000 470.000 m 
+530.000 470.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+532.00 477.00 Td
+(DIO1) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+513.57 481.00 Td
+(13) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+510.000 480.000 m 
+530.000 480.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+532.00 487.00 Td
+(GND) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+513.57 491.00 Td
+(12) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+510.000 490.000 m 
+530.000 490.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+607.36 487.00 Td
+(GND) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+635.00 491.00 Td
+(11) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+650.000 490.000 m 
+630.000 490.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+607.36 477.00 Td
+(GND) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+635.00 481.00 Td
+(10) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+650.000 480.000 m 
+630.000 480.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+609.29 467.00 Td
+(VCC) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+635.00 471.00 Td
+(9) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+650.000 470.000 m 
+630.000 470.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+604.49 457.00 Td
+(DIO2) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+635.00 461.00 Td
+(8) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+650.000 460.000 m 
+630.000 460.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+603.87 447.00 Td
+(TXEN) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+635.00 451.00 Td
+(7) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+650.000 450.000 m 
+630.000 450.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+603.16 437.00 Td
+(RXEN) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+635.00 441.00 Td
+(6) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+650.000 440.000 m 
+630.000 440.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+607.36 427.00 Td
+(GND) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+635.00 431.00 Td
+(5) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+650.000 430.000 m 
+630.000 430.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+607.36 417.00 Td
+(GND) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+635.00 421.00 Td
+(4) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+650.000 420.000 m 
+630.000 420.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+607.36 397.00 Td
+(GND) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+635.00 401.00 Td
+(3) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+650.000 400.000 m 
+630.000 400.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+607.36 387.00 Td
+(GND) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+635.00 391.00 Td
+(2) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+650.000 390.000 m 
+630.000 390.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+607.36 377.00 Td
+(GND) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+635.00 381.00 Td
+(1) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+650.000 380.000 m 
+630.000 380.000 l
+S
+2 J
+0 j
+100 M
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+532.000 500.000 m 
+628.000 500.000 l
+629.105 500.000 630.000 499.105 630.000 498.000 c
+630.000 362.000 l
+630.000 360.895 628.895 360.000 628.000 360.000 c
+532.000 360.000 l
+530.895 360.000 530.000 361.105 530.000 362.000 c
+530.000 498.000 l
+530.000 499.105 531.105 500.000 532.000 500.000 c
+S
+10.00 w
+BT
+/F3 9 Tf
+9.00 TL
+0.000 0.000 0.502 rg
+863.96 498.33 Td
+(E22-900M30S) Tj
+ET
+10.00 w
+BT
+/F3 9 Tf
+9.00 TL
+0.000 0.000 0.502 rg
+863.96 507.33 Td
+(E22-900M30S) Tj
+ET
+2 J
+0 j
+100 M
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+822.000 495.000 m 
+918.000 495.000 l
+919.105 495.000 920.000 494.105 920.000 493.000 c
+920.000 357.000 l
+920.000 355.895 918.895 355.000 918.000 355.000 c
+822.000 355.000 l
+820.895 355.000 820.000 356.105 820.000 357.000 c
+820.000 493.000 l
+820.000 494.105 821.105 495.000 822.000 495.000 c
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+897.36 372.00 Td
+(GND) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+925.00 376.00 Td
+(1) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+940.000 375.000 m 
+920.000 375.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+897.36 382.00 Td
+(GND) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+925.00 386.00 Td
+(2) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+940.000 385.000 m 
+920.000 385.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+897.36 392.00 Td
+(GND) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+925.00 396.00 Td
+(3) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+940.000 395.000 m 
+920.000 395.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+897.36 412.00 Td
+(GND) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+925.00 416.00 Td
+(4) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+940.000 415.000 m 
+920.000 415.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+897.36 422.00 Td
+(GND) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+925.00 426.00 Td
+(5) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+940.000 425.000 m 
+920.000 425.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+893.16 432.00 Td
+(RXEN) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+925.00 436.00 Td
+(6) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+940.000 435.000 m 
+920.000 435.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+893.87 442.00 Td
+(TXEN) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+925.00 446.00 Td
+(7) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+940.000 445.000 m 
+920.000 445.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+894.49 452.00 Td
+(DIO2) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+925.00 456.00 Td
+(8) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+940.000 455.000 m 
+920.000 455.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+899.29 462.00 Td
+(VCC) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+925.00 466.00 Td
+(9) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+940.000 465.000 m 
+920.000 465.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+899.29 472.00 Td
+(VCC) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+925.00 476.00 Td
+(10) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+940.000 475.000 m 
+920.000 475.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+897.36 482.00 Td
+(GND) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+925.00 486.00 Td
+(11) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+940.000 485.000 m 
+920.000 485.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+822.00 482.00 Td
+(GND) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+803.57 486.00 Td
+(12) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+800.000 485.000 m 
+820.000 485.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+822.00 472.00 Td
+(DIO1) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+803.57 476.00 Td
+(13) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+800.000 475.000 m 
+820.000 475.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+822.00 462.00 Td
+(BUSY) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+803.57 466.00 Td
+(14) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+800.000 465.000 m 
+820.000 465.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+822.00 452.00 Td
+(NRST) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+803.57 456.00 Td
+(15) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+800.000 455.000 m 
+820.000 455.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+822.00 442.00 Td
+(MISO) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+803.57 446.00 Td
+(16) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+800.000 445.000 m 
+820.000 445.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+822.00 432.00 Td
+(MOSI) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+803.57 436.00 Td
+(17) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+800.000 435.000 m 
+820.000 435.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+822.00 422.00 Td
+(SCK) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+803.57 426.00 Td
+(18) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+800.000 425.000 m 
+820.000 425.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+822.00 412.00 Td
+(NSS) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+803.57 416.00 Td
+(19) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+800.000 415.000 m 
+820.000 415.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+822.00 392.00 Td
+(GND) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+803.57 396.00 Td
+(20) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+800.000 395.000 m 
+820.000 395.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+822.00 382.00 Td
+(ANT) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+803.57 386.00 Td
+(21) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+800.000 385.000 m 
+820.000 385.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+822.00 372.00 Td
+(GND) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+803.57 376.00 Td
+(22) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+800.000 375.000 m 
+820.000 375.000 l
+S
+10.00 w
+BT
+/F3 9 Tf
+9.00 TL
+0.000 0.000 0.502 rg
+293.99 488.33 Td
+(E22-400MM22S) Tj
+ET
+10.00 w
+BT
+/F3 9 Tf
+9.00 TL
+0.000 0.000 0.502 rg
+293.99 497.33 Td
+(E22-900MM22S) Tj
+ET
+2 J
+0 j
+100 M
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+267.000 485.000 m 
+333.000 485.000 l
+334.105 485.000 335.000 484.105 335.000 483.000 c
+335.000 377.000 l
+335.000 375.895 333.895 375.000 333.000 375.000 c
+267.000 375.000 l
+265.895 375.000 265.000 376.105 265.000 377.000 c
+265.000 483.000 l
+265.000 484.105 266.105 485.000 267.000 485.000 c
+S
+1.00 w
+0.53 0.00 0.00 RG
+0.53 0.00 0.00 rg
+[] 0 d
+271.50 480.00 m 271.50 480.83 270.83 481.50 270.00 481.50 c
+269.17 481.50 268.50 480.83 268.50 480.00 c
+268.50 479.17 269.17 478.50 270.00 478.50 c
+270.83 478.50 271.50 479.17 271.50 480.00 c
+B
+BT
+/F1 9 Tf
+9.00 TL
+1.000 0.000 0.000 rg
+268.70 471.00 Td
+(VCC) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+1.000 0.000 0.000 rg
+258.79 476.00 Td
+(1) Tj
+ET
+1 J
+1 j
+1.00 w
+1.00 0.00 0.00 RG
+[] 0 d
+255.000 475.000 m 
+265.000 475.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 g
+268.70 461.00 Td
+(GND) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 g
+258.79 466.00 Td
+(2) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+[] 0 d
+255.000 465.000 m 
+265.000 465.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+268.70 451.00 Td
+(NRST) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+258.79 456.00 Td
+(3) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+255.000 455.000 m 
+265.000 455.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+268.70 441.00 Td
+(NC) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+258.79 446.00 Td
+(4) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+255.000 445.000 m 
+265.000 445.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+268.70 431.00 Td
+(NC) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+258.79 436.00 Td
+(5) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+255.000 435.000 m 
+265.000 435.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+268.70 421.00 Td
+(ANT) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+258.79 426.00 Td
+(6) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+255.000 425.000 m 
+265.000 425.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 g
+268.70 411.00 Td
+(GND) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 g
+258.79 416.00 Td
+(7) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+[] 0 d
+255.000 415.000 m 
+265.000 415.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+268.70 401.00 Td
+(NC) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+258.79 406.00 Td
+(8) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+255.000 405.000 m 
+265.000 405.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+268.70 391.00 Td
+(TXEN) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+258.79 396.00 Td
+(9) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+255.000 395.000 m 
+265.000 395.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+268.70 381.00 Td
+(RXEN) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+253.07 386.00 Td
+(10) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+255.000 385.000 m 
+265.000 385.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+306.87 381.00 Td
+(BUSY) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+335.50 386.00 Td
+(11) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+345.000 385.000 m 
+335.000 385.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+306.71 391.00 Td
+(MISO) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+335.50 396.00 Td
+(12) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+345.000 395.000 m 
+335.000 395.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+306.71 401.00 Td
+(MOSI) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+335.50 406.00 Td
+(13) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+345.000 405.000 m 
+335.000 405.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+312.27 411.00 Td
+(NSS) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+335.50 416.00 Td
+(14) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+345.000 415.000 m 
+335.000 415.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+312.64 421.00 Td
+(SCK) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+335.50 426.00 Td
+(15) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+345.000 425.000 m 
+335.000 425.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 g
+310.66 431.00 Td
+(GND) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 g
+335.50 436.00 Td
+(16) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+[] 0 d
+345.000 435.000 m 
+335.000 435.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+318.29 441.00 Td
+(NC) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+335.50 446.00 Td
+(17) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+345.000 445.000 m 
+335.000 445.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+307.79 451.00 Td
+(DIO3) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+335.50 456.00 Td
+(18) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+345.000 455.000 m 
+335.000 455.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+307.79 461.00 Td
+(DIO2) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+335.50 466.00 Td
+(19) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+345.000 465.000 m 
+335.000 465.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+307.79 471.00 Td
+(DIO1) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+335.50 476.00 Td
+(20) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+345.000 475.000 m 
+335.000 475.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 366.70 381.60 Tm
+(BUSY) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+345.000 385.000 m 
+350.000 390.000 l
+365.000 390.000 l
+365.000 380.000 l
+350.000 380.000 l
+345.000 385.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 203.19 381.40 Tm
+(RXEN) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+255.000 385.000 m 
+250.000 380.000 l
+235.000 380.000 l
+235.000 390.000 l
+250.000 390.000 l
+255.000 385.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 366.71 421.60 Tm
+(SCK) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+345.000 425.000 m 
+350.000 430.000 l
+365.000 430.000 l
+365.000 420.000 l
+350.000 420.000 l
+345.000 425.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 367.00 391.60 Tm
+(MISO) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+345.000 395.000 m 
+350.000 400.000 l
+365.000 400.000 l
+365.000 390.000 l
+350.000 390.000 l
+345.000 395.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 367.00 401.60 Tm
+(MOSI) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+345.000 405.000 m 
+350.000 410.000 l
+365.000 410.000 l
+365.000 400.000 l
+350.000 400.000 l
+345.000 405.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 367.00 411.60 Tm
+(CS) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+345.000 415.000 m 
+350.000 420.000 l
+365.000 420.000 l
+365.000 410.000 l
+350.000 410.000 l
+345.000 415.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 367.01 461.15 Tm
+(DIO2) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+345.000 465.000 m 
+350.000 470.000 l
+365.000 470.000 l
+365.000 460.000 l
+350.000 460.000 l
+345.000 465.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 367.00 471.60 Tm
+(IRQ) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+345.000 475.000 m 
+350.000 480.000 l
+365.000 480.000 l
+365.000 470.000 l
+350.000 470.000 l
+345.000 475.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 203.74 391.40 Tm
+(TXEN) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+255.000 395.000 m 
+250.000 390.000 l
+235.000 390.000 l
+235.000 400.000 l
+250.000 400.000 l
+255.000 395.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 205.06 451.57 Tm
+(NRST) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+255.000 455.000 m 
+250.000 450.000 l
+235.000 450.000 l
+235.000 460.000 l
+250.000 460.000 l
+255.000 455.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 367.01 451.15 Tm
+(DIO3) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+345.000 455.000 m 
+350.000 460.000 l
+365.000 460.000 l
+365.000 450.000 l
+350.000 450.000 l
+345.000 455.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 460.06 456.57 Tm
+(NRST) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+510.000 460.000 m 
+505.000 455.000 l
+490.000 455.000 l
+490.000 465.000 l
+505.000 465.000 l
+510.000 460.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 671.71 446.60 Tm
+(TXEN) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+650.000 450.000 m 
+655.000 455.000 l
+670.000 455.000 l
+670.000 445.000 l
+655.000 445.000 l
+650.000 450.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 469.19 476.40 Tm
+(IRQ) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+510.000 480.000 m 
+505.000 475.000 l
+490.000 475.000 l
+490.000 485.000 l
+505.000 485.000 l
+510.000 480.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 672.01 456.15 Tm
+(DIO2) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+650.000 460.000 m 
+655.000 465.000 l
+670.000 465.000 l
+670.000 455.000 l
+655.000 455.000 l
+650.000 460.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 474.69 416.40 Tm
+(CS) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+510.000 420.000 m 
+505.000 415.000 l
+490.000 415.000 l
+490.000 425.000 l
+505.000 425.000 l
+510.000 420.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 460.61 436.40 Tm
+(MOSI) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+510.000 440.000 m 
+505.000 435.000 l
+490.000 435.000 l
+490.000 445.000 l
+505.000 445.000 l
+510.000 440.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 460.61 446.40 Tm
+(MISO) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+510.000 450.000 m 
+505.000 445.000 l
+490.000 445.000 l
+490.000 455.000 l
+505.000 455.000 l
+510.000 450.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 466.77 426.40 Tm
+(SCK) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+510.000 430.000 m 
+505.000 425.000 l
+490.000 425.000 l
+490.000 435.000 l
+505.000 435.000 l
+510.000 430.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 671.71 436.60 Tm
+(RXEN) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+650.000 440.000 m 
+655.000 445.000 l
+670.000 445.000 l
+670.000 435.000 l
+655.000 435.000 l
+650.000 440.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 458.85 466.40 Tm
+(BUSY) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+510.000 470.000 m 
+505.000 465.000 l
+490.000 465.000 l
+490.000 475.000 l
+505.000 475.000 l
+510.000 470.000 l
+S
+BT
+/F2 12 Tf
+12.00 TL
+0.000 g
+1.00 -0.00 0.00 1.00 467.50 395.92 Tm
+(GND) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+500.000 400.000 m 
+510.000 400.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+500.000 409.000 m 
+500.000 391.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+498.000 406.000 m 
+498.000 394.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+496.000 403.000 m 
+496.000 397.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+494.000 401.000 m 
+494.000 399.000 l
+S
+BT
+/F2 12 Tf
+12.00 TL
+0.000 g
+1.00 -0.00 0.00 1.00 467.50 375.92 Tm
+(GND) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+500.000 380.000 m 
+510.000 380.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+500.000 389.000 m 
+500.000 371.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+498.000 386.000 m 
+498.000 374.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+496.000 383.000 m 
+496.000 377.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+494.000 381.000 m 
+494.000 379.000 l
+S
+BT
+/F2 12 Tf
+12.00 TL
+0.000 g
+1.00 -0.00 0.00 1.00 637.00 352.76 Tm
+(GND) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+650.000 370.000 m 
+650.000 380.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+641.000 370.000 m 
+659.000 370.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+644.000 368.000 m 
+656.000 368.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+647.000 366.000 m 
+653.000 366.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+649.000 364.000 m 
+651.000 364.000 l
+S
+BT
+/F2 12 Tf
+12.00 TL
+0.000 g
+1.00 -0.00 0.00 1.00 637.00 509.13 Tm
+(GND) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+650.000 500.000 m 
+650.000 490.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+659.000 500.000 m 
+641.000 500.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+656.000 502.000 m 
+644.000 502.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+653.000 504.000 m 
+647.000 504.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+651.000 506.000 m 
+649.000 506.000 l
+S
+BT
+/F2 12 Tf
+12.00 TL
+0.000 g
+1.00 -0.00 0.00 1.00 467.50 485.92 Tm
+(GND) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+500.000 490.000 m 
+510.000 490.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+500.000 499.000 m 
+500.000 481.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+498.000 496.000 m 
+498.000 484.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+496.000 493.000 m 
+496.000 487.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+494.000 491.000 m 
+494.000 489.000 l
+S
+BT
+/F2 12 Tf
+12.00 TL
+0.000 g
+1.00 -0.00 0.00 1.00 361.50 430.92 Tm
+(GND) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+355.000 435.000 m 
+345.000 435.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+355.000 426.000 m 
+355.000 444.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+357.000 429.000 m 
+357.000 441.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+359.000 432.000 m 
+359.000 438.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+361.000 434.000 m 
+361.000 436.000 l
+S
+BT
+/F2 12 Tf
+12.00 TL
+0.000 g
+1.00 -0.00 0.00 1.00 212.50 410.93 Tm
+(GND) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+245.000 415.000 m 
+255.000 415.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+245.000 424.000 m 
+245.000 406.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+243.000 421.000 m 
+243.000 409.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+241.000 418.000 m 
+241.000 412.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+239.000 416.000 m 
+239.000 414.000 l
+S
+BT
+/F2 12 Tf
+12.00 TL
+0.000 g
+1.00 -0.00 0.00 1.00 212.50 460.93 Tm
+(GND) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+245.000 465.000 m 
+255.000 465.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+245.000 474.000 m 
+245.000 456.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+243.000 471.000 m 
+243.000 459.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+241.000 468.000 m 
+241.000 462.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+239.000 466.000 m 
+239.000 464.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 0.53 0.00 RG
+0.00 g
+[] 0 d
+940.000 370.000 m 
+940.000 425.000 l
+S
+BT
+/F2 12 Tf
+12.00 TL
+0.000 g
+1.00 -0.00 0.00 1.00 757.50 480.92 Tm
+(GND) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+790.000 485.000 m 
+800.000 485.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+790.000 494.000 m 
+790.000 476.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+788.000 491.000 m 
+788.000 479.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+786.000 488.000 m 
+786.000 482.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+784.000 486.000 m 
+784.000 484.000 l
+S
+BT
+/F2 12 Tf
+12.00 TL
+0.000 g
+1.00 -0.00 0.00 1.00 927.00 504.09 Tm
+(GND) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+940.000 495.000 m 
+940.000 485.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+949.000 495.000 m 
+931.000 495.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+946.000 497.000 m 
+934.000 497.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+943.000 499.000 m 
+937.000 499.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+941.000 501.000 m 
+939.000 501.000 l
+S
+BT
+/F2 12 Tf
+12.00 TL
+0.000 g
+1.00 -0.00 0.00 1.00 757.50 370.92 Tm
+(GND) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+790.000 375.000 m 
+800.000 375.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+790.000 384.000 m 
+790.000 366.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+788.000 381.000 m 
+788.000 369.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+786.000 378.000 m 
+786.000 372.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+784.000 376.000 m 
+784.000 374.000 l
+S
+BT
+/F2 12 Tf
+12.00 TL
+0.000 g
+1.00 -0.00 0.00 1.00 757.50 390.92 Tm
+(GND) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+790.000 395.000 m 
+800.000 395.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+790.000 404.000 m 
+790.000 386.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+788.000 401.000 m 
+788.000 389.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+786.000 398.000 m 
+786.000 392.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+784.000 396.000 m 
+784.000 394.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 748.85 461.40 Tm
+(BUSY) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+800.000 465.000 m 
+795.000 460.000 l
+780.000 460.000 l
+780.000 470.000 l
+795.000 470.000 l
+800.000 465.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 961.71 431.60 Tm
+(RXEN) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+940.000 435.000 m 
+945.000 440.000 l
+960.000 440.000 l
+960.000 430.000 l
+945.000 430.000 l
+940.000 435.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 756.77 421.40 Tm
+(SCK) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+800.000 425.000 m 
+795.000 420.000 l
+780.000 420.000 l
+780.000 430.000 l
+795.000 430.000 l
+800.000 425.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 750.61 441.40 Tm
+(MISO) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+800.000 445.000 m 
+795.000 440.000 l
+780.000 440.000 l
+780.000 450.000 l
+795.000 450.000 l
+800.000 445.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 750.61 431.40 Tm
+(MOSI) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+800.000 435.000 m 
+795.000 430.000 l
+780.000 430.000 l
+780.000 440.000 l
+795.000 440.000 l
+800.000 435.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 764.69 411.40 Tm
+(CS) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+800.000 415.000 m 
+795.000 410.000 l
+780.000 410.000 l
+780.000 420.000 l
+795.000 420.000 l
+800.000 415.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 962.01 451.15 Tm
+(DIO2) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+940.000 455.000 m 
+945.000 460.000 l
+960.000 460.000 l
+960.000 450.000 l
+945.000 450.000 l
+940.000 455.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 759.19 471.40 Tm
+(IRQ) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+800.000 475.000 m 
+795.000 470.000 l
+780.000 470.000 l
+780.000 480.000 l
+795.000 480.000 l
+800.000 475.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 961.71 441.60 Tm
+(TXEN) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+940.000 445.000 m 
+945.000 450.000 l
+960.000 450.000 l
+960.000 440.000 l
+945.000 440.000 l
+940.000 445.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 750.06 451.57 Tm
+(NRST) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+800.000 455.000 m 
+795.000 450.000 l
+780.000 450.000 l
+780.000 460.000 l
+795.000 460.000 l
+800.000 455.000 l
+S
+BT
+/F2 12 Tf
+12.00 TL
+0.000 g
+1.00 -0.00 0.00 1.00 927.00 342.76 Tm
+(GND) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+940.000 360.000 m 
+940.000 370.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+931.000 360.000 m 
+949.000 360.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+934.000 358.000 m 
+946.000 358.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+937.000 356.000 m 
+943.000 356.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+939.000 354.000 m 
+941.000 354.000 l
+S
+BT
+/F2 12 Tf
+12.00 TL
+0.000 g
+1.00 -0.00 0.00 1.00 243.00 487.00 Tm
+(VCC) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+255.000 485.000 m 
+255.000 475.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+250.000 485.000 m 
+260.000 485.000 l
+S
+BT
+/F2 12 Tf
+12.00 TL
+0.000 g
+1.00 -0.00 0.00 1.00 660.50 465.93 Tm
+(VCC) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+660.000 470.000 m 
+650.000 470.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+660.000 475.000 m 
+660.000 465.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 0.53 0.00 RG
+0.00 g
+[] 0 d
+175.000 425.000 m 
+210.000 425.000 l
+255.000 425.000 l
+S
+BT
+/F2 12 Tf
+12.00 TL
+0.000 g
+1.00 -0.00 0.00 1.00 142.00 429.00 Tm
+(GND) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+155.000 445.000 m 
+155.000 455.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+146.000 445.000 m 
+164.000 445.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+149.000 443.000 m 
+161.000 443.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+152.000 441.000 m 
+158.000 441.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+154.000 439.000 m 
+156.000 439.000 l
+S
+BT
+/F2 12 Tf
+12.00 TL
+0.000 g
+1.00 -0.00 0.00 1.00 182.00 428.00 Tm
+(GND) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+195.000 445.000 m 
+195.000 455.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+186.000 445.000 m 
+204.000 445.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+189.000 443.000 m 
+201.000 443.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+192.000 441.000 m 
+198.000 441.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+194.000 439.000 m 
+196.000 439.000 l
+S
+BT
+/F2 12 Tf
+12.00 TL
+0.000 g
+1.00 -0.00 0.00 1.00 950.50 460.92 Tm
+(+5V) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+950.000 465.000 m 
+940.000 465.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+950.000 470.000 m 
+950.000 460.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 0.53 0.00 RG
+0.00 g
+[] 0 d
+650.000 490.000 m 
+650.000 480.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 0.53 0.00 RG
+0.00 g
+[] 0 d
+940.000 465.000 m 
+940.000 475.000 l
+S
+1 J
+1 j
+1.00 w
+0.20 0.80 0.20 RG
+[] 0 d
+231.000 294.000 m 
+239.000 286.000 l
+239.000 294.000 m 
+231.000 286.000 l
+S
+1 J
+1 j
+1.00 w
+0.20 0.80 0.20 RG
+[] 0 d
+371.000 244.000 m 
+379.000 236.000 l
+379.000 244.000 m 
+371.000 236.000 l
+S
+1 J
+1 j
+1.00 w
+0.20 0.80 0.20 RG
+[] 0 d
+371.000 284.000 m 
+379.000 276.000 l
+379.000 284.000 m 
+371.000 276.000 l
+S
+1 J
+1 j
+1.00 w
+0.20 0.80 0.20 RG
+[] 0 d
+371.000 274.000 m 
+379.000 266.000 l
+379.000 274.000 m 
+371.000 266.000 l
+S
+1 J
+1 j
+1.00 w
+0.20 0.80 0.20 RG
+[] 0 d
+231.000 204.000 m 
+239.000 196.000 l
+239.000 204.000 m 
+231.000 196.000 l
+S
+1 J
+1 j
+1.00 w
+0.20 0.80 0.20 RG
+[] 0 d
+371.000 204.000 m 
+379.000 196.000 l
+379.000 204.000 m 
+371.000 196.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 397.71 246.28 Tm
+(NRST) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+375.000 250.000 m 
+380.000 255.000 l
+395.000 255.000 l
+395.000 245.000 l
+380.000 245.000 l
+375.000 250.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 397.00 256.60 Tm
+(IRQ) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+375.000 260.000 m 
+380.000 265.000 l
+395.000 265.000 l
+395.000 255.000 l
+380.000 255.000 l
+375.000 260.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 183.85 236.40 Tm
+(BUSY) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+235.000 240.000 m 
+230.000 235.000 l
+215.000 235.000 l
+215.000 245.000 l
+230.000 245.000 l
+235.000 240.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 199.69 246.40 Tm
+(CS) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+235.000 250.000 m 
+230.000 245.000 l
+215.000 245.000 l
+215.000 255.000 l
+230.000 255.000 l
+235.000 250.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 185.61 266.40 Tm
+(MOSI) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+235.000 270.000 m 
+230.000 265.000 l
+215.000 265.000 l
+215.000 275.000 l
+230.000 275.000 l
+235.000 270.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 191.77 256.40 Tm
+(SCK) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+235.000 260.000 m 
+230.000 255.000 l
+215.000 255.000 l
+215.000 265.000 l
+230.000 265.000 l
+235.000 260.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 185.61 276.40 Tm
+(MISO) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+235.000 280.000 m 
+230.000 275.000 l
+215.000 275.000 l
+215.000 285.000 l
+230.000 285.000 l
+235.000 280.000 l
+S
+10.00 w
+BT
+/F3 9 Tf
+9.00 TL
+0.000 0.000 0.502 rg
+298.96 313.33 Td
+(E80-900M2213S) Tj
+ET
+10.00 w
+BT
+/F3 9 Tf
+9.00 TL
+0.000 0.000 0.502 rg
+298.96 322.33 Td
+(E80-900M2213S) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+257.00 187.00 Td
+(GND) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+238.57 191.00 Td
+(22) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+235.000 190.000 m 
+255.000 190.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+257.00 197.00 Td
+(ANT_2.4) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+238.57 201.00 Td
+(21) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+235.000 200.000 m 
+255.000 200.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+257.00 207.00 Td
+(GND) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+238.57 211.00 Td
+(20) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+235.000 210.000 m 
+255.000 210.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+257.00 227.00 Td
+(GND) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+238.57 231.00 Td
+(19) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+235.000 230.000 m 
+255.000 230.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+257.00 237.00 Td
+(BUSY) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+238.57 241.00 Td
+(18) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+235.000 240.000 m 
+255.000 240.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+257.00 247.00 Td
+(NSS) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+238.57 251.00 Td
+(17) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+235.000 250.000 m 
+255.000 250.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+257.00 257.00 Td
+(SCK) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+238.57 261.00 Td
+(16) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+235.000 260.000 m 
+255.000 260.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+257.00 267.00 Td
+(MOSI) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+238.57 271.00 Td
+(15) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+235.000 270.000 m 
+255.000 270.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+257.00 277.00 Td
+(MISO) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+238.57 281.00 Td
+(14) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+235.000 280.000 m 
+255.000 280.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+257.00 287.00 Td
+(NC) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+238.57 291.00 Td
+(13) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+235.000 290.000 m 
+255.000 290.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+257.00 297.00 Td
+(GND) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+238.57 301.00 Td
+(12) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+235.000 300.000 m 
+255.000 300.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+332.36 297.00 Td
+(GND) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+360.00 301.00 Td
+(11) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+375.000 300.000 m 
+355.000 300.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+334.29 287.00 Td
+(VCC) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+360.00 291.00 Td
+(10) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+375.000 290.000 m 
+355.000 290.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+329.49 277.00 Td
+(DIO7) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+360.00 281.00 Td
+(9) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+375.000 280.000 m 
+355.000 280.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+329.49 267.00 Td
+(DIO8) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+360.00 271.00 Td
+(8) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+375.000 270.000 m 
+355.000 270.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+329.49 257.00 Td
+(DIO9) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+360.00 261.00 Td
+(7) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+375.000 260.000 m 
+355.000 260.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+328.32 247.00 Td
+(NRST) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+360.00 251.00 Td
+(6) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+375.000 250.000 m 
+355.000 250.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+339.99 237.00 Td
+(NC) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+360.00 241.00 Td
+(5) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+375.000 240.000 m 
+355.000 240.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+332.36 227.00 Td
+(GND) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+360.00 231.00 Td
+(4) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+375.000 230.000 m 
+355.000 230.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+332.36 207.00 Td
+(GND) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+360.00 211.00 Td
+(3) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+375.000 210.000 m 
+355.000 210.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+311.72 197.00 Td
+(ANT_900) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+360.00 201.00 Td
+(2) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+375.000 200.000 m 
+355.000 200.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+332.36 187.00 Td
+(GND) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+360.00 191.00 Td
+(1) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+375.000 190.000 m 
+355.000 190.000 l
+S
+2 J
+0 j
+100 M
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+257.000 310.000 m 
+353.000 310.000 l
+354.105 310.000 355.000 309.105 355.000 308.000 c
+355.000 172.000 l
+355.000 170.895 353.895 170.000 353.000 170.000 c
+257.000 170.000 l
+255.895 170.000 255.000 171.105 255.000 172.000 c
+255.000 308.000 l
+255.000 309.105 256.105 310.000 257.000 310.000 c
+S
+BT
+/F2 12 Tf
+12.00 TL
+0.000 g
+1.00 -0.00 0.00 1.00 362.00 163.00 Tm
+(GND) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+375.000 180.000 m 
+375.000 190.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+366.000 180.000 m 
+384.000 180.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+369.000 178.000 m 
+381.000 178.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+372.000 176.000 m 
+378.000 176.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+374.000 174.000 m 
+376.000 174.000 l
+S
+BT
+/F2 12 Tf
+12.00 TL
+0.000 g
+1.00 -0.00 0.00 1.00 391.50 206.00 Tm
+(GND) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+385.000 210.000 m 
+375.000 210.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+385.000 201.000 m 
+385.000 219.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+387.000 204.000 m 
+387.000 216.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+389.000 207.000 m 
+389.000 213.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+391.000 209.000 m 
+391.000 211.000 l
+S
+BT
+/F2 12 Tf
+12.00 TL
+0.000 g
+1.00 -0.00 0.00 1.00 391.50 226.00 Tm
+(GND) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+385.000 230.000 m 
+375.000 230.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+385.000 221.000 m 
+385.000 239.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+387.000 224.000 m 
+387.000 236.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+389.000 227.000 m 
+389.000 233.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+391.000 229.000 m 
+391.000 231.000 l
+S
+BT
+/F2 12 Tf
+12.00 TL
+0.000 g
+1.00 -0.00 0.00 1.00 391.50 296.00 Tm
+(GND) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+385.000 300.000 m 
+375.000 300.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+385.000 291.000 m 
+385.000 309.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+387.000 294.000 m 
+387.000 306.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+389.000 297.000 m 
+389.000 303.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+391.000 299.000 m 
+391.000 301.000 l
+S
+BT
+/F2 12 Tf
+12.00 TL
+0.000 g
+1.00 -0.00 0.00 1.00 192.50 296.00 Tm
+(GND) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+225.000 300.000 m 
+235.000 300.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+225.000 309.000 m 
+225.000 291.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+223.000 306.000 m 
+223.000 294.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+221.000 303.000 m 
+221.000 297.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+219.000 301.000 m 
+219.000 299.000 l
+S
+BT
+/F2 12 Tf
+12.00 TL
+0.000 g
+1.00 -0.00 0.00 1.00 192.50 226.00 Tm
+(GND) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+225.000 230.000 m 
+235.000 230.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+225.000 239.000 m 
+225.000 221.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+223.000 236.000 m 
+223.000 224.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+221.000 233.000 m 
+221.000 227.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+219.000 231.000 m 
+219.000 229.000 l
+S
+BT
+/F2 12 Tf
+12.00 TL
+0.000 g
+1.00 -0.00 0.00 1.00 192.50 206.00 Tm
+(GND) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+225.000 210.000 m 
+235.000 210.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+225.000 219.000 m 
+225.000 201.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+223.000 216.000 m 
+223.000 204.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+221.000 213.000 m 
+221.000 207.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+219.000 211.000 m 
+219.000 209.000 l
+S
+BT
+/F2 12 Tf
+12.00 TL
+0.000 g
+1.00 -0.00 0.00 1.00 192.50 186.00 Tm
+(GND) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+225.000 190.000 m 
+235.000 190.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+225.000 199.000 m 
+225.000 181.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+223.000 196.000 m 
+223.000 184.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+221.000 193.000 m 
+221.000 187.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+219.000 191.000 m 
+219.000 189.000 l
+S
+BT
+/F2 12 Tf
+12.00 TL
+0.000 g
+1.00 -0.00 0.00 1.00 386.00 286.00 Tm
+(VCC) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+385.000 290.000 m 
+375.000 290.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+385.000 295.000 m 
+385.000 285.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 0.53 0.00 RG
+0.00 g
+[] 0 d
+160.000 675.000 m 
+160.000 680.000 l
+160.000 685.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 0.53 0.00 RG
+0.00 g
+[] 0 d
+145.000 655.000 m 
+160.000 655.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 0.53 0.00 RG
+0.00 g
+[] 0 d
+145.000 645.000 m 
+160.000 645.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 0.53 0.00 RG
+0.00 g
+[] 0 d
+145.000 635.000 m 
+160.000 635.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 0.53 0.00 RG
+0.00 g
+[] 0 d
+145.000 625.000 m 
+160.000 625.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 0.53 0.00 RG
+0.00 g
+[] 0 d
+145.000 615.000 m 
+160.000 615.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 0.53 0.00 RG
+0.00 g
+[] 0 d
+145.000 605.000 m 
+160.000 605.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 112.70 591.40 Tm
+(P1.06) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+160.000 595.000 m 
+155.000 590.000 l
+140.000 590.000 l
+140.000 600.000 l
+155.000 600.000 l
+160.000 595.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 112.70 701.40 Tm
+(P0.06) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+160.000 705.000 m 
+155.000 700.000 l
+140.000 700.000 l
+140.000 710.000 l
+155.000 710.000 l
+160.000 705.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 112.70 691.40 Tm
+(P0.08) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+160.000 695.000 m 
+155.000 690.000 l
+140.000 690.000 l
+140.000 700.000 l
+155.000 700.000 l
+160.000 695.000 l
+S
+10.00 w
+BT
+/F3 9 Tf
+9.00 TL
+0.000 0.000 0.502 rg
+417.00 632.75 Td
+(1.5M) Tj
+ET
+10.00 w
+BT
+/F3 9 Tf
+9.00 TL
+0.000 0.000 0.502 rg
+417.00 641.75 Td
+(R2) Tj
+ET
+2 J
+0 j
+100 M
+1.00 w
+0.63 0.00 0.00 RG
+[] 0 d
+405.00 655.00 10.00 -20.00 re
+S
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+410.000 655.000 m 
+410.000 665.000 l
+S
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+410.000 635.000 m 
+410.000 625.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+0.00 1.00 -1.00 0.00 413.70 727.50 Tm
+(Batt) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+410.000 705.000 m 
+405.000 710.000 l
+405.000 725.000 l
+415.000 725.000 l
+415.000 710.000 l
+410.000 705.000 l
+S
+1 J
+1 j
+1.00 w
+0.20 0.80 0.20 RG
+[] 0 d
+186.000 549.000 m 
+194.000 541.000 l
+194.000 549.000 m 
+186.000 541.000 l
+S
+1 J
+1 j
+1.00 w
+0.20 0.80 0.20 RG
+[] 0 d
+196.000 549.000 m 
+204.000 541.000 l
+204.000 549.000 m 
+196.000 541.000 l
+S
+1 J
+1 j
+1.00 w
+0.20 0.80 0.20 RG
+[] 0 d
+206.000 549.000 m 
+214.000 541.000 l
+214.000 549.000 m 
+206.000 541.000 l
+S
+1 J
+1 j
+1.00 w
+0.20 0.80 0.20 RG
+[] 0 d
+276.000 719.000 m 
+284.000 711.000 l
+284.000 719.000 m 
+276.000 711.000 l
+S
+1 J
+1 j
+1.00 w
+0.20 0.80 0.20 RG
+[] 0 d
+156.000 719.000 m 
+164.000 711.000 l
+164.000 719.000 m 
+156.000 711.000 l
+S
+BT
+/F2 12 Tf
+12.00 TL
+0.000 g
+1.00 -0.00 0.00 1.00 397.00 599.00 Tm
+(GND) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+410.000 615.000 m 
+410.000 625.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+401.000 615.000 m 
+419.000 615.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+404.000 613.000 m 
+416.000 613.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+407.000 611.000 m 
+413.000 611.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+409.000 609.000 m 
+411.000 609.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 0.53 0.00 RG
+0.00 g
+[] 0 d
+410.000 665.000 m 
+280.000 665.000 l
+S
+10.00 w
+BT
+/F3 9 Tf
+9.00 TL
+0.000 0.000 0.502 rg
+417.00 672.75 Td
+(1M) Tj
+ET
+10.00 w
+BT
+/F3 9 Tf
+9.00 TL
+0.000 0.000 0.502 rg
+417.00 681.75 Td
+(R1) Tj
+ET
+2 J
+0 j
+100 M
+1.00 w
+0.63 0.00 0.00 RG
+[] 0 d
+405.00 695.00 10.00 -20.00 re
+S
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+410.000 695.000 m 
+410.000 705.000 l
+S
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+410.000 675.000 m 
+410.000 665.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 0.53 0.00 RG
+0.00 g
+[] 0 d
+290.000 685.000 m 
+280.000 685.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 312.01 681.07 Tm
+(RBtn) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+290.000 685.000 m 
+295.000 690.000 l
+310.000 690.000 l
+310.000 680.000 l
+295.000 680.000 l
+290.000 685.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 99.24 621.60 Tm
+(UBtn) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+145.000 625.000 m 
+140.000 620.000 l
+125.000 620.000 l
+125.000 630.000 l
+140.000 630.000 l
+145.000 625.000 l
+S
+BT
+/F2 12 Tf
+12.00 TL
+0.000 g
+1.00 -0.00 0.00 1.00 117.50 676.00 Tm
+(GND) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+150.000 680.000 m 
+160.000 680.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+150.000 689.000 m 
+150.000 671.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+148.000 686.000 m 
+148.000 674.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+146.000 683.000 m 
+146.000 677.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+144.000 681.000 m 
+144.000 679.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 0.53 0.00 RG
+0.00 g
+[] 0 d
+290.000 595.000 m 
+280.000 595.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 0.53 0.00 RG
+0.00 g
+[] 0 d
+290.000 655.000 m 
+280.000 655.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 0.53 0.00 RG
+0.00 g
+[] 0 d
+290.000 605.000 m 
+280.000 605.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 0.53 0.00 RG
+0.00 g
+[] 0 d
+290.000 625.000 m 
+280.000 625.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 92.64 631.40 Tm
+(GPSen) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+145.000 635.000 m 
+140.000 630.000 l
+125.000 630.000 l
+125.000 640.000 l
+140.000 640.000 l
+145.000 635.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 93.85 651.40 Tm
+(GPSrx) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+145.000 655.000 m 
+140.000 650.000 l
+125.000 650.000 l
+125.000 660.000 l
+140.000 660.000 l
+145.000 655.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 94.40 641.40 Tm
+(GPStx) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+145.000 645.000 m 
+140.000 640.000 l
+125.000 640.000 l
+125.000 650.000 l
+140.000 650.000 l
+145.000 645.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 0.53 0.00 RG
+0.00 g
+[] 0 d
+290.000 615.000 m 
+280.000 615.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 0.53 0.00 RG
+0.00 g
+[] 0 d
+290.000 635.000 m 
+280.000 635.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 0.53 0.00 RG
+0.00 g
+[] 0 d
+290.000 645.000 m 
+280.000 645.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 0.53 0.00 RG
+0.00 g
+[] 0 d
+345.000 695.000 m 
+280.000 695.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 0.53 0.00 RG
+0.00 g
+[] 0 d
+345.000 675.000 m 
+280.000 675.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 312.00 601.60 Tm
+(IRQ) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+290.000 605.000 m 
+295.000 610.000 l
+310.000 610.000 l
+310.000 600.000 l
+295.000 600.000 l
+290.000 605.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 312.50 591.60 Tm
+(NRST) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+290.000 595.000 m 
+295.000 600.000 l
+310.000 600.000 l
+310.000 590.000 l
+295.000 590.000 l
+290.000 595.000 l
+S
+BT
+/F2 12 Tf
+12.00 TL
+0.000 g
+1.00 -0.00 0.00 1.00 356.00 671.00 Tm
+(VCC) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+355.000 675.000 m 
+345.000 675.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+355.000 680.000 m 
+355.000 670.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 312.00 621.60 Tm
+(CS) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+290.000 625.000 m 
+295.000 630.000 l
+310.000 630.000 l
+310.000 620.000 l
+295.000 620.000 l
+290.000 625.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 312.00 631.60 Tm
+(MOSI) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+290.000 635.000 m 
+295.000 640.000 l
+310.000 640.000 l
+310.000 630.000 l
+295.000 630.000 l
+290.000 635.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 312.00 641.60 Tm
+(MISO) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+290.000 645.000 m 
+295.000 650.000 l
+310.000 650.000 l
+310.000 640.000 l
+295.000 640.000 l
+290.000 645.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 311.84 611.60 Tm
+(SCk) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+290.000 615.000 m 
+295.000 620.000 l
+310.000 620.000 l
+310.000 610.000 l
+295.000 610.000 l
+290.000 615.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 311.70 651.60 Tm
+(BUSY) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+290.000 655.000 m 
+295.000 660.000 l
+310.000 660.000 l
+310.000 650.000 l
+295.000 650.000 l
+290.000 655.000 l
+S
+BT
+/F2 12 Tf
+12.00 TL
+0.000 g
+1.00 -0.00 0.00 1.00 361.50 691.00 Tm
+(GND) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+355.000 695.000 m 
+345.000 695.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+355.000 686.000 m 
+355.000 704.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+357.000 689.000 m 
+357.000 701.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+359.000 692.000 m 
+359.000 698.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+361.000 694.000 m 
+361.000 696.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 302.50 701.30 Tm
+(Batt) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+280.000 705.000 m 
+285.000 710.000 l
+300.000 710.000 l
+300.000 700.000 l
+285.000 700.000 l
+280.000 705.000 l
+S
+10.00 w
+BT
+/F1 13 Tf
+13.00 TL
+0.000 0.000 1.000 rg
+1015.00 25.00 Td
+(Nom De Tom) Tj
+ET
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 647.00 251.60 Tm
+(IRQ) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+625.000 255.000 m 
+630.000 260.000 l
+645.000 260.000 l
+645.000 250.000 l
+630.000 250.000 l
+625.000 255.000 l
+S
+BT
+/F2 12 Tf
+12.00 TL
+0.000 g
+1.00 -0.00 0.00 1.00 513.00 297.00 Tm
+(VCC) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+525.000 295.000 m 
+525.000 285.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+520.000 295.000 m 
+530.000 295.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 0.53 0.00 RG
+0.00 g
+[] 0 d
+625.000 175.000 m 
+625.000 215.000 l
+S
+BT
+/F2 12 Tf
+12.00 TL
+0.000 g
+1.00 -0.00 0.00 1.00 612.00 149.00 Tm
+(GND) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+625.000 165.000 m 
+625.000 175.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+616.000 165.000 m 
+634.000 165.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+619.000 163.000 m 
+631.000 163.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+622.000 161.000 m 
+628.000 161.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+624.000 159.000 m 
+626.000 159.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 474.33 201.85 Tm
+(BUSY) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+525.000 205.000 m 
+520.000 200.000 l
+505.000 200.000 l
+505.000 210.000 l
+520.000 210.000 l
+525.000 205.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 473.74 191.85 Tm
+(RXEN) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+525.000 195.000 m 
+520.000 190.000 l
+505.000 190.000 l
+505.000 200.000 l
+520.000 200.000 l
+525.000 195.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 482.41 231.85 Tm
+(SCK) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+525.000 235.000 m 
+520.000 230.000 l
+505.000 230.000 l
+505.000 240.000 l
+520.000 240.000 l
+525.000 235.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 476.41 251.85 Tm
+(MISO) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+525.000 255.000 m 
+520.000 250.000 l
+505.000 250.000 l
+505.000 260.000 l
+520.000 260.000 l
+525.000 255.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 476.48 241.85 Tm
+(MOSI) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+525.000 245.000 m 
+520.000 240.000 l
+505.000 240.000 l
+505.000 250.000 l
+520.000 250.000 l
+525.000 245.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 489.69 221.45 Tm
+(CS) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+525.000 225.000 m 
+520.000 220.000 l
+505.000 220.000 l
+505.000 230.000 l
+520.000 230.000 l
+525.000 225.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 647.01 241.15 Tm
+(DIO2) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+625.000 245.000 m 
+630.000 250.000 l
+645.000 250.000 l
+645.000 240.000 l
+630.000 240.000 l
+625.000 245.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 474.33 181.85 Tm
+(TXEN) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+525.000 185.000 m 
+520.000 180.000 l
+505.000 180.000 l
+505.000 190.000 l
+520.000 190.000 l
+525.000 185.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 475.06 261.57 Tm
+(NRST) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+525.000 265.000 m 
+520.000 260.000 l
+505.000 260.000 l
+505.000 270.000 l
+520.000 270.000 l
+525.000 265.000 l
+S
+10.00 w
+BT
+/F3 9 Tf
+9.00 TL
+0.000 0.000 0.502 rg
+568.96 298.33 Td
+(SX1262_MOD) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+584.58 282.00 Td
+(ANT) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+610.00 286.00 Td
+(16) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+625.000 285.000 m 
+605.000 285.000 l
+S
+10.00 w
+BT
+/F3 9 Tf
+9.00 TL
+0.000 0.000 0.502 rg
+568.96 307.33 Td
+(CORE_SX1262) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+582.36 202.00 Td
+(GND) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+610.00 206.00 Td
+(2) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+625.000 205.000 m 
+605.000 205.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+547.00 192.00 Td
+(RXEN) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+534.28 196.00 Td
+(3) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+525.000 195.000 m 
+545.000 195.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+547.00 182.00 Td
+(TXEN) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+534.28 186.00 Td
+(4) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+525.000 185.000 m 
+545.000 185.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+579.49 242.00 Td
+(DIO2) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+610.00 246.00 Td
+(5) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+625.000 245.000 m 
+605.000 245.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+579.49 252.00 Td
+(DIO1) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+610.00 256.00 Td
+(6) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+625.000 255.000 m 
+605.000 255.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+582.36 192.00 Td
+(GND) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+610.00 196.00 Td
+(7) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+625.000 195.000 m 
+605.000 195.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+547.00 282.00 Td
+(3V3) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+534.28 286.00 Td
+(8) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+525.000 285.000 m 
+545.000 285.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+547.00 202.00 Td
+(BUSY) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+534.28 206.00 Td
+(9) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+525.000 205.000 m 
+545.000 205.000 l
+S
+1.00 w
+0.53 0.00 0.00 RG
+545.00 265.00 m 545.00 266.66 543.66 268.00 542.00 268.00 c
+540.34 268.00 539.00 266.66 539.00 265.00 c
+539.00 263.34 540.34 262.00 542.00 262.00 c
+543.66 262.00 545.00 263.34 545.00 265.00 c
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+547.00 262.00 Td
+(RST) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+528.57 266.00 Td
+(10) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+525.000 265.000 m 
+539.000 265.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+547.00 252.00 Td
+(MISO) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+528.57 256.00 Td
+(11) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+525.000 255.000 m 
+545.000 255.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+547.00 242.00 Td
+(MOSI) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+528.57 246.00 Td
+(12) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+525.000 245.000 m 
+545.000 245.000 l
+S
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+545.000 232.000 m 
+548.000 235.000 l
+545.000 238.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+547.00 232.00 Td
+(CLK) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+528.57 236.00 Td
+(13) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+525.000 235.000 m 
+545.000 235.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+547.00 222.00 Td
+(CS) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+528.57 226.00 Td
+(14) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+525.000 225.000 m 
+545.000 225.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+582.36 182.00 Td
+(GND) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+610.00 186.00 Td
+(15) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+625.000 185.000 m 
+605.000 185.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+582.36 212.00 Td
+(GND) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+610.00 216.00 Td
+(1) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+625.000 215.000 m 
+605.000 215.000 l
+S
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+0.00 g
+[] 0 d
+550.000 295.000 m 
+600.000 295.000 l
+S
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+0.00 g
+[] 0 d
+605.000 290.000 m 
+605.000 180.000 l
+S
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+0.00 g
+[] 0 d
+600.000 175.000 m 
+550.000 175.000 l
+S
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+0.00 g
+[] 0 d
+545.000 180.000 m 
+545.000 290.000 l
+S
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+545.000 290.000 m 
+545.000 295.000 545.000 295.000 550.000 295.000 c
+S
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+600.000 295.000 m 
+605.000 295.000 605.000 295.000 605.000 290.000 c
+S
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+605.000 180.000 m 
+605.000 175.000 605.000 175.000 600.000 175.000 c
+S
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+545.000 180.000 m 
+545.000 175.000 545.000 175.000 550.000 175.000 c
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 737.72 681.45 Tm
+(MCU_RXEN) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+820.000 685.000 m 
+815.000 680.000 l
+800.000 680.000 l
+800.000 690.000 l
+815.000 690.000 l
+820.000 685.000 l
+S
+10.00 w
+BT
+/F3 9 Tf
+9.00 TL
+0.000 0.000 0.502 rg
+1115.00 362.67 Td
+(100uF) Tj
+ET
+10.00 w
+BT
+/F3 9 Tf
+9.00 TL
+0.000 0.000 0.502 rg
+1115.00 371.67 Td
+(C1) Tj
+ET
+1 J
+1 j
+1.00 w
+0.63 0.00 0.00 RG
+0.00 g
+[] 0 d
+1113.000 373.000 m 
+1097.000 373.000 l
+S
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+1105.000 365.000 m 
+1105.000 355.000 l
+S
+1 J
+1 j
+1.00 w
+0.63 0.00 0.00 RG
+0.00 g
+[] 0 d
+1105.000 385.000 m 
+1105.000 377.000 l
+S
+1 J
+1 j
+1.00 w
+0.63 0.00 0.00 RG
+0.00 g
+[] 0 d
+1097.000 377.000 m 
+1113.000 377.000 l
+S
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+1105.000 385.000 m 
+1105.000 395.000 l
+S
+1 J
+1 j
+1.00 w
+0.63 0.00 0.00 RG
+0.00 g
+[] 0 d
+1105.000 373.000 m 
+1105.000 365.000 l
+S
+10.00 w
+BT
+/F3 9 Tf
+9.00 TL
+0.000 0.000 0.502 rg
+1065.00 362.67 Td
+(100uF) Tj
+ET
+10.00 w
+BT
+/F3 9 Tf
+9.00 TL
+0.000 0.000 0.502 rg
+1065.00 371.67 Td
+(C2) Tj
+ET
+1 J
+1 j
+1.00 w
+0.63 0.00 0.00 RG
+0.00 g
+[] 0 d
+1063.000 373.000 m 
+1047.000 373.000 l
+S
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+1055.000 365.000 m 
+1055.000 355.000 l
+S
+1 J
+1 j
+1.00 w
+0.63 0.00 0.00 RG
+0.00 g
+[] 0 d
+1055.000 385.000 m 
+1055.000 377.000 l
+S
+1 J
+1 j
+1.00 w
+0.63 0.00 0.00 RG
+0.00 g
+[] 0 d
+1047.000 377.000 m 
+1063.000 377.000 l
+S
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+1055.000 385.000 m 
+1055.000 395.000 l
+S
+1 J
+1 j
+1.00 w
+0.63 0.00 0.00 RG
+0.00 g
+[] 0 d
+1055.000 373.000 m 
+1055.000 365.000 l
+S
+BT
+/F2 12 Tf
+12.00 TL
+0.000 g
+1.00 -0.00 0.00 1.00 1092.00 329.00 Tm
+(GND) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+1105.000 345.000 m 
+1105.000 355.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+1096.000 345.000 m 
+1114.000 345.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+1099.000 343.000 m 
+1111.000 343.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+1102.000 341.000 m 
+1108.000 341.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+1104.000 339.000 m 
+1106.000 339.000 l
+S
+BT
+/F2 12 Tf
+12.00 TL
+0.000 g
+1.00 -0.00 0.00 1.00 1043.00 407.00 Tm
+(VCC) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+1055.000 405.000 m 
+1055.000 395.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+1050.000 405.000 m 
+1060.000 405.000 l
+S
+BT
+/F2 12 Tf
+12.00 TL
+0.000 g
+1.00 -0.00 0.00 1.00 1042.00 327.76 Tm
+(GND) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+1055.000 345.000 m 
+1055.000 355.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+1046.000 345.000 m 
+1064.000 345.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+1049.000 343.000 m 
+1061.000 343.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+1052.000 341.000 m 
+1058.000 341.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+1054.000 339.000 m 
+1056.000 339.000 l
+S
+BT
+/F2 12 Tf
+12.00 TL
+0.000 g
+1.00 -0.00 0.00 1.00 1095.00 407.00 Tm
+(+5V) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+1105.000 405.000 m 
+1105.000 395.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+1100.000 405.000 m 
+1110.000 405.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 102.98 611.40 Tm
+(SCL) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+145.000 615.000 m 
+140.000 610.000 l
+125.000 610.000 l
+125.000 620.000 l
+140.000 620.000 l
+145.000 615.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 101.11 601.40 Tm
+(SDA) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+145.000 605.000 m 
+140.000 600.000 l
+125.000 600.000 l
+125.000 610.000 l
+140.000 610.000 l
+145.000 605.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 0.53 0.00 RG
+0.00 g
+[] 0 d
+820.000 685.000 m 
+840.000 685.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 77.72 661.45 Tm
+(MCU_RXEN) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+160.000 665.000 m 
+155.000 660.000 l
+140.000 660.000 l
+140.000 670.000 l
+155.000 670.000 l
+160.000 665.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 0.53 0.00 RG
+0.00 g
+[] 0 d
+160.000 715.000 m 
+165.000 715.000 l
+S
+1 J
+1 j
+1.00 w
+0.20 0.80 0.20 RG
+[] 0 d
+621.000 289.000 m 
+629.000 281.000 l
+629.000 289.000 m 
+621.000 281.000 l
+S
+1 J
+1 j
+1.00 w
+0.20 0.80 0.20 RG
+[] 0 d
+251.000 439.000 m 
+259.000 431.000 l
+259.000 439.000 m 
+251.000 431.000 l
+S
+1 J
+1 j
+1.00 w
+0.20 0.80 0.20 RG
+[] 0 d
+251.000 449.000 m 
+259.000 441.000 l
+259.000 449.000 m 
+251.000 441.000 l
+S
+1 J
+1 j
+1.00 w
+0.20 0.80 0.20 RG
+[] 0 d
+341.000 449.000 m 
+349.000 441.000 l
+349.000 449.000 m 
+341.000 441.000 l
+S
+1 J
+1 j
+1.00 w
+0.20 0.80 0.20 RG
+[] 0 d
+251.000 409.000 m 
+259.000 401.000 l
+259.000 409.000 m 
+251.000 401.000 l
+S
+1 J
+1 j
+1.00 w
+0.20 0.80 0.20 RG
+[] 0 d
+171.000 479.000 m 
+179.000 471.000 l
+179.000 479.000 m 
+171.000 471.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 432.69 661.28 Tm
+(ADC) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+410.000 665.000 m 
+415.000 670.000 l
+430.000 670.000 l
+430.000 660.000 l
+415.000 660.000 l
+410.000 665.000 l
+S
+10.00 w
+BT
+/F3 9 Tf
+9.00 TL
+0.000 0.000 0.502 rg
+213.86 728.26 Td
+(PRO_MICRO_NRF52840_29P) Tj
+ET
+10.00 w
+BT
+/F3 9 Tf
+9.00 TL
+0.000 0.000 0.502 rg
+213.86 737.11 Td
+(PRO-MICRO) Tj
+ET
+2 J
+0 j
+100 M
+1.00 w
+0.55 0.14 0.14 RG
+[] 0 d
+180.00 725.00 80.00 -160.00 re
+S
+BT
+/F1 7 Tf
+7.00 TL
+0.553 0.137 0.137 rg
+234.94 702.00 Td
+(BATIN) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.553 0.137 0.137 rg
+266.00 706.00 Td
+(25) Tj
+ET
+1 J
+1 j
+1.00 w
+0.55 0.14 0.14 RG
+[] 0 d
+280.000 705.000 m 
+260.000 705.000 l
+S
+BT
+/F1 7 Tf
+7.00 TL
+0.553 0.137 0.137 rg
+240.95 692.00 Td
+(GND) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.553 0.137 0.137 rg
+266.00 696.00 Td
+(24) Tj
+ET
+1 J
+1 j
+1.00 w
+0.55 0.14 0.14 RG
+[] 0 d
+280.000 695.000 m 
+260.000 695.000 l
+S
+BT
+/F1 7 Tf
+7.00 TL
+0.553 0.137 0.137 rg
+243.04 682.00 Td
+(RST) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.553 0.137 0.137 rg
+266.00 686.00 Td
+(23) Tj
+ET
+1 J
+1 j
+1.00 w
+0.55 0.14 0.14 RG
+[] 0 d
+280.000 685.000 m 
+260.000 685.000 l
+S
+BT
+/F1 7 Tf
+7.00 TL
+0.553 0.137 0.137 rg
+226.28 672.00 Td
+(3.3v Out) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.553 0.137 0.137 rg
+266.00 676.00 Td
+(22) Tj
+ET
+1 J
+1 j
+1.00 w
+0.55 0.14 0.14 RG
+[] 0 d
+280.000 675.000 m 
+260.000 675.000 l
+S
+BT
+/F1 7 Tf
+7.00 TL
+0.553 0.137 0.137 rg
+236.90 632.00 Td
+(P1.15) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.553 0.137 0.137 rg
+266.00 636.00 Td
+(18) Tj
+ET
+1 J
+1 j
+1.00 w
+0.55 0.14 0.14 RG
+[] 0 d
+280.000 635.000 m 
+260.000 635.000 l
+S
+BT
+/F1 7 Tf
+7.00 TL
+0.553 0.137 0.137 rg
+236.90 662.00 Td
+(P0.31) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.553 0.137 0.137 rg
+266.00 666.00 Td
+(21) Tj
+ET
+1 J
+1 j
+1.00 w
+0.55 0.14 0.14 RG
+[] 0 d
+280.000 665.000 m 
+260.000 665.000 l
+S
+BT
+/F1 7 Tf
+7.00 TL
+0.553 0.137 0.137 rg
+183.00 692.00 Td
+(P0.08) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.553 0.137 0.137 rg
+168.28 696.00 Td
+(3) Tj
+ET
+1 J
+1 j
+1.00 w
+0.55 0.14 0.14 RG
+[] 0 d
+160.000 695.000 m 
+180.000 695.000 l
+S
+BT
+/F1 7 Tf
+7.00 TL
+0.553 0.137 0.137 rg
+236.90 622.00 Td
+(P1.13) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.553 0.137 0.137 rg
+266.00 626.00 Td
+(17) Tj
+ET
+1 J
+1 j
+1.00 w
+0.55 0.14 0.14 RG
+[] 0 d
+280.000 625.000 m 
+260.000 625.000 l
+S
+BT
+/F1 7 Tf
+7.00 TL
+0.553 0.137 0.137 rg
+236.90 652.00 Td
+(P0.29) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.553 0.137 0.137 rg
+266.00 656.00 Td
+(20) Tj
+ET
+1 J
+1 j
+1.00 w
+0.55 0.14 0.14 RG
+[] 0 d
+280.000 655.000 m 
+260.000 655.000 l
+S
+BT
+/F1 7 Tf
+7.00 TL
+0.553 0.137 0.137 rg
+236.90 612.00 Td
+(P1.11) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.553 0.137 0.137 rg
+266.00 616.00 Td
+(16) Tj
+ET
+1 J
+1 j
+1.00 w
+0.55 0.14 0.14 RG
+[] 0 d
+280.000 615.000 m 
+260.000 615.000 l
+S
+BT
+/F1 7 Tf
+7.00 TL
+0.553 0.137 0.137 rg
+236.90 642.00 Td
+(P0.02) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.553 0.137 0.137 rg
+266.00 646.00 Td
+(19) Tj
+ET
+1 J
+1 j
+1.00 w
+0.55 0.14 0.14 RG
+[] 0 d
+280.000 645.000 m 
+260.000 645.000 l
+S
+BT
+/F1 7 Tf
+7.00 TL
+0.553 0.137 0.137 rg
+183.00 682.00 Td
+(GND) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.553 0.137 0.137 rg
+168.28 686.00 Td
+(4) Tj
+ET
+1 J
+1 j
+1.00 w
+0.55 0.14 0.14 RG
+[] 0 d
+160.000 685.000 m 
+180.000 685.000 l
+S
+1.00 w
+0.55 0.14 0.14 RG
+180.00 705.00 m 180.00 706.66 178.66 708.00 177.00 708.00 c
+175.34 708.00 174.00 706.66 174.00 705.00 c
+174.00 703.34 175.34 702.00 177.00 702.00 c
+178.66 702.00 180.00 703.34 180.00 705.00 c
+S
+BT
+/F1 7 Tf
+7.00 TL
+0.553 0.137 0.137 rg
+183.00 702.00 Td
+(P0.06) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.553 0.137 0.137 rg
+168.28 706.00 Td
+(2) Tj
+ET
+1 J
+1 j
+1.00 w
+0.55 0.14 0.14 RG
+[] 0 d
+160.000 705.000 m 
+174.000 705.000 l
+S
+BT
+/F1 7 Tf
+7.00 TL
+0.553 0.137 0.137 rg
+236.90 592.00 Td
+(P0.09) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.553 0.137 0.137 rg
+266.00 596.00 Td
+(14) Tj
+ET
+1 J
+1 j
+1.00 w
+0.55 0.14 0.14 RG
+[] 0 d
+280.000 595.000 m 
+260.000 595.000 l
+S
+BT
+/F1 7 Tf
+7.00 TL
+0.553 0.137 0.137 rg
+236.90 602.00 Td
+(P0.10) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.553 0.137 0.137 rg
+266.00 606.00 Td
+(15) Tj
+ET
+1 J
+1 j
+1.00 w
+0.55 0.14 0.14 RG
+[] 0 d
+280.000 605.000 m 
+260.000 605.000 l
+S
+BT
+/F1 7 Tf
+7.00 TL
+0.553 0.137 0.137 rg
+183.00 602.00 Td
+(P1.04) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.553 0.137 0.137 rg
+162.57 606.00 Td
+(12) Tj
+ET
+1 J
+1 j
+1.00 w
+0.55 0.14 0.14 RG
+[] 0 d
+160.000 605.000 m 
+180.000 605.000 l
+S
+BT
+/F1 7 Tf
+7.00 TL
+0.553 0.137 0.137 rg
+183.00 672.00 Td
+(GND) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.553 0.137 0.137 rg
+168.28 676.00 Td
+(5) Tj
+ET
+1 J
+1 j
+1.00 w
+0.55 0.14 0.14 RG
+[] 0 d
+160.000 675.000 m 
+180.000 675.000 l
+S
+BT
+/F1 7 Tf
+7.00 TL
+0.553 0.137 0.137 rg
+183.00 662.00 Td
+(P0.17) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.553 0.137 0.137 rg
+168.28 666.00 Td
+(6) Tj
+ET
+1 J
+1 j
+1.00 w
+0.55 0.14 0.14 RG
+[] 0 d
+160.000 665.000 m 
+180.000 665.000 l
+S
+BT
+/F1 7 Tf
+7.00 TL
+0.553 0.137 0.137 rg
+183.00 652.00 Td
+(P0.20) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.553 0.137 0.137 rg
+168.28 656.00 Td
+(7) Tj
+ET
+1 J
+1 j
+1.00 w
+0.55 0.14 0.14 RG
+[] 0 d
+160.000 655.000 m 
+180.000 655.000 l
+S
+BT
+/F1 7 Tf
+7.00 TL
+0.553 0.137 0.137 rg
+183.00 642.00 Td
+(P0.22) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.553 0.137 0.137 rg
+168.28 646.00 Td
+(8) Tj
+ET
+1 J
+1 j
+1.00 w
+0.55 0.14 0.14 RG
+[] 0 d
+160.000 645.000 m 
+180.000 645.000 l
+S
+BT
+/F1 7 Tf
+7.00 TL
+0.553 0.137 0.137 rg
+183.00 632.00 Td
+(P0.24) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.553 0.137 0.137 rg
+168.28 636.00 Td
+(9) Tj
+ET
+1 J
+1 j
+1.00 w
+0.55 0.14 0.14 RG
+[] 0 d
+160.000 635.000 m 
+180.000 635.000 l
+S
+BT
+/F1 7 Tf
+7.00 TL
+0.553 0.137 0.137 rg
+183.00 622.00 Td
+(P1.00) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.553 0.137 0.137 rg
+162.57 626.00 Td
+(10) Tj
+ET
+1 J
+1 j
+1.00 w
+0.55 0.14 0.14 RG
+[] 0 d
+160.000 625.000 m 
+180.000 625.000 l
+S
+BT
+/F1 7 Tf
+7.00 TL
+0.553 0.137 0.137 rg
+183.00 612.00 Td
+(P0.11) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.553 0.137 0.137 rg
+162.57 616.00 Td
+(11) Tj
+ET
+1 J
+1 j
+1.00 w
+0.55 0.14 0.14 RG
+[] 0 d
+160.000 615.000 m 
+180.000 615.000 l
+S
+BT
+/F1 7 Tf
+7.00 TL
+0.553 0.137 0.137 rg
+183.00 592.00 Td
+(P1.06) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.553 0.137 0.137 rg
+162.57 596.00 Td
+(13) Tj
+ET
+1 J
+1 j
+1.00 w
+0.55 0.14 0.14 RG
+[] 0 d
+160.000 595.000 m 
+180.000 595.000 l
+S
+BT
+/F1 7 Tf
+7.00 TL
+0.553 0.137 0.137 rg
+0.00 1.00 -1.00 0.00 193.00 568.00 Tm
+(P1.01) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.553 0.137 0.137 rg
+0.00 1.00 -1.00 0.00 189.00 547.57 Tm
+(27) Tj
+ET
+1 J
+1 j
+1.00 w
+0.55 0.14 0.14 RG
+[] 0 d
+190.000 545.000 m 
+190.000 565.000 l
+S
+BT
+/F1 7 Tf
+7.00 TL
+0.553 0.137 0.137 rg
+0.00 1.00 -1.00 0.00 203.00 568.00 Tm
+(P1.02) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.553 0.137 0.137 rg
+0.00 1.00 -1.00 0.00 199.00 547.57 Tm
+(28) Tj
+ET
+1 J
+1 j
+1.00 w
+0.55 0.14 0.14 RG
+[] 0 d
+200.000 545.000 m 
+200.000 565.000 l
+S
+BT
+/F1 7 Tf
+7.00 TL
+0.553 0.137 0.137 rg
+0.00 1.00 -1.00 0.00 213.00 568.00 Tm
+(P1.07) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.553 0.137 0.137 rg
+0.00 1.00 -1.00 0.00 209.00 547.57 Tm
+(29) Tj
+ET
+1 J
+1 j
+1.00 w
+0.55 0.14 0.14 RG
+[] 0 d
+210.000 545.000 m 
+210.000 565.000 l
+S
+BT
+/F1 7 Tf
+7.00 TL
+0.553 0.137 0.137 rg
+234.94 712.00 Td
+(BATIN) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.553 0.137 0.137 rg
+266.00 716.00 Td
+(26) Tj
+ET
+1 J
+1 j
+1.00 w
+0.55 0.14 0.14 RG
+[] 0 d
+280.000 715.000 m 
+260.000 715.000 l
+S
+BT
+/F1 7 Tf
+7.00 TL
+0.553 0.137 0.137 rg
+183.00 712.00 Td
+(GND) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.553 0.137 0.137 rg
+168.28 716.00 Td
+(1) Tj
+ET
+1 J
+1 j
+1.00 w
+0.55 0.14 0.14 RG
+[] 0 d
+160.000 715.000 m 
+180.000 715.000 l
+S
+10.00 w
+BT
+/F3 9 Tf
+9.00 TL
+0.000 0.000 0.502 rg
+864.25 253.00 Td
+(RA-02_C9900010926) Tj
+ET
+10.00 w
+BT
+/F3 9 Tf
+9.00 TL
+0.000 0.000 0.502 rg
+864.25 262.00 Td
+(RA-02) Tj
+ET
+2 J
+0 j
+100 M
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+837.000 250.000 m 
+903.000 250.000 l
+904.105 250.000 905.000 249.105 905.000 248.000 c
+905.000 162.000 l
+905.000 160.895 903.895 160.000 903.000 160.000 c
+837.000 160.000 l
+835.895 160.000 835.000 161.105 835.000 162.000 c
+835.000 248.000 l
+835.000 249.105 836.105 250.000 837.000 250.000 c
+S
+1.00 w
+0.53 0.00 0.00 RG
+0.53 0.00 0.00 rg
+[] 0 d
+841.50 245.00 m 841.50 245.83 840.83 246.50 840.00 246.50 c
+839.17 246.50 838.50 245.83 838.50 245.00 c
+838.50 244.17 839.17 243.50 840.00 243.50 c
+840.83 243.50 841.50 244.17 841.50 245.00 c
+B
+BT
+/F1 9 Tf
+9.00 TL
+0.000 g
+838.70 236.00 Td
+(GND) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 g
+828.78 241.00 Td
+(1) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+[] 0 d
+825.000 240.000 m 
+835.000 240.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 g
+838.70 226.00 Td
+(GND) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 g
+828.78 231.00 Td
+(2) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+[] 0 d
+825.000 230.000 m 
+835.000 230.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+838.70 216.00 Td
+(3.3V) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+828.78 221.00 Td
+(3) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+825.000 220.000 m 
+835.000 220.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+838.70 206.00 Td
+(RESET) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+828.78 211.00 Td
+(4) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+825.000 210.000 m 
+835.000 210.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+838.70 196.00 Td
+(DIO0) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+828.78 201.00 Td
+(5) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+825.000 200.000 m 
+835.000 200.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+838.70 186.00 Td
+(DIO1) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+828.78 191.00 Td
+(6) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+825.000 190.000 m 
+835.000 190.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+838.70 176.00 Td
+(DIO2) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+828.78 181.00 Td
+(7) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+825.000 180.000 m 
+835.000 180.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+838.70 166.00 Td
+(DIO3) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+828.78 171.00 Td
+(8) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+825.000 170.000 m 
+835.000 170.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 g
+880.66 166.00 Td
+(GND) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 g
+905.50 171.00 Td
+(9) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+[] 0 d
+915.000 170.000 m 
+905.000 170.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+877.79 176.00 Td
+(DIO4) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+905.50 181.00 Td
+(10) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+915.000 180.000 m 
+905.000 180.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+877.79 186.00 Td
+(DIO5) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+905.50 191.00 Td
+(11) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+915.000 190.000 m 
+905.000 190.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+882.64 196.00 Td
+(SCK) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+905.50 201.00 Td
+(12) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+915.000 200.000 m 
+905.000 200.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+876.71 206.00 Td
+(MISO) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+905.50 211.00 Td
+(13) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+915.000 210.000 m 
+905.000 210.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+876.71 216.00 Td
+(MOSI) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+905.50 221.00 Td
+(14) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+915.000 220.000 m 
+905.000 220.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+882.27 226.00 Td
+(NSS) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 0.000 1.000 rg
+905.50 231.00 Td
+(15) Tj
+ET
+1 J
+1 j
+1.00 w
+0.53 0.00 0.00 RG
+[] 0 d
+915.000 230.000 m 
+905.000 230.000 l
+S
+BT
+/F1 9 Tf
+9.00 TL
+0.000 g
+880.66 236.00 Td
+(GND) Tj
+ET
+BT
+/F1 9 Tf
+9.00 TL
+0.000 g
+905.50 241.00 Td
+(16) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+[] 0 d
+915.000 240.000 m 
+905.000 240.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 773.85 196.40 Tm
+(BUSY) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+825.000 200.000 m 
+820.000 195.000 l
+805.000 195.000 l
+805.000 205.000 l
+820.000 205.000 l
+825.000 200.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 937.00 226.60 Tm
+(CS) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+915.000 230.000 m 
+920.000 235.000 l
+935.000 235.000 l
+935.000 225.000 l
+920.000 225.000 l
+915.000 230.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 936.71 196.60 Tm
+(SCK) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+915.000 200.000 m 
+920.000 205.000 l
+935.000 205.000 l
+935.000 195.000 l
+920.000 195.000 l
+915.000 200.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 937.00 216.60 Tm
+(MOSI) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+915.000 220.000 m 
+920.000 225.000 l
+935.000 225.000 l
+935.000 215.000 l
+920.000 215.000 l
+915.000 220.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 937.00 206.60 Tm
+(MISO) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+915.000 210.000 m 
+920.000 215.000 l
+935.000 215.000 l
+935.000 205.000 l
+920.000 205.000 l
+915.000 210.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 775.06 206.57 Tm
+(NRST) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+825.000 210.000 m 
+820.000 205.000 l
+805.000 205.000 l
+805.000 215.000 l
+820.000 215.000 l
+825.000 210.000 l
+S
+BT
+/F2 11 Tf
+11.00 TL
+0.000 0.000 1.000 rg
+1.00 -0.00 0.00 1.00 784.19 186.40 Tm
+(IRQ) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 0.00 1.00 RG
+0.00 g
+[] 0 d
+825.000 190.000 m 
+820.000 185.000 l
+805.000 185.000 l
+805.000 195.000 l
+820.000 195.000 l
+825.000 190.000 l
+S
+BT
+/F2 12 Tf
+12.00 TL
+0.000 g
+1.00 -0.00 0.00 1.00 931.50 166.00 Tm
+(GND) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+925.000 170.000 m 
+915.000 170.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+925.000 161.000 m 
+925.000 179.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+927.000 164.000 m 
+927.000 176.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+929.000 167.000 m 
+929.000 173.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+931.000 169.000 m 
+931.000 171.000 l
+S
+BT
+/F2 12 Tf
+12.00 TL
+0.000 g
+1.00 -0.00 0.00 1.00 931.50 236.00 Tm
+(GND) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+925.000 240.000 m 
+915.000 240.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+925.000 231.000 m 
+925.000 249.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+927.000 234.000 m 
+927.000 246.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+929.000 237.000 m 
+929.000 243.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+931.000 239.000 m 
+931.000 241.000 l
+S
+BT
+/F2 12 Tf
+12.00 TL
+0.000 g
+1.00 -0.00 0.00 1.00 782.50 236.00 Tm
+(GND) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+815.000 240.000 m 
+825.000 240.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+815.000 249.000 m 
+815.000 231.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+813.000 246.000 m 
+813.000 234.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+811.000 243.000 m 
+811.000 237.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+809.000 241.000 m 
+809.000 239.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 0.53 0.00 RG
+0.00 g
+[] 0 d
+825.000 240.000 m 
+825.000 230.000 l
+S
+BT
+/F2 12 Tf
+12.00 TL
+0.000 g
+1.00 -0.00 0.00 1.00 789.82 216.00 Tm
+(VCC) Tj
+ET
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+815.000 220.000 m 
+825.000 220.000 l
+S
+1 J
+1 j
+1.00 w
+0.00 G
+0.00 g
+[] 0 d
+815.000 215.000 m 
+815.000 225.000 l
+S
+1 J
+1 j
+1.00 w
+0.20 0.80 0.20 RG
+[] 0 d
+911.000 194.000 m 
+919.000 186.000 l
+919.000 194.000 m 
+911.000 186.000 l
+S
+1 J
+1 j
+1.00 w
+0.20 0.80 0.20 RG
+[] 0 d
+911.000 184.000 m 
+919.000 176.000 l
+919.000 184.000 m 
+911.000 176.000 l
+S
+1 J
+1 j
+1.00 w
+0.20 0.80 0.20 RG
+[] 0 d
+821.000 184.000 m 
+829.000 176.000 l
+829.000 184.000 m 
+821.000 176.000 l
+S
+1 J
+1 j
+1.00 w
+0.20 0.80 0.20 RG
+[] 0 d
+821.000 174.000 m 
+829.000 166.000 l
+829.000 174.000 m 
+821.000 166.000 l
+S
+0.80 0.00 0.00 rg
+652.50 420.00 m 652.50 421.38 651.38 422.50 650.00 422.50 c
+648.62 422.50 647.50 421.38 647.50 420.00 c
+647.50 418.62 648.62 417.50 650.00 417.50 c
+651.38 417.50 652.50 418.62 652.50 420.00 c
+f
+0.80 0.00 0.00 rg
+942.50 415.00 m 942.50 416.38 941.38 417.50 940.00 417.50 c
+938.62 417.50 937.50 416.38 937.50 415.00 c
+937.50 413.62 938.62 412.50 940.00 412.50 c
+941.38 412.50 942.50 413.62 942.50 415.00 c
+f
+0.80 0.00 0.00 rg
+942.50 395.00 m 942.50 396.38 941.38 397.50 940.00 397.50 c
+938.62 397.50 937.50 396.38 937.50 395.00 c
+937.50 393.62 938.62 392.50 940.00 392.50 c
+941.38 392.50 942.50 393.62 942.50 395.00 c
+f
+0.80 0.00 0.00 rg
+942.50 385.00 m 942.50 386.38 941.38 387.50 940.00 387.50 c
+938.62 387.50 937.50 386.38 937.50 385.00 c
+937.50 383.62 938.62 382.50 940.00 382.50 c
+941.38 382.50 942.50 383.62 942.50 385.00 c
+f
+0.80 0.00 0.00 rg
+942.50 375.00 m 942.50 376.38 941.38 377.50 940.00 377.50 c
+938.62 377.50 937.50 376.38 937.50 375.00 c
+937.50 373.62 938.62 372.50 940.00 372.50 c
+941.38 372.50 942.50 373.62 942.50 375.00 c
+f
+0.80 0.00 0.00 rg
+652.50 490.00 m 652.50 491.38 651.38 492.50 650.00 492.50 c
+648.62 492.50 647.50 491.38 647.50 490.00 c
+647.50 488.62 648.62 487.50 650.00 487.50 c
+651.38 487.50 652.50 488.62 652.50 490.00 c
+f
+0.80 0.00 0.00 rg
+942.50 465.00 m 942.50 466.38 941.38 467.50 940.00 467.50 c
+938.62 467.50 937.50 466.38 937.50 465.00 c
+937.50 463.62 938.62 462.50 940.00 462.50 c
+941.38 462.50 942.50 463.62 942.50 465.00 c
+f
+0.80 0.00 0.00 rg
+412.50 665.00 m 412.50 666.38 411.38 667.50 410.00 667.50 c
+408.62 667.50 407.50 666.38 407.50 665.00 c
+407.50 663.62 408.62 662.50 410.00 662.50 c
+411.38 662.50 412.50 663.62 412.50 665.00 c
+f
+0.80 0.00 0.00 rg
+162.50 680.00 m 162.50 681.38 161.38 682.50 160.00 682.50 c
+158.62 682.50 157.50 681.38 157.50 680.00 c
+157.50 678.62 158.62 677.50 160.00 677.50 c
+161.38 677.50 162.50 678.62 162.50 680.00 c
+f
+0.80 0.00 0.00 rg
+627.50 185.00 m 627.50 186.38 626.38 187.50 625.00 187.50 c
+623.62 187.50 622.50 186.38 622.50 185.00 c
+622.50 183.62 623.62 182.50 625.00 182.50 c
+626.38 182.50 627.50 183.62 627.50 185.00 c
+f
+0.80 0.00 0.00 rg
+627.50 195.00 m 627.50 196.38 626.38 197.50 625.00 197.50 c
+623.62 197.50 622.50 196.38 622.50 195.00 c
+622.50 193.62 623.62 192.50 625.00 192.50 c
+626.38 192.50 627.50 193.62 627.50 195.00 c
+f
+0.80 0.00 0.00 rg
+627.50 205.00 m 627.50 206.38 626.38 207.50 625.00 207.50 c
+623.62 207.50 622.50 206.38 622.50 205.00 c
+622.50 203.62 623.62 202.50 625.00 202.50 c
+626.38 202.50 627.50 203.62 627.50 205.00 c
+f
+0.80 0.00 0.00 rg
+827.50 240.00 m 827.50 241.38 826.38 242.50 825.00 242.50 c
+823.62 242.50 822.50 241.38 822.50 240.00 c
+822.50 238.62 823.62 237.50 825.00 237.50 c
+826.38 237.50 827.50 238.62 827.50 240.00 c
+f
+q
+102.00 0 0 20.00 706.00 30.50 cm
+/I0 Do
+Q
+endstream
+endobj
+1 0 obj
+<>
+endobj
+5 0 obj
+<<
+/Descent -209
+/CapHeight 727
+/StemV 0
+/Type /FontDescriptor
+/Flags 32
+/FontBBox [-559 -303 1446 1050]
+/FontName /Verdana
+/ItalicAngle 0
+/Ascent 1005
+>>
+endobj
+6 0 obj
+<>
+endobj
+7 0 obj
+<<
+/Type /Font
+/BaseFont /Times-Roman
+/Subtype /Type1
+/Encoding /WinAnsiEncoding
+/FirstChar 32
+/LastChar 255
+>>
+endobj
+8 0 obj
+<<
+/Descent -325
+/CapHeight 500
+/StemV 80
+/Type /FontDescriptor
+/Flags 32
+/FontBBox [-665 -325 2000 1006]
+/FontName /Arial
+/ItalicAngle 0
+/Ascent 1006
+>>
+endobj
+9 0 obj
+<>
+endobj
+10 0 obj
+<<
+/Type /XObject
+/Subtype /Image
+/Width 520
+/Height 105
+/ColorSpace /DeviceRGB
+/BitsPerComponent 8
+/DecodeParms <>
+/SMask 11 0 R
+/Length 6251
+/Filter /FlateDecode
+>>
+stream
+xKqǣ{$V>:dm]uXbřZ>ـlhy-a$`!qMrN|G^_LUz8gfdf0~	SEQe"EQaAQEۢ&\gn_@QJk#o(sdAO%1GŘf!Eykn!׍&쯯),rlUӳR(p\DUnGo),m(.@Qҳ\9TEYdd#ܼsu.)rUXWqvkG<7yW(Jk)˶yns
?'ȶ섡RtOQ:oNsk(kȯ`U7(ƬjY8n+jRݠ(ʚK@+U೸֙ٚ4Bd^T7(
+W㊞g)}]
4TIQc2+D+H	]noh6<+S`?w~N*c{!q~j`z&VPRe 4hy4AQ5!vQo_}?cEQր*Q	>yû(>?-hQV₞ɡ7ߦb~>HRǸ!<^}v~[TTaYUmAX$;9lφ"w9$3;yFQ<b~x-Q.}|	ӱu
+=9ԭ,jic>9R#bɪ|X_4eb'6~/vK!I"Nbejӎa?f򃔼b꧃1N3ȺwErU4;q5A6<0tϤ"/R>X$%AZ1c{od6^Sr)k-䔎zD/⇺l,bzs&gGL1HXɲUS]ҋRBrēwLwX|楔]2CI2w,!S*Nf&Ybd]]9U`~qQ]e3}GؑJRYQ඾r֌.͌uNO79ĝ(0'OvJg{d	٥wq9
d+,өQBV=>qU6FB%1ڷD؈_gVPW)By24qaJԌ$pk8q]t	q.!y-8́},wȷP%?C>4pTa߇8'ZNm19 m>QeMi$-:1̱mt^"\˩
84R!t	"!W'
}g>fd5hDuO3|m0I?x]r
fR4H48BKrYA1cL:{%o;gZpD1[{P|=`2(K^6gr_9Nو? 9,zYD4<*W)*/ws8y+<.E	嚞˹/u%NQA>9ϴch@93hvs~~I7k[|9)s&*þ[<#e
+ٜӓ(m!èkzP\`\̞hOa^Q]Bvl:P]}~Ո~zyfduۅjz'>)o\n`i%4Nk4GRI]/[|M=.-uV'W3A̯
_:<`I-jFLP]KcH&Ϙ~
W178YnW=!l 3n4)ZPeS	V5JR1=9ʾ0ɰAʛt1_d%ghl3%c
+nŔZ!g?+sDNoz8'"L5(BY;q5~'ųZ"慊o?JaЛc\%\MsɔiLq]PE['Uʎ_z7(C3rt$@EBe~9IoN@2?ԫ܍Q972ý.3@v^_}xZɶn\rR.ɳzz_MDI"t:V^Õ
+2/;؁y9
+©h	
+5vWP޻H#n
6*8W$1{ eB*rb4$!&?˵bJŰrtǀYGȥI	+~ǰװO
+NRT62Oy\Yw񑭖C{kKl/,4_}5iCpQ~"(Py.x1m0Mrڧ/ug]|&S_.=ę!V!t=)l7	t:ݤ'REgH&w9Zr]3ܺrc;hH9yK *g\mcbG`M@Qj<|)~Et
+8;N/$%4qI_KSp{pkx;Vi7u_N$C`F67ˣM-|2(/5)M*>]	&%[aǫG$	+B=etHLEy0{oD̔KMpT7FDA7?7nL
aRqQ[^1@(R@lk7	\pRa
[yC;eDx{RSZ\;GɞJh^ipNbH݈x;^XRƼ\gbMBTK-Pp;mpP.v:j;>*o
+ĽIG1|%z((y}D
+ć%O1$(wO _=Â7)^'*Bݲ#ULc6p7nPȫN+\^y;PjG82ܚG?!Vne2doŭϼ
+q1JO텘"ӻA n_5mE~qTiwu	8+i*x؆	Vu+^f|`(pp8ԔK}
+Zq9=	%&6紦uKe	}FX\q5&HOhӴTGw;G*@ӡ`n]0ss}ZWhNѰt\\ JYEpN1'{im[/`5a!np)'6}ڟBUǭ~嗩op:Vf/fVF[
!t'<}
S1ţc8}.4baΉ"+)!u(ofO|
qB	K?wCi!bѕ`+bjb1+/miɭg.X:rgUKK,3rڐf">[)˚+Djbna5[oL"pe|r(L^e̟gQYm5P]tݬĝ鐭xj1ՅDe\X[DV7TEF6/C@hbo1A`PoT:-݈}Vq!,J_j%D1#7;D$I(St(0'KK\SW}/;*b>)9]Jw+[CDi,ТˣRIᅖZe@l=Qbk tjAT`&wm3@] r28\ݸREMP+*zE❩{~|ԃMlwǶpZfo@3/M`cw$VLQ.%D6v]/p*4B)Ddb5~|
+J
+$ ۝zW3ovѨ}.R{L%o#4>݂q)C?.$a,nl&vJ,c>l*U4v)ɢ+iͿUM`娘lSƩP0؄Ha>"IUh+VQ7aJQr.6ҷǀf3@ŕ+z$e&SR#}[M"ڊPңey׀UA_bP1%2rJTd)J2&2MhIu*k
+F\UQkM}v(FjbS(I"kc
QO%)Ǧ(4L0gUwX^4'R_hXgmׯR9YiF|yLʕ.-%]g^\ϜTRSL1hAI6E	JZt)(PŠ(\@(rF-
+endstream
+endobj
+11 0 obj
+<<
+/Type /XObject
+/Subtype /Image
+/Width 520
+/Height 105
+/ColorSpace /DeviceGray
+/BitsPerComponent 8
+/DecodeParms <>
+/Length 6577
+/Filter /FlateDecode
+>>
+stream
+x]M?c=ȳJQj"*"xIJhGQ"o袌4(`B0_}{}3W3[g{{{k p*Bn"5-߯Ds0uN\'!WfBKl5Gt\1g}vD]EԄ\᾽3珧/Sډ&B!ދIɻ:fVW&>ľ~Jz\z
"`O>o/t[mGT]/u }EM4(uBW+I~
@SvXMq:~=|EP(BxF=hƕnWV/Ϗjpw,z~PvЬ]9ޕ,gv{NM[u)+++?DPɩ~^vJu?	)2tGqL
+Ï*ʋIȌ'#GR$$뵏[<ҡ䔊]]L'{KG9x)Lԉ
+0G6.ݡ92P-b|N2NU#4}K&jG
DԷc#By&ZdQ%ND#BݵԚv>)s\RPB>Wiк3k.
+p5|aΈ	ԈQQ5xO!XdAB"9g~2P<Z2s1v/tFtd/4Yx7wa鮋(:Bc7
E`~wa'S>{~
+0ㄠ)9ZmΔ>EE-#
+_xEbeAvc]DeCӏOs@j=oj+58`~W/x}љ^VzMQv7GU|CEbTK0CEңU%ێ^NO{K-q"+W`No`VW~md1JwKf.*(c*s=
+@qǭ/G|#A8tf:Vo	2g| <ʬ3i|r>V[%{gX7닅;%6&Z8(˰ؚ4+{>3'HgvM=MBt:LnukTl4ӉHDuNşvGXX~!,!5:M_cssQI>k#+0~ǎj'1\%P8ՠ*
+C"hoW!;yTv9.:64lLd6cm)gӕzʅwLd`:kj/f5O'3w2^$b^~ejS[z]*_~c#eI2[BӧC.⴨Q({z+WnݺB<=p2nCQ{w)[ב{\zZl[h.jyMt9]'pn7Fخ8Qp%| kN»3g2{ۜ#Հػ/r	@`Six΀?_wijpo"9{sS]r61B)z<;h!/
eT	nGAQis79Wbp k=i~ݵ)KX[n
+K3w̧$Apbz#D*J)2$)Wo&9VWeޱL\4@)69ֆՠH23`O@?zm~ GBQI
?=))Q,p1'nўXfb,̎ZY06GYw1=n32"0pyq0WH|,|WXm`R)^o;{ƌ&?Se
*:D?d6G+RQsi9+v
+EqwKmfP7JgNJ<ۀ3n-*:侟HvlwRs^0GjFy-NHu{T8xЪ̽
lmd`|8X~g.ty	H/m'4/8Nvor(dO9‹@1	bՄoA*e1Z쎕&L`- lR,l1xwݞ9t>D} p1~&)%,,0^j

4>N}춖1w6miW0crAI~aߊ?*{JIڢ	&ѿ+qTnLdz.~vKDFyо\y%[6mjrg">tCrRY)S@ڂ`ZرB8]`.f1J|!\2Yc:H6c/Qۜvo^aL%	Y"#qwǛqW_i,2Kz=◧IdV^\Y.G+ǻ6Dў4S)UrCD
+7#lg]|H'bRNUt~i'
n+
f&ݍPr'Rd:4".;mi氧/=j훌wJc	neWCn/PA5^b6I#6O%2A|ǧ㽎ԛ^MN@e.z	1ۓ	ý6(-+j	6g);8)tKTn?pgN{砱
+L!KI 4aҎ:
+r \4l'qK)o5UY#/h16ƁB2dV
yK
+6F8"ƍSSK_dRh4*_?LѫVS[+?޺IzE=B"ҔH׸3n+4d(b"`W~D}Gerp{)/B"hMh@#j~4-f`IkLtؐΒԣI4&ݿ֬_7KR$hyhJw3Tu0W|P&L/Y50_d&ןZB.B4eӋPB?%
+xYŰt#m#C`Xhѩp'zOCd~7p?DQaBC%'Qn'w 9{JCitWq,YO֦0:෤'҉FF߹:iy* ~%k/aXxQT4	EZ%{sIb&EjMQw4붘.qT7P@j@LJ7AhY<3P`P(&ia8=n5'>t^B͗Ym\_p2]KN/*5^1@&OVJ`
+hN%:OwoF|r`oX"-[ATw	m0y(
ǂہ[-68*6_558$Cne;h҉1c;[jȱ&gיDvoc߮I|RZ>BO>rBWȉT!9Oe	0+:BcbBP9i{6mB'e>Ty#xOZH{tT<`	3ރә@2l-&@WA>KZumx(11f8RuJWD+(f_ld9qmx1A65nd3RL~
+\rt4z*yKo܀LlYwO/;LoXeBG4WOpWCx) aR$OB?* ʹdՌ]lI yсK|3ܺ60s]n@{)R]#*1ѢX5K,-j."n^`W.8ufR;=wT"a´㓽l(.~iX\kf=Uaۏ*{IcEa1ʹTsxXQ,~Qė@梽R,@UR-J))J$}aͣ/)UXQ3[e¶5KFNe`fEїi	Ċ|r|+de&4\!qaj)2Z[E]oz#HFR?2.beгPd
+1^a4S)]Hph^@7
+WmNIY]|9ŋK]@toYɱJmͯ7^Al2+XWZ0^߱]^025_f4#/UGCJG[<~7ݲԎۭ5bչk}y1Ԭ0r2euZQM/6Z,`|S2ʺMJ(83w	[n
+}~s<_t)OΎT+(Zd%I5|`T뉃
+*͑tb"F42/*>>/ԣ@ ;$X2wׂiM=agCʽFWXl˨+RT^Or

Cwp]"H:u"##ҘRN/_z#)Kj=r+Vy<+Xn\G!!B_8V'w#Ev·s`EPR7«À!!ZAuTLmV#"oƐlogc"c';oHok/WE0]IXF]!wE0Xy-lx3ōaQ
+
tjMnUBQf<_E	X4f.]A0FIϋ*> ;\DPp#AT ?7
+endstream
+endobj
+2 0 obj
+<<
+/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]
+/Font <<
+/F1 6 0 R
+/F2 7 0 R
+/F3 9 0 R
+>>
+/XObject <<
+/I0 10 0 R
+>>
+>>
+endobj
+12 0 obj
+<<
+/Producer (jsPDF 0.0.0)
+/CreationDate (D:20241217154849-00'00')
+>>
+endobj
+13 0 obj
+<<
+/Type /Catalog
+/Pages 1 0 R
+/OpenAction [3 0 R /FitH null]
+/PageLayout /OneColumn
+>>
+endobj
+xref
+0 14
+0000000000 65535 f 
+0000102899 00000 n 
+0000118853 00000 n 
+0000000015 00000 n 
+0000000125 00000 n 
+0000102956 00000 n 
+0000103126 00000 n 
+0000104180 00000 n 
+0000104307 00000 n 
+0000104476 00000 n 
+0000105520 00000 n 
+0000112030 00000 n 
+0000118988 00000 n 
+0000119074 00000 n 
+trailer
+<<
+/Size 14
+/Root 13 0 R
+/Info 12 0 R
+/ID [ <906A4C76C35816C42EB6FFD13B3B7D92> <906A4C76C35816C42EB6FFD13B3B7D92> ]
+>>
+startxref
+119178
+%%EOF
\ No newline at end of file
diff --git a/variants/diy/nrf52_promicro_diy_tcxo/rfswitch.h b/variants/diy/nrf52_promicro_diy_tcxo/rfswitch.h
new file mode 100644
index 000000000..2258c3135
--- /dev/null
+++ b/variants/diy/nrf52_promicro_diy_tcxo/rfswitch.h
@@ -0,0 +1,17 @@
+#include "RadioLib.h"
+
+// RF Switch Matrix SubG RFO_HP_LF / RFO_LP_LF / RFI_[NP]_LF0
+// DIO5 -> RFSW0_V1
+// DIO6 -> RFSW1_V2
+// DIO7 -> ANT_CTRL_ON + ESP_IO9/LR_GPS_ANT_DC_EN -> RFI_GPS (Bias-T GPS) (LR11x0 only)
+
+static const uint32_t rfswitch_dio_pins[] = {RADIOLIB_LR11X0_DIO5, RADIOLIB_LR11X0_DIO6, RADIOLIB_LR11X0_DIO7, RADIOLIB_NC,
+                                             RADIOLIB_NC};
+
+static const Module::RfSwitchMode_t rfswitch_table[] = {
+    // mode                  DIO5  DIO6  DIO7
+    {LR11x0::MODE_STBY, {LOW, LOW, LOW}},  {LR11x0::MODE_RX, {HIGH, LOW, LOW}},
+    {LR11x0::MODE_TX, {LOW, HIGH, LOW}},   {LR11x0::MODE_TX_HP, {LOW, HIGH, LOW}},
+    {LR11x0::MODE_TX_HF, {LOW, LOW, LOW}}, {LR11x0::MODE_GNSS, {LOW, LOW, HIGH}},
+    {LR11x0::MODE_WIFI, {LOW, LOW, LOW}},  END_OF_MODE_TABLE,
+};
\ No newline at end of file
diff --git a/variants/diy/nrf52_promicro_diy_tcxo/variant.h b/variants/diy/nrf52_promicro_diy_tcxo/variant.h
index 5c535ba1e..6ffb86cff 100644
--- a/variants/diy/nrf52_promicro_diy_tcxo/variant.h
+++ b/variants/diy/nrf52_promicro_diy_tcxo/variant.h
@@ -122,12 +122,13 @@ NRF52 PRO MICRO PIN ASSIGNMENT
 #define USE_SX1262
 #define USE_RF95
 #define USE_SX1268
+#define USE_LR1121
 
 // RF95 CONFIG
 
-#define LORA_DIO0 (0 + 29) // P0.10 IRQ
+#define LORA_DIO0 (0 + 29) // P0.29 BUSY
 #define LORA_DIO1 (0 + 10) // P0.10 IRQ
-#define LORA_RESET (0 + 9) // P0.09
+#define LORA_RESET (0 + 9) // P0.09 NRST
 
 // RX/TX for RFM95/SX127x
 #define RF95_RXEN (0 + 17)    // P0.17
@@ -143,6 +144,19 @@ NRF52 PRO MICRO PIN ASSIGNMENT
 #define SX126X_RXEN (0 + 17)     // P0.17
 #define SX126X_TXEN RADIOLIB_NC  // Assuming that DIO2 is connected to TXEN pin. If not, TXEN must be connected.
 
+// LR1121
+#ifdef USE_LR1121
+#define LR1121_IRQ_PIN (0 + 10)      // P0.10 IRQ
+#define LR1121_NRESET_PIN LORA_RESET // P0.09 NRST
+#define LR1121_BUSY_PIN (0 + 29)     // P0.29 BUSY
+#define LR1121_SPI_NSS_PIN LORA_CS   // P1.13
+#define LR1121_SPI_SCK_PIN LORA_SCK
+#define LR1121_SPI_MOSI_PIN LORA_MOSI
+#define LR1121_SPI_MISO_PIN LORA_MISO
+#define LR11X0_DIO3_TCXO_VOLTAGE 1.8
+#define LR11X0_DIO_AS_RF_SWITCH
+#endif
+
 // #define SX126X_MAX_POWER 8 set this if using a high-power board!
 
 /*
@@ -164,6 +178,7 @@ settings.
 | Seeed        | Wio-SX1262       | yes  | Int       | Sooooo cute!                          |
 | AI-Thinker   | RA-02            | No   | Int       | SX1278 **433mhz band only**           |
 | RF Solutions | RFM95            | No   | Int       | Untested                              |
+| Ebyte        | E80-900M2213S    | Yes  | Int       | LR1121 radio                          |
 
 */
 
@@ -179,4 +194,4 @@ extern float tcxoVoltage; // make this available everywhere
  *        Arduino objects - C++ only
  *----------------------------------------------------------------------------*/
 
-#endif
+#endif
\ No newline at end of file
diff --git a/variants/diy/platformio.ini b/variants/diy/platformio.ini
index 83e2175c8..b7f3f6a92 100644
--- a/variants/diy/platformio.ini
+++ b/variants/diy/platformio.ini
@@ -2,7 +2,6 @@
 [env:meshtastic-diy-v1]
 extends = esp32_base
 board = esp32doit-devkit-v1
-board_level = extra
 board_check = true
 build_flags =
   ${esp32_base.build_flags}
@@ -62,7 +61,6 @@ debug_tool = jlink
 [env:nrf52_promicro_diy_tcxo]
 extends = nrf52840_base
 board = promicro-nrf52840
-board_level = extra
 build_flags = ${nrf52840_base.build_flags}
   -I variants/diy/nrf52_promicro_diy_tcxo
   -D NRF52_PROMICRO_DIY
@@ -89,73 +87,3 @@ build_flags =
   -D ARDUINO_USB_MODE=0
   -D ARDUINO_USB_CDC_ON_BOOT=1
   -I variants/diy/t-energy-s3_e22
-
-; esp32-s3 + ra-sh01 lora + 3.2" ILI9143
-[env:mesh-tab]
-extends = esp32s3_base
-board = um_feathers3
-board_level = extra
-board_upload.flash_size = 16MB
-board_build.partitions = default_16MB.csv
-upload_protocol = esptool
-build_flags = ${esp32s3_base.build_flags}
-  -D MESH_TAB
-  -D PRIVATE_HW
-  -D CONFIG_ARDUHAL_ESP_LOG
-  -D CONFIG_ARDUHAL_LOG_COLORS=1
-  -D CONFIG_DISABLE_HAL_LOCKS=1 ; "feels" to be a bit more stable without locks
-  -D MESHTASTIC_EXCLUDE_CANNEDMESSAGES=1
-  -D MESHTASTIC_EXCLUDE_INPUTBROKER=1
-  -D MESHTASTIC_EXCLUDE_BLUETOOTH=1
-  -D MESHTASTIC_EXCLUDE_WEBSERVER=1
-  -D LV_LVGL_H_INCLUDE_SIMPLE
-  -D LV_CONF_INCLUDE_SIMPLE
-  -D LV_COMP_CONF_INCLUDE_SIMPLE
-  -D LV_USE_SYSMON=0
-  -D LV_USE_PROFILER=0
-  -D LV_USE_PERF_MONITOR=0
-  -D LV_USE_MEM_MONITOR=0
-  -D LV_USE_LOG=0
-  -D LV_BUILD_TEST=0
-  -D USE_LOG_DEBUG
-  -D LOG_DEBUG_INC=\"DebugConfiguration.h\"
-  -D RADIOLIB_SPI_PARANOID=0
-  -D MAX_NUM_NODES=250
-  -D MAX_THREADS=40
-  -D HAS_SCREEN=0
-  -D HAS_TFT=1
-  -D RAM_SIZE=1024
-  -D LGFX_DRIVER_TEMPLATE
-  -D LGFX_DRIVER=LGFX_GENERIC
-  -D LGFX_PANEL=ILI9341
-  -D LGFX_OFFSET_ROTATION=1
-  -D LGFX_TOUCH=XPT2046
-  -D LGFX_PIN_SCK=12
-  -D LGFX_PIN_MOSI=13
-  -D LGFX_PIN_MISO=11
-  -D LGFX_PIN_DC=16
-  -D LGFX_PIN_CS=10
-  -D LGFX_PIN_RST=-1
-  -D LGFX_PIN_BL=42
-  -D LGFX_TOUCH_INT=41
-  -D LGFX_TOUCH_CS=7
-  -D LGFX_TOUCH_CLK=12
-  -D LGFX_TOUCH_DO=11
-  -D LGFX_TOUCH_DIN=13
-  -D LGFX_TOUCH_X_MIN=300
-  -D LGFX_TOUCH_X_MAX=3900
-  -D LGFX_TOUCH_Y_MIN=400
-  -D LGFX_TOUCH_Y_MAX=3900
-  -D VIEW_320x240
-  -D USE_PACKET_API
-  -I lib/device-ui/generated/ui_320x240
-  -I variants/diy/mesh-tab
-build_src_filter = ${esp32_base.build_src_filter}
-  +<../lib/device-ui/generated/ui_320x240>
-  +<../lib/device-ui/resources>
-  +<../lib/device-ui/locale>
-  +<../lib/device-ui/source>
-lib_deps = ${esp32_base.lib_deps}
-  lovyan03/LovyanGFX@^1.1.16
-  earlephilhower/ESP8266Audio@^1.9.7
-  earlephilhower/ESP8266SAM@^1.0.1
diff --git a/variants/heltec_capsule_sensor_v3/platformio.ini b/variants/heltec_capsule_sensor_v3/platformio.ini
index f1aef925d..b5ffb65c2 100644
--- a/variants/heltec_capsule_sensor_v3/platformio.ini
+++ b/variants/heltec_capsule_sensor_v3/platformio.ini
@@ -7,5 +7,4 @@ build_flags =
   ${esp32s3_base.build_flags} -I variants/heltec_capsule_sensor_v3
   -D HELTEC_CAPSULE_SENSOR_V3
   -D GPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely.
-  ;-D DEBUG_DISABLED ; uncomment this line to disable DEBUG output
-
+  ;-D DEBUG_DISABLED ; uncomment this line to disable DEBUG output
\ No newline at end of file
diff --git a/variants/heltec_wireless_paper_v1/platformio.ini b/variants/heltec_wireless_paper_v1/platformio.ini
index 999f1586a..c94bcacca 100644
--- a/variants/heltec_wireless_paper_v1/platformio.ini
+++ b/variants/heltec_wireless_paper_v1/platformio.ini
@@ -1,5 +1,6 @@
 [env:heltec-wireless-paper-v1_0]
 extends = esp32s3_base
+board_level = extra
 board = heltec_wifi_lora_32_V3
 build_flags = 
   ${esp32s3_base.build_flags} 
diff --git a/variants/heltec_wireless_tracker_V1_0/platformio.ini b/variants/heltec_wireless_tracker_V1_0/platformio.ini
index 303e27dbf..0e48c72f2 100644
--- a/variants/heltec_wireless_tracker_V1_0/platformio.ini
+++ b/variants/heltec_wireless_tracker_V1_0/platformio.ini
@@ -1,14 +1,13 @@
 [env:heltec-wireless-tracker-V1-0]
 extends = esp32s3_base
+board_level = extra
 board = heltec_wireless_tracker
 upload_protocol = esptool
-
 build_flags = 
   ${esp32s3_base.build_flags} -I variants/heltec_wireless_tracker_V1_0
   -D HELTEC_TRACKER_V1_0
   -D GPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely.
   ;-D DEBUG_DISABLED ; uncomment this line to disable DEBUG output
-
 lib_deps =
   ${esp32s3_base.lib_deps}
   lovyan03/LovyanGFX@^1.1.8
\ No newline at end of file
diff --git a/variants/mesh-tab/pins_arduino.h b/variants/mesh-tab/pins_arduino.h
new file mode 100644
index 000000000..c995f638c
--- /dev/null
+++ b/variants/mesh-tab/pins_arduino.h
@@ -0,0 +1,65 @@
+#ifndef Pins_Arduino_h
+#define Pins_Arduino_h
+
+#include "soc/soc_caps.h"
+#include 
+
+#define USB_VID 0x303A
+#define USB_PID 0x80D6
+
+static const uint8_t TX = 43;
+static const uint8_t RX = 44;
+
+static const uint8_t SDA = 8;
+static const uint8_t SCL = 9;
+
+static const uint8_t SS = 5;
+static const uint8_t MOSI = 35;
+static const uint8_t MISO = 37;
+static const uint8_t SDO = 35;
+static const uint8_t SDI = 37;
+static const uint8_t SCK = 36;
+
+static const uint8_t A0 = 1;
+static const uint8_t A1 = 2;
+static const uint8_t A2 = 3;
+static const uint8_t A3 = 4;
+static const uint8_t A4 = 5;
+static const uint8_t A5 = 6;
+static const uint8_t A6 = 7;
+static const uint8_t A7 = 8;
+static const uint8_t A8 = 9;
+static const uint8_t A9 = 10;
+static const uint8_t A10 = 11;
+static const uint8_t A11 = 12;
+static const uint8_t A12 = 13;
+
+static const uint8_t T1 = 1;
+static const uint8_t T3 = 3;
+static const uint8_t T5 = 5;
+static const uint8_t T6 = 6;
+static const uint8_t T7 = 7;
+static const uint8_t T8 = 8;
+static const uint8_t T9 = 9;
+static const uint8_t T10 = 10;
+static const uint8_t T11 = 11;
+static const uint8_t T12 = 12;
+static const uint8_t T14 = 14;
+
+static const uint8_t VBAT_SENSE = 2;
+static const uint8_t VBUS_SENSE = 34;
+
+// User LED
+#define LED_BUILTIN 13
+#define BUILTIN_LED LED_BUILTIN // backward compatibility
+
+static const uint8_t RGB_DATA = 40;
+// RGB_BUILTIN and RGB_BRIGHTNESS can be used in new Arduino API neopixelWrite()
+#define RGB_BUILTIN (RGB_DATA + SOC_GPIO_PIN_COUNT)
+#define RGB_BRIGHTNESS 64
+
+static const uint8_t RGB_PWR = 39;
+static const uint8_t LDO2 = 39;
+static const uint8_t LED = 13;
+
+#endif /* Pins_Arduino_h */
diff --git a/variants/mesh-tab/platformio.ini b/variants/mesh-tab/platformio.ini
new file mode 100644
index 000000000..26b072cde
--- /dev/null
+++ b/variants/mesh-tab/platformio.ini
@@ -0,0 +1,233 @@
+; Base for Mesh-Tab device (esp32-s3 N16R2 + ra-sh01 lora)
+; https://github.com/valzzu/Mesh-Tab
+[mesh_tab_base]
+extends = esp32s3_base
+board = mesh-tab
+board_level = extra
+board_upload.flash_size = 16MB
+board_build.partitions = default_16MB.csv
+upload_protocol = esptool
+build_flags = ${esp32s3_base.build_flags}
+  -D MESH_TAB
+  -D CONFIG_ARDUHAL_ESP_LOG
+  -D CONFIG_ARDUHAL_LOG_COLORS=1
+  -D CONFIG_DISABLE_HAL_LOCKS=1
+  -D MESHTASTIC_EXCLUDE_CANNEDMESSAGES=1
+  -D MESHTASTIC_EXCLUDE_INPUTBROKER=1
+  -D MESHTASTIC_EXCLUDE_BLUETOOTH=1
+  -D MESHTASTIC_EXCLUDE_WEBSERVER=1
+  -D LV_LVGL_H_INCLUDE_SIMPLE
+  -D LV_CONF_INCLUDE_SIMPLE
+  -D LV_COMP_CONF_INCLUDE_SIMPLE
+  -D LV_USE_SYSMON=0
+  -D LV_USE_PROFILER=0
+  -D LV_USE_PERF_MONITOR=0
+  -D LV_USE_MEM_MONITOR=0
+  -D LV_USE_LOG=0
+  -D LV_BUILD_TEST=0
+  -D USE_LOG_DEBUG
+  -D LOG_DEBUG_INC=\"DebugConfiguration.h\"
+  -D RADIOLIB_SPI_PARANOID=0
+  -D MAX_NUM_NODES=250
+  -D MAX_THREADS=40
+  -D HAS_SCREEN=0
+  -D HAS_TFT=1
+  -D USE_PIN_BUZZER
+  -D RAM_SIZE=1024
+  -D LGFX_DRIVER_TEMPLATE
+  -D LGFX_DRIVER=LGFX_GENERIC
+  -D LGFX_PIN_SCK=12
+  -D LGFX_PIN_MOSI=13
+  -D LGFX_PIN_MISO=11
+  -D LGFX_PIN_DC=16
+  -D LGFX_PIN_CS=10
+  -D LGFX_PIN_RST=-1
+  -D LGFX_PIN_BL=42
+  -D LGFX_TOUCH_INT=41
+  -D VIEW_320x240
+  -D USE_PACKET_API
+  -I lib/device-ui/generated/ui_320x240
+  -I variants/mesh-tab
+build_src_filter = ${esp32_base.build_src_filter}
+  +<../lib/device-ui/generated/ui_320x240>
+  +<../lib/device-ui/resources>
+  +<../lib/device-ui/locale>
+  +<../lib/device-ui/source>
+lib_deps = ${esp32_base.lib_deps}
+  lovyan03/LovyanGFX@^1.1.16
+
+; 3.2" TN TFT ST7789 / XPT2046: https://vi.aliexpress.com/item/1005005933490544.html
+[env:mesh-tab-3-2-TN-resistive]
+extends = mesh_tab_base
+build_flags = ${mesh_tab_base.build_flags}
+  -D LGFX_SCREEN_WIDTH=240
+  -D LGFX_SCREEN_HEIGHT=320
+  -D LGFX_PANEL=ST7789
+  -D LGFX_INVERT_COLOR=false
+  -D LGFX_RGB_ORDER=false
+  -D LGFX_ROTATION=3
+  -D LGFX_TOUCH=XPT2046
+  -D SPI_FREQUENCY=60000000
+  -D LGFX_TOUCH_SPI_FREQ=2500000
+  -D LGFX_TOUCH_SPI_HOST=2
+  -D LGFX_TOUCH_CS=7
+  -D LGFX_TOUCH_CLK=12
+  -D LGFX_TOUCH_DO=11
+  -D LGFX_TOUCH_DIN=13
+  -D LGFX_TOUCH_X_MIN=300
+  -D LGFX_TOUCH_X_MAX=3900
+  -D LGFX_TOUCH_Y_MIN=400
+  -D LGFX_TOUCH_Y_MAX=3900
+  -D LGFX_TOUCH_ROTATION=4
+
+; 3.2" IPS TFT ILI9341 / XPT2046: https://www.aliexpress.com/item/1005006258575617.html
+[env:mesh-tab-3-2-IPS-resistive]
+extends = mesh_tab_base
+build_flags = ${mesh_tab_base.build_flags}
+  -D LGFX_SCREEN_WIDTH=240
+  -D LGFX_SCREEN_HEIGHT=320
+  -D LGFX_PANEL=ILI9341
+  -D LGFX_INVERT_COLOR=true
+  -D LGFX_RGB_ORDER=false
+  -D LGFX_ROTATION=1
+  -D LGFX_TOUCH=XPT2046
+  -D SPI_FREQUENCY=60000000 ; if image is distorted then lower to 40 MHz
+  -D LGFX_TOUCH_SPI_FREQ=2500000
+  -D LGFX_TOUCH_SPI_HOST=2
+  -D LGFX_TOUCH_CS=7
+  -D LGFX_TOUCH_CLK=12
+  -D LGFX_TOUCH_DO=11
+  -D LGFX_TOUCH_DIN=13
+  -D LGFX_TOUCH_X_MIN=300
+  -D LGFX_TOUCH_X_MAX=3900
+  -D LGFX_TOUCH_Y_MIN=400
+  -D LGFX_TOUCH_Y_MAX=3900
+  -D LGFX_TOUCH_ROTATION=4
+
+; 3.5" IPS TFT ILI9488 / XPT2046: https://vi.aliexpress.com/item/1005006333922639.html
+[env:mesh-tab-3-5-IPS-resistive]
+extends = mesh_tab_base
+build_flags = ${mesh_tab_base.build_flags}
+  -D DISPLAY_SET_RESOLUTION
+  -D LGFX_SCREEN_WIDTH=320
+  -D LGFX_SCREEN_HEIGHT=480
+  -D LGFX_PANEL=ILI9488
+  -D LGFX_INVERT_COLOR=true
+  -D LGFX_RGB_ORDER=false
+  -D LGFX_DLEN_16BITS=false
+  -D LGFX_ROTATION=0
+  -D LGFX_TOUCH=XPT2046
+  -D SPI_FREQUENCY=40000000 ; may go higher upto 40/60/80 MHz
+  -D LGFX_TOUCH_SPI_FREQ=2500000
+  -D LGFX_TOUCH_SPI_HOST=2
+  -D LGFX_TOUCH_CS=7
+  -D LGFX_TOUCH_CLK=12
+  -D LGFX_TOUCH_DO=11
+  -D LGFX_TOUCH_DIN=13
+  -D LGFX_TOUCH_X_MIN=300
+  -D LGFX_TOUCH_X_MAX=3900
+  -D LGFX_TOUCH_Y_MIN=400
+  -D LGFX_TOUCH_Y_MAX=3900
+  -D LGFX_TOUCH_ROTATION=0
+
+; 3.5" TN TFT ILI9488 / XPT2046: https://vi.aliexpress.com/item/32985467436.html
+[env:mesh-tab-3-5-TN-resistive]
+extends = mesh_tab_base
+build_flags = ${mesh_tab_base.build_flags}
+  -D DISPLAY_SET_RESOLUTION
+  -D LGFX_SCREEN_WIDTH=320
+  -D LGFX_SCREEN_HEIGHT=480
+  -D LGFX_PANEL=HX8357B
+  -D SPI_FREQUENCY=60000000
+  -D LGFX_INVERT_COLOR=false
+  -D LGFX_RGB_ORDER=false
+  -D LGFX_DLEN_16BITS=false
+  -D LGFX_ROTATION=4
+  -D LGFX_TOUCH=XPT2046
+  -D LGFX_TOUCH_SPI_FREQ=2500000
+  -D LGFX_TOUCH_SPI_HOST=2
+  -D LGFX_TOUCH_CS=7
+  -D LGFX_TOUCH_CLK=12
+  -D LGFX_TOUCH_DO=11
+  -D LGFX_TOUCH_DIN=13
+  -D LGFX_TOUCH_X_MIN=300
+  -D LGFX_TOUCH_X_MAX=3900
+  -D LGFX_TOUCH_Y_MIN=400
+  -D LGFX_TOUCH_Y_MAX=3900
+  -D LGFX_TOUCH_ROTATION=2
+
+; 3.2" IPS TFT ILI9341 / FT6236: https://vi.aliexpress.com/item/1005006624072350.html
+[env:mesh-tab-3-2-IPS-capacitive]
+extends = mesh_tab_base
+build_flags = ${mesh_tab_base.build_flags}
+  -D LGFX_SCREEN_WIDTH=240
+  -D LGFX_SCREEN_HEIGHT=320
+  -D LGFX_PANEL=ILI9341
+  -D LGFX_INVERT_COLOR=true
+  -D LGFX_RGB_ORDER=false
+  -D LGFX_ROTATION=1
+  -D LGFX_TOUCH=FT5x06
+  -D SPI_FREQUENCY=40000000 ; may go higher upto 60/80 MHz
+  -D LGFX_TOUCH_I2C_PORT=0
+  -D LGFX_TOUCH_I2C_ADDR=0x38
+  -D LGFX_TOUCH_I2C_SDA=8
+  -D LGFX_TOUCH_I2C_SCL=9
+  -D LGFX_TOUCH_RST=7
+  -D LGFX_TOUCH_X_MIN=0
+  -D LGFX_TOUCH_X_MAX=319
+  -D LGFX_TOUCH_Y_MIN=0
+  -D LGFX_TOUCH_Y_MAX=479
+  -D LGFX_TOUCH_ROTATION=0
+  -D LGFX_TOUCH_I2C_FREQ=1000000
+
+; 3.5" IPS TFT ILI9488 / FT6236: https://vi.aliexpress.com/item/1005006893699919.html
+[env:mesh-tab-3-5-IPS-capacitive]
+extends = mesh_tab_base
+build_flags = ${mesh_tab_base.build_flags}
+  -D DISPLAY_SET_RESOLUTION
+  -D LGFX_SCREEN_WIDTH=320
+  -D LGFX_SCREEN_HEIGHT=480
+  -D LGFX_PANEL=ILI9488
+  -D LGFX_INVERT_COLOR=true
+  -D LGFX_RGB_ORDER=false
+  -D LGFX_DLEN_16BITS=false
+  -D LGFX_ROTATION=1
+  -D LGFX_TOUCH=FT5x06
+  -D SPI_FREQUENCY=30000000 ; may go higher upto 40/60/80 MHz
+  -D LGFX_TOUCH_I2C_PORT=0
+  -D LGFX_TOUCH_I2C_ADDR=0x38
+  -D LGFX_TOUCH_I2C_SDA=8
+  -D LGFX_TOUCH_I2C_SCL=9
+  -D LGFX_TOUCH_RST=7
+  -D LGFX_TOUCH_X_MIN=0
+  -D LGFX_TOUCH_X_MAX=319
+  -D LGFX_TOUCH_Y_MIN=0
+  -D LGFX_TOUCH_Y_MAX=479
+  -D LGFX_TOUCH_ROTATION=1
+  -D LGFX_TOUCH_I2C_FREQ=1000000
+
+; 4.0" IPS TFT ILI9488 / FT6236: https://vi.aliexpress.com/item/1005007082906950.html
+[env:mesh-tab-4-0-IPS-capacitive]
+extends = mesh_tab_base
+build_flags = ${mesh_tab_base.build_flags}
+  -D DISPLAY_SET_RESOLUTION
+  -D LGFX_SCREEN_WIDTH=320
+  -D LGFX_SCREEN_HEIGHT=480
+  -D LGFX_PANEL=HX8357B
+  -D LGFX_INVERT_COLOR=true
+  -D LGFX_RGB_ORDER=false
+  -D LGFX_DLEN_16BITS=false
+  -D LGFX_ROTATION=4
+  -D LGFX_TOUCH=FT5x06
+  -D SPI_FREQUENCY=30000000 ; may go higher upto 40/60/80 MHz
+  -D LGFX_TOUCH_I2C_PORT=0
+  -D LGFX_TOUCH_I2C_ADDR=0x38
+  -D LGFX_TOUCH_I2C_SDA=8
+  -D LGFX_TOUCH_I2C_SCL=9
+  -D LGFX_TOUCH_RST=7
+  -D LGFX_TOUCH_X_MIN=0
+  -D LGFX_TOUCH_X_MAX=319
+  -D LGFX_TOUCH_Y_MIN=0
+  -D LGFX_TOUCH_Y_MAX=479
+  -D LGFX_TOUCH_ROTATION=1
+  -D LGFX_TOUCH_I2C_FREQ=1000000
\ No newline at end of file
diff --git a/variants/diy/mesh-tab/variant.h b/variants/mesh-tab/variant.h
similarity index 67%
rename from variants/diy/mesh-tab/variant.h
rename to variants/mesh-tab/variant.h
index 0a23a3c36..533c931bc 100644
--- a/variants/diy/mesh-tab/variant.h
+++ b/variants/mesh-tab/variant.h
@@ -7,8 +7,8 @@
 
 // Analog pins
 #define BATTERY_PIN 4 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
-// ratio of voltage divider = 2.0
-#define ADC_MULTIPLIER 2.11 // 2.0 + 10% for correction of display undervoltage.
+// ratio of voltage divider (100k, 220k)
+#define ADC_MULTIPLIER 1.6 // 1.45 + 10% for correction of display undervoltage.
 #define ADC_CHANNEL ADC1_GPIO4_CHANNEL
 
 // LED
@@ -17,6 +17,9 @@
 // Button
 #define BUTTON_PIN 0
 
+// Button
+#define PIN_BUZZER 5
+
 // GPS
 #define GPS_RX_PIN 18
 #define GPS_TX_PIN 17
@@ -28,20 +31,26 @@
 #define SPI_CS 10
 #define SDCARD_CS 6
 
+// LORA MODULES
+#define USE_SX1262
+
 // LORA SPI
 #define LORA_SCK 36
 #define LORA_MISO 37
 #define LORA_MOSI 35
 #define LORA_CS 39
 
-// LORA MODULES
-#define USE_SX1262
-
 // LORA CONFIG
+#define LORA_DIO0 -1 // a No connect on the SX1262 module
+#define LORA_RESET 14
+#define LORA_DIO1 15 // SX1262 IRQ
+#define LORA_DIO2 40 // SX1262 BUSY
+#define LORA_DIO3    // Not connected on PCB, but internally on the TTGO SX1262
+
 #define SX126X_CS LORA_CS
-#define SX126X_DIO1 15
+#define SX126X_DIO1 LORA_DIO1
 #define SX126X_DIO2_AS_RF_SWITCH
-#define SX126X_BUSY 40
+#define SX126X_BUSY LORA_DIO2
 #define SX126X_RESET 14
 #define SX126X_RXEN 47
 #define SX126X_TXEN RADIOLIB_NC // Assuming that DIO2 is connected to TXEN pin
diff --git a/variants/nibble_esp32/platformio.ini b/variants/nibble_esp32/platformio.ini
new file mode 100644
index 000000000..24d2ee2a5
--- /dev/null
+++ b/variants/nibble_esp32/platformio.ini
@@ -0,0 +1,6 @@
+[env:nibble-esp32]
+extends = esp32s3_base
+board = esp32-s3-zero
+board_level = extra
+build_flags = 
+  ${esp32_base.build_flags} -D PRIVATE_HW -I variants/nibble_esp32
\ No newline at end of file
diff --git a/variants/nibble_esp32/variant.h b/variants/nibble_esp32/variant.h
new file mode 100644
index 000000000..8ffbd9d59
--- /dev/null
+++ b/variants/nibble_esp32/variant.h
@@ -0,0 +1,18 @@
+#define I2C_SDA 11 // I2C pins for this board
+#define I2C_SCL 10
+
+#define LED_PIN 1 // If defined we will blink this LED
+
+#define BUTTON_PIN 0 // If defined, this will be used for user button presses
+#define BUTTON_NEED_PULLUP
+
+#define USE_RF95
+#define LORA_SCK 6
+#define LORA_MISO 7
+#define LORA_MOSI 8
+#define LORA_CS 9
+#define LORA_DIO0 5 // a No connect on the SX1262 module
+#define LORA_RESET 4
+
+#define LORA_DIO1 RADIOLIB_NC
+#define LORA_DIO2 RADIOLIB_NC
\ No newline at end of file
diff --git a/variants/nibble_rp2040/platformio.ini b/variants/nibble_rp2040/platformio.ini
new file mode 100644
index 000000000..ad987895f
--- /dev/null
+++ b/variants/nibble_rp2040/platformio.ini
@@ -0,0 +1,17 @@
+[env:nibble-rp2040]
+extends = rp2040_base
+board = rpipico
+board_level = extra
+upload_protocol = picotool
+
+# add our variants files to the include and src paths
+build_flags = ${rp2040_base.build_flags} 
+  -DPRIVATE_HW
+  -Ivariants/nibble_rp2040
+  -DDEBUG_RP2040_PORT=Serial
+  -DHW_SPI1_DEVICE
+  -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m0plus"
+lib_deps =
+  ${rp2040_base.lib_deps}
+debug_build_flags = ${rp2040_base.build_flags}, -g
+debug_tool = cmsis-dap ; for e.g. Picotool
\ No newline at end of file
diff --git a/variants/nibble_rp2040/variant.h b/variants/nibble_rp2040/variant.h
new file mode 100644
index 000000000..0f71b98e9
--- /dev/null
+++ b/variants/nibble_rp2040/variant.h
@@ -0,0 +1,18 @@
+#define ARDUINO_ARCH_AVR
+
+#define BUTTON_PIN -1 // Pin 17 used for antenna switching via DIO4
+
+#define LED_PIN 1
+
+#define HAS_CPU_SHUTDOWN 1
+
+#define USE_RF95
+#define LORA_SCK 10
+#define LORA_MISO 12
+#define LORA_MOSI 11
+#define LORA_CS 13
+
+#define LORA_DIO0 14
+#define LORA_RESET 15
+#define LORA_DIO1 RADIOLIB_NC
+#define LORA_DIO2 RADIOLIB_NC
diff --git a/variants/nugget_s2_lora/platformio.ini b/variants/nugget_s2_lora/platformio.ini
new file mode 100644
index 000000000..2a7ff1013
--- /dev/null
+++ b/variants/nugget_s2_lora/platformio.ini
@@ -0,0 +1,6 @@
+[env:nugget-s2-lora]
+extends = esp32s2_base
+board = lolin_s2_mini
+board_level = extra
+build_flags = 
+  ${esp32s2_base.build_flags} -D PRIVATE_HW -I variants/nugget_s2_lora
\ No newline at end of file
diff --git a/variants/nugget_s2_lora/variant.h b/variants/nugget_s2_lora/variant.h
new file mode 100644
index 000000000..2d123d603
--- /dev/null
+++ b/variants/nugget_s2_lora/variant.h
@@ -0,0 +1,23 @@
+#define I2C_SDA 34 // I2C pins for this board
+#define I2C_SCL 36
+
+#define LED_PIN 15 // If defined we will blink this LED
+
+#define HAS_NEOPIXEL                         // Enable the use of neopixels
+#define NEOPIXEL_COUNT 3                     // How many neopixels are connected
+#define NEOPIXEL_DATA 12                     // gpio pin used to send data to the neopixels
+#define NEOPIXEL_TYPE (NEO_GRB + NEO_KHZ800) // type of neopixels in use
+
+#define BUTTON_PIN 0 // If defined, this will be used for user button presses
+#define BUTTON_NEED_PULLUP
+
+#define USE_RF95
+#define LORA_SCK 6
+#define LORA_MISO 8
+#define LORA_MOSI 10
+#define LORA_CS 13
+#define LORA_DIO0 16
+#define LORA_RESET 5
+
+#define LORA_DIO1 RADIOLIB_NC
+#define LORA_DIO2 RADIOLIB_NC
\ No newline at end of file
diff --git a/variants/nugget_s3_lora/platformio.ini b/variants/nugget_s3_lora/platformio.ini
new file mode 100644
index 000000000..729a3ef23
--- /dev/null
+++ b/variants/nugget_s3_lora/platformio.ini
@@ -0,0 +1,6 @@
+[env:nugget-s3-lora]
+extends = esp32s3_base
+board = lolin_s3_mini
+board_level = extra
+build_flags = 
+  ${esp32s3_base.build_flags} -D PRIVATE_HW -I variants/nugget_s3_lora
\ No newline at end of file
diff --git a/variants/nugget_s3_lora/variant.h b/variants/nugget_s3_lora/variant.h
new file mode 100644
index 000000000..488fe4e44
--- /dev/null
+++ b/variants/nugget_s3_lora/variant.h
@@ -0,0 +1,23 @@
+#define I2C_SDA 34 // I2C pins for this board
+#define I2C_SCL 38
+
+#define LED_PIN 15 // If defined we will blink this LED
+
+#define HAS_NEOPIXEL                         // Enable the use of neopixels
+#define NEOPIXEL_COUNT 3                     // How many neopixels are connected
+#define NEOPIXEL_DATA 10                     // gpio pin used to send data to the neopixels
+#define NEOPIXEL_TYPE (NEO_GRB + NEO_KHZ800) // type of neopixels in use
+
+#define BUTTON_PIN 0 // If defined, this will be used for user button presses
+#define BUTTON_NEED_PULLUP
+
+#define USE_RF95
+#define LORA_SCK 6
+#define LORA_MISO 7
+#define LORA_MOSI 8
+#define LORA_CS 9
+#define LORA_DIO0 16 // a No connect on the SX1262 module
+#define LORA_RESET 4
+
+#define LORA_DIO1 RADIOLIB_NC
+#define LORA_DIO2 RADIOLIB_NC
\ No newline at end of file
diff --git a/variants/portduino-buildroot/platformio.ini b/variants/portduino-buildroot/platformio.ini
new file mode 100644
index 000000000..3fbd26910
--- /dev/null
+++ b/variants/portduino-buildroot/platformio.ini
@@ -0,0 +1,8 @@
+[env:buildroot]
+extends = portduino_base
+; Optional libraries should be appended to `PLATFORMIO_BUILD_FLAGS`
+; environment variable in the buildroot environment.
+build_flags = ${portduino_base.build_flags} -O0 -I variants/portduino-buildroot
+board = buildroot
+lib_deps = ${portduino_base.lib_deps}
+build_src_filter = ${portduino_base.build_src_filter}
\ No newline at end of file
diff --git a/variants/portduino-buildroot/variant.h b/variants/portduino-buildroot/variant.h
new file mode 100644
index 000000000..b7b39d6e8
--- /dev/null
+++ b/variants/portduino-buildroot/variant.h
@@ -0,0 +1,5 @@
+#define HAS_SCREEN 1
+#define CANNED_MESSAGE_MODULE_ENABLE 1
+#define HAS_GPS 1
+#define MAX_RX_TOPHONE settingsMap[maxtophone]
+#define MAX_NUM_NODES settingsMap[maxnodes]
\ No newline at end of file
diff --git a/variants/portduino/platformio.ini b/variants/portduino/platformio.ini
index aa11142f7..cad87ea8c 100644
--- a/variants/portduino/platformio.ini
+++ b/variants/portduino/platformio.ini
@@ -9,3 +9,7 @@ build_flags = ${portduino_base.build_flags} -O0 -I variants/portduino
 board = cross_platform
 lib_deps = ${portduino_base.lib_deps}
 build_src_filter = ${portduino_base.build_src_filter}
+
+[env:coverage]
+extends = env:native
+build_flags = -lgcov --coverage -fprofile-abs-path ${env:native.build_flags}
diff --git a/variants/rak2560/RAK9154Sensor.cpp b/variants/rak2560/RAK9154Sensor.cpp
index 9f660947e..43affe581 100644
--- a/variants/rak2560/RAK9154Sensor.cpp
+++ b/variants/rak2560/RAK9154Sensor.cpp
@@ -37,11 +37,11 @@ static void onewire_evt(const uint8_t pid, const uint8_t sid, const SNHUBAPI_EVT
         break;
 
     case SNHUBAPI_EVT_ADD_SID:
-        // LOG_INFO("+ADD:SID:[%02x]\r\n", msg[0]);
+        // LOG_INFO("+ADD:SID:[%02x]", msg[0]);
         break;
 
     case SNHUBAPI_EVT_ADD_PID:
-        // LOG_INFO("+ADD:PID:[%02x]\r\n", msg[0]);
+        // LOG_INFO("+ADD:PID:[%02x]", msg[0]);
 #ifdef BOOT_DATA_REQ
         provision = msg[0];
 #endif
@@ -55,12 +55,12 @@ static void onewire_evt(const uint8_t pid, const uint8_t sid, const SNHUBAPI_EVT
 
     case SNHUBAPI_EVT_SDATA_REQ:
 
-        // LOG_INFO("+EVT:PID[%02x],IPSO[%02x]\r\n",pid,msg[0]);
+        // LOG_INFO("+EVT:PID[%02x],IPSO[%02x]",pid,msg[0]);
         // for( uint16_t i=1; i 0) ? true : false;
 }
-#endif // HAS_RAKPROT
\ No newline at end of file
+#endif // HAS_RAKPROT
diff --git a/variants/rp2040-lora/variant.h b/variants/rp2040-lora/variant.h
index f1826605f..92b067457 100644
--- a/variants/rp2040-lora/variant.h
+++ b/variants/rp2040-lora/variant.h
@@ -15,7 +15,7 @@
 // rxd = 9
 
 #define EXT_NOTIFY_OUT 22
-#undef BUTTON_PIN // Pin 17 used for antenna switching via DIO4
+#define BUTTON_PIN -1 // Pin 17 used for antenna switching via DIO4
 
 #define LED_PIN PIN_LED
 
@@ -57,4 +57,4 @@
 #define SX126X_DIO2_AS_RF_SWITCH // Antenna switch CTRL
 #define SX126X_RXEN LORA_DIO4    // Antenna switch !CTRL via GPIO17
 // #define SX126X_DIO3_TCXO_VOLTAGE 1.8
-#endif
\ No newline at end of file
+#endif
diff --git a/variants/seeed-sensecap-indicator/platformio.ini b/variants/seeed-sensecap-indicator/platformio.ini
index e6bb2145e..86d6d0412 100644
--- a/variants/seeed-sensecap-indicator/platformio.ini
+++ b/variants/seeed-sensecap-indicator/platformio.ini
@@ -2,7 +2,7 @@
 [env:seeed-sensecap-indicator]
 extends = esp32s3_base
 platform_packages =
-    platformio/framework-arduinoespressif32 @ https://github.com/mverch67/arduino-esp32.git#add_tca9535 ; based on 2.0.16
+    platformio/framework-arduinoespressif32 @ https://github.com/mverch67/arduino-esp32.git#aef7fef6de3329ed6f75512d46d63bba12b09bb5 ; add_tca9535 (based on 2.0.16)
 
 board = seeed-sensecap-indicator
 board_check = true
diff --git a/variants/seeed-sensecap-indicator/variant.h b/variants/seeed-sensecap-indicator/variant.h
index aec61f0bc..106bce8c0 100644
--- a/variants/seeed-sensecap-indicator/variant.h
+++ b/variants/seeed-sensecap-indicator/variant.h
@@ -43,6 +43,7 @@
 // // Buzzer
 // #define PIN_BUZZER 19
 
+#define GPS_DEFAULT_NOT_PRESENT 1
 #define GPS_RX_PIN 20
 #define GPS_TX_PIN 19
 #define HAS_GPS 1
diff --git a/variants/seeed_xiao_s3/variant.h b/variants/seeed_xiao_s3/variant.h
index ab886d354..8f9282a7a 100644
--- a/variants/seeed_xiao_s3/variant.h
+++ b/variants/seeed_xiao_s3/variant.h
@@ -41,7 +41,7 @@ L76K GPS Module Information : https://www.seeedstudio.com/L76K-GNSS-Module-for-S
     L76K Expansion Board can not directly used, L76K Reset Pin needs to override or physically remove it,
     otherwise it will conflict with the SPI pins
 */
-// #define GPS_L76K
+#define GPS_L76K
 #ifdef GPS_L76K
 #define GPS_RX_PIN 44
 #define GPS_TX_PIN 43
@@ -80,5 +80,7 @@ L76K GPS Module Information : https://www.seeedstudio.com/L76K-GNSS-Module-for-S
 
 //  DIO2 controlls an antenna switch and the TCXO voltage is controlled by DIO3
 #define SX126X_DIO2_AS_RF_SWITCH
+#define SX126X_RXEN 38
+#define SX126X_TXEN RADIOLIB_NC
 #define SX126X_DIO3_TCXO_VOLTAGE 1.8
-#endif
\ No newline at end of file
+#endif
diff --git a/variants/t-deck/variant.h b/variants/t-deck/variant.h
index 6d398391e..91c12ab3d 100644
--- a/variants/t-deck/variant.h
+++ b/variants/t-deck/variant.h
@@ -29,7 +29,7 @@
 
 #define BUTTON_PIN 0
 // #define BUTTON_NEED_PULLUP
-
+#define GPS_DEFAULT_NOT_PRESENT 1
 #define GPS_RX_PIN 44
 #define GPS_TX_PIN 43
 
diff --git a/variants/tlora_t3s3_epaper/variant.h b/variants/tlora_t3s3_epaper/variant.h
index 461ce0c31..732869b20 100644
--- a/variants/tlora_t3s3_epaper/variant.h
+++ b/variants/tlora_t3s3_epaper/variant.h
@@ -19,6 +19,7 @@
 #define I2C_SCL SCL
 
 // external qwiic connector
+#define GPS_DEFAULT_NOT_PRESENT 1
 #define GPS_RX_PIN 44
 #define GPS_TX_PIN 43
 
diff --git a/variants/tlora_v2_1_16/variant.h b/variants/tlora_v2_1_16/variant.h
index 8bb5ce3b1..48c069ab7 100644
--- a/variants/tlora_v2_1_16/variant.h
+++ b/variants/tlora_v2_1_16/variant.h
@@ -8,10 +8,7 @@
 #define I2C_SDA 21 // I2C pins for this board
 #define I2C_SCL 22
 
-#define LED_PIN 25    // If defined we will blink this LED
-#define BUTTON_PIN 12 // If defined, this will be used for user button presses,
-
-#define BUTTON_NEED_PULLUP
+#define LED_PIN 25 // If defined we will blink this LED
 
 #define USE_RF95
 #define LORA_DIO0 26 // a No connect on the SX1262 module
diff --git a/variants/tlora_v2_1_16_tcxo/platformio.ini b/variants/tlora_v2_1_16_tcxo/platformio.ini
index e54c1a920..538fd81b0 100644
--- a/variants/tlora_v2_1_16_tcxo/platformio.ini
+++ b/variants/tlora_v2_1_16_tcxo/platformio.ini
@@ -1,5 +1,6 @@
 [env:tlora-v2-1-1_6-tcxo]
 extends = esp32_base
+board_level = extra
 board = ttgo-lora32-v21
 build_flags = 
   ${esp32_base.build_flags}
diff --git a/variants/tlora_v2_1_18/platformio.ini b/variants/tlora_v2_1_18/platformio.ini
index 36d6a3157..48a001ced 100644
--- a/variants/tlora_v2_1_18/platformio.ini
+++ b/variants/tlora_v2_1_18/platformio.ini
@@ -1,5 +1,6 @@
 [env:tlora-v2-1-1_8]
 extends = esp32_base
+board_level = extra
 board = ttgo-lora32-v21
 
 build_flags = 
diff --git a/variants/tlora_v3_3_0_tcxo/platformio.ini b/variants/tlora_v3_3_0_tcxo/platformio.ini
new file mode 100644
index 000000000..4066d64b0
--- /dev/null
+++ b/variants/tlora_v3_3_0_tcxo/platformio.ini
@@ -0,0 +1,11 @@
+[env:tlora-v3-3-0-tcxo]
+extends = esp32_base
+board = ttgo-lora32-v21
+board_level = extra
+build_flags = 
+  ${esp32_base.build_flags}
+  -D TLORA_V2_1_16
+  -I variants/tlora_v2_1_16
+  -D GPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely.
+  -D LORA_TCXO_GPIO=12
+  -D BUTTON_PIN=0
\ No newline at end of file
diff --git a/variants/tracker-t1000-e/platformio.ini b/variants/tracker-t1000-e/platformio.ini
index 075811610..0bce9fbb5 100644
--- a/variants/tracker-t1000-e/platformio.ini
+++ b/variants/tracker-t1000-e/platformio.ini
@@ -4,6 +4,7 @@ board = tracker-t1000-e
 build_flags = ${nrf52840_base.build_flags} -Ivariants/tracker-t1000-e -Isrc/platform/nrf52/softdevice -Isrc/platform/nrf52/softdevice/nrf52 -DTRACKER_T1000_E
   -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard"
   -DGPS_POWER_TOGGLE
+  -DMESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR_EXTERNAL=1
 board_build.ldscript = src/platform/nrf52/nrf52840_s140_v7.ld
 build_src_filter = ${nrf52_base.build_src_filter} +<../variants/tracker-t1000-e>
 lib_deps = 
@@ -11,4 +12,4 @@ lib_deps =
   https://github.com/meshtastic/QMA6100P_Arduino_Library.git#14c900b8b2e4feaac5007a7e41e0c1b7f0841136
 debug_tool = jlink
 ; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm)
-upload_protocol = nrfutil
+upload_protocol = nrfutil
\ No newline at end of file
diff --git a/variants/unphone/pins_arduino.h b/variants/unphone/pins_arduino.h
index c4e9add1c..74067359f 100644
--- a/variants/unphone/pins_arduino.h
+++ b/variants/unphone/pins_arduino.h
@@ -6,14 +6,6 @@
 #define USB_VID 0x16D0
 #define USB_PID 0x1178
 
-#define EXTERNAL_NUM_INTERRUPTS 46
-#define NUM_DIGITAL_PINS 48
-#define NUM_ANALOG_INPUTS 20
-
-#define analogInputToDigitalPin(p) (((p) < 20) ? (analogChannelToDigitalPin(p)) : -1)
-#define digitalPinToInterrupt(p) (((p) < 48) ? (p) : -1)
-#define digitalPinHasPWM(p) (p < 46)
-
 #define LED_BUILTIN 13
 #define BUILTIN_LED LED_BUILTIN // backward compatibility
 
diff --git a/version.properties b/version.properties
index bed14bad5..800529e39 100644
--- a/version.properties
+++ b/version.properties
@@ -1,4 +1,4 @@
 [VERSION]  
 major = 2
 minor = 5
-build = 14
+build = 19