diff --git a/.github/actions/build-variant/action.yml b/.github/actions/build-variant/action.yml index 67d002eea..f611908ee 100644 --- a/.github/actions/build-variant/action.yml +++ b/.github/actions/build-variant/action.yml @@ -27,10 +27,10 @@ inputs: description: A newline separated list of paths to store as artifacts required: false default: "" - include-web-ui: - description: Include the web UI in the build - required: false - default: "false" + # include-web-ui: + # description: Include the web UI in the build + # required: false + # default: "false" arch: description: Processor arch name required: true @@ -43,29 +43,29 @@ runs: id: base uses: ./.github/actions/setup-base - - name: Get web ui version - if: inputs.include-web-ui == 'true' - id: webver - shell: bash - run: | - echo "ver=$(cat bin/web.version)" >> $GITHUB_OUTPUT + # - name: Get web ui version + # if: inputs.include-web-ui == 'true' + # id: webver + # shell: bash + # run: | + # echo "ver=$(cat bin/web.version)" >> $GITHUB_OUTPUT - - name: Pull web ui - if: inputs.include-web-ui == 'true' - uses: dsaltares/fetch-gh-release-asset@master - with: - repo: meshtastic/web - file: build.tar - target: build.tar - token: ${{ inputs.github_token }} - version: tags/v${{ steps.webver.outputs.ver }} + # - name: Pull web ui + # if: inputs.include-web-ui == 'true' + # uses: dsaltares/fetch-gh-release-asset@master + # with: + # repo: meshtastic/web + # file: build.tar + # target: build.tar + # token: ${{ inputs.github_token }} + # version: tags/v${{ steps.webver.outputs.ver }} - - name: Unpack web ui - if: inputs.include-web-ui == 'true' - shell: bash - run: | - tar -xf build.tar -C data/static - rm build.tar + # - name: Unpack web ui + # if: inputs.include-web-ui == 'true' + # shell: bash + # run: | + # tar -xf build.tar -C data/static + # rm build.tar - name: Remove debug flags for release shell: bash diff --git a/.github/workflows/build_esp32.yml b/.github/workflows/build_esp32.yml index 4fc31f22c..32cd45000 100644 --- a/.github/workflows/build_esp32.yml +++ b/.github/workflows/build_esp32.yml @@ -11,27 +11,30 @@ permissions: read-all jobs: build-esp32: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 + - name: Get release version string + shell: bash + run: echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT + id: version + - name: Build ESP32 id: build - uses: ./.github/actions/build-variant + uses: meshtastic/gh-action-firmware@main with: - github_token: ${{ secrets.GITHUB_TOKEN }} - board: ${{ inputs.board }} - remove-debug-flags: >- - ./arch/esp32/esp32.ini - ./arch/esp32/esp32s2.ini - ./arch/esp32/esp32s3.ini - ./arch/esp32/esp32c3.ini - ./arch/esp32/esp32c6.ini - build-script-path: bin/build-esp32.sh - ota-firmware-source: firmware.bin - ota-firmware-target: release/bleota.bin - artifact-paths: | + pio_platform: esp32 + pio_env: ${{ inputs.board }} + pio_target: build + ota_firmware_source: firmware.bin + ota_firmware_target: release/bleota.bin + + - name: Store binaries as an artifact + uses: actions/upload-artifact@v4 + with: + name: firmware-esp32-${{ inputs.board }}-${{ steps.version.outputs.long }}.zip + overwrite: true + path: | release/*.bin release/*.elf - include-web-ui: true - arch: esp32 diff --git a/.github/workflows/build_esp32_c3.yml b/.github/workflows/build_esp32_c3.yml index 546762952..161786f99 100644 --- a/.github/workflows/build_esp32_c3.yml +++ b/.github/workflows/build_esp32_c3.yml @@ -11,27 +11,30 @@ permissions: read-all jobs: build-esp32-c3: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 + - name: Get release version string + shell: bash + run: echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT + id: version + - name: Build ESP32-C3 id: build - uses: ./.github/actions/build-variant + uses: meshtastic/gh-action-firmware@main with: - github_token: ${{ secrets.GITHUB_TOKEN }} - board: ${{ inputs.board }} - remove-debug-flags: >- - ./arch/esp32/esp32.ini - ./arch/esp32/esp32s2.ini - ./arch/esp32/esp32s3.ini - ./arch/esp32/esp32c3.ini - ./arch/esp32/esp32c6.ini - build-script-path: bin/build-esp32.sh - ota-firmware-source: firmware-c3.bin - ota-firmware-target: release/bleota-c3.bin - artifact-paths: | + pio_platform: esp32 + pio_env: ${{ inputs.board }} + pio_target: build + ota_firmware_source: firmware-c3.bin + ota_firmware_target: release/bleota-c3.bin + + - name: Store binaries as an artifact + uses: actions/upload-artifact@v4 + with: + name: firmware-esp32c3-${{ inputs.board }}-${{ steps.version.outputs.long }}.zip + overwrite: true + path: | release/*.bin release/*.elf - include-web-ui: true - arch: esp32c3 diff --git a/.github/workflows/build_esp32_c6.yml b/.github/workflows/build_esp32_c6.yml index 56d4d806d..90cdcc78e 100644 --- a/.github/workflows/build_esp32_c6.yml +++ b/.github/workflows/build_esp32_c6.yml @@ -11,27 +11,30 @@ permissions: read-all jobs: build-esp32-c6: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 + - name: Get release version string + shell: bash + run: echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT + id: version + - name: Build ESP32-C6 id: build - uses: ./.github/actions/build-variant + uses: meshtastic/gh-action-firmware@main with: - github_token: ${{ secrets.GITHUB_TOKEN }} - board: ${{ inputs.board }} - remove-debug-flags: >- - ./arch/esp32/esp32.ini - ./arch/esp32/esp32s2.ini - ./arch/esp32/esp32s3.ini - ./arch/esp32/esp32c3.ini - ./arch/esp32/esp32c6.ini - build-script-path: bin/build-esp32.sh - ota-firmware-source: firmware-c3.bin - ota-firmware-target: release/bleota-c3.bin - artifact-paths: | + pio_platform: esp32 + pio_env: ${{ inputs.board }} + pio_target: build + ota_firmware_source: firmware-c3.bin + ota_firmware_target: release/bleota-c3.bin + + - name: Store binaries as an artifact + uses: actions/upload-artifact@v4 + with: + name: firmware-esp32c6-${{ inputs.board }}-${{ steps.version.outputs.long }}.zip + overwrite: true + path: | release/*.bin release/*.elf - include-web-ui: true - arch: esp32c6 diff --git a/.github/workflows/build_esp32_s3.yml b/.github/workflows/build_esp32_s3.yml index a9c067ee1..e5ed48e3e 100644 --- a/.github/workflows/build_esp32_s3.yml +++ b/.github/workflows/build_esp32_s3.yml @@ -11,27 +11,30 @@ permissions: read-all jobs: build-esp32-s3: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 + - name: Get release version string + shell: bash + run: echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT + id: version + - name: Build ESP32-S3 id: build - uses: ./.github/actions/build-variant + uses: meshtastic/gh-action-firmware@main with: - github_token: ${{ secrets.GITHUB_TOKEN }} - board: ${{ inputs.board }} - remove-debug-flags: >- - ./arch/esp32/esp32.ini - ./arch/esp32/esp32s2.ini - ./arch/esp32/esp32s3.ini - ./arch/esp32/esp32c3.ini - ./arch/esp32/esp32c6.ini - build-script-path: bin/build-esp32.sh - ota-firmware-source: firmware-s3.bin - ota-firmware-target: release/bleota-s3.bin - artifact-paths: | + pio_platform: esp32 + pio_env: ${{ inputs.board }} + pio_target: build + ota_firmware_source: firmware-s3.bin + ota_firmware_target: release/bleota-s3.bin + + - name: Store binaries as an artifact + uses: actions/upload-artifact@v4 + with: + name: firmware-esp32s3-${{ inputs.board }}-${{ steps.version.outputs.long }}.zip + overwrite: true + path: | release/*.bin release/*.elf - include-web-ui: true - arch: esp32s3 diff --git a/.github/workflows/build_nrf52.yml b/.github/workflows/build_nrf52.yml index 786508f86..312aeb372 100644 --- a/.github/workflows/build_nrf52.yml +++ b/.github/workflows/build_nrf52.yml @@ -11,20 +11,30 @@ permissions: read-all jobs: build-nrf52: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 + - name: Get release version string + shell: bash + run: echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT + id: version + - name: Build NRF52 id: build - uses: ./.github/actions/build-variant + uses: meshtastic/gh-action-firmware@main with: - github_token: ${{ secrets.GITHUB_TOKEN }} - board: ${{ inputs.board }} - build-script-path: bin/build-nrf52.sh - artifact-paths: | - release/*.hex + pio_platform: nrf52 + pio_env: ${{ inputs.board }} + pio_target: build + + - name: Store binaries as an artifact + uses: actions/upload-artifact@v4 + with: + name: firmware-nrf52840-${{ inputs.board }}-${{ steps.version.outputs.long }}.zip + overwrite: true + path: | release/*.uf2 release/*.elf - release/*.zip - arch: nrf52840 + release/*.hex + release/*-ota.zip diff --git a/.github/workflows/build_rpi2040.yml b/.github/workflows/build_rpi2040.yml index 53fee34d2..2abd7a839 100644 --- a/.github/workflows/build_rpi2040.yml +++ b/.github/workflows/build_rpi2040.yml @@ -11,18 +11,28 @@ permissions: read-all jobs: build-rpi2040: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 + - name: Get release version string + shell: bash + run: echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT + id: version + - name: Build Raspberry Pi 2040 id: build - uses: ./.github/actions/build-variant + uses: meshtastic/gh-action-firmware@main with: - github_token: ${{ secrets.GITHUB_TOKEN }} - board: ${{ inputs.board }} - build-script-path: bin/build-rpi2040.sh - artifact-paths: | + pio_platform: rp2xx0 + pio_env: ${{ inputs.board }} + pio_target: build + + - name: Store binaries as an artifact + uses: actions/upload-artifact@v4 + with: + name: firmware-rp2040-${{ inputs.board }}-${{ steps.version.outputs.long }}.zip + overwrite: true + path: | release/*.uf2 release/*.elf - arch: rp2040 diff --git a/.github/workflows/build_stm32.yml b/.github/workflows/build_stm32.yml index dc469d994..10680f422 100644 --- a/.github/workflows/build_stm32.yml +++ b/.github/workflows/build_stm32.yml @@ -11,19 +11,29 @@ permissions: read-all jobs: build-stm32: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 + - name: Get release version string + shell: bash + run: echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT + id: version + - name: Build STM32WL id: build - uses: ./.github/actions/build-variant + uses: meshtastic/gh-action-firmware@main with: - github_token: ${{ secrets.GITHUB_TOKEN }} - board: ${{ inputs.board }} - build-script-path: bin/build-stm32.sh - artifact-paths: | + pio_platform: stm32wl + pio_env: ${{ inputs.board }} + pio_target: build + + - name: Store binaries as an artifact + uses: actions/upload-artifact@v4 + with: + name: firmware-stm32-${{ inputs.board }}-${{ steps.version.outputs.long }}.zip + overwrite: true + path: | release/*.hex release/*.bin release/*.elf - arch: stm32 diff --git a/.github/workflows/daily_packaging.yml b/.github/workflows/daily_packaging.yml index 18939d567..63d24687b 100644 --- a/.github/workflows/daily_packaging.yml +++ b/.github/workflows/daily_packaging.yml @@ -30,7 +30,7 @@ jobs: strategy: fail-fast: false matrix: - series: [plucky, oracular, noble, jammy] + series: [plucky, noble, jammy] uses: ./.github/workflows/package_ppa.yml with: ppa_repo: ppa:meshtastic/daily diff --git a/.github/workflows/main_matrix.yml b/.github/workflows/main_matrix.yml index 9b9877e04..a676efa1e 100644 --- a/.github/workflows/main_matrix.yml +++ b/.github/workflows/main_matrix.yml @@ -135,6 +135,7 @@ jobs: board: ${{ matrix.board }} build-debian-src: + if: github.repository == 'meshtastic/firmware' uses: ./.github/workflows/build_debian_src.yml with: series: UNRELEASED @@ -257,7 +258,6 @@ jobs: ./device-*.sh ./device-*.bat ./littlefs-*.bin - ./littlefswebui-*.bin ./bleota*bin ./Meshtastic_nRF52_factory_erase*.uf2 retention-days: 30 @@ -426,7 +426,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} publish-firmware: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 if: ${{ github.event_name == 'workflow_dispatch' }} needs: [release-firmware] env: diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 36ec22f17..309772b12 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -8,6 +8,7 @@ permissions: read-all jobs: trunk_check: + if: github.repository == 'meshtastic/firmware' name: Trunk Check and Upload runs-on: ubuntu-24.04 @@ -21,6 +22,7 @@ jobs: trunk-token: ${{ secrets.TRUNK_TOKEN }} trunk_upgrade: + if: github.repository == 'meshtastic/firmware' # See: https://github.com/trunk-io/trunk-action/blob/v1/readme.md#automatic-upgrades name: Trunk Upgrade (PR) runs-on: ubuntu-24.04 diff --git a/.github/workflows/release_channels.yml b/.github/workflows/release_channels.yml index aac57fcbf..ed2de1717 100644 --- a/.github/workflows/release_channels.yml +++ b/.github/workflows/release_channels.yml @@ -20,7 +20,7 @@ jobs: strategy: fail-fast: false matrix: - series: [plucky, oracular, noble, jammy] + series: [plucky, noble, jammy] uses: ./.github/workflows/package_ppa.yml with: ppa_repo: |- diff --git a/.github/workflows/sec_sast_semgrep_cron.yml b/.github/workflows/sec_sast_semgrep_cron.yml index d7eef29b4..e391aa07b 100644 --- a/.github/workflows/sec_sast_semgrep_cron.yml +++ b/.github/workflows/sec_sast_semgrep_cron.yml @@ -13,6 +13,7 @@ permissions: jobs: semgrep-full: + if: github.repository == 'meshtastic/firmware' runs-on: ubuntu-24.04 container: image: semgrep/semgrep diff --git a/.github/workflows/stale_bot.yml b/.github/workflows/stale_bot.yml index 5ae6bdfc9..5a11fdfa8 100644 --- a/.github/workflows/stale_bot.yml +++ b/.github/workflows/stale_bot.yml @@ -11,6 +11,7 @@ permissions: jobs: stale_issues: + if: github.repository == 'meshtastic/firmware' name: Close Stale Issues runs-on: ubuntu-latest diff --git a/.github/workflows/test_native.yml b/.github/workflows/test_native.yml index 536d93665..dc05959fd 100644 --- a/.github/workflows/test_native.yml +++ b/.github/workflows/test_native.yml @@ -143,7 +143,7 @@ jobs: merge-multiple: true - name: Test Report - uses: dorny/test-reporter@v2.1.0 + uses: dorny/test-reporter@v2.1.1 with: name: PlatformIO Tests path: testreport.xml diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 28b6a40a5..34b28b39c 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -12,9 +12,11 @@ permissions: jobs: native-tests: + if: github.repository == 'meshtastic/firmware' uses: ./.github/workflows/test_native.yml hardware-tests: + if: github.repository == 'meshtastic/firmware' runs-on: test-runner steps: - name: Checkout code diff --git a/.gitignore b/.gitignore index b63f431d1..cc742c6c1 100644 --- a/.gitignore +++ b/.gitignore @@ -37,4 +37,7 @@ release/ .vscode/extensions.json /compile_commands.json src/mesh/raspihttp/certificate.pem -src/mesh/raspihttp/private_key.pem \ No newline at end of file +src/mesh/raspihttp/private_key.pem + +# Ignore logo (set at build time with platformio-custom.py) +data/boot/logo.* diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml index b40f9458b..f0271c856 100644 --- a/.trunk/trunk.yaml +++ b/.trunk/trunk.yaml @@ -4,25 +4,25 @@ cli: plugins: sources: - id: trunk - ref: v1.7.0 + ref: v1.7.1 uri: https://github.com/trunk-io/plugins lint: enabled: - - checkov@3.2.442 - - renovate@40.60.3 - - prettier@3.5.3 + - checkov@3.2.450 + - renovate@41.29.1 + - prettier@3.6.2 - trufflehog@3.89.2 - yamllint@1.37.1 - - bandit@1.8.5 - - trivy@0.63.0 + - bandit@1.8.6 + - trivy@0.64.1 - taplo@0.9.3 - - ruff@0.12.0 + - ruff@0.12.2 - isort@6.0.1 - markdownlint@0.45.0 - oxipng@9.1.5 - - svgo@3.3.2 + - svgo@4.0.0 - actionlint@1.7.7 - - flake8@7.2.0 + - flake8@7.3.0 - hadolint@2.12.1-beta - shfmt@3.6.0 - shellcheck@0.10.0 diff --git a/arch/esp32/esp32.ini b/arch/esp32/esp32.ini index cba84181b..6b9ebcb24 100644 --- a/arch/esp32/esp32.ini +++ b/arch/esp32/esp32.ini @@ -49,13 +49,13 @@ lib_deps = ${environmental_extra.lib_deps} ${radiolib_base.lib_deps} # renovate: datasource=git-refs depName=meshtastic-esp32_https_server packageName=https://github.com/meshtastic/esp32_https_server gitBranch=master - https://github.com/meshtastic/esp32_https_server/archive/896f1771ceb5979987a0b41028bf1b4e7aad419b.zip + https://github.com/meshtastic/esp32_https_server/archive/3223704846752e6d545139204837bdb2a55459ca.zip # renovate: datasource=custom.pio depName=NimBLE-Arduino packageName=h2zero/library/NimBLE-Arduino h2zero/NimBLE-Arduino@^1.4.3 # renovate: datasource=git-refs depName=libpax packageName=https://github.com/dbinfrago/libpax gitBranch=master https://github.com/dbinfrago/libpax/archive/3cdc0371c375676a97967547f4065607d4c53fd1.zip # renovate: datasource=custom.pio depName=XPowersLib packageName=lewisxhe/library/XPowersLib - lewisxhe/XPowersLib@^0.2.7 + lewisxhe/XPowersLib@0.3.0 # renovate: datasource=git-refs depName=meshtastic-ESP32_Codec2 packageName=https://github.com/meshtastic/ESP32_Codec2 gitBranch=master https://github.com/meshtastic/ESP32_Codec2/archive/633326c78ac251c059ab3a8c430fcdf25b41672f.zip # renovate: datasource=custom.pio depName=rweather/Crypto packageName=rweather/library/Crypto diff --git a/arch/esp32/esp32c6.ini b/arch/esp32/esp32c6.ini index 26b5c0f5b..1afb9b547 100644 --- a/arch/esp32/esp32c6.ini +++ b/arch/esp32/esp32c6.ini @@ -28,7 +28,7 @@ lib_deps = ${environmental_extra.lib_deps} ${radiolib_base.lib_deps} # renovate: datasource=custom.pio depName=XPowersLib packageName=lewisxhe/library/XPowersLib - lewisxhe/XPowersLib@^0.2.7 + lewisxhe/XPowersLib@0.3.0 # renovate: datasource=git-refs depName=meshtastic-ESP32_Codec2 packageName=https://github.com/meshtastic/ESP32_Codec2 gitBranch=master https://github.com/meshtastic/ESP32_Codec2/archive/633326c78ac251c059ab3a8c430fcdf25b41672f.zip # renovate: datasource=custom.pio depName=rweather/Crypto packageName=rweather/library/Crypto diff --git a/arch/portduino/portduino.ini b/arch/portduino/portduino.ini index 429e010f5..03a8a6583 100644 --- a/arch/portduino/portduino.ini +++ b/arch/portduino/portduino.ini @@ -2,7 +2,7 @@ [portduino_base] platform = # renovate: datasource=git-refs depName=platform-native packageName=https://github.com/meshtastic/platform-native gitBranch=develop - https://github.com/meshtastic/platform-native/archive/681ee029207e9fd040afa223df6e54074cbbe084.zip + https://github.com/meshtastic/platform-native/archive/6cb7a455b440dd0738e8ed74a18136ed5cf7ea63.zip framework = arduino build_src_filter = @@ -30,6 +30,8 @@ lib_deps = lovyan03/LovyanGFX@^1.2.0 # renovate: datasource=git-refs depName=libch341-spi-userspace packageName=https://github.com/pine64/libch341-spi-userspace gitBranch=main https://github.com/pine64/libch341-spi-userspace/archive/af9bc27c9c30fa90772279925b7c5913dff789b4.zip + # renovate: datasource=custom.pio depName=adafruit/Adafruit seesaw Library packageName=adafruit/library/Adafruit seesaw Library + adafruit/Adafruit seesaw Library@1.7.9 build_flags = ${arduino_base.build_flags} @@ -48,4 +50,7 @@ build_flags = -std=gnu17 -std=c++17 -lib_ignore = Adafruit NeoPixel +lib_ignore = + Adafruit NeoPixel + Adafruit ST7735 and ST7789 Library + SD diff --git a/arch/stm32/stm32.ini b/arch/stm32/stm32.ini index e7a340f92..be1ed662f 100644 --- a/arch/stm32/stm32.ini +++ b/arch/stm32/stm32.ini @@ -16,14 +16,17 @@ build_flags = ${arduino_base.build_flags} -flto -Isrc/platform/stm32wl -g - -DMESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR - -DMESHTASTIC_EXCLUDE_INPUTBROKER - -DMESHTASTIC_EXCLUDE_I2C - -DMESHTASTIC_EXCLUDE_POWERMON - -DMESHTASTIC_EXCLUDE_SCREEN - -DMESHTASTIC_EXCLUDE_MQTT - -DMESHTASTIC_EXCLUDE_BLUETOOTH - -DMESHTASTIC_EXCLUDE_GPS + -DMESHTASTIC_EXCLUDE_AUDIO=1 + -DMESHTASTIC_EXCLUDE_ATAK=1 ; ATAK is quite big, disable it for big flash savings. + -DMESHTASTIC_EXCLUDE_INPUTBROKER=1 + -DMESHTASTIC_EXCLUDE_POWERMON=1 + -DMESHTASTIC_EXCLUDE_SCREEN=1 + -DMESHTASTIC_EXCLUDE_MQTT=1 + -DMESHTASTIC_EXCLUDE_BLUETOOTH=1 + -DMESHTASTIC_EXCLUDE_GPS=1 + -DMESHTASTIC_EXCLUDE_WIFI=1 + -DMESHTASTIC_EXCLUDE_TZ=1 ; Exclude TZ to save some flash space. + -DPIO_FRAMEWORK_ARDUINO_NANOLIB_FLOAT_PRINTF ; This is REQUIRED for at least traceroute debug prints - without it the length ends up uninitialized. ;-DDEBUG_MUTE -fmerge-all-constants -ffunction-sections @@ -39,9 +42,9 @@ debug_tool = stlink lib_deps = ${env.lib_deps} ${radiolib_base.lib_deps} + # renovate: datasource=git-refs depName=caveman99-stm32-Crypto packageName=https://github.com/caveman99/Crypto gitBranch=main https://github.com/caveman99/Crypto/archive/eae9c768054118a9399690f8af202853d1ae8516.zip lib_ignore = - mathertel/OneButton@2.6.1 - Wire + OneButton diff --git a/bin/build-esp32.sh b/bin/build-esp32.sh index a0635e997..92836db23 100755 --- a/bin/build-esp32.sh +++ b/bin/build-esp32.sh @@ -11,7 +11,7 @@ rm -f $OUTDIR/firmware* rm -r $OUTDIR/* || true # Important to pull latest version of libs into all device flavors, otherwise some devices might be stale -platformio pkg update -e $1 +platformio pkg install -e $1 echo "Building for $1 with $PLATFORMIO_BUILD_FLAGS" rm -f .pio/build/$1/firmware.* @@ -34,11 +34,12 @@ SRCBIN=.pio/build/$1/firmware.bin cp $SRCBIN $OUTDIR/$basename-update.bin echo "Building Filesystem for ESP32 targets" -pio run --environment $1 -t buildfs -cp .pio/build/$1/littlefs.bin $OUTDIR/littlefswebui-$1-$VERSION.bin -# Remove webserver files from the filesystem and rebuild -ls -l data/static # Diagnostic list of files -rm -rf data/static +# If you want to build the webui, uncomment the following lines +# pio run --environment $1 -t buildfs +# cp .pio/build/$1/littlefs.bin $OUTDIR/littlefswebui-$1-$VERSION.bin +# # Remove webserver files from the filesystem and rebuild +# ls -l data/static # Diagnostic list of files +# rm -rf data/static pio run --environment $1 -t buildfs cp .pio/build/$1/littlefs.bin $OUTDIR/littlefs-$1-$VERSION.bin cp bin/device-install.* $OUTDIR diff --git a/bin/build-native.sh b/bin/build-native.sh index 51379ad76..fff86e87e 100755 --- a/bin/build-native.sh +++ b/bin/build-native.sh @@ -25,7 +25,7 @@ mkdir -p $OUTDIR/ rm -r $OUTDIR/* || true # Important to pull latest version of libs into all device flavors, otherwise some devices might be stale -pio pkg update --environment "$PIO_ENV" || platformioFailed +pio pkg install --environment "$PIO_ENV" || platformioFailed pio run --environment "$PIO_ENV" || platformioFailed cp ".pio/build/$PIO_ENV/program" "$OUTDIR/meshtasticd_linux_$(uname -m)" cp bin/native-install.* $OUTDIR diff --git a/bin/build-nrf52.sh b/bin/build-nrf52.sh index 9d0b3dfdd..deca209d2 100755 --- a/bin/build-nrf52.sh +++ b/bin/build-nrf52.sh @@ -11,7 +11,7 @@ rm -f $OUTDIR/firmware* rm -r $OUTDIR/* || true # Important to pull latest version of libs into all device flavors, otherwise some devices might be stale -platformio pkg update -e $1 +platformio pkg install -e $1 echo "Building for $1 with $PLATFORMIO_BUILD_FLAGS" rm -f .pio/build/$1/firmware.* diff --git a/bin/build-rpi2040.sh b/bin/build-rp2xx0.sh similarity index 96% rename from bin/build-rpi2040.sh rename to bin/build-rp2xx0.sh index dad6a7e67..cb4865914 100755 --- a/bin/build-rpi2040.sh +++ b/bin/build-rp2xx0.sh @@ -11,7 +11,7 @@ rm -f $OUTDIR/firmware* rm -r $OUTDIR/* || true # Important to pull latest version of libs into all device flavors, otherwise some devices might be stale -platformio pkg update -e $1 +platformio pkg install -e $1 echo "Building for $1 with $PLATFORMIO_BUILD_FLAGS" rm -f .pio/build/$1/firmware.* diff --git a/bin/build-stm32.sh b/bin/build-stm32wl.sh similarity index 95% rename from bin/build-stm32.sh rename to bin/build-stm32wl.sh index 76c5a75fb..f62df4842 100755 --- a/bin/build-stm32.sh +++ b/bin/build-stm32wl.sh @@ -11,7 +11,7 @@ rm -f $OUTDIR/firmware* rm -r $OUTDIR/* || true # Important to pull latest version of libs into all device flavors, otherwise some devices might be stale -platformio pkg update -e $1 +platformio pkg install -e $1 echo "Building for $1 with $PLATFORMIO_BUILD_FLAGS" rm -f .pio/build/$1/firmware.* diff --git a/bin/config-dist.yaml b/bin/config-dist.yaml index b40fb85a5..b4cc81792 100644 --- a/bin/config-dist.yaml +++ b/bin/config-dist.yaml @@ -199,6 +199,10 @@ HostMetrics: # UserStringCommand: cat /sys/firmware/devicetree/base/serial-number # Command to execute, to send the results as the userString +Config: +# DisplayMode: TWOCOLOR # uncomment to force BaseUI +# DisplayMode: COLOR # uncomment to force MUI + General: MaxNodes: 200 MaxMessageQueue: 100 diff --git a/bin/config.d/display-waveshare-1-44.yaml b/bin/config.d/display-waveshare-1-44.yaml index 1d85a4a3b..d37f6cf6a 100644 --- a/bin/config.d/display-waveshare-1-44.yaml +++ b/bin/config.d/display-waveshare-1-44.yaml @@ -22,5 +22,5 @@ Input: TrackballLeft: 5 TrackballRight: 26 TrackballPress: 13 - + TrackballDirection: FALLING # User: 21 diff --git a/bin/config.d/lora-MeshAdv-Mini-900M22S.yaml b/bin/config.d/lora-MeshAdv-Mini-900M22S.yaml index 554116b57..b47b5c996 100644 --- a/bin/config.d/lora-MeshAdv-Mini-900M22S.yaml +++ b/bin/config.d/lora-MeshAdv-Mini-900M22S.yaml @@ -6,6 +6,6 @@ Lora: IRQ: 16 Busy: 20 Reset: 24 - TXen: 13 + RXen: 12 DIO2_AS_RF_SWITCH: true DIO3_TCXO_VOLTAGE: true diff --git a/bin/config.d/lora-ws-raspberry-pico-to-orangepi-03.yaml b/bin/config.d/lora-ws-raspberry-pico-to-orangepi-03.yaml new file mode 100644 index 000000000..37d7e27d2 --- /dev/null +++ b/bin/config.d/lora-ws-raspberry-pico-to-orangepi-03.yaml @@ -0,0 +1,52 @@ +# https://www.waveshare.com/pico-lora-sx1262-868m.htm +# http://www.orangepi.org/html/hardWare/computerAndMicrocontrollers/details/Orange-Pi-Zero-3.html +# +# See Orange Pi Zero3 manual, chapter 3.16, page 124 for 26-pin header pinout +# +# Pin Connection +# Waveshare Orange Pi Zero3 +# 36 3.3V 17 +# 15 MOSI 19 +# 16 MISO 21 +# 14 CLK 23 +# 38 GND 25 +# 4 BUSY 18 +# 20 RESET 22 +# 5 CS 24 +# 26 DIO1/IRQ 26 + +Lora: + Module: sx1262 # Waveshare Raspberry Pico Lora module + DIO2_AS_RF_SWITCH: true + DIO3_TCXO_VOLTAGE: true + # Specify either the spidev1_1 or the CS below, not both! + # On DietPi Linux, when using the user overlay dietpi-spi1_1.dtbo, CS will be configured with spidev1.1 + spidev: spidev1.1 # See Orange Pi Zero3 manual, chapter 3.18.3, page 130 +# CS: # CS PIN_24 -> chip 1, line 233 +# pin: 24 +# gpiochip: 1 +# line: 233 + SCK: # SCK PIN_23 -> chip 1, line 230 + pin: 23 + gpiochip: 1 + line: 230 + Busy: # BUSY PIN_18 -> chip 1, line 78 + pin: 18 + gpiochip: 1 + line: 78 + MOSI: # MOSI PIN_19 -> chip 1, line 231 + pin: 19 + gpiochip: 1 + line: 231 + MISO: # MISO PIN_21 -> chip 1, line 232 + pin: 21 + gpiochip: 1 + line: 232 + Reset: # NRST PIN_22 -> chip 1, line 71 + pin: 22 + gpiochip: 1 + line: 71 + IRQ: # DIO1 PIN_26 -> chip 1, line 74 + pin: 26 + gpiochip: 1 + line: 74 diff --git a/bin/device-install.bat b/bin/device-install.bat index 816d2fbba..12bfd4f6e 100755 --- a/bin/device-install.bat +++ b/bin/device-install.bat @@ -5,7 +5,6 @@ TITLE Meshtastic device-install SET "SCRIPT_NAME=%~nx0" SET "DEBUG=0" SET "PYTHON=" -SET "WEB_APP=0" SET "TFT_BUILD=0" SET "BIGDB8=0" SET "BIGDB16=0" @@ -25,7 +24,7 @@ GOTO getopts :help ECHO Flash image file to device, but first erasing and writing system information. ECHO. -ECHO Usage: %SCRIPT_NAME% -f filename [-p PORT] [-P python] (--web) [--1200bps-reset] +ECHO Usage: %SCRIPT_NAME% -f filename [-p PORT] [-P python] [--1200bps-reset] ECHO. ECHO Options: ECHO -f filename The firmware .bin file to flash. Custom to your device type and region. (required) @@ -35,13 +34,12 @@ ECHO If not set, ESPTOOL iterates all ports (Dangerous). ECHO -P python Specify alternate python interpreter to use to invoke esptool. (default: python) ECHO If supplied the script will use python. ECHO If not supplied the script will try to find esptool in Path. -ECHO --web Enable WebUI. (default: false) ECHO --1200bps-reset Attempt to place the device in correct mode. (1200bps Reset) ECHO Some hardware requires this twice. ECHO. ECHO Example: %SCRIPT_NAME% -p COM17 --1200bps-reset ECHO Example: %SCRIPT_NAME% -f firmware-t-deck-tft-2.6.0.0b106d4.bin -p COM11 -ECHO Example: %SCRIPT_NAME% -f firmware-unphone-2.6.0.0b106d4.bin -p COM11 --web +ECHO Example: %SCRIPT_NAME% -f firmware-unphone-2.6.0.0b106d4.bin -p COM11 GOTO eof :version @@ -61,7 +59,6 @@ IF /I "%~1"=="-f" SET "FILENAME=%~2" & SHIFT IF "%~1"=="-p" SET "ESPTOOL_PORT=%~2" & SHIFT IF /I "%~1"=="--port" SET "ESPTOOL_PORT=%~2" & SHIFT IF "%~1"=="-P" SET "PYTHON=%~2" & SHIFT -IF /I "%~1"=="--web" SET "WEB_APP=1" IF /I "%~1"=="--1200bps-reset" SET "BPS_RESET=1" SHIFT GOTO getopts @@ -153,9 +150,6 @@ IF %BPS_RESET% EQU 1 ( @REM https://github.com/meshtastic/web-flasher/blob/main/types/resources.ts#L3 IF NOT "!FILENAME:-tft-=!"=="!FILENAME!" ( CALL :LOG_MESSAGE DEBUG "We are working with a *-tft-* file. !FILENAME!" - IF %WEB_APP% EQU 1 ( - CALL :LOG_MESSAGE ERROR "Cannot enable WebUI (--web) and MUI." & GOTO eof - ) SET "TFT_BUILD=1" ) ELSE ( CALL :LOG_MESSAGE DEBUG "We are NOT working with a *-tft-* file. !FILENAME!" @@ -209,13 +203,8 @@ SET "OTA_FILENAME=bleota.bin" :end_loop_c3 CALL :LOG_MESSAGE DEBUG "Set OTA_FILENAME to: !OTA_FILENAME!" -@REM Check if (--web) is enabled and prefix BASENAME with "littlefswebui-" else "littlefs-". -IF %WEB_APP% EQU 1 ( - CALL :LOG_MESSAGE INFO "WebUI selected." - SET "SPIFFS_FILENAME=littlefswebui-%BASENAME%" -) ELSE ( - SET "SPIFFS_FILENAME=littlefs-%BASENAME%" -) +@REM Set SPIFFS filename with "littlefs-" prefix. +SET "SPIFFS_FILENAME=littlefs-%BASENAME%" CALL :LOG_MESSAGE DEBUG "Set SPIFFS_FILENAME to: !SPIFFS_FILENAME!" @REM Default offsets. diff --git a/bin/device-install.sh b/bin/device-install.sh index 613696d2f..4674113b6 100755 --- a/bin/device-install.sh +++ b/bin/device-install.sh @@ -1,7 +1,6 @@ #!/bin/bash PYTHON=${PYTHON:-$(which python3 python | head -n 1)} -WEB_APP=false BPS_RESET=false TFT_BUILD=false MCU="" @@ -76,14 +75,13 @@ set -e # Usage info show_help() { cat <&2 @@ -55,7 +63,7 @@ while getopts ":hp:P:f:" opt; do done shift "$((OPTIND-1))" -if [[ $CHANGE_MODE == true ]]; then +if [ "$CHANGE_MODE" = true ]; then $ESPTOOL_CMD --baud 1200 --after no_reset read_flash_status exit 0 fi diff --git a/bin/org.meshtastic.meshtasticd.metainfo.xml b/bin/org.meshtastic.meshtasticd.metainfo.xml index f9f647dae..291fe7a7c 100644 --- a/bin/org.meshtastic.meshtasticd.metainfo.xml +++ b/bin/org.meshtastic.meshtasticd.metainfo.xml @@ -87,7 +87,13 @@ - + + https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.3 + + + https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.2 + + https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.1 diff --git a/bin/platformio-custom.py b/bin/platformio-custom.py index 600f9447f..be2a9ab71 100644 --- a/bin/platformio-custom.py +++ b/bin/platformio-custom.py @@ -131,3 +131,33 @@ for lb in env.GetLibBuilders(): if lb.name == "meshtastic-device-ui": lb.env.Append(CPPDEFINES=[("APP_VERSION", verObj["long"])]) break + +# Get the display resolution from macros +def get_display_resolution(build_flags): + # Check "DISPLAY_SIZE" to determine the screen resolution + for flag in build_flags: + if isinstance(flag, tuple) and flag[0] == "DISPLAY_SIZE": + screen_width, screen_height = map(int, flag[1].split("x")) + return screen_width, screen_height + print("No screen resolution defined in build_flags. Please define DISPLAY_SIZE.") + exit(1) + +def load_boot_logo(source, target, env): + build_flags = env.get("CPPDEFINES", []) + logo_w, logo_h = get_display_resolution(build_flags) + print(f"TFT build with {logo_w}x{logo_h} resolution detected") + + # Load the boot logo from `branding/logo_x.png` if it exists + source_path = join(env["PROJECT_DIR"], "branding", f"logo_{logo_w}x{logo_h}.png") + dest_dir = join(env["PROJECT_DIR"], "data", "boot") + dest_path = join(dest_dir, "logo.png") + if env.File(source_path).exists(): + print(f"Loading boot logo from {source_path}") + # Prepare the destination + env.Execute(f"mkdir -p {dest_dir} && rm -f {dest_path}") + # Copy the logo to the `data/boot` directory + env.Execute(f"cp {source_path} {dest_path}") + +# Load the boot logo on TFT builds +if ("HAS_TFT", 1) in env.get("CPPDEFINES", []): + env.AddPreAction('$BUILD_DIR/littlefs.bin', load_boot_logo) diff --git a/bin/web.version b/bin/web.version index a4db534a2..e46a05b19 100644 --- a/bin/web.version +++ b/bin/web.version @@ -1 +1 @@ -2.5.3 \ No newline at end of file +2.6.4 \ No newline at end of file diff --git a/boards/heltec_mesh_node_t114.json b/boards/heltec_mesh_node_t114.json index d516c9701..eda0ac3df 100644 --- a/boards/heltec_mesh_node_t114.json +++ b/boards/heltec_mesh_node_t114.json @@ -10,7 +10,8 @@ "hwids": [ ["0x239A", "0x4405"], ["0x239A", "0x0029"], - ["0x239A", "0x002A"] + ["0x239A", "0x002A"], + ["0x2886", "0x1667"] ], "usb_product": "HT-n5262", "mcu": "nrf52840", diff --git a/boards/seeed_wio_tracker_L1.json b/boards/seeed_wio_tracker_L1.json index 7c7bc62fa..e2bb93573 100644 --- a/boards/seeed_wio_tracker_L1.json +++ b/boards/seeed_wio_tracker_L1.json @@ -7,7 +7,10 @@ "cpu": "cortex-m4", "extra_flags": "-DARDUINO_MDBT50Q_RX -DNRF52840_XXAA", "f_cpu": "64000000L", - "hwids": [["0x2886", "0x1668"]], + "hwids": [ + ["0x2886", "0x1668"], + ["0x2886", "0x1667"] + ], "usb_product": "TRACKER L1", "mcu": "nrf52840", "variant": "seeed_wio_tracker_L1", diff --git a/boards/tracker-t1000-e.json b/boards/tracker-t1000-e.json index 2be716e22..9e8870041 100644 --- a/boards/tracker-t1000-e.json +++ b/boards/tracker-t1000-e.json @@ -11,7 +11,8 @@ ["0x239A", "0x8029"], ["0x239A", "0x0029"], ["0x239A", "0x002A"], - ["0x239A", "0x802A"] + ["0x239A", "0x802A"], + ["0x2886", "0x0057"] ], "usb_product": "T1000-E-BOOT", "mcu": "nrf52840", diff --git a/boards/wiscore_rak3312.json b/boards/wiscore_rak3312.json new file mode 100644 index 000000000..192e1c03c --- /dev/null +++ b/boards/wiscore_rak3312.json @@ -0,0 +1,41 @@ +{ + "build": { + "arduino": { + "ldscript": "esp32s3_out.ld", + "memory_type": "qio_opi", + "partitions": "default_16MB.csv" + }, + "core": "esp32", + "extra_flags": [ + "-DRAK3312", + "-DARDUINO_USB_CDC_ON_BOOT=1", + "-DARDUINO_USB_MODE=1", + "-DARDUINO_RUNNING_CORE=1", + "-DARDUINO_EVENT_RUNNING_CORE=1", + "-DBOARD_HAS_PSRAM" + ], + "f_cpu": "240000000L", + "f_flash": "80000000L", + "flash_mode": "dio", + "hwids": [["0x303A", "0x1001"]], + "mcu": "esp32s3", + "variant": "rak3312" + }, + "connectivity": ["wifi", "bluetooth"], + "debug": { + "openocd_target": "esp32s3.cfg" + }, + "frameworks": ["arduino", "espidf"], + "name": "WisCore RAK3312 Board", + "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": 921600 + }, + "url": "https://www.rakwireless.com/en-us", + "vendor": "rakwireless" +} diff --git a/branding/README.md b/branding/README.md new file mode 100644 index 000000000..3a558bf20 --- /dev/null +++ b/branding/README.md @@ -0,0 +1,17 @@ +# Meshtastic Branding / Whitelabeling + +This directory is consumed during the creation of **event** firmware. + +`bin/platformio-custom.py` determines the display resolution, and locates the corresponding `logo_x.png`. + +Ex: + +- `logo_800x480.png` +- `logo_480x480.png` +- `logo_480x320.png` +- `logo_320x480.png` +- `logo_320x240.png` + +This file is copied to `data/boot/logo.png` before filesytem image compilation. + +For additional examples see the [`event/defcon33` branch](https://github.com/meshtastic/firmware/tree/event/defcon33). diff --git a/debian/changelog b/debian/changelog index 4629e8c3a..b5009028a 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -meshtasticd (2.7.1.0) UNRELEASED; urgency=medium +meshtasticd (2.7.3.0) UNRELEASED; urgency=medium [ Austin Lane ] * Initial packaging @@ -25,4 +25,10 @@ meshtasticd (2.7.1.0) UNRELEASED; urgency=medium [ ] * GitHub Actions Automatic version bump - -- Sat, 21 Jun 2025 15:51:49 +0000 + [ ] + * GitHub Actions Automatic version bump + + [ Ubuntu ] + * GitHub Actions Automatic version bump + + -- Ubuntu Thu, 10 Jul 2025 16:29:27 +0000 diff --git a/platformio.ini b/platformio.ini index 06b3fdf6f..e24794939 100644 --- a/platformio.ini +++ b/platformio.ini @@ -50,11 +50,11 @@ build_flags = -Wno-missing-field-initializers -DMESHTASTIC_EXCLUDE_DROPZONE=1 -DMESHTASTIC_EXCLUDE_REMOTEHARDWARE=1 -DMESHTASTIC_EXCLUDE_HEALTH_TELEMETRY=1 - -DMESHTASTIC_EXCLUDE_POWERSTRESS=1 ; exclude power stress test module from main firmware + -DMESHTASTIC_EXCLUDE_POWERSTRESS=1 ; exclude power stress test module from main firmware -DMESHTASTIC_EXCLUDE_GENERIC_THREAD_MODULE=1 -D MAX_THREADS=40 ; As we've split modules, we have more threads to manage - #-DBUILD_EPOCH=$UNIX_TIME - #-D OLED_PL=1 + #-DBUILD_EPOCH=$UNIX_TIME + #-D OLED_PL=1 monitor_speed = 115200 monitor_filters = direct @@ -105,18 +105,18 @@ lib_deps = [radiolib_base] lib_deps = # renovate: datasource=custom.pio depName=RadioLib packageName=jgromes/library/RadioLib - jgromes/RadioLib@7.2.0 + jgromes/RadioLib@7.2.1 [device-ui_base] lib_deps = # renovate: datasource=git-refs depName=meshtastic/device-ui packageName=https://github.com/meshtastic/device-ui gitBranch=master - https://github.com/meshtastic/device-ui/archive/cdc6e5bdeedb8293d10e4a02be6ca64e95a7c515.zip + https://github.com/meshtastic/device-ui/archive/86a09a7360f92d10053fbbf8d74f67f85b0ceb09.zip ; Common libs for environmental measurements in telemetry module [environmental_base] lib_deps = # renovate: datasource=custom.pio depName=Adafruit BusIO packageName=adafruit/library/Adafruit BusIO - adafruit/Adafruit BusIO@1.17.1 + adafruit/Adafruit BusIO@1.17.2 # renovate: datasource=custom.pio depName=Adafruit Unified Sensor packageName=adafruit/library/Adafruit Unified Sensor adafruit/Adafruit Unified Sensor@1.1.15 # renovate: datasource=custom.pio depName=Adafruit BMP280 packageName=adafruit/library/Adafruit BMP280 Library @@ -130,7 +130,7 @@ lib_deps = # renovate: datasource=custom.pio depName=Adafruit MCP9808 packageName=adafruit/library/Adafruit MCP9808 Library adafruit/Adafruit MCP9808 Library@2.0.2 # renovate: datasource=custom.pio depName=Adafruit INA260 packageName=adafruit/library/Adafruit INA260 Library - adafruit/Adafruit INA260 Library@1.5.2 + adafruit/Adafruit INA260 Library@1.5.3 # renovate: datasource=custom.pio depName=Adafruit INA219 packageName=adafruit/library/Adafruit INA219 adafruit/Adafruit INA219@1.2.3 # renovate: datasource=custom.pio depName=Adafruit PM25 AQI Sensor packageName=adafruit/library/Adafruit PM25 AQI Sensor @@ -169,8 +169,8 @@ lib_deps = adafruit/Adafruit PCT2075@1.0.5 # renovate: datasource=custom.pio depName=DFRobot_BMM150 packageName=dfrobot/library/DFRobot_BMM150 dfrobot/DFRobot_BMM150@1.0.0 - - ; (not included in native / portduino) + +; (not included in native / portduino) [environmental_extra] lib_deps = # renovate: datasource=custom.pio depName=Adafruit BMP3XX packageName=adafruit/library/Adafruit BMP3XX Library @@ -196,4 +196,8 @@ lib_deps = # renovate: datasource=custom.pio depName=Bosch BME68x packageName=boschsensortec/library/BME68x Sensor Library boschsensortec/BME68x Sensor Library@1.3.40408 # renovate: datasource=git-refs depName=meshtastic-DFRobot_LarkWeatherStation packageName=https://github.com/meshtastic/DFRobot_LarkWeatherStation gitBranch=master - https://github.com/meshtastic/DFRobot_LarkWeatherStation/archive/4de3a9cadef0f6a5220a8a906cf9775b02b0040d.zip \ No newline at end of file + https://github.com/meshtastic/DFRobot_LarkWeatherStation/archive/4de3a9cadef0f6a5220a8a906cf9775b02b0040d.zip + # renovate: datasource=custom.pio depName=Sensirion Core packageName=sensirion/library/Sensirion Core + sensirion/Sensirion Core@0.7.1 + # renovate: datasource=custom.pio depName=Sensirion I2C SCD4x packageName=sensirion/library/Sensirion I2C SCD4x + sensirion/Sensirion I2C SCD4x@1.1.0 diff --git a/protobufs b/protobufs index 6791138f0..584f0a3a3 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 6791138f0ba2b7c471072bd4bba6cbb8bacffe2d +Subproject commit 584f0a3a359103acf0bfce506c1b1fc32c639841 diff --git a/src/Power.cpp b/src/Power.cpp index 400b6c6eb..9c67977bd 100644 --- a/src/Power.cpp +++ b/src/Power.cpp @@ -103,7 +103,7 @@ NullSensor ina3221Sensor; #endif -#if !MESHTASTIC_EXCLUDE_I2C && !defined(ARCH_STM32WL) +#if !MESHTASTIC_EXCLUDE_I2C #include "modules/Telemetry/Sensor/MAX17048Sensor.h" #include extern std::pair nodeTelemetrySensorsMap[_meshtastic_TelemetrySensorType_MAX + 1]; @@ -278,7 +278,7 @@ class AnalogBatteryLevel : public HasBatteryLevel } #endif -#if HAS_TELEMETRY && !defined(ARCH_STM32WL) && !defined(HAS_PMU) && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR +#if HAS_TELEMETRY && !defined(HAS_PMU) && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR if (hasINA()) { return getINAVoltage(); } @@ -456,8 +456,7 @@ 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_STM32WL) && \ - !defined(DISABLE_INA_CHARGING_DETECTION) +#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && !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 @@ -503,7 +502,7 @@ class AnalogBatteryLevel : public HasBatteryLevel } #endif -#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && !defined(ARCH_STM32WL) +#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR uint16_t getINAVoltage() { if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA219].first == config.power.device_battery_ina_address) { @@ -682,7 +681,7 @@ bool Power::setup() void Power::shutdown() { - LOG_INFO("Shutting down"); + LOG_INFO("Shutting Down"); #if defined(ARCH_NRF52) || defined(ARCH_ESP32) || defined(ARCH_RP2040) #ifdef PIN_LED1 @@ -1161,7 +1160,7 @@ bool Power::axpChipInit() #endif } -#if !MESHTASTIC_EXCLUDE_I2C && !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) +#if !MESHTASTIC_EXCLUDE_I2C && __has_include() /** * Wrapper class for an I2C MAX17048 Lipo battery sensor. diff --git a/src/commands.h b/src/commands.h index e0bfab330..603003e5c 100644 --- a/src/commands.h +++ b/src/commands.h @@ -13,5 +13,6 @@ enum class Cmd { START_FIRMWARE_UPDATE_SCREEN, STOP_BOOT_SCREEN, SHOW_PREV_FRAME, - SHOW_NEXT_FRAME + SHOW_NEXT_FRAME, + NOOP }; \ No newline at end of file diff --git a/src/configuration.h b/src/configuration.h index 89257ff2f..cddc7ba7a 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -189,6 +189,7 @@ along with this program. If not, see . #define DFROBOT_RAIN_ADDR 0x1d #define NAU7802_ADDR 0x2A #define MAX30102_ADDR 0x57 +#define SCD4X_ADDR 0x62 #define MLX90614_ADDR_DEF 0x5A #define CGRADSENS_ADDR 0x66 #define LTR390UV_ADDR 0x53 diff --git a/src/detect/ScanI2C.cpp b/src/detect/ScanI2C.cpp index e6236251c..170bef3a6 100644 --- a/src/detect/ScanI2C.cpp +++ b/src/detect/ScanI2C.cpp @@ -41,6 +41,12 @@ ScanI2C::FoundDevice ScanI2C::firstAccelerometer() const return firstOfOrNONE(9, types); } +ScanI2C::FoundDevice ScanI2C::firstAQI() const +{ + ScanI2C::DeviceType types[] = {PMSA0031, SCD4X}; + return firstOfOrNONE(2, types); +} + ScanI2C::FoundDevice ScanI2C::firstRGBLED() const { ScanI2C::DeviceType types[] = {NCP5623, LP5562}; @@ -80,4 +86,4 @@ bool ScanI2C::DeviceAddress::operator<(const ScanI2C::DeviceAddress &other) cons || (port != NO_I2C && other.port != NO_I2C && (address < other.address)); } -ScanI2C::FoundDevice::FoundDevice(ScanI2C::DeviceType type, ScanI2C::DeviceAddress address) : type(type), address(address) {} \ No newline at end of file +ScanI2C::FoundDevice::FoundDevice(ScanI2C::DeviceType type, ScanI2C::DeviceAddress address) : type(type), address(address) {} diff --git a/src/detect/ScanI2C.h b/src/detect/ScanI2C.h index 90467abd0..dd290db98 100644 --- a/src/detect/ScanI2C.h +++ b/src/detect/ScanI2C.h @@ -61,6 +61,7 @@ class ScanI2C FT6336U, STK8BAXX, ICM20948, + SCD4X, MAX30102, TPS65233, MPR121KB, @@ -126,6 +127,8 @@ class ScanI2C FoundDevice firstAccelerometer() const; + FoundDevice firstAQI() const; + FoundDevice firstRGBLED() const; virtual FoundDevice find(DeviceType) const; diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index fd3d1c80b..9e9441123 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -447,6 +447,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) SCAN_SIMPLE_CASE(DFROBOT_RAIN_ADDR, DFROBOT_RAIN, "DFRobot Rain Gauge", (uint8_t)addr.address); SCAN_SIMPLE_CASE(LTR390UV_ADDR, LTR390UV, "LTR390UV", (uint8_t)addr.address); SCAN_SIMPLE_CASE(PCT2075_ADDR, PCT2075, "PCT2075", (uint8_t)addr.address); + SCAN_SIMPLE_CASE(SCD4X_ADDR, SCD4X, "SCD4X", (uint8_t)addr.address); SCAN_SIMPLE_CASE(BMM150_ADDR, BMM150, "BMM150", (uint8_t)addr.address); #ifdef HAS_TPS65233 SCAN_SIMPLE_CASE(TPS65233_ADDR, TPS65233, "TPS65233", (uint8_t)addr.address); @@ -556,4 +557,4 @@ void ScanI2CTwoWire::logFoundDevice(const char *device, uint8_t address) { LOG_INFO("%s found at address 0x%x", device, address); } -#endif \ No newline at end of file +#endif diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index 142241c43..345c738d6 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -1536,7 +1536,10 @@ The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of s if (t.tm_mon > -1) { LOG_DEBUG("NMEA GPS time %02d-%02d-%02d %02d:%02d:%02d age %d", d.year(), d.month(), t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec, ti.age()); - perhapsSetRTC(RTCQualityGPS, t); + if (perhapsSetRTC(RTCQualityGPS, t) == RTCSetResultInvalidTime) { + // Clear the GPS buffer if we got an invalid time + clearBuffer(); + } return true; } else return false; diff --git a/src/gps/RTC.cpp b/src/gps/RTC.cpp index af964eab5..5054be3f0 100644 --- a/src/gps/RTC.cpp +++ b/src/gps/RTC.cpp @@ -105,7 +105,7 @@ void readFromRTC() * * If we haven't yet set our RTC this boot, set it from a GPS derived time */ -bool perhapsSetRTC(RTCQuality q, const struct timeval *tv, bool forceUpdate) +RTCSetResult perhapsSetRTC(RTCQuality q, const struct timeval *tv, bool forceUpdate) { static uint32_t lastSetMsec = 0; uint32_t now = millis(); @@ -113,7 +113,7 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv, bool forceUpdate) #ifdef BUILD_EPOCH if (tv->tv_sec < BUILD_EPOCH) { LOG_WARN("Ignore time (%ld) before build epoch (%ld)!", printableEpoch, BUILD_EPOCH); - return false; + return RTCSetResultInvalidTime; } #endif @@ -184,9 +184,9 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv, bool forceUpdate) readFromRTC(); #endif - return true; + return RTCSetResultSuccess; } else { - return false; + return RTCSetResultNotSet; // RTC was already set with a higher quality time } } @@ -215,7 +215,7 @@ const char *RtcName(RTCQuality quality) * @param t The time to potentially set the RTC to. * @return True if the RTC was set to the provided time, false otherwise. */ -bool perhapsSetRTC(RTCQuality q, struct tm &t) +RTCSetResult perhapsSetRTC(RTCQuality q, struct tm &t) { /* Convert to unix time The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of seconds that have elapsed since January 1, 1970 @@ -231,7 +231,7 @@ bool perhapsSetRTC(RTCQuality q, struct tm &t) // LOG_DEBUG("Got time from GPS month=%d, year=%d, unixtime=%ld", t.tm_mon, t.tm_year, tv.tv_sec); if (t.tm_year < 0 || t.tm_year >= 300) { // LOG_DEBUG("Ignore invalid GPS month=%d, year=%d, unixtime=%ld", t.tm_mon, t.tm_year, tv.tv_sec); - return false; + return RTCSetResultInvalidTime; } else { return perhapsSetRTC(q, &tv); } @@ -244,11 +244,15 @@ bool perhapsSetRTC(RTCQuality q, struct tm &t) */ int32_t getTZOffset() { +#if MESHTASTIC_EXCLUDE_TZ + return 0; +#else time_t now = getTime(false); struct tm *gmt; gmt = gmtime(&now); gmt->tm_isdst = -1; return (int32_t)difftime(now, mktime(gmt)); +#endif } /** diff --git a/src/gps/RTC.h b/src/gps/RTC.h index caa48dc06..96dec575b 100644 --- a/src/gps/RTC.h +++ b/src/gps/RTC.h @@ -22,13 +22,22 @@ enum RTCQuality { RTCQualityGPS = 4 }; +/// The RTC set result codes +/// Used to indicate the result of an attempt to set the RTC. +enum RTCSetResult { + RTCSetResultNotSet = 0, ///< RTC was set successfully + RTCSetResultSuccess = 1, ///< RTC was set successfully + RTCSetResultInvalidTime = 3, ///< The provided time was invalid (e.g., before the build epoch) + RTCSetResultError = 4 ///< An error occurred while setting the RTC +}; + RTCQuality getRTCQuality(); extern uint32_t lastSetFromPhoneNtpOrGps; /// If we haven't yet set our RTC this boot, set it from a GPS derived time -bool perhapsSetRTC(RTCQuality q, const struct timeval *tv, bool forceUpdate = false); -bool perhapsSetRTC(RTCQuality q, struct tm &t); +RTCSetResult perhapsSetRTC(RTCQuality q, const struct timeval *tv, bool forceUpdate = false); +RTCSetResult perhapsSetRTC(RTCQuality q, struct tm &t); /// Return a string name for the quality const char *RtcName(RTCQuality quality); diff --git a/src/graphics/EInkDisplay2.cpp b/src/graphics/EInkDisplay2.cpp index 5a2749482..66c7938b5 100644 --- a/src/graphics/EInkDisplay2.cpp +++ b/src/graphics/EInkDisplay2.cpp @@ -6,6 +6,10 @@ #include "main.h" #include +#ifdef GXEPD2_DRIVER_0 +#include "einkDetect.h" +#endif + /* The macros EINK_DISPLAY_MODEL, EINK_WIDTH, and EINK_HEIGHT are defined as build_flags in a variant's platformio.ini Previously, these macros were defined at the top of this file. @@ -174,9 +178,8 @@ bool EInkDisplay::connect() } } -#elif defined(HELTEC_WIRELESS_PAPER_V1_0) || defined(HELTEC_WIRELESS_PAPER) || defined(HELTEC_VISION_MASTER_E213) || \ - defined(HELTEC_VISION_MASTER_E290) || defined(TLORA_T3S3_EPAPER) || defined(CROWPANEL_ESP32S3_5_EPAPER) || \ - defined(CROWPANEL_ESP32S3_4_EPAPER) || defined(CROWPANEL_ESP32S3_2_EPAPER) +#elif defined(HELTEC_WIRELESS_PAPER_V1_0) || defined(HELTEC_VISION_MASTER_E290) || defined(TLORA_T3S3_EPAPER) || \ + defined(CROWPANEL_ESP32S3_5_EPAPER) || defined(CROWPANEL_ESP32S3_4_EPAPER) || defined(CROWPANEL_ESP32S3_2_EPAPER) { // Start HSPI hspi = new SPIClass(HSPI); @@ -232,6 +235,23 @@ bool EInkDisplay::connect() adafruitDisplay->init(); adafruitDisplay->setRotation(3); } +#elif defined(HELTEC_WIRELESS_PAPER) || defined(HELTEC_VISION_MASTER_E213) + + // Detect display model, before starting SPI + EInkDetectionResult displayModel = detectEInk(); + + // Start HSPI + hspi = new SPIClass(HSPI); + hspi->begin(PIN_EINK_SCLK, -1, PIN_EINK_MOSI, PIN_EINK_CS); // SCLK, MISO, MOSI, SS + + // Create GxEPD2 object + adafruitDisplay = new GxEPD2_Multi((uint8_t)displayModel, PIN_EINK_CS, PIN_EINK_DC, + PIN_EINK_RES, PIN_EINK_BUSY, *hspi); + + // Init GxEPD2 + adafruitDisplay->init(); + adafruitDisplay->setRotation(3); + #endif return true; diff --git a/src/graphics/EInkDisplay2.h b/src/graphics/EInkDisplay2.h index 93be197b0..284337627 100644 --- a/src/graphics/EInkDisplay2.h +++ b/src/graphics/EInkDisplay2.h @@ -5,6 +5,10 @@ #include "GxEPD2_BW.h" #include +#ifdef GXEPD2_DRIVER_0 // If variant has multiple possible display models +#include "GxEPD2Multi.h" +#endif + /** * An adapter class that allows using the GxEPD2 library as if it was an OLEDDisplay implementation. * @@ -63,8 +67,15 @@ class EInkDisplay : public OLEDDisplay // Connect to the display virtual bool connect() override; - // AdafruitGFX display object - instantiated in connect(), variant specific +#ifdef GXEPD2_DRIVER_0 + // AdafruitGFX display object - wrapper for multiple drivers + // Allows runtime detection of multiple displays + // Avoid this situation if possible! + GxEPD2_Multi *adafruitDisplay = NULL; +#else + // AdafruitGFX display object (for single display model) - instantiated in connect(), variant specific GxEPD2_BW *adafruitDisplay = NULL; +#endif // If display uses HSPI #if defined(HELTEC_WIRELESS_PAPER) || defined(HELTEC_WIRELESS_PAPER_V1_0) || defined(HELTEC_VISION_MASTER_E213) || \ diff --git a/src/graphics/GxEPD2Multi.h b/src/graphics/GxEPD2Multi.h new file mode 100644 index 000000000..f3807c9de --- /dev/null +++ b/src/graphics/GxEPD2Multi.h @@ -0,0 +1,135 @@ +// Wrapper class for GxEPD2_BW + +// Generic signature at build-time, so that we can detect display model at run-time +// Workaround for issue of GxEPD2_BW objects not having a shared base class +// Only exposes methods which we are actually using + +template class GxEPD2_Multi +{ + public: + void drawPixel(int16_t x, int16_t y, uint16_t color) + { + if (which == 0) + driver0->drawPixel(x, y, color); + else + driver1->drawPixel(x, y, color); + } + + bool nextPage() + { + if (which == 0) + return driver0->nextPage(); + else + return driver1->nextPage(); + } + + void hibernate() + { + if (which == 0) + driver0->hibernate(); + else + driver1->hibernate(); + } + + void init(uint32_t serial_diag_bitrate = 0) + { + if (which == 0) + driver0->init(serial_diag_bitrate); + else + driver1->init(serial_diag_bitrate); + } + + void init(uint32_t serial_diag_bitrate, bool initial, uint16_t reset_duration = 20, bool pulldown_rst_mode = false) + { + if (which == 0) + driver0->init(serial_diag_bitrate, initial, reset_duration, pulldown_rst_mode); + else + driver1->init(serial_diag_bitrate, initial, reset_duration, pulldown_rst_mode); + } + + void setRotation(uint8_t x) + { + if (which == 0) + driver0->setRotation(x); + else + driver1->setRotation(x); + } + + void setPartialWindow(uint16_t x, uint16_t y, uint16_t w, uint16_t h) + { + if (which == 0) + driver0->setPartialWindow(x, y, w, h); + else + driver1->setPartialWindow(x, y, w, h); + } + + void setFullWindow() + { + if (which == 0) + driver0->setFullWindow(); + else + driver1->setFullWindow(); + } + + int16_t width() + { + if (which == 0) + return driver0->width(); + else + return driver1->width(); + } + + int16_t height() + { + if (which == 0) + return driver0->height(); + else + return driver1->height(); + } + + void clearScreen(uint8_t value = 0xFF) + { + if (which == 0) + driver0->clearScreen(); + else + driver1->clearScreen(); + } + + void endAsyncFull() + { + if (which == 0) + driver0->endAsyncFull(); + else + driver1->endAsyncFull(); + } + + // Exposes methods of the GxEPD2_EPD object which is usually available as GxEPD2_BW::epd + class Epd2Wrapper + { + public: + bool isBusy() { return m_epd2->isBusy(); } + GxEPD2_EPD *m_epd2; + } epd2; + + // Constructor + // Select driver by passing whichDriver as 0 or 1 + GxEPD2_Multi(uint8_t whichDriver, int16_t cs, int16_t dc, int16_t rst, int16_t busy, SPIClass &spi) + { + assert(whichDriver == 0 || whichDriver == 1); + which = whichDriver; + LOG_DEBUG("GxEPD2_Multi driver: %d", which); + + if (which == 0) { + driver0 = new GxEPD2_BW(Driver0(cs, dc, rst, busy, spi)); + epd2.m_epd2 = &(driver0->epd2); + } else if (which == 1) { + driver1 = new GxEPD2_BW(Driver1(cs, dc, rst, busy, spi)); + epd2.m_epd2 = &(driver1->epd2); + } + } + + private: + uint8_t which; + GxEPD2_BW *driver0; + GxEPD2_BW *driver1; +}; \ No newline at end of file diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 0818619a6..1f2e7e4d9 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -21,6 +21,7 @@ along with this program. If not, see . */ #include "Screen.h" +#include "NodeDB.h" #include "PowerMon.h" #include "Throttle.h" #include "configuration.h" @@ -31,6 +32,7 @@ along with this program. If not, see . #include "TimeFormatters.h" #include "draw/ClockRenderer.h" #include "draw/DebugRenderer.h" +#include "draw/MenuHandler.h" #include "draw/MessageRenderer.h" #include "draw/NodeListRenderer.h" #include "draw/NotificationRenderer.h" @@ -43,7 +45,6 @@ along with this program. If not, see . #endif #include "FSCommon.h" #include "MeshService.h" -#include "NodeDB.h" #include "RadioLibInterface.h" #include "error.h" #include "gps/GeoCoord.h" @@ -68,6 +69,8 @@ using graphics::Emote; using graphics::emotes; using graphics::numEmotes; +extern uint16_t TFT_MESH; + #if HAS_WIFI && !defined(ARCH_PORTDUINO) #include "mesh/wifi/WiFiAPClient.h" #endif @@ -134,21 +137,82 @@ extern bool hasUnreadMessage; // Displays a temporary centered banner message (e.g., warning, status, etc.) // The banner appears in the center of the screen and disappears after the specified duration -// Called to trigger a banner with custom message and duration -void Screen::showOverlayBanner(const char *message, uint32_t durationMs, uint8_t options, std::function bannerCallback, - int8_t InitialSelected) +void Screen::showSimpleBanner(const char *message, uint32_t durationMs) { + BannerOverlayOptions options; + options.message = message; + options.durationMs = durationMs; + options.notificationType = notificationTypeEnum::text_banner; + showOverlayBanner(options); +} + +// Called to trigger a banner with custom message and duration +void Screen::showOverlayBanner(BannerOverlayOptions banner_overlay_options) +{ +#ifdef USE_EINK + EINK_ADD_FRAMEFLAG(dispdev, DEMAND_FAST); // Skip full refresh for all overlay menus +#endif + // Store the message and set the expiration timestamp + strncpy(NotificationRenderer::alertBannerMessage, banner_overlay_options.message, 255); + NotificationRenderer::alertBannerMessage[255] = '\0'; // Ensure null termination + NotificationRenderer::alertBannerUntil = + (banner_overlay_options.durationMs == 0) ? 0 : millis() + banner_overlay_options.durationMs; + NotificationRenderer::optionsArrayPtr = banner_overlay_options.optionsArrayPtr; + NotificationRenderer::optionsEnumPtr = banner_overlay_options.optionsEnumPtr; + NotificationRenderer::alertBannerOptions = banner_overlay_options.optionsCount; + NotificationRenderer::alertBannerCallback = banner_overlay_options.bannerCallback; + NotificationRenderer::curSelected = banner_overlay_options.InitialSelected; + NotificationRenderer::pauseBanner = false; + NotificationRenderer::current_notification_type = notificationTypeEnum::selection_picker; + static OverlayCallback overlays[] = {graphics::UIRenderer::drawNavigationBar, NotificationRenderer::drawBannercallback}; + ui->setOverlays(overlays, sizeof(overlays) / sizeof(overlays[0])); + ui->setTargetFPS(60); + ui->update(); +} + +// Called to trigger a banner with custom message and duration +void Screen::showNodePicker(const char *message, uint32_t durationMs, std::function bannerCallback) +{ +#ifdef USE_EINK + EINK_ADD_FRAMEFLAG(dispdev, DEMAND_FAST); // Skip full refresh for all overlay menus +#endif + nodeDB->pause_sort(true); // Store the message and set the expiration timestamp strncpy(NotificationRenderer::alertBannerMessage, message, 255); NotificationRenderer::alertBannerMessage[255] = '\0'; // Ensure null termination NotificationRenderer::alertBannerUntil = (durationMs == 0) ? 0 : millis() + durationMs; - NotificationRenderer::alertBannerOptions = options; NotificationRenderer::alertBannerCallback = bannerCallback; - NotificationRenderer::curSelected = InitialSelected; NotificationRenderer::pauseBanner = false; - static OverlayCallback overlays[] = {graphics::UIRenderer::drawNavigationBar, NotificationRenderer::drawAlertBannerOverlay}; + NotificationRenderer::curSelected = 0; + NotificationRenderer::current_notification_type = notificationTypeEnum::node_picker; + + static OverlayCallback overlays[] = {graphics::UIRenderer::drawNavigationBar, NotificationRenderer::drawBannercallback}; ui->setOverlays(overlays, sizeof(overlays) / sizeof(overlays[0])); - setFastFramerate(); // Draw ASAP + ui->setTargetFPS(60); + ui->update(); +} + +// Called to trigger a banner with custom message and duration +void Screen::showNumberPicker(const char *message, uint32_t durationMs, uint8_t digits, + std::function bannerCallback) +{ +#ifdef USE_EINK + EINK_ADD_FRAMEFLAG(dispdev, DEMAND_FAST); // Skip full refresh for all overlay menus +#endif + // Store the message and set the expiration timestamp + strncpy(NotificationRenderer::alertBannerMessage, message, 255); + NotificationRenderer::alertBannerMessage[255] = '\0'; // Ensure null termination + NotificationRenderer::alertBannerUntil = (durationMs == 0) ? 0 : millis() + durationMs; + NotificationRenderer::alertBannerCallback = bannerCallback; + NotificationRenderer::pauseBanner = false; + NotificationRenderer::curSelected = 0; + NotificationRenderer::current_notification_type = notificationTypeEnum::number_picker; + NotificationRenderer::numDigits = digits; + NotificationRenderer::currentNumber = 0; + + static OverlayCallback overlays[] = {graphics::UIRenderer::drawNavigationBar, NotificationRenderer::drawBannercallback}; + ui->setOverlays(overlays, sizeof(overlays) / sizeof(overlays[0])); + ui->setTargetFPS(60); ui->update(); } @@ -203,7 +267,7 @@ float Screen::estimatedHeading(double lat, double lon) if (d < 10) // haven't moved enough, just keep current bearing return b; - b = GeoCoord::bearing(oldLat, oldLon, lat, lon); + b = GeoCoord::bearing(oldLat, oldLon, lat, lon) * RAD_TO_DEG; oldLat = lat; oldLon = lon; @@ -225,6 +289,20 @@ Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_O : concurrency::OSThread("Screen"), address_found(address), model(screenType), geometry(geometry), cmdQueue(32) { graphics::normalFrames = new FrameCallback[MAX_NUM_NODES + NUM_EXTRA_FRAMES]; + + LOG_INFO("Protobuf Value uiconfig.screen_rgb_color: %d", uiconfig.screen_rgb_color); + int32_t rawRGB = uiconfig.screen_rgb_color; + if (rawRGB > 0 && rawRGB <= 255255255) { + uint8_t TFT_MESH_r = (rawRGB >> 16) & 0xFF; + uint8_t TFT_MESH_g = (rawRGB >> 8) & 0xFF; + uint8_t TFT_MESH_b = rawRGB & 0xFF; + LOG_INFO("Values of r,g,b: %d, %d, %d", TFT_MESH_r, TFT_MESH_g, TFT_MESH_b); + + if (TFT_MESH_r <= 255 && TFT_MESH_g <= 255 && TFT_MESH_b <= 255) { + TFT_MESH = COLOR565(TFT_MESH_r, TFT_MESH_g, TFT_MESH_b); + } + } + #if defined(USE_SH1106) || defined(USE_SH1107) || defined(USE_SH1107_128_64) dispdev = new SH1106Wire(address.address, -1, -1, geometry, (address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE); @@ -234,8 +312,8 @@ Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_O ST7789_MISO, ST7789_SCK); #else dispdev = new ST7789Spi(&SPI1, ST7789_RESET, ST7789_RS, ST7789_NSS, GEOMETRY_RAWMODE, TFT_WIDTH, TFT_HEIGHT); - static_cast(dispdev)->setRGB(COLOR565(255, 255, 128)); #endif + static_cast(dispdev)->setRGB(TFT_MESH); #elif defined(USE_SSD1306) dispdev = new SSD1306Wire(address.address, -1, -1, geometry, (address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE); @@ -381,9 +459,22 @@ void Screen::handleSetOn(bool on, FrameCallback einkScreensaver) void Screen::setup() { + // === Enable display rendering === useDisplay = true; + // === Load saved brightness from UI config === + // For OLED displays (SSD1306), default brightness is 255 if not set + if (uiconfig.screen_brightness == 0) { +#if defined(USE_OLED) || defined(USE_SSD1306) || defined(USE_SH1106) || defined(USE_SH1107) + brightness = 255; // Default for OLED +#else + brightness = BRIGHTNESS_DEFAULT; +#endif + } else { + brightness = uiconfig.screen_brightness; + } + // === Detect OLED subtype (if supported by board variant) === #ifdef AutoOLEDWire_h if (isAUTOOled) @@ -411,10 +502,17 @@ void Screen::setup() ui->disableAllIndicators(); // Disable page indicator dots ui->getUiState()->userData = this; // Allow static callbacks to access Screen instance + // === Apply loaded brightness === +#if defined(ST7789_CS) + static_cast(dispdev)->setDisplayBrightness(brightness); +#elif defined(USE_OLED) || defined(USE_SSD1306) || defined(USE_SH1106) || defined(USE_SH1107) + dispdev->setBrightness(brightness); +#endif + LOG_INFO("Applied screen brightness: %d", brightness); + // === Set custom overlay callbacks === static OverlayCallback overlays[] = { - graphics::UIRenderer::drawFunctionOverlay, // For mute/buzzer modifiers etc. - graphics::UIRenderer::drawNavigationBar // Custom indicator icons for each frame + graphics::UIRenderer::drawNavigationBar // Custom indicator icons for each frame }; ui->setOverlays(overlays, sizeof(overlays) / sizeof(overlays[0])); @@ -471,6 +569,7 @@ void Screen::setup() // === Turn on display and trigger first draw === handleSetOn(true); + determineResolution(dispdev->height(), dispdev->width()); ui->update(); #ifndef USE_EINK ui->update(); // Some SSD1306 clones drop the first draw, so run twice @@ -541,6 +640,11 @@ void Screen::forceDisplay(bool forceUiUpdate) // Tell EInk class to update the display static_cast(dispdev)->forceDisplay(); +#else + // No delay between UI frame rendering + if (forceUiUpdate) { + setFastFramerate(); + } #endif } @@ -557,6 +661,7 @@ int32_t Screen::runOnce() if (displayHeight == 0) { displayHeight = dispdev->getHeight(); } + menuHandler::handleMenuSwitch(dispdev); // Show boot screen for first logo_timeout seconds, then switch to normal operation. // serialSinceMsec adjusts for additional serial wait time during nRF52 bootup @@ -585,11 +690,11 @@ int32_t Screen::runOnce() #ifndef DISABLE_WELCOME_UNSET if (!NotificationRenderer::isOverlayBannerShowing() && config.lora.region == meshtastic_Config_LoRaConfig_RegionCode_UNSET) { - LoraRegionPicker(0); + menuHandler::LoraRegionPicker(0); } #endif if (!NotificationRenderer::isOverlayBannerShowing() && rebootAtMsec != 0) { - showOverlayBanner("Rebooting...", 0); + showSimpleBanner("Rebooting...", 0); } // Process incoming commands. @@ -636,6 +741,8 @@ int32_t Screen::runOnce() EINK_ADD_FRAMEFLAG(dispdev, COSMETIC); // E-Ink: Explicitly use full-refresh for next frame setFrames(); break; + case Cmd::NOOP: + break; default: LOG_ERROR("Invalid screen cmd"); } @@ -768,32 +875,6 @@ void Screen::setFrames(FrameFocus focus) indicatorIcons.clear(); size_t numframes = 0; - moduleFrames = MeshModule::GetMeshModulesWithUIFrames(); - LOG_DEBUG("Show %d module frames", moduleFrames.size()); - - // put all of the module frames first. - // this is a little bit of a dirty hack; since we're going to call - // the same drawModuleFrame handler here for all of these module frames - // and then we'll just assume that the state->currentFrame value - // is the same offset into the moduleFrames vector - // so that we can invoke the module's callback - for (auto i = moduleFrames.begin(); i != moduleFrames.end(); ++i) { - // Draw the module frame, using the hack described above - normalFrames[numframes] = drawModuleFrame; - - // Check if the module being drawn has requested focus - // We will honor this request later, if setFrames was triggered by a UIFrameEvent - MeshModule *m = *i; - if (m->isRequestingFocus()) - fsi.positions.focusedModule = numframes; - if (m == waypointModule) - fsi.positions.waypoint = numframes; - - indicatorIcons.push_back(icon_module); - numframes++; - } - - LOG_DEBUG("Added modules. numframes: %d", numframes); // If we have a critical fault, show it first fsi.positions.fault = numframes; @@ -805,9 +886,9 @@ void Screen::setFrames(FrameFocus focus) #if defined(DISPLAY_CLOCK_FRAME) fsi.positions.clock = numframes; - normalFrames[numframes++] = graphics::ClockRenderer::digitalWatchFace ? graphics::ClockRenderer::drawDigitalClockFrame - : &graphics::ClockRenderer::drawAnalogClockFrame; - indicatorIcons.push_back(icon_clock); + normalFrames[numframes++] = uiconfig.is_clockface_analog ? graphics::ClockRenderer::drawAnalogClockFrame + : graphics::ClockRenderer::drawDigitalClockFrame; + indicatorIcons.push_back(digital_icon_clock); #endif // Declare this early so it’s available in FOCUS_PRESERVE block @@ -822,22 +903,27 @@ void Screen::setFrames(FrameFocus focus) indicatorIcons.push_back(icon_mail); #ifndef USE_EINK + fsi.positions.nodelist = numframes; normalFrames[numframes++] = graphics::NodeListRenderer::drawDynamicNodeListScreen; indicatorIcons.push_back(icon_nodes); #endif // Show detailed node views only on E-Ink builds #ifdef USE_EINK + fsi.positions.nodelist_lastheard = numframes; normalFrames[numframes++] = graphics::NodeListRenderer::drawLastHeardScreen; indicatorIcons.push_back(icon_nodes); + fsi.positions.nodelist_hopsignal = numframes; normalFrames[numframes++] = graphics::NodeListRenderer::drawHopSignalScreen; indicatorIcons.push_back(icon_signal); + fsi.positions.nodelist_distance = numframes; normalFrames[numframes++] = graphics::NodeListRenderer::drawDistanceScreen; indicatorIcons.push_back(icon_distance); #endif #if HAS_GPS + fsi.positions.nodelist_bearings = numframes; normalFrames[numframes++] = graphics::NodeListRenderer::drawNodeListWithCompasses; indicatorIcons.push_back(icon_list); @@ -857,26 +943,11 @@ void Screen::setFrames(FrameFocus focus) } #if !defined(DISPLAY_CLOCK_FRAME) fsi.positions.clock = numframes; - normalFrames[numframes++] = graphics::ClockRenderer::drawDigitalClockFrame; - indicatorIcons.push_back(icon_clock); + normalFrames[numframes++] = uiconfig.is_clockface_analog ? graphics::ClockRenderer::drawAnalogClockFrame + : graphics::ClockRenderer::drawDigitalClockFrame; + indicatorIcons.push_back(digital_icon_clock); #endif - // We don't show the node info of our node (if we have it yet - we should) - size_t numMeshNodes = nodeDB->getNumMeshNodes(); - if (numMeshNodes > 0) - numMeshNodes--; - - for (size_t i = 0; i < nodeDB->getNumMeshNodes(); i++) { - const meshtastic_NodeInfoLite *n = nodeDB->getMeshNodeByIndex(i); - if (n && n->num != nodeDB->getNodeNum() && n->is_favorite) { - if (fsi.positions.firstFavorite == 255) - fsi.positions.firstFavorite = numframes; - fsi.positions.lastFavorite = numframes; - normalFrames[numframes++] = graphics::UIRenderer::drawNodeInfo; - indicatorIcons.push_back(icon_node); - } - } - #if HAS_WIFI && !defined(ARCH_PORTDUINO) if (!dismissedFrames.wifi && isWifiAvailable()) { fsi.positions.wifi = numframes; @@ -885,6 +956,64 @@ void Screen::setFrames(FrameFocus focus) } #endif + // Beware of what changes you make in this code! + // We pass numframes into GetMeshModulesWithUIFrames() which is highly important! + // Inside of that callback, goes over to MeshModule.cpp and we run + // modulesWithUIFrames.resize(startIndex, nullptr), to insert nullptr + // entries until we're ready to start building the matching entries. + // We are doing our best to keep the normalFrames vector + // and the moduleFrames vector in lock step. + moduleFrames = MeshModule::GetMeshModulesWithUIFrames(numframes); + LOG_DEBUG("Show %d module frames", moduleFrames.size()); + + for (auto i = moduleFrames.begin(); i != moduleFrames.end(); ++i) { + // Draw the module frame, using the hack described above + if (*i != nullptr) { + normalFrames[numframes] = drawModuleFrame; + + // Check if the module being drawn has requested focus + // We will honor this request later, if setFrames was triggered by a UIFrameEvent + MeshModule *m = *i; + if (m && m->isRequestingFocus()) + fsi.positions.focusedModule = numframes; + if (m && m == waypointModule) + fsi.positions.waypoint = numframes; + + indicatorIcons.push_back(icon_module); + numframes++; + } + } + + LOG_DEBUG("Added modules. numframes: %d", numframes); + + // We don't show the node info of our node (if we have it yet - we should) + size_t numMeshNodes = nodeDB->getNumMeshNodes(); + if (numMeshNodes > 0) + numMeshNodes--; + + // Temporary array to hold favorite node frames + std::vector favoriteFrames; + + for (size_t i = 0; i < nodeDB->getNumMeshNodes(); i++) { + const meshtastic_NodeInfoLite *n = nodeDB->getMeshNodeByIndex(i); + if (n && n->num != nodeDB->getNodeNum() && n->is_favorite) { + favoriteFrames.push_back(graphics::UIRenderer::drawNodeInfo); + } + } + + // Insert favorite frames *after* collecting them all + if (!favoriteFrames.empty()) { + fsi.positions.firstFavorite = numframes; + for (auto &f : favoriteFrames) { + normalFrames[numframes++] = f; + indicatorIcons.push_back(icon_node); + } + fsi.positions.lastFavorite = numframes - 1; + } else { + fsi.positions.firstFavorite = 255; + fsi.positions.lastFavorite = 255; + } + fsi.frameCount = numframes; // Total framecount is used to apply FOCUS_PRESERVE this->frameCount = numframes; // ✅ Save frame count for use in custom overlay LOG_DEBUG("Finished build frames. numframes: %d", numframes); @@ -893,11 +1022,10 @@ void Screen::setFrames(FrameFocus focus) ui->disableAllIndicators(); // Add overlays: frame icons and alert banner) - static OverlayCallback overlays[] = {graphics::UIRenderer::drawNavigationBar, NotificationRenderer::drawAlertBannerOverlay}; + static OverlayCallback overlays[] = {graphics::UIRenderer::drawNavigationBar, NotificationRenderer::drawBannercallback}; ui->setOverlays(overlays, sizeof(overlays) / sizeof(overlays[0])); - prevFrame = -1; // Force drawNodeInfo to pick a new node (because our list - // just changed) + prevFrame = -1; // Force drawNodeInfo to pick a new node (because our list just changed) // Focus on a specific frame, in the frame set we just created switch (focus) { @@ -916,6 +1044,14 @@ void Screen::setFrames(FrameFocus focus) // If no module requested focus, will show the first frame instead ui->switchToFrame(fsi.positions.focusedModule); break; + case FOCUS_CLOCK: + // Whichever frame was marked by MeshModule::requestFocus(), if any + // If no module requested focus, will show the first frame instead + ui->switchToFrame(fsi.positions.clock); + break; + case FOCUS_SYSTEM: + ui->switchToFrame(fsi.positions.memory); + break; case FOCUS_PRESERVE: // No more adjustment — force stay on same index @@ -1126,40 +1262,45 @@ int Screen::handleTextMessage(const meshtastic_MeshPacket *packet) devicestate.has_rx_text_message = true; // Needed to include the message frame hasUnreadMessage = true; // Enables mail icon in the header setFrames(FOCUS_PRESERVE); // Refresh frame list without switching view - forceDisplay(); // Forces screen redraw - // === Prepare banner content === - const meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(packet->from); - const char *longName = (node && node->has_user) ? node->user.long_name : nullptr; + // Only wake/force display if the configuration allows it + if (shouldWakeOnReceivedMessage()) { + setOn(true); // Wake up the screen first + forceDisplay(); // Forces screen redraw - const char *msgRaw = reinterpret_cast(packet->decoded.payload.bytes); + // === Prepare banner content === + const meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(packet->from); + const char *longName = (node && node->has_user) ? node->user.long_name : nullptr; - char banner[256]; + const char *msgRaw = reinterpret_cast(packet->decoded.payload.bytes); - // Check for bell character in message to determine alert type - bool isAlert = false; - for (size_t i = 0; i < packet->decoded.payload.size && i < 100; i++) { - if (msgRaw[i] == '\x07') { - isAlert = true; - break; + char banner[256]; + + // Check for bell character in message to determine alert type + bool isAlert = false; + for (size_t i = 0; i < packet->decoded.payload.size && i < 100; i++) { + if (msgRaw[i] == '\x07') { + isAlert = true; + break; + } } - } - if (isAlert) { - if (longName && longName[0]) { - snprintf(banner, sizeof(banner), "Alert Received from\n%s", longName); + if (isAlert) { + if (longName && longName[0]) { + snprintf(banner, sizeof(banner), "Alert Received from\n%s", longName); + } else { + strcpy(banner, "Alert Received"); + } } else { - strcpy(banner, "Alert Received"); + if (longName && longName[0]) { + snprintf(banner, sizeof(banner), "New Message from\n%s", longName); + } else { + strcpy(banner, "New Message"); + } } - } else { - if (longName && longName[0]) { - snprintf(banner, sizeof(banner), "New Message from\n%s", longName); - } else { - strcpy(banner, "New Message"); - } - } - screen->showOverlayBanner(banner, 3000); + screen->showSimpleBanner(banner, 3000); + } } } @@ -1198,29 +1339,15 @@ int Screen::handleInputEvent(const InputEvent *event) setFastFramerate(); // Draw ASAP #endif if (NotificationRenderer::isOverlayBannerShowing()) { - NotificationRenderer::inEvent = event->inputEvent; - static OverlayCallback overlays[] = {graphics::UIRenderer::drawNavigationBar, - NotificationRenderer::drawAlertBannerOverlay}; + NotificationRenderer::inEvent = *event; + static OverlayCallback overlays[] = {graphics::UIRenderer::drawNavigationBar, NotificationRenderer::drawBannercallback}; ui->setOverlays(overlays, sizeof(overlays) / sizeof(overlays[0])); setFastFramerate(); // Draw ASAP ui->update(); + + menuHandler::handleMenuSwitch(dispdev); return 0; } - /* - #if defined(DISPLAY_CLOCK_FRAME) - // For the T-Watch, intercept touches to the 'toggle digital/analog watch face' button - uint8_t watchFaceFrame = error_code ? 1 : 0; - - if (this->ui->getUiState()->currentFrame == watchFaceFrame && event->touchX >= 204 && event->touchX <= 240 && - event->touchY >= 204 && event->touchY <= 240) { - screen->digitalWatchFace = !screen->digitalWatchFace; - - setFrames(); - - return 0; - } - #endif - */ // Use left or right input from a keyboard to move between frames, // so long as a mesh module isn't using these events for some other purpose @@ -1229,7 +1356,7 @@ int Screen::handleInputEvent(const InputEvent *event) // Ask any MeshModules if they're handling keyboard input right now bool inputIntercepted = false; for (MeshModule *module : moduleFrames) { - if (module->interceptingKeyboardInput()) + if (module && module->interceptingKeyboardInput()) inputIntercepted = true; } @@ -1241,129 +1368,33 @@ int Screen::handleInputEvent(const InputEvent *event) showNextFrame(); } else if (event->inputEvent == INPUT_BROKER_SELECT) { if (this->ui->getUiState()->currentFrame == framesetInfo.positions.home) { - const char *banner_message; - int options; - if (kb_found) { - banner_message = "Action?\nBack\nSleep Screen\nNew Preset Msg\nNew Freetext Msg"; - options = 4; - } else { - banner_message = "Action?\nBack\nSleep Screen\nNew Preset Msg"; - options = 3; - } - showOverlayBanner(banner_message, 30000, options, [](int selected) -> void { - if (selected == 1) { - screen->setOn(false); - } else if (selected == 2) { - cannedMessageModule->LaunchWithDestination(NODENUM_BROADCAST); - } else if (selected == 3) { - cannedMessageModule->LaunchFreetextWithDestination(NODENUM_BROADCAST); - } - }); -#if HAS_TFT + menuHandler::homeBaseMenu(); } else if (this->ui->getUiState()->currentFrame == framesetInfo.positions.memory) { - showOverlayBanner("Switch to MUI?\nYes\nNo", 30000, 2, [](int selected) -> void { - if (selected == 0) { - config.display.displaymode = meshtastic_Config_DisplayConfig_DisplayMode_COLOR; - config.bluetooth.enabled = false; - service->reloadConfig(SEGMENT_CONFIG); - rebootAtMsec = (millis() + DEFAULT_REBOOT_SECONDS * 1000); - } - }); -#else - } else if (this->ui->getUiState()->currentFrame == framesetInfo.positions.memory) { - showOverlayBanner( - "Beeps Mode\nAll Enabled\nDisabled\nNotifications\nSystem Only", 30000, 4, - [](int selected) -> void { - config.device.buzzer_mode = (meshtastic_Config_DeviceConfig_BuzzerMode)selected; - service->reloadConfig(SEGMENT_CONFIG); - }, - config.device.buzzer_mode); -#endif + menuHandler::systemBaseMenu(); #if HAS_GPS } else if (this->ui->getUiState()->currentFrame == framesetInfo.positions.gps && gps) { - showOverlayBanner( - "Toggle GPS\nBack\nEnabled\nDisabled", 30000, 3, - [](int selected) -> void { - if (selected == 1) { - config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_ENABLED; - playGPSEnableBeep(); - gps->enable(); - service->reloadConfig(SEGMENT_CONFIG); - } else if (selected == 2) { - config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_DISABLED; - playGPSDisableBeep(); - gps->disable(); - service->reloadConfig(SEGMENT_CONFIG); - } - }, - config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_ENABLED ? 1 - : 2); // set inital selection + menuHandler::positionBaseMenu(); #endif } else if (this->ui->getUiState()->currentFrame == framesetInfo.positions.clock) { - TZPicker(); + menuHandler::clockMenu(); } else if (this->ui->getUiState()->currentFrame == framesetInfo.positions.lora) { - LoraRegionPicker(); + menuHandler::LoraRegionPicker(); } else if (this->ui->getUiState()->currentFrame == framesetInfo.positions.textMessage && devicestate.rx_text_message.from) { - const char *banner_message; - int options; - if (kb_found) { - banner_message = "Message Action?\nBack\nDismiss\nReply via Preset\nReply via Freetext"; - options = 4; - } else { - banner_message = "Message Action?\nBack\nDismiss\nReply via Preset"; - options = 3; - } -#ifdef HAS_I2S - banner_message = "Message Action?\nBack\nDismiss\nReply via Preset\nReply via Freetext\nRead Aloud"; - options = 5; -#endif - showOverlayBanner(banner_message, 30000, options, [](int selected) -> void { - if (selected == 1) { - screen->dismissCurrentFrame(); - } else if (selected == 2) { - if (devicestate.rx_text_message.to == NODENUM_BROADCAST) { - cannedMessageModule->LaunchWithDestination(NODENUM_BROADCAST, - devicestate.rx_text_message.channel); - } else { - cannedMessageModule->LaunchWithDestination(devicestate.rx_text_message.from); - } - } else if (selected == 3) { - if (devicestate.rx_text_message.to == NODENUM_BROADCAST) { - cannedMessageModule->LaunchFreetextWithDestination(NODENUM_BROADCAST, - devicestate.rx_text_message.channel); - } else { - cannedMessageModule->LaunchFreetextWithDestination(devicestate.rx_text_message.from); - } - } -#ifdef HAS_I2S - else if (selected == 4) { - const meshtastic_MeshPacket &mp = devicestate.rx_text_message; - const char *msg = reinterpret_cast(mp.decoded.payload.bytes); - - audioThread->readAloud(msg); - } -#endif - }); + menuHandler::messageResponseMenu(); } else if (framesetInfo.positions.firstFavorite != 255 && this->ui->getUiState()->currentFrame >= framesetInfo.positions.firstFavorite && this->ui->getUiState()->currentFrame <= framesetInfo.positions.lastFavorite) { - const char *banner_message; - int options; - if (kb_found) { - banner_message = "Message Node?\nCancel\nNew Preset Msg\nNew Freetext Msg"; - options = 3; - } else { - banner_message = "Message Node?\nCancel\nConfirm"; - options = 2; - } - showOverlayBanner(banner_message, 30000, options, [](int selected) -> void { - if (selected == 1) { - cannedMessageModule->LaunchWithDestination(graphics::UIRenderer::currentFavoriteNodeNum); - } else if (selected == 2) { - cannedMessageModule->LaunchFreetextWithDestination(graphics::UIRenderer::currentFavoriteNodeNum); - } - }); + menuHandler::favoriteBaseMenu(); + } else if (this->ui->getUiState()->currentFrame == framesetInfo.positions.nodelist || + this->ui->getUiState()->currentFrame == framesetInfo.positions.nodelist_lastheard || + this->ui->getUiState()->currentFrame == framesetInfo.positions.nodelist_hopsignal || + this->ui->getUiState()->currentFrame == framesetInfo.positions.nodelist_distance || + this->ui->getUiState()->currentFrame == framesetInfo.positions.nodelist_hopsignal || + this->ui->getUiState()->currentFrame == framesetInfo.positions.nodelist_bearings) { + menuHandler::nodeListMenu(); + } else if (this->ui->getUiState()->currentFrame == framesetInfo.positions.wifi) { + menuHandler::wifiBaseMenu(); } } else if (event->inputEvent == INPUT_BROKER_BACK) { showPrevFrame(); @@ -1397,98 +1428,28 @@ bool Screen::isOverlayBannerShowing() return NotificationRenderer::isOverlayBannerShowing(); } -void Screen::LoraRegionPicker(uint32_t duration) -{ - showOverlayBanner( - "Set the LoRa " - "region\nBack\nUS\nEU_433\nEU_868\nCN\nJP\nANZ\nKR\nTW\nRU\nIN\nNZ_865\nTH\nLORA_24\nUA_433\nUA_868\nMY_433\nMY_" - "919\nSG_" - "923\nPH_433\nPH_868\nPH_915\nANZ_433", - duration, 23, - [](int selected) -> void { - if (selected != 0 && config.lora.region != _meshtastic_Config_LoRaConfig_RegionCode(selected)) { - config.lora.region = _meshtastic_Config_LoRaConfig_RegionCode(selected); - // This is needed as we wait til picking the LoRa region to generate keys for the first time. - if (!owner.is_licensed) { - bool keygenSuccess = false; - if (config.security.private_key.size == 32) { - // public key is derived from private, so this will always have the same result. - if (crypto->regeneratePublicKey(config.security.public_key.bytes, config.security.private_key.bytes)) { - keygenSuccess = true; - } - } else { - LOG_INFO("Generate new PKI keys"); - crypto->generateKeyPair(config.security.public_key.bytes, config.security.private_key.bytes); - keygenSuccess = true; - } - if (keygenSuccess) { - config.security.public_key.size = 32; - config.security.private_key.size = 32; - owner.public_key.size = 32; - memcpy(owner.public_key.bytes, config.security.public_key.bytes, 32); - } - } - config.lora.tx_enabled = true; - initRegion(); - if (myRegion->dutyCycle < 100) { - config.lora.ignore_mqtt = true; // Ignore MQTT by default if region has a duty cycle limit - } - service->reloadConfig(SEGMENT_CONFIG); - rebootAtMsec = (millis() + DEFAULT_REBOOT_SECONDS * 1000); - } - }, - 0); -} - -void Screen::TZPicker() -{ - showOverlayBanner( - "Pick " - "Timezone\nBack\nUS/Hawaii\nUS/Alaska\nUS/Pacific\nUS/Mountain\nUS/Central\nUS/Eastern\nUTC\nEU/Western\nEU/" - "Central\nEU/Eastern\nAsia/Kolkata\nAsia/Hong_Kong\nAU/AWST\nAU/ACST\nAU/AEST\nPacific/NZ", - 30000, 17, [](int selected) -> void { - if (selected == 1) { // Hawaii - strncpy(config.device.tzdef, "HST10", sizeof(config.device.tzdef)); - } else if (selected == 2) { // Alaska - strncpy(config.device.tzdef, "AKST9AKDT,M3.2.0,M11.1.0", sizeof(config.device.tzdef)); - } else if (selected == 3) { // Pacific - strncpy(config.device.tzdef, "PST8PDT,M3.2.0,M11.1.0", sizeof(config.device.tzdef)); - } else if (selected == 4) { // Mountain - strncpy(config.device.tzdef, "MST7MDT,M3.2.0,M11.1.0", sizeof(config.device.tzdef)); - } else if (selected == 5) { // Central - strncpy(config.device.tzdef, "CST6CDT,M3.2.0,M11.1.0", sizeof(config.device.tzdef)); - } else if (selected == 6) { // Eastern - strncpy(config.device.tzdef, "EST5EDT,M3.2.0,M11.1.0", sizeof(config.device.tzdef)); - } else if (selected == 7) { // UTC - strncpy(config.device.tzdef, "UTC", sizeof(config.device.tzdef)); - } else if (selected == 8) { // EU/Western - strncpy(config.device.tzdef, "GMT0BST,M3.5.0/1,M10.5.0", sizeof(config.device.tzdef)); - } else if (selected == 9) { // EU/Central - strncpy(config.device.tzdef, "CET-1CEST,M3.5.0,M10.5.0/3", sizeof(config.device.tzdef)); - } else if (selected == 10) { // EU/Eastern - strncpy(config.device.tzdef, "EET-2EEST,M3.5.0/3,M10.5.0/4", sizeof(config.device.tzdef)); - } else if (selected == 11) { // Asia/Kolkata - strncpy(config.device.tzdef, "IST-5:30", sizeof(config.device.tzdef)); - } else if (selected == 12) { // China - strncpy(config.device.tzdef, "HKT-8", sizeof(config.device.tzdef)); - } else if (selected == 13) { // AU/AWST - strncpy(config.device.tzdef, "AWST-8", sizeof(config.device.tzdef)); - } else if (selected == 14) { // AU/ACST - strncpy(config.device.tzdef, "ACST-9:30ACDT,M10.1.0,M4.1.0/3", sizeof(config.device.tzdef)); - } else if (selected == 15) { // AU/AEST - strncpy(config.device.tzdef, "AEST-10AEDT,M10.1.0,M4.1.0/3", sizeof(config.device.tzdef)); - } else if (selected == 16) { // NZ - strncpy(config.device.tzdef, "NZST-12NZDT,M9.5.0,M4.1.0/3", sizeof(config.device.tzdef)); - } - if (selected != 0) { - setenv("TZ", config.device.tzdef, 1); - service->reloadConfig(SEGMENT_CONFIG); - } - }); -} - } // namespace graphics #else graphics::Screen::Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY) {} #endif // HAS_SCREEN + +bool shouldWakeOnReceivedMessage() +{ + /* + The goal here is to determine when we do NOT wake up the screen on message received: + - Any ext. notifications are turned on + - If role is not client / client_mute + - If the battery level is very low + */ + if (moduleConfig.external_notification.enabled) { + return false; + } + if (!meshtastic_Config_DeviceConfig_Role_CLIENT && !meshtastic_Config_DeviceConfig_Role_CLIENT_MUTE) { + return false; + } + if (powerStatus && powerStatus->getBatteryChargePercent() < 10) { + return false; + } + return true; +} diff --git a/src/graphics/Screen.h b/src/graphics/Screen.h index 8a836edfc..265900131 100644 --- a/src/graphics/Screen.h +++ b/src/graphics/Screen.h @@ -5,10 +5,28 @@ #include "detect/ScanI2C.h" #include "mesh/generated/meshtastic/config.pb.h" #include +#include #include #include #define getStringCenteredX(s) ((SCREEN_WIDTH - display->getStringWidth(s)) / 2) +namespace graphics +{ +enum notificationTypeEnum { none, text_banner, selection_picker, node_picker, number_picker }; + +struct BannerOverlayOptions { + const char *message; + uint32_t durationMs = 30000; + const char **optionsArrayPtr = nullptr; + const int *optionsEnumPtr = nullptr; + uint8_t optionsCount = 0; + std::function bannerCallback = nullptr; + int8_t InitialSelected = 0; + notificationTypeEnum notificationType = notificationTypeEnum::text_banner; +}; +} // namespace graphics + +bool shouldWakeOnReceivedMessage(); #if !HAS_SCREEN #include "power.h" @@ -24,6 +42,8 @@ class Screen FOCUS_FAULT, FOCUS_TEXTMESSAGE, FOCUS_MODULE, // Note: target module should call requestFocus(), otherwise no info about which module to focus + FOCUS_CLOCK, + FOCUS_SYSTEM, }; explicit Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY); @@ -38,10 +58,8 @@ class Screen void setFunctionSymbol(std::string) {} void removeFunctionSymbol(std::string) {} void startAlert(const char *) {} - void showOverlayBanner(const char *message, uint32_t durationMs = 3000, uint8_t options = 0, - std::function bannerCallback = NULL, int8_t InitialSelected = 0) - { - } + void showSimpleBanner(const char *message, uint32_t durationMs = 0) {} + void showOverlayBanner(BannerOverlayOptions) {} void setFrames(FrameFocus focus) {} void endAlert() {} }; @@ -76,6 +94,7 @@ class Screen #include "commands.h" #include "concurrency/LockGuard.h" #include "concurrency/OSThread.h" +#include "graphics/draw/MenuHandler.h" #include "input/InputBroker.h" #include "mesh/MeshModule.h" #include "modules/AdminModule.h" @@ -198,6 +217,7 @@ class Screen : public concurrency::OSThread CallbackObserver(this, &Screen::handleAdminMessage); public: + OLEDDisplay *getDisplayDevice() { return dispdev; } explicit Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY); size_t frameCount = 0; // Total number of active frames ~Screen(); @@ -209,6 +229,8 @@ class Screen : public concurrency::OSThread FOCUS_FAULT, FOCUS_TEXTMESSAGE, FOCUS_MODULE, // Note: target module should call requestFocus(), otherwise no info about which module to focus + FOCUS_CLOCK, + FOCUS_SYSTEM, }; // Regenerate the normal set of frames, focusing a specific frame if requested @@ -286,8 +308,17 @@ class Screen : public concurrency::OSThread enqueueCmd(cmd); } - void showOverlayBanner(const char *message, uint32_t durationMs = 3000, uint8_t options = 0, - std::function bannerCallback = NULL, int8_t InitialSelected = 0); + void showSimpleBanner(const char *message, uint32_t durationMs = 0); + void showOverlayBanner(BannerOverlayOptions); + + void showNodePicker(const char *message, uint32_t durationMs, std::function bannerCallback); + void showNumberPicker(const char *message, uint32_t durationMs, uint8_t digits, std::function bannerCallback); + + void requestMenu(graphics::menuHandler::screenMenus menuToShow) + { + graphics::menuHandler::menuQueue = menuToShow; + runNow(); + } void startFirmwareUpdateScreen() { @@ -301,7 +332,7 @@ class Screen : public concurrency::OSThread void setHeading(long _heading) { hasCompass = true; - compassHeading = _heading; + compassHeading = fmod(_heading, 360); } bool hasHeading() { return hasCompass; } @@ -321,6 +352,12 @@ class Screen : public concurrency::OSThread /// Stops showing the boot screen. void stopBootScreen() { enqueueCmd(ScreenCmd{.cmd = Cmd::STOP_BOOT_SCREEN}); } + void runNow() + { + setFastFramerate(); + enqueueCmd(ScreenCmd{.cmd = Cmd::NOOP}); + } + /// Overrides the default utf8 character conversion, to replace empty space with question marks static char customFontTableLookup(const uint8_t ch) { @@ -602,8 +639,6 @@ class Screen : public concurrency::OSThread void handleShowNextFrame(); void handleShowPrevFrame(); void handleStartFirmwareUpdateScreen(); - void TZPicker(); - void LoraRegionPicker(uint32_t duration = 30000); // Info collected by setFrames method. // Index location of specific frames. @@ -612,7 +647,6 @@ class Screen : public concurrency::OSThread struct FramesetInfo { struct FramePositions { uint8_t fault = 255; - uint8_t textMessage = 255; uint8_t waypoint = 255; uint8_t focusedModule = 255; uint8_t log = 255; @@ -622,6 +656,12 @@ class Screen : public concurrency::OSThread uint8_t memory = 255; uint8_t gps = 255; uint8_t home = 255; + uint8_t textMessage = 255; + uint8_t nodelist = 255; + uint8_t nodelist_lastheard = 255; + uint8_t nodelist_hopsignal = 255; + uint8_t nodelist_distance = 255; + uint8_t nodelist_bearings = 255; uint8_t clock = 255; uint8_t firstFavorite = 255; uint8_t lastFavorite = 255; @@ -679,5 +719,6 @@ class Screen : public concurrency::OSThread // Extern declarations for function symbols used in UIRenderer extern std::vector functionSymbol; extern std::string functionSymbolString; +extern graphics::Screen *screen; #endif \ No newline at end of file diff --git a/src/graphics/SharedUIDisplay.cpp b/src/graphics/SharedUIDisplay.cpp index af427cae4..7cd876ac5 100644 --- a/src/graphics/SharedUIDisplay.cpp +++ b/src/graphics/SharedUIDisplay.cpp @@ -10,9 +10,22 @@ namespace graphics { +void determineResolution(int16_t screenheight, int16_t screenwidth) +{ + if (screenwidth > 128) { + isHighResolution = true; + } + + // Special case for Heltec Wireless Tracker v1.1 + if (screenwidth == 160 && screenheight == 80) { + isHighResolution = false; + } +} + // === Shared External State === bool hasUnreadMessage = false; bool isMuted = false; +bool isHighResolution = false; // === Internal State === bool isBoltVisibleShared = true; @@ -40,7 +53,7 @@ void drawRoundedHighlight(OLEDDisplay *display, int16_t x, int16_t y, int16_t w, // ************************* // * Common Header Drawing * // ************************* -void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *titleStr) +void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *titleStr, bool battery_only) { constexpr int HEADER_OFFSET_Y = 1; y += HEADER_OFFSET_Y; @@ -56,34 +69,47 @@ void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *ti const int screenW = display->getWidth(); const int screenH = display->getHeight(); - const bool useBigIcons = (screenW > 128); - - // === Inverted Header Background === - if (isInverted) { - drawRoundedHighlight(display, x, y, screenW, highlightHeight, 2); - display->setColor(BLACK); - } else { - display->setColor(BLACK); - display->fillRect(0, 0, screenW, highlightHeight + 3); - display->setColor(WHITE); - if (screenW > 128) { - display->drawLine(0, 20, screenW, 20); + if (!battery_only) { + // === Inverted Header Background === + if (isInverted) { + display->setColor(BLACK); + display->fillRect(0, 0, screenW, highlightHeight + 2); + display->setColor(WHITE); + drawRoundedHighlight(display, x, y, screenW, highlightHeight, 2); + display->setColor(BLACK); } else { - display->drawLine(0, 14, screenW, 14); + display->setColor(BLACK); + display->fillRect(0, 0, screenW, highlightHeight + 2); + display->setColor(WHITE); + if (isHighResolution) { + display->drawLine(0, 20, screenW, 20); + } else { + display->drawLine(0, 14, screenW, 14); + } } - } - // === Screen Title === - display->setTextAlignment(TEXT_ALIGN_CENTER); - display->drawString(SCREEN_WIDTH / 2, y, titleStr); - if (config.display.heading_bold) { - display->drawString((SCREEN_WIDTH / 2) + 1, y, titleStr); + // === Screen Title === + display->setTextAlignment(TEXT_ALIGN_CENTER); + display->drawString(SCREEN_WIDTH / 2, y, titleStr); + if (config.display.heading_bold) { + display->drawString((SCREEN_WIDTH / 2) + 1, y, titleStr); + } } display->setTextAlignment(TEXT_ALIGN_LEFT); // === Battery State === int chargePercent = powerStatus->getBatteryChargePercent(); - bool isCharging = powerStatus->getIsCharging() == meshtastic::OptionalBool::OptTrue; + bool isCharging = powerStatus->getIsCharging(); + bool usbPowered = powerStatus->getHasUSB(); + + if (chargePercent >= 100) { + isCharging = false; + } + if (chargePercent == 101) { + usbPowered = true; // Forcing this flag on for the express purpose that some devices have no concept of having a USB cable + // plugged in + } + uint32_t now = millis(); #ifndef USE_EINK @@ -93,53 +119,66 @@ void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *ti } #endif - bool useHorizontalBattery = (screenW > 128 && screenW >= screenH); + bool useHorizontalBattery = (isHighResolution && screenW >= screenH); const int textY = y + (highlightHeight - FONT_HEIGHT_SMALL) / 2; + int batteryX = 1; + int batteryY = HEADER_OFFSET_Y + 1; + // === Battery Icons === - if (useHorizontalBattery) { - int batteryX = 2; - int batteryY = HEADER_OFFSET_Y + 2; - display->drawXbm(batteryX, batteryY, 29, 15, batteryBitmap_h); - if (isCharging && isBoltVisibleShared) - display->drawXbm(batteryX + 9, batteryY + 1, 9, 13, lightning_bolt_h); - else { - display->drawXbm(batteryX + 8, batteryY, 12, 15, batteryBitmap_sidegaps_h); - int fillWidth = 24 * chargePercent / 100; - display->fillRect(batteryX + 1, batteryY + 1, fillWidth, 13); + if (usbPowered && !isCharging) { // This is a basic check to determine USB Powered is flagged but not charging + batteryX += 1; + batteryY += 2; + if (isHighResolution) { + display->drawXbm(batteryX, batteryY, 19, 12, imgUSB_HighResolution); + batteryX += 20; // Icon + 1 pixel + } else { + display->drawXbm(batteryX, batteryY, 10, 8, imgUSB); + batteryX += 11; // Icon + 1 pixel } } else { - int batteryX = 1; - int batteryY = HEADER_OFFSET_Y + 1; + if (useHorizontalBattery) { + batteryX += 1; + batteryY += 2; + display->drawXbm(batteryX, batteryY, 9, 13, batteryBitmap_h_bottom); + display->drawXbm(batteryX + 9, batteryY, 9, 13, batteryBitmap_h_top); + if (isCharging && isBoltVisibleShared) + display->drawXbm(batteryX + 4, batteryY, 9, 13, lightning_bolt_h); + else { + display->drawLine(batteryX + 5, batteryY, batteryX + 10, batteryY); + display->drawLine(batteryX + 5, batteryY + 12, batteryX + 10, batteryY + 12); + int fillWidth = 14 * chargePercent / 100; + display->fillRect(batteryX + 1, batteryY + 1, fillWidth, 11); + } + batteryX += 18; // Icon + 2 pixels + } else { #ifdef USE_EINK - batteryY += 2; + batteryY += 2; #endif - display->drawXbm(batteryX, batteryY, 7, 11, batteryBitmap_v); - if (isCharging && isBoltVisibleShared) - display->drawXbm(batteryX + 1, batteryY + 3, 5, 5, lightning_bolt_v); - else { - display->drawXbm(batteryX - 1, batteryY + 4, 8, 3, batteryBitmap_sidegaps_v); - int fillHeight = 8 * chargePercent / 100; - int fillY = batteryY - fillHeight; - display->fillRect(batteryX + 1, fillY + 10, 5, fillHeight); + display->drawXbm(batteryX, batteryY, 7, 11, batteryBitmap_v); + if (isCharging && isBoltVisibleShared) + display->drawXbm(batteryX + 1, batteryY + 3, 5, 5, lightning_bolt_v); + else { + display->drawXbm(batteryX - 1, batteryY + 4, 8, 3, batteryBitmap_sidegaps_v); + int fillHeight = 8 * chargePercent / 100; + int fillY = batteryY - fillHeight; + display->fillRect(batteryX + 1, fillY + 10, 5, fillHeight); + } + batteryX += 9; // Icon + 2 pixels } } - // === Battery % Display === - char chargeStr[4]; - snprintf(chargeStr, sizeof(chargeStr), "%d", chargePercent); - int chargeNumWidth = display->getStringWidth(chargeStr); - const int batteryOffset = useHorizontalBattery ? 28 : 6; -#ifdef USE_EINK - const int percentX = x + xOffset + batteryOffset - 2; -#else - const int percentX = x + xOffset + batteryOffset; -#endif - display->drawString(percentX, textY, chargeStr); - display->drawString(percentX + chargeNumWidth - 1, textY, "%"); - if (isBold) { - display->drawString(percentX + 1, textY, chargeStr); - display->drawString(percentX + chargeNumWidth, textY, "%"); + if (chargePercent != 101) { + // === Battery % Display === + char chargeStr[4]; + snprintf(chargeStr, sizeof(chargeStr), "%d", chargePercent); + int chargeNumWidth = display->getStringWidth(chargeStr); + display->drawString(batteryX, textY, chargeStr); + display->drawString(batteryX + chargeNumWidth - 1, textY, "%"); + if (isBold) { + display->drawString(batteryX + 1, textY, chargeStr); + display->drawString(batteryX + chargeNumWidth, textY, "%"); + } } // === Time and Right-aligned Icons === @@ -148,7 +187,7 @@ void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *ti int timeStrWidth = display->getStringWidth("12:34"); // Default alignment int timeX = screenW - xOffset - timeStrWidth + 4; - if (rtc_sec > 0) { + if (rtc_sec > 0 && !battery_only) { // === Build Time String === long hms = (rtc_sec % SEC_PER_DAY + SEC_PER_DAY) % SEC_PER_DAY; int hour = hms / SEC_PER_HOUR; @@ -164,7 +203,7 @@ void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *ti } timeStrWidth = display->getStringWidth(timeStr); - timeX = screenW - xOffset - timeStrWidth + 4; + timeX = screenW - xOffset - timeStrWidth + 3; // === Show Mail or Mute Icon to the Left of Time === int iconRightEdge = timeX - 1; @@ -217,7 +256,7 @@ void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *ti display->drawXbm(iconX, iconY, mail_width, mail_height, mail); } } else if (isMuted) { - if (useBigIcons) { + if (isHighResolution) { int iconX = iconRightEdge - mute_symbol_big_width; int iconY = textY + (FONT_HEIGHT_SMALL - mute_symbol_big_height) / 2; @@ -259,6 +298,7 @@ void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *ti bool showMail = false; +#ifndef USE_EINK if (hasUnreadMessage) { if (now - lastMailBlink > 500) { isMailIconVisible = !isMailIconVisible; @@ -266,6 +306,11 @@ void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *ti } showMail = isMailIconVisible; } +#else + if (hasUnreadMessage) { + showMail = true; + } +#endif if (showMail) { if (useHorizontalBattery) { @@ -281,7 +326,7 @@ void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *ti display->drawXbm(iconX, iconY, mail_width, mail_height, mail); } } else if (isMuted) { - if (useBigIcons) { + if (isHighResolution) { int iconX = iconRightEdge - mute_symbol_big_width; int iconY = textY + (FONT_HEIGHT_SMALL - mute_symbol_big_height) / 2; display->drawXbm(iconX, iconY, mute_symbol_big_width, mute_symbol_big_height, mute_symbol_big); @@ -300,7 +345,7 @@ const int *getTextPositions(OLEDDisplay *display) { static int textPositions[7]; // Static array that persists beyond function scope - if (display->getHeight() > 64) { + if (isHighResolution) { textPositions[0] = textZeroLine; textPositions[1] = textFirstLine_medium; textPositions[2] = textSecondLine_medium; @@ -320,4 +365,30 @@ const int *getTextPositions(OLEDDisplay *display) return textPositions; } +bool isAllowedPunctuation(char c) +{ + const std::string allowed = ".,!?;:-_()[]{}'\"@#$/\\&+=%~^ "; + return allowed.find(c) != std::string::npos; +} + +std::string sanitizeString(const std::string &input) +{ + std::string output; + bool inReplacement = false; + + for (char c : input) { + if (std::isalnum(static_cast(c)) || isAllowedPunctuation(c)) { + output += c; + inReplacement = false; + } else { + if (!inReplacement) { + output += 0xbf; // ISO-8859-1 for inverted question mark + inReplacement = true; + } + } + } + + return output; +} + } // namespace graphics diff --git a/src/graphics/SharedUIDisplay.h b/src/graphics/SharedUIDisplay.h index 41411ba7f..b8d82795e 100644 --- a/src/graphics/SharedUIDisplay.h +++ b/src/graphics/SharedUIDisplay.h @@ -1,6 +1,7 @@ #pragma once #include +#include namespace graphics { @@ -41,13 +42,19 @@ namespace graphics // Shared state (declare inside namespace) extern bool hasUnreadMessage; extern bool isMuted; +extern bool isHighResolution; +void determineResolution(int16_t screenheight, int16_t screenwidth); // Rounded highlight (used for inverted headers) void drawRoundedHighlight(OLEDDisplay *display, int16_t x, int16_t y, int16_t w, int16_t h, int16_t r); // Shared battery/time/mail header -void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *titleStr = ""); +void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *titleStr = "", bool battery_only = false); const int *getTextPositions(OLEDDisplay *display); +bool isAllowedPunctuation(char c); + +std::string sanitizeString(const std::string &input); + } // namespace graphics diff --git a/src/graphics/TFTDisplay.cpp b/src/graphics/TFTDisplay.cpp index 92b2c3d02..3e9bafc6c 100644 --- a/src/graphics/TFTDisplay.cpp +++ b/src/graphics/TFTDisplay.cpp @@ -1,5 +1,6 @@ #include "configuration.h" #include "main.h" + #if ARCH_PORTDUINO #include "platform/portduino/PortduinoGlue.h" #endif @@ -14,8 +15,10 @@ extern SX1509 gpioExtender; #endif -#ifndef TFT_MESH -#define TFT_MESH COLOR565(0x67, 0xEA, 0x94) +#ifdef TFT_MESH_OVERRIDE +uint16_t TFT_MESH = TFT_MESH_OVERRIDE; +#else +uint16_t TFT_MESH = COLOR565(0x67, 0xEA, 0x94); #endif #if defined(ST7735S) diff --git a/src/graphics/draw/ClockRenderer.cpp b/src/graphics/draw/ClockRenderer.cpp index 2e301b4e1..8d7e91000 100644 --- a/src/graphics/draw/ClockRenderer.cpp +++ b/src/graphics/draw/ClockRenderer.cpp @@ -146,6 +146,7 @@ void drawVerticalSegment(OLEDDisplay *display, int x, int y, int width, int heig display->fillTriangle(x, y + width, x + height - 1, y + width, x + halfHeight, y + width + halfHeight); } +/* void drawWatchFaceToggleButton(OLEDDisplay *display, int16_t x, int16_t y, bool digitalMode, float scale) { uint16_t segmentWidth = SEGMENT_WIDTH * scale; @@ -179,21 +180,22 @@ void drawWatchFaceToggleButton(OLEDDisplay *display, int16_t x, int16_t y, bool drawVerticalSegment(display, segmentFourX, segmentFourY, segmentWidth, segmentHeight); } } - +*/ // Draw a digital clock void drawDigitalClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) { display->clear(); display->setTextAlignment(TEXT_ALIGN_LEFT); int line = 1; + // === Set Title, Blank for Clock + const char *titleStr = ""; + // === Header === + graphics::drawCommonHeader(display, x, y, titleStr, true); #ifdef T_WATCH_S3 if (nimbleBluetooth && nimbleBluetooth->isConnected()) { - graphics::ClockRenderer::drawBluetoothConnectedIcon(display, display->getWidth() - 18, y + 2); + graphics::ClockRenderer::drawBluetoothConnectedIcon(display, display->getWidth() - 18, display->getHeight() - 14); } - - drawWatchFaceToggleButton(display, display->getWidth() - 36, display->getHeight() - 36, - graphics::ClockRenderer::digitalWatchFace, 1); #endif uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityDevice, true); // Display local timezone @@ -230,7 +232,7 @@ void drawDigitalClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int1 float scale = 1.5; #else float scale = 0.75; - if (SCREEN_WIDTH > 128) { + if (isHighResolution) { scale = 1.5; } #endif @@ -276,17 +278,20 @@ void drawDigitalClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int1 // draw seconds string display->setFont(FONT_SMALL); - int xOffset = (SCREEN_WIDTH > 128) ? 0 : -1; + int xOffset = (isHighResolution) ? 0 : -1; if (hour >= 10) { - xOffset += (SCREEN_WIDTH > 128) ? 32 : 18; + xOffset += (isHighResolution) ? 32 : 18; } - int yOffset = (SCREEN_WIDTH > 128) ? 3 : 1; + int yOffset = (isHighResolution) ? 3 : 1; +#ifdef SENSECAP_INDICATOR + yOffset -= 3; +#endif if (config.display.use_12h_clock) { display->drawString(startingHourMinuteTextX + xOffset, (display->getHeight() - hourMinuteTextY) - yOffset - 2, isPM ? "pm" : "am"); } #ifndef USE_EINK - xOffset = (SCREEN_WIDTH > 128) ? 18 : 10; + xOffset = (isHighResolution) ? 18 : 10; display->drawString(startingHourMinuteTextX + timeStringWidth - xOffset, (display->getHeight() - hourMinuteTextY) - yOffset, secondString); #endif @@ -301,31 +306,30 @@ void drawBluetoothConnectedIcon(OLEDDisplay *display, int16_t x, int16_t y) void drawAnalogClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) { display->setTextAlignment(TEXT_ALIGN_LEFT); + // === Set Title, Blank for Clock + const char *titleStr = ""; + // === Header === + graphics::drawCommonHeader(display, x, y, titleStr, true); - graphics::UIRenderer::drawBattery(display, x, y + 7, imgBattery, powerStatus); - - if (powerStatus->getHasBattery()) { - char batteryPercent[8]; - snprintf(batteryPercent, sizeof(batteryPercent), "%d%%", powerStatus->getBatteryChargePercent()); - - display->setFont(FONT_SMALL); - - display->drawString(x + 20, y + 2, batteryPercent); - } #ifdef T_WATCH_S3 if (nimbleBluetooth && nimbleBluetooth->isConnected()) { - drawBluetoothConnectedIcon(display, display->getWidth() - 18, y + 2); + drawBluetoothConnectedIcon(display, display->getWidth() - 18, display->getHeight() - 14); } #endif - drawWatchFaceToggleButton(display, display->getWidth() - 36, display->getHeight() - 36, - graphics::ClockRenderer::digitalWatchFace, 1); - // clock face center coordinates int16_t centerX = display->getWidth() / 2; int16_t centerY = display->getHeight() / 2; // clock face radius - int16_t radius = (display->getWidth() / 2) * 0.8; + int16_t radius = 0; + if (display->getHeight() < display->getWidth()) { + radius = (display->getHeight() / 2) * 0.9; + } else { + radius = (display->getWidth() / 2) * 0.9; + } +#ifdef T_WATCH_S3 + radius = (display->getWidth() / 2) * 0.8; +#endif // noon (0 deg) coordinates (outermost circle) int16_t noonX = centerX; @@ -338,10 +342,16 @@ void drawAnalogClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16 int16_t tickMarkOuterNoonY = secondHandNoonY; // seconds tick mark inner y coordinate; (second nested circle) - double secondsTickMarkInnerNoonY = (double)noonY + 8; + double secondsTickMarkInnerNoonY = (double)noonY + 4; + if (isHighResolution) { + secondsTickMarkInnerNoonY = (double)noonY + 8; + } // hours tick mark inner y coordinate; (third nested circle) - double hoursTickMarkInnerNoonY = (double)noonY + 16; + double hoursTickMarkInnerNoonY = (double)noonY + 6; + if (isHighResolution) { + hoursTickMarkInnerNoonY = (double)noonY + 16; + } // minute hand y coordinate int16_t minuteHandNoonY = secondsTickMarkInnerNoonY + 4; @@ -350,7 +360,10 @@ void drawAnalogClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16 int16_t hourStringNoonY = minuteHandNoonY + 18; // hour hand radius and y coordinate - int16_t hourHandRadius = radius * 0.55; + int16_t hourHandRadius = radius * 0.35; + if (isHighResolution) { + int16_t hourHandRadius = radius * 0.55; + } int16_t hourHandNoonY = centerY - hourHandRadius; display->setColor(OLEDDISPLAY_COLOR::WHITE); @@ -366,7 +379,20 @@ void drawAnalogClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16 int minute = (hms % SEC_PER_HOUR) / SEC_PER_MIN; int second = (hms % SEC_PER_HOUR) % SEC_PER_MIN; // or hms % SEC_PER_MIN - hour = hour > 12 ? hour - 12 : hour; + bool isPM = hour >= 12; + if (config.display.use_12h_clock) { + bool isPM = hour >= 12; + display->setFont(FONT_SMALL); + int yOffset = isHighResolution ? 1 : 0; +#ifdef USE_EINK + yOffset += 3; +#endif + display->drawString(centerX - (display->getStringWidth(isPM ? "pm" : "am") / 2), centerY + yOffset, + isPM ? "pm" : "am"); + } + hour %= 12; + if (hour == 0) + hour = 12; int16_t degreesPerHour = 30; int16_t degreesPerMinuteOrSecond = 6; @@ -443,16 +469,32 @@ void drawAnalogClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16 double hourStringX = (sineAngleInRadians * (hourStringNoonY - centerY) + noonX) - hourStringXOffset; double hourStringY = (cosineAngleInRadians * (hourStringNoonY - centerY) + centerY) - hourStringYOffset; +#ifdef T_WATCH_S3 // draw hour number display->drawStringf(hourStringX, hourStringY, buffer, "%d", hourInt); +#else +#ifdef USE_EINK + if (isHighResolution) { + // draw hour number + display->drawStringf(hourStringX, hourStringY, buffer, "%d", hourInt); + } +#else + if (isHighResolution && (hourInt == 3 || hourInt == 6 || hourInt == 9 || hourInt == 12)) { + // draw hour number + display->drawStringf(hourStringX, hourStringY, buffer, "%d", hourInt); + } +#endif +#endif } if (angle % degreesPerMinuteOrSecond == 0) { double startX = sineAngleInRadians * (secondsTickMarkInnerNoonY - centerY) + noonX; double startY = cosineAngleInRadians * (secondsTickMarkInnerNoonY - centerY) + centerY; - // draw minute tick mark - display->drawLine(startX, startY, endX, endY); + if (isHighResolution) { + // draw minute tick mark + display->drawLine(startX, startY, endX, endY); + } } } @@ -461,9 +503,10 @@ void drawAnalogClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16 // draw minute hand display->drawLine(centerX, centerY, minuteX, minuteY); - +#ifndef USE_EINK // draw second hand display->drawLine(centerX, centerY, secondX, secondY); +#endif } } diff --git a/src/graphics/draw/ClockRenderer.h b/src/graphics/draw/ClockRenderer.h index 4660dcc35..c8ba62868 100644 --- a/src/graphics/draw/ClockRenderer.h +++ b/src/graphics/draw/ClockRenderer.h @@ -11,8 +11,6 @@ class Screen; namespace ClockRenderer { -// Whether we are showing the digital watch face or the analog one -static bool digitalWatchFace = true; // Clock frame functions void drawAnalogClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y); @@ -25,7 +23,7 @@ void drawHorizontalSegment(OLEDDisplay *display, int x, int y, int width, int he void drawVerticalSegment(OLEDDisplay *display, int x, int y, int width, int height); // UI elements for clock displays -void drawWatchFaceToggleButton(OLEDDisplay *display, int16_t x, int16_t y, bool digitalMode = true, float scale = 1); +// void drawWatchFaceToggleButton(OLEDDisplay *display, int16_t x, int16_t y, bool digitalMode = true, float scale = 1); void drawBluetoothConnectedIcon(OLEDDisplay *display, int16_t x, int16_t y); } // namespace ClockRenderer diff --git a/src/graphics/draw/CompassRenderer.cpp b/src/graphics/draw/CompassRenderer.cpp index fef993e2d..0e5a1d727 100644 --- a/src/graphics/draw/CompassRenderer.cpp +++ b/src/graphics/draw/CompassRenderer.cpp @@ -4,6 +4,7 @@ #include "configuration.h" #include "gps/GeoCoord.h" #include "graphics/ScreenFonts.h" +#include "graphics/SharedUIDisplay.h" #include namespace graphics @@ -45,17 +46,18 @@ void drawCompassNorth(OLEDDisplay *display, int16_t compassX, int16_t compassY, // This could draw a "N" indicator or north arrow // For now, we'll draw a simple north indicator // const float radius = 17.0f; - if (display->width() > 128) { + if (isHighResolution) { radius += 4; } Point north(0, -radius); - north.rotate(-myHeading); + if (uiconfig.compass_mode != meshtastic_CompassMode_FIXED_RING) + north.rotate(-myHeading); north.translate(compassX, compassY); display->setFont(FONT_SMALL); display->setTextAlignment(TEXT_ALIGN_CENTER); display->setColor(BLACK); - if (display->width() > 128) { + if (isHighResolution) { display->fillRect(north.x - 8, north.y - 1, display->getStringWidth("N") + 3, FONT_HEIGHT_SMALL - 6); } else { display->fillRect(north.x - 4, north.y - 1, display->getStringWidth("N") + 2, FONT_HEIGHT_SMALL - 6); @@ -91,18 +93,22 @@ void drawArrowToNode(OLEDDisplay *display, int16_t x, int16_t y, int16_t size, f float radians = bearing * DEG_TO_RAD; Point tip(0, -size / 2); - Point left(-size / 4, size / 4); - Point right(size / 4, size / 4); + Point left(-size / 6, size / 4); + Point right(size / 6, size / 4); + Point tail(0, size / 4.5); tip.rotate(radians); left.rotate(radians); right.rotate(radians); + tail.rotate(radians); tip.translate(x, y); left.translate(x, y); right.translate(x, y); + tail.translate(x, y); - display->drawTriangle(tip.x, tip.y, left.x, left.y, right.x, right.y); + display->fillTriangle(tip.x, tip.y, left.x, left.y, tail.x, tail.y); + display->fillTriangle(tip.x, tip.y, right.x, right.y, tail.x, tail.y); } float estimatedHeading(double lat, double lon) @@ -127,14 +133,5 @@ uint16_t getCompassDiam(uint32_t displayWidth, uint32_t displayHeight) return maxDiam; } -float calculateBearing(double lat1, double lon1, double lat2, double lon2) -{ - double dLon = (lon2 - lon1) * DEG_TO_RAD; - double y = sin(dLon) * cos(lat2 * DEG_TO_RAD); - double x = cos(lat1 * DEG_TO_RAD) * sin(lat2 * DEG_TO_RAD) - sin(lat1 * DEG_TO_RAD) * cos(lat2 * DEG_TO_RAD) * cos(dLon); - double bearing = atan2(y, x) * RAD_TO_DEG; - return fmod(bearing + 360.0, 360.0); -} - } // namespace CompassRenderer } // namespace graphics diff --git a/src/graphics/draw/CompassRenderer.h b/src/graphics/draw/CompassRenderer.h index 4b26e6463..ca7532b66 100644 --- a/src/graphics/draw/CompassRenderer.h +++ b/src/graphics/draw/CompassRenderer.h @@ -28,9 +28,6 @@ void drawArrowToNode(OLEDDisplay *display, int16_t x, int16_t y, int16_t size, f float estimatedHeading(double lat, double lon); uint16_t getCompassDiam(uint32_t displayWidth, uint32_t displayHeight); -// Utility functions for bearing calculations -float calculateBearing(double lat1, double lon1, double lat2, double lon2); - } // namespace CompassRenderer } // namespace graphics diff --git a/src/graphics/draw/DebugRenderer.cpp b/src/graphics/draw/DebugRenderer.cpp index 2c3a3a3a8..b1a901f99 100644 --- a/src/graphics/draw/DebugRenderer.cpp +++ b/src/graphics/draw/DebugRenderer.cpp @@ -67,21 +67,6 @@ void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16 char channelStr[20]; snprintf(channelStr, sizeof(channelStr), "#%s", channels.getName(channels.getPrimaryIndex())); - - // Display power status - if (powerStatus->getHasBattery()) { - if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT) { - UIRenderer::drawBattery(display, x, y + 2, imgBattery, powerStatus); - } else { - UIRenderer::drawBattery(display, x + 1, y + 3, imgBattery, powerStatus); - } - } else if (powerStatus->knowsUSB()) { - if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT) { - display->drawFastImage(x, y + 2, 16, 8, powerStatus->getHasUSB() ? imgUSB : imgPower); - } else { - display->drawFastImage(x + 1, y + 3, 16, 8, powerStatus->getHasUSB() ? imgUSB : imgPower); - } - } // Display nodes status if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT) { UIRenderer::drawNodes(display, x + (SCREEN_WIDTH * 0.25), y + 2, nodeStatus); @@ -393,7 +378,7 @@ void drawLoRaFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int line = 1; // === Set Title - const char *titleStr = (SCREEN_WIDTH > 128) ? "LoRa Info" : "LoRa"; + const char *titleStr = (isHighResolution) ? "LoRa Info" : "LoRa"; // === Header === graphics::drawCommonHeader(display, x, y, titleStr); @@ -444,12 +429,12 @@ void drawLoRaFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, char chUtilPercentage[10]; snprintf(chUtilPercentage, sizeof(chUtilPercentage), "%2.0f%%", airTime->channelUtilizationPercent()); - int chUtil_x = (SCREEN_WIDTH > 128) ? display->getStringWidth(chUtil) + 10 : display->getStringWidth(chUtil) + 5; + int chUtil_x = (isHighResolution) ? display->getStringWidth(chUtil) + 10 : display->getStringWidth(chUtil) + 5; int chUtil_y = getTextPositions(display)[line] + 3; - int chutil_bar_width = (SCREEN_WIDTH > 128) ? 100 : 50; - int chutil_bar_height = (SCREEN_WIDTH > 128) ? 12 : 7; - int extraoffset = (SCREEN_WIDTH > 128) ? 6 : 3; + int chutil_bar_width = (isHighResolution) ? 100 : 50; + int chutil_bar_height = (isHighResolution) ? 12 : 7; + int extraoffset = (isHighResolution) ? 6 : 3; int chutil_percent = airTime->channelUtilizationPercent(); int centerofscreen = SCREEN_WIDTH / 2; @@ -516,7 +501,10 @@ void drawMemoryUsage(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int line = 1; const int barHeight = 6; const int labelX = x; - const int barsOffset = (SCREEN_WIDTH > 128) ? 24 : 0; + int barsOffset = (isHighResolution) ? 24 : 0; +#ifdef USE_EINK + barsOffset -= 12; +#endif const int barX = x + 40 + barsOffset; auto drawUsageRow = [&](const char *label, uint32_t used, uint32_t total, bool isHeap = false) { @@ -526,7 +514,7 @@ void drawMemoryUsage(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int percent = (used * 100) / total; char combinedStr[24]; - if (SCREEN_WIDTH > 128) { + if (isHighResolution) { snprintf(combinedStr, sizeof(combinedStr), "%s%3d%% %u/%uKB", (percent > 80) ? "! " : "", percent, used / 1024, total / 1024); } else { diff --git a/src/graphics/draw/MenuHandler.cpp b/src/graphics/draw/MenuHandler.cpp new file mode 100644 index 000000000..f6b250ebc --- /dev/null +++ b/src/graphics/draw/MenuHandler.cpp @@ -0,0 +1,1145 @@ +#include "configuration.h" +#if HAS_SCREEN +#include "ClockRenderer.h" +#include "GPS.h" +#include "MenuHandler.h" +#include "MeshRadio.h" +#include "MeshService.h" +#include "NodeDB.h" +#include "buzz.h" +#include "graphics/Screen.h" +#include "graphics/SharedUIDisplay.h" +#include "graphics/draw/UIRenderer.h" +#include "main.h" +#include "modules/AdminModule.h" +#include "modules/CannedMessageModule.h" +#include "modules/KeyVerificationModule.h" + +extern uint16_t TFT_MESH; + +namespace graphics +{ +menuHandler::screenMenus menuHandler::menuQueue = menu_none; +bool test_enabled = false; +uint8_t test_count = 0; + +void menuHandler::LoraRegionPicker(uint32_t duration) +{ + static const char *optionsArray[] = {"Back", + "US", + "EU_433", + "EU_868", + "CN", + "JP", + "ANZ", + "KR", + "TW", + "RU", + "IN", + "NZ_865", + "TH", + "LORA_24", + "UA_433", + "UA_868", + "MY_433", + "MY_" + "919", + "SG_" + "923", + "PH_433", + "PH_868", + "PH_915", + "ANZ_433", + "KZ_433", + "KZ_863"}; + BannerOverlayOptions bannerOptions; + bannerOptions.message = "Set the LoRa region"; + bannerOptions.durationMs = duration; + bannerOptions.optionsArrayPtr = optionsArray; + bannerOptions.optionsCount = 25; + bannerOptions.InitialSelected = 0; + bannerOptions.bannerCallback = [](int selected) -> void { + if (selected != 0 && config.lora.region != _meshtastic_Config_LoRaConfig_RegionCode(selected)) { + config.lora.region = _meshtastic_Config_LoRaConfig_RegionCode(selected); + // This is needed as we wait til picking the LoRa region to generate keys for the first time. + if (!owner.is_licensed) { + bool keygenSuccess = false; + if (config.security.private_key.size == 32) { + // public key is derived from private, so this will always have the same result. + if (crypto->regeneratePublicKey(config.security.public_key.bytes, config.security.private_key.bytes)) { + keygenSuccess = true; + } + } else { + LOG_INFO("Generate new PKI keys"); + crypto->generateKeyPair(config.security.public_key.bytes, config.security.private_key.bytes); + keygenSuccess = true; + } + if (keygenSuccess) { + config.security.public_key.size = 32; + config.security.private_key.size = 32; + owner.public_key.size = 32; + memcpy(owner.public_key.bytes, config.security.public_key.bytes, 32); + } + } + config.lora.tx_enabled = true; + initRegion(); + if (myRegion->dutyCycle < 100) { + config.lora.ignore_mqtt = true; // Ignore MQTT by default if region has a duty cycle limit + } + service->reloadConfig(SEGMENT_CONFIG); + rebootAtMsec = (millis() + DEFAULT_REBOOT_SECONDS * 1000); + } + }; + screen->showOverlayBanner(bannerOptions); +} + +void menuHandler::TwelveHourPicker() +{ + static const char *optionsArray[] = {"Back", "12-hour", "24-hour"}; + enum optionsNumbers { Back = 0, twelve = 1, twentyfour = 2 }; + BannerOverlayOptions bannerOptions; + bannerOptions.message = "Time Format"; + bannerOptions.optionsArrayPtr = optionsArray; + bannerOptions.optionsCount = 3; + bannerOptions.bannerCallback = [](int selected) -> void { + if (selected == Back) { + menuHandler::menuQueue = menuHandler::clock_menu; + screen->runNow(); + } else if (selected == twelve) { + config.display.use_12h_clock = true; + } else { + config.display.use_12h_clock = false; + } + service->reloadConfig(SEGMENT_CONFIG); + }; + screen->showOverlayBanner(bannerOptions); +} + +void menuHandler::ClockFacePicker() +{ + static const char *optionsArray[] = {"Back", "Digital", "Analog"}; + enum optionsNumbers { Back = 0, Digital = 1, Analog = 2 }; + BannerOverlayOptions bannerOptions; + bannerOptions.message = "Which Face?"; + bannerOptions.optionsArrayPtr = optionsArray; + bannerOptions.optionsCount = 3; + bannerOptions.bannerCallback = [](int selected) -> void { + if (selected == Back) { + menuHandler::menuQueue = menuHandler::clock_menu; + screen->runNow(); + } else if (selected == Digital) { + uiconfig.is_clockface_analog = false; + saveUIConfig(); + screen->setFrames(Screen::FOCUS_CLOCK); + } else { + uiconfig.is_clockface_analog = true; + saveUIConfig(); + screen->setFrames(Screen::FOCUS_CLOCK); + } + }; + bannerOptions.InitialSelected = uiconfig.is_clockface_analog ? 2 : 1; + screen->showOverlayBanner(bannerOptions); +} + +void menuHandler::TZPicker() +{ + static const char *optionsArray[] = {"Back", + "US/Hawaii", + "US/Alaska", + "US/Pacific", + "US/Arizona", + "US/Mountain", + "US/Central", + "US/Eastern", + "UTC", + "EU/Western", + "EU/" + "Central", + "EU/Eastern", + "Asia/Kolkata", + "Asia/Hong_Kong", + "AU/AWST", + "AU/ACST", + "AU/AEST", + "Pacific/NZ"}; + BannerOverlayOptions bannerOptions; + bannerOptions.message = "Pick Timezone"; + bannerOptions.optionsArrayPtr = optionsArray; + bannerOptions.optionsCount = 17; + bannerOptions.bannerCallback = [](int selected) -> void { + if (selected == 0) { + menuHandler::menuQueue = menuHandler::clock_menu; + screen->runNow(); + } else if (selected == 1) { // Hawaii + strncpy(config.device.tzdef, "HST10", sizeof(config.device.tzdef)); + } else if (selected == 2) { // Alaska + strncpy(config.device.tzdef, "AKST9AKDT,M3.2.0,M11.1.0", sizeof(config.device.tzdef)); + } else if (selected == 3) { // Pacific + strncpy(config.device.tzdef, "PST8PDT,M3.2.0,M11.1.0", sizeof(config.device.tzdef)); + } else if (selected == 4) { // Arizona + strncpy(config.device.tzdef, "MST7", sizeof(config.device.tzdef)); + } else if (selected == 5) { // Mountain + strncpy(config.device.tzdef, "MST7MDT,M3.2.0,M11.1.0", sizeof(config.device.tzdef)); + } else if (selected == 6) { // Central + strncpy(config.device.tzdef, "CST6CDT,M3.2.0,M11.1.0", sizeof(config.device.tzdef)); + } else if (selected == 7) { // Eastern + strncpy(config.device.tzdef, "EST5EDT,M3.2.0,M11.1.0", sizeof(config.device.tzdef)); + } else if (selected == 8) { // UTC + strncpy(config.device.tzdef, "UTC", sizeof(config.device.tzdef)); + } else if (selected == 9) { // EU/Western + strncpy(config.device.tzdef, "GMT0BST,M3.5.0/1,M10.5.0", sizeof(config.device.tzdef)); + } else if (selected == 10) { // EU/Central + strncpy(config.device.tzdef, "CET-1CEST,M3.5.0,M10.5.0/3", sizeof(config.device.tzdef)); + } else if (selected == 11) { // EU/Eastern + strncpy(config.device.tzdef, "EET-2EEST,M3.5.0/3,M10.5.0/4", sizeof(config.device.tzdef)); + } else if (selected == 12) { // Asia/Kolkata + strncpy(config.device.tzdef, "IST-5:30", sizeof(config.device.tzdef)); + } else if (selected == 13) { // China + strncpy(config.device.tzdef, "HKT-8", sizeof(config.device.tzdef)); + } else if (selected == 14) { // AU/AWST + strncpy(config.device.tzdef, "AWST-8", sizeof(config.device.tzdef)); + } else if (selected == 15) { // AU/ACST + strncpy(config.device.tzdef, "ACST-9:30ACDT,M10.1.0,M4.1.0/3", sizeof(config.device.tzdef)); + } else if (selected == 16) { // AU/AEST + strncpy(config.device.tzdef, "AEST-10AEDT,M10.1.0,M4.1.0/3", sizeof(config.device.tzdef)); + } else if (selected == 17) { // NZ + strncpy(config.device.tzdef, "NZST-12NZDT,M9.5.0,M4.1.0/3", sizeof(config.device.tzdef)); + } + if (selected != 0) { + setenv("TZ", config.device.tzdef, 1); + service->reloadConfig(SEGMENT_CONFIG); + } + }; + screen->showOverlayBanner(bannerOptions); +} + +void menuHandler::clockMenu() +{ + static const char *optionsArray[] = {"Back", "Clock Face", "Time Format", "Timezone"}; + enum optionsNumbers { Back = 0, Clock = 1, Time = 2, Timezone = 3 }; + BannerOverlayOptions bannerOptions; + bannerOptions.message = "Clock Action"; + bannerOptions.optionsArrayPtr = optionsArray; + bannerOptions.optionsCount = 4; + bannerOptions.bannerCallback = [](int selected) -> void { + if (selected == Clock) { + menuHandler::menuQueue = menuHandler::clock_face_picker; + screen->runNow(); + } else if (selected == Time) { + menuHandler::menuQueue = menuHandler::twelve_hour_picker; + screen->runNow(); + } else if (selected == Timezone) { + menuHandler::menuQueue = menuHandler::TZ_picker; + screen->runNow(); + } + }; + screen->showOverlayBanner(bannerOptions); +} + +void menuHandler::messageResponseMenu() +{ + enum optionsNumbers { Back = 0, Dismiss = 1, Preset = 2, Freetext = 3, Aloud = 4, enumEnd = 5 }; + + static const char *optionsArray[enumEnd] = {"Back", "Dismiss", "Reply via Preset"}; + static int optionsEnumArray[enumEnd] = {Back, Dismiss, Preset}; + int options = 3; + + if (kb_found) { + optionsArray[options] = "Reply via Freetext"; + optionsEnumArray[options++] = Freetext; + } + +#ifdef HAS_I2S + optionsArray[options] = "Read Aloud"; + optionsEnumArray[options++] = Aloud; +#endif + BannerOverlayOptions bannerOptions; + bannerOptions.message = "Message Action"; + bannerOptions.optionsArrayPtr = optionsArray; + bannerOptions.optionsEnumPtr = optionsEnumArray; + bannerOptions.optionsCount = options; + bannerOptions.bannerCallback = [](int selected) -> void { + if (selected == Dismiss) { + screen->dismissCurrentFrame(); + } else if (selected == Preset) { + if (devicestate.rx_text_message.to == NODENUM_BROADCAST) { + cannedMessageModule->LaunchWithDestination(NODENUM_BROADCAST, devicestate.rx_text_message.channel); + } else { + cannedMessageModule->LaunchWithDestination(devicestate.rx_text_message.from); + } + } else if (selected == Freetext) { + if (devicestate.rx_text_message.to == NODENUM_BROADCAST) { + cannedMessageModule->LaunchFreetextWithDestination(NODENUM_BROADCAST, devicestate.rx_text_message.channel); + } else { + cannedMessageModule->LaunchFreetextWithDestination(devicestate.rx_text_message.from); + } + } +#ifdef HAS_I2S + else if (selected == Aloud) { + const meshtastic_MeshPacket &mp = devicestate.rx_text_message; + const char *msg = reinterpret_cast(mp.decoded.payload.bytes); + + audioThread->readAloud(msg); + } +#endif + }; + screen->showOverlayBanner(bannerOptions); +} + +void menuHandler::homeBaseMenu() +{ + enum optionsNumbers { Back, Backlight, Position, Preset, Freetext, Bluetooth, Sleep, enumEnd }; + + static const char *optionsArray[enumEnd] = {"Back"}; + static int optionsEnumArray[enumEnd] = {Back}; + int options = 1; + +#ifdef PIN_EINK_EN + optionsArray[options] = "Toggle Backlight"; + optionsEnumArray[options++] = Backlight; +#else + optionsArray[options] = "Sleep Screen"; + optionsEnumArray[options++] = Sleep; +#endif + + optionsArray[options] = "Send Position"; + optionsEnumArray[options++] = Position; + optionsArray[options] = "New Preset Msg"; + optionsEnumArray[options++] = Preset; + if (kb_found) { + optionsArray[options] = "New Freetext Msg"; + optionsEnumArray[options++] = Freetext; + } + optionsArray[options] = "Bluetooth Toggle"; + optionsEnumArray[options++] = Bluetooth; + + BannerOverlayOptions bannerOptions; + bannerOptions.message = "Home Action"; + bannerOptions.optionsArrayPtr = optionsArray; + bannerOptions.optionsEnumPtr = optionsEnumArray; + bannerOptions.optionsCount = options; + bannerOptions.bannerCallback = [](int selected) -> void { + if (selected == Backlight) { +#ifdef PIN_EINK_EN + if (digitalRead(PIN_EINK_EN) == HIGH) { + digitalWrite(PIN_EINK_EN, LOW); + } else { + digitalWrite(PIN_EINK_EN, HIGH); + } +#endif + } else if (selected == Sleep) { + screen->setOn(false); + } else if (selected == Position) { + InputEvent event = {.inputEvent = (input_broker_event)INPUT_BROKER_SEND_PING, .kbchar = 0, .touchX = 0, .touchY = 0}; + inputBroker->injectInputEvent(&event); + } else if (selected == Preset) { + cannedMessageModule->LaunchWithDestination(NODENUM_BROADCAST); + } else if (selected == Freetext) { + cannedMessageModule->LaunchFreetextWithDestination(NODENUM_BROADCAST); + } else if (selected == Bluetooth) { + menuQueue = bluetooth_toggle_menu; + screen->runNow(); + } + }; + screen->showOverlayBanner(bannerOptions); +} + +void menuHandler::systemBaseMenu() +{ + // Check if brightness is supported + bool hasSupportBrightness = false; +#if defined(ST7789_CS) || defined(USE_OLED) || defined(USE_SSD1306) || defined(USE_SH1106) || defined(USE_SH1107) || HAS_TFT + hasSupportBrightness = true; +#endif + + enum optionsNumbers { Back, Notifications, ScreenOptions, PowerMenu, Test, enumEnd }; + static const char *optionsArray[enumEnd] = {"Back"}; + static int optionsEnumArray[enumEnd] = {Back}; + int options = 1; + + optionsArray[options] = "Notifications"; + optionsEnumArray[options++] = Notifications; +#if defined(ST7789_CS) || defined(USE_OLED) || defined(USE_SSD1306) || defined(USE_SH1106) || defined(USE_SH1107) || \ + defined(HELTEC_MESH_NODE_T114) || defined(HELTEC_VISION_MASTER_T190) || HAS_TFT + optionsArray[options] = "Screen Options"; + optionsEnumArray[options++] = ScreenOptions; +#endif + + optionsArray[options] = "Reboot/Shutdown"; + optionsEnumArray[options++] = PowerMenu; + + if (test_enabled) { + optionsArray[options] = "Test Menu"; + optionsEnumArray[options++] = Test; + } + + BannerOverlayOptions bannerOptions; + bannerOptions.message = "System Action"; + bannerOptions.optionsArrayPtr = optionsArray; + bannerOptions.optionsCount = options; + bannerOptions.optionsEnumPtr = optionsEnumArray; + bannerOptions.bannerCallback = [](int selected) -> void { + if (selected == Notifications) { + menuHandler::menuQueue = menuHandler::notifications_menu; + screen->runNow(); + } else if (selected == ScreenOptions) { + menuHandler::menuQueue = menuHandler::screen_options_menu; + screen->runNow(); + } else if (selected == PowerMenu) { + menuHandler::menuQueue = menuHandler::power_menu; + screen->runNow(); + } else if (selected == Test) { + menuHandler::menuQueue = menuHandler::test_menu; + screen->runNow(); + } else if (selected == Back && !test_enabled) { + test_count++; + if (test_count > 4) { + test_enabled = true; + } + } + }; + screen->showOverlayBanner(bannerOptions); +} + +void menuHandler::favoriteBaseMenu() +{ + enum optionsNumbers { Back, Preset, Freetext, Remove, enumEnd }; + static const char *optionsArray[enumEnd] = {"Back", "New Preset Msg"}; + static int optionsEnumArray[enumEnd] = {Back, Preset}; + int options = 2; + + if (kb_found) { + optionsArray[options] = "New Freetext Msg"; + optionsEnumArray[options++] = Freetext; + } + optionsArray[options] = "Remove Favorite"; + optionsEnumArray[options++] = Remove; + + BannerOverlayOptions bannerOptions; + bannerOptions.message = "Favorites Action"; + bannerOptions.optionsArrayPtr = optionsArray; + bannerOptions.optionsEnumPtr = optionsEnumArray; + bannerOptions.optionsCount = options; + bannerOptions.bannerCallback = [](int selected) -> void { + if (selected == 1) { + cannedMessageModule->LaunchWithDestination(graphics::UIRenderer::currentFavoriteNodeNum); + } else if (selected == 2 && kb_found) { + cannedMessageModule->LaunchFreetextWithDestination(graphics::UIRenderer::currentFavoriteNodeNum); + } else if ((!kb_found && selected == 2) || (selected == 3 && kb_found)) { + menuHandler::menuQueue = menuHandler::remove_favorite; + screen->runNow(); + } + }; + screen->showOverlayBanner(bannerOptions); +} + +void menuHandler::positionBaseMenu() +{ + enum optionsNumbers { Back, GPSToggle, CompassMenu, CompassCalibrate, enumEnd }; + + static const char *optionsArray[enumEnd] = {"Back", "GPS Toggle", "Compass"}; + static int optionsEnumArray[enumEnd] = {Back, GPSToggle, CompassMenu}; + int options = 3; + + if (accelerometerThread) { + optionsArray[options] = "Compass Calibrate"; + optionsEnumArray[options++] = CompassCalibrate; + } + BannerOverlayOptions bannerOptions; + bannerOptions.message = "Position Action"; + bannerOptions.optionsArrayPtr = optionsArray; + bannerOptions.optionsEnumPtr = optionsEnumArray; + bannerOptions.optionsCount = options; + bannerOptions.bannerCallback = [](int selected) -> void { + if (selected == GPSToggle) { + menuQueue = gps_toggle_menu; + screen->runNow(); + } else if (selected == CompassMenu) { + menuQueue = compass_point_north_menu; + screen->runNow(); + } else if (selected == CompassCalibrate) { + accelerometerThread->calibrate(30); + } + }; + screen->showOverlayBanner(bannerOptions); +} + +void menuHandler::nodeListMenu() +{ + enum optionsNumbers { Back, Favorite, Verify, Reset }; + static const char *optionsArray[] = {"Back", "Add Favorite", "Key Verification", "Reset NodeDB"}; + BannerOverlayOptions bannerOptions; + bannerOptions.message = "Node Action"; + bannerOptions.optionsArrayPtr = optionsArray; + bannerOptions.optionsCount = 4; + bannerOptions.bannerCallback = [](int selected) -> void { + if (selected == Favorite) { + menuQueue = add_favorite; + screen->runNow(); + } else if (selected == Verify) { + menuQueue = key_verification_init; + screen->runNow(); + } else if (selected == Reset) { + menuQueue = reset_node_db_menu; + screen->runNow(); + } + }; + screen->showOverlayBanner(bannerOptions); +} + +void menuHandler::resetNodeDBMenu() +{ + static const char *optionsArray[] = {"Back", "Confirm"}; + BannerOverlayOptions bannerOptions; + bannerOptions.message = "Confirm Reset NodeDB"; + bannerOptions.optionsArrayPtr = optionsArray; + bannerOptions.optionsCount = 2; + bannerOptions.bannerCallback = [](int selected) -> void { + if (selected == 1) { + disableBluetooth(); + LOG_INFO("Initiate node-db reset"); + nodeDB->resetNodes(); + rebootAtMsec = (millis() + DEFAULT_REBOOT_SECONDS * 1000); + } + }; + screen->showOverlayBanner(bannerOptions); +} + +void menuHandler::compassNorthMenu() +{ + enum optionsNumbers { Back, Dynamic, Fixed, Freeze }; + static const char *optionsArray[] = {"Back", "Dynamic", "Fixed Ring", "Freeze Heading"}; + BannerOverlayOptions bannerOptions; + bannerOptions.message = "North Directions?"; + bannerOptions.optionsArrayPtr = optionsArray; + bannerOptions.optionsCount = 4; + bannerOptions.InitialSelected = uiconfig.compass_mode + 1; + bannerOptions.bannerCallback = [](int selected) -> void { + if (selected == Dynamic) { + if (uiconfig.compass_mode != meshtastic_CompassMode_DYNAMIC) { + uiconfig.compass_mode = meshtastic_CompassMode_DYNAMIC; + saveUIConfig(); + screen->setFrames(graphics::Screen::FOCUS_PRESERVE); + } + } else if (selected == Fixed) { + if (uiconfig.compass_mode != meshtastic_CompassMode_FIXED_RING) { + uiconfig.compass_mode = meshtastic_CompassMode_FIXED_RING; + saveUIConfig(); + screen->setFrames(graphics::Screen::FOCUS_PRESERVE); + } + } else if (selected == Freeze) { + if (uiconfig.compass_mode != meshtastic_CompassMode_FREEZE_HEADING) { + uiconfig.compass_mode = meshtastic_CompassMode_FREEZE_HEADING; + saveUIConfig(); + screen->setFrames(graphics::Screen::FOCUS_PRESERVE); + } + } else if (selected == Back) { + menuQueue = position_base_menu; + screen->runNow(); + } + }; + screen->showOverlayBanner(bannerOptions); +} + +#if !MESHTASTIC_EXCLUDE_GPS +void menuHandler::GPSToggleMenu() +{ + + static const char *optionsArray[] = {"Back", "Enabled", "Disabled"}; + BannerOverlayOptions bannerOptions; + bannerOptions.message = "Toggle GPS"; + bannerOptions.optionsArrayPtr = optionsArray; + bannerOptions.optionsCount = 3; + bannerOptions.bannerCallback = [](int selected) -> void { + if (selected == 1) { + config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_ENABLED; + playGPSEnableBeep(); + gps->enable(); + service->reloadConfig(SEGMENT_CONFIG); + } else if (selected == 2) { + config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_DISABLED; + playGPSDisableBeep(); + gps->disable(); + service->reloadConfig(SEGMENT_CONFIG); + } else { + menuQueue = position_base_menu; + screen->runNow(); + } + }; + bannerOptions.InitialSelected = config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_ENABLED ? 1 : 2; + screen->showOverlayBanner(bannerOptions); +} +#endif + +void menuHandler::BluetoothToggleMenu() +{ + static const char *optionsArray[] = {"Back", "Enabled", "Disabled"}; + BannerOverlayOptions bannerOptions; + bannerOptions.message = "Toggle Bluetooth"; + bannerOptions.optionsArrayPtr = optionsArray; + bannerOptions.optionsCount = 3; + bannerOptions.bannerCallback = [](int selected) -> void { + if (selected == 1 || selected == 2) { + InputEvent event = {.inputEvent = (input_broker_event)170, .kbchar = 170, .touchX = 0, .touchY = 0}; + inputBroker->injectInputEvent(&event); + } + }; + bannerOptions.InitialSelected = config.bluetooth.enabled ? 1 : 2; + screen->showOverlayBanner(bannerOptions); +} + +void menuHandler::BuzzerModeMenu() +{ + static const char *optionsArray[] = {"All Enabled", "Disabled", "Notifications", "System Only"}; + BannerOverlayOptions bannerOptions; + bannerOptions.message = "Buzzer Mode"; + bannerOptions.optionsArrayPtr = optionsArray; + bannerOptions.optionsCount = 4; + bannerOptions.bannerCallback = [](int selected) -> void { + config.device.buzzer_mode = (meshtastic_Config_DeviceConfig_BuzzerMode)selected; + service->reloadConfig(SEGMENT_CONFIG); + }; + bannerOptions.InitialSelected = config.device.buzzer_mode; + screen->showOverlayBanner(bannerOptions); +} + +void menuHandler::BrightnessPickerMenu() +{ + static const char *optionsArray[] = {"Back", "Low", "Medium", "High"}; + + // Get current brightness level to set initial selection + int currentSelection = 1; // Default to Medium + if (uiconfig.screen_brightness >= 255) { + currentSelection = 3; // Very High + } else if (uiconfig.screen_brightness >= 128) { + currentSelection = 2; // High + } else { + currentSelection = 1; // Medium + } + + BannerOverlayOptions bannerOptions; + bannerOptions.message = "Brightness"; + bannerOptions.optionsArrayPtr = optionsArray; + bannerOptions.optionsCount = 4; + bannerOptions.bannerCallback = [](int selected) -> void { + if (selected == 1) { // Medium + uiconfig.screen_brightness = 64; + } else if (selected == 2) { // High + uiconfig.screen_brightness = 128; + } else if (selected == 3) { // Very High + uiconfig.screen_brightness = 255; + } + + if (selected != 0) { // Not "Back" + // Apply brightness immediately +#if defined(HELTEC_MESH_NODE_T114) || defined(HELTEC_VISION_MASTER_T190) + // For HELTEC devices, use analogWrite to control backlight + analogWrite(VTFT_LEDA, uiconfig.screen_brightness); +#elif defined(ST7789_CS) + static_cast(screen->getDisplayDevice())->setDisplayBrightness(uiconfig.screen_brightness); +#elif defined(USE_OLED) || defined(USE_SSD1306) || defined(USE_SH1106) || defined(USE_SH1107) + screen->getDisplayDevice()->setBrightness(uiconfig.screen_brightness); +#endif + + // Save to device + saveUIConfig(); + + LOG_INFO("Screen brightness set to %d", uiconfig.screen_brightness); + } + }; + bannerOptions.InitialSelected = currentSelection; + screen->showOverlayBanner(bannerOptions); +} + +void menuHandler::switchToMUIMenu() +{ + static const char *optionsArray[] = {"No", "Yes"}; + BannerOverlayOptions bannerOptions; + bannerOptions.message = "Switch to MUI?"; + bannerOptions.optionsArrayPtr = optionsArray; + bannerOptions.optionsCount = 2; + bannerOptions.bannerCallback = [](int selected) -> void { + if (selected == 1) { + config.display.displaymode = meshtastic_Config_DisplayConfig_DisplayMode_COLOR; + config.bluetooth.enabled = false; + service->reloadConfig(SEGMENT_CONFIG); + rebootAtMsec = (millis() + DEFAULT_REBOOT_SECONDS * 1000); + } + }; + screen->showOverlayBanner(bannerOptions); +} + +void menuHandler::TFTColorPickerMenu(OLEDDisplay *display) +{ + static const char *optionsArray[] = {"Back", "Default", "Meshtastic Green", "Yellow", "Red", "Orange", "Purple", "Teal", + "Pink", "White"}; + BannerOverlayOptions bannerOptions; + bannerOptions.message = "Select Screen Color"; + bannerOptions.optionsArrayPtr = optionsArray; + bannerOptions.optionsCount = 10; + bannerOptions.bannerCallback = [display](int selected) -> void { + uint8_t TFT_MESH_r = 0; + uint8_t TFT_MESH_g = 0; + uint8_t TFT_MESH_b = 0; + if (selected == 1) { + LOG_INFO("Setting color to system default or defined variant"); + // Given just before we set all these to zero, we will allow this to go through + } else if (selected == 2) { + LOG_INFO("Setting color to Meshtastic Green"); + TFT_MESH_r = 103; + TFT_MESH_g = 234; + TFT_MESH_b = 148; + } else if (selected == 3) { + LOG_INFO("Setting color to Yellow"); + TFT_MESH_r = 255; + TFT_MESH_g = 255; + TFT_MESH_b = 128; + } else if (selected == 4) { + LOG_INFO("Setting color to Red"); + TFT_MESH_r = 255; + TFT_MESH_g = 64; + TFT_MESH_b = 64; + } else if (selected == 5) { + LOG_INFO("Setting color to Orange"); + TFT_MESH_r = 255; + TFT_MESH_g = 160; + TFT_MESH_b = 20; + } else if (selected == 6) { + LOG_INFO("Setting color to Purple"); + TFT_MESH_r = 204; + TFT_MESH_g = 153; + TFT_MESH_b = 255; + } else if (selected == 7) { + LOG_INFO("Setting color to Teal"); + TFT_MESH_r = 64; + TFT_MESH_g = 224; + TFT_MESH_b = 208; + } else if (selected == 8) { + LOG_INFO("Setting color to Pink"); + TFT_MESH_r = 255; + TFT_MESH_g = 105; + TFT_MESH_b = 180; + } else if (selected == 9) { + LOG_INFO("Setting color to White"); + TFT_MESH_r = 255; + TFT_MESH_g = 255; + TFT_MESH_b = 255; + } else { + menuQueue = system_base_menu; + screen->runNow(); + } + +#if defined(HELTEC_MESH_NODE_T114) || defined(HELTEC_VISION_MASTER_T190) || HAS_TFT + if (selected != 0) { + display->setColor(BLACK); + display->fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); + display->setColor(WHITE); + + if (TFT_MESH_r == 0 && TFT_MESH_g == 0 && TFT_MESH_b == 0) { +#ifdef TFT_MESH_OVERRIDE + TFT_MESH = TFT_MESH_OVERRIDE; +#else + TFT_MESH = COLOR565(0x67, 0xEA, 0x94); +#endif + } else { + TFT_MESH = COLOR565(TFT_MESH_r, TFT_MESH_g, TFT_MESH_b); + } + +#if defined(HELTEC_MESH_NODE_T114) || defined(HELTEC_VISION_MASTER_T190) + static_cast(screen->getDisplayDevice())->setRGB(TFT_MESH); +#endif + + screen->setFrames(graphics::Screen::FOCUS_SYSTEM); + if (TFT_MESH_r == 0 && TFT_MESH_g == 0 && TFT_MESH_b == 0) { + uiconfig.screen_rgb_color = 0; + } else { + uiconfig.screen_rgb_color = (TFT_MESH_r << 16) | (TFT_MESH_g << 8) | TFT_MESH_b; + } + LOG_INFO("Storing Value of %d to uiconfig.screen_rgb_color", uiconfig.screen_rgb_color); + saveUIConfig(); + } +#endif + }; + screen->showOverlayBanner(bannerOptions); +} + +void menuHandler::rebootMenu() +{ + static const char *optionsArray[] = {"Back", "Confirm"}; + BannerOverlayOptions bannerOptions; + bannerOptions.message = "Reboot Device?"; + bannerOptions.optionsArrayPtr = optionsArray; + bannerOptions.optionsCount = 2; + bannerOptions.bannerCallback = [](int selected) -> void { + if (selected == 1) { + IF_SCREEN(screen->showSimpleBanner("Rebooting...", 0)); + nodeDB->saveToDisk(); + rebootAtMsec = millis() + DEFAULT_REBOOT_SECONDS * 1000; + } else { + menuQueue = power_menu; + screen->runNow(); + } + }; + screen->showOverlayBanner(bannerOptions); +} + +void menuHandler::shutdownMenu() +{ + static const char *optionsArray[] = {"Back", "Confirm"}; + BannerOverlayOptions bannerOptions; + bannerOptions.message = "Shutdown Device?"; + bannerOptions.optionsArrayPtr = optionsArray; + bannerOptions.optionsCount = 2; + bannerOptions.bannerCallback = [](int selected) -> void { + if (selected == 1) { + IF_SCREEN(screen->showSimpleBanner("Shutting Down...", 0)); + nodeDB->saveToDisk(); + power->shutdown(); + } else { + menuQueue = power_menu; + screen->runNow(); + } + }; + screen->showOverlayBanner(bannerOptions); +} + +void menuHandler::addFavoriteMenu() +{ + screen->showNodePicker("Node To Favorite", 30000, [](uint32_t nodenum) -> void { + LOG_WARN("Nodenum: %u", nodenum); + nodeDB->set_favorite(true, nodenum); + screen->setFrames(graphics::Screen::FOCUS_PRESERVE); + }); +} + +void menuHandler::removeFavoriteMenu() +{ + + static const char *optionsArray[] = {"Back", "Yes"}; + BannerOverlayOptions bannerOptions; + std::string message = "Unfavorite This Node?\n"; + auto node = nodeDB->getMeshNode(graphics::UIRenderer::currentFavoriteNodeNum); + if (node && node->has_user) { + message += sanitizeString(node->user.long_name).substr(0, 15); + } + bannerOptions.message = message.c_str(); + bannerOptions.optionsArrayPtr = optionsArray; + bannerOptions.optionsCount = 2; + bannerOptions.bannerCallback = [](int selected) -> void { + if (selected == 1) { + nodeDB->set_favorite(false, graphics::UIRenderer::currentFavoriteNodeNum); + screen->setFrames(graphics::Screen::FOCUS_PRESERVE); + } + }; + screen->showOverlayBanner(bannerOptions); +} + +void menuHandler::testMenu() +{ + + static const char *optionsArray[] = {"Back", "Number Picker"}; + BannerOverlayOptions bannerOptions; + std::string message = "Test to Run?\n"; + bannerOptions.message = message.c_str(); + bannerOptions.optionsArrayPtr = optionsArray; + bannerOptions.optionsCount = 2; + bannerOptions.bannerCallback = [](int selected) -> void { + if (selected == 1) { + menuQueue = number_test; + screen->runNow(); + } + }; + screen->showOverlayBanner(bannerOptions); +} + +void menuHandler::numberTest() +{ + screen->showNumberPicker("Pick a number\n ", 30000, 4, + [](int number_picked) -> void { LOG_WARN("Nodenum: %u", number_picked); }); +} + +void menuHandler::wifiBaseMenu() +{ + enum optionsNumbers { Back, Wifi_toggle }; + + static const char *optionsArray[] = {"Back", "WiFi Toggle"}; + BannerOverlayOptions bannerOptions; + bannerOptions.message = "WiFi Menu"; + bannerOptions.optionsArrayPtr = optionsArray; + bannerOptions.optionsCount = 2; + bannerOptions.bannerCallback = [](int selected) -> void { + if (selected == Wifi_toggle) { + menuQueue = wifi_toggle_menu; + screen->runNow(); + } + }; + screen->showOverlayBanner(bannerOptions); +} + +void menuHandler::wifiToggleMenu() +{ + enum optionsNumbers { Back, Wifi_toggle }; + + static const char *optionsArray[] = {"Back", "Disable"}; + BannerOverlayOptions bannerOptions; + bannerOptions.message = "Disable Wifi and\nEnable Bluetooth?"; + bannerOptions.optionsArrayPtr = optionsArray; + bannerOptions.optionsCount = 2; + bannerOptions.bannerCallback = [](int selected) -> void { + if (selected == Wifi_toggle) { + config.network.wifi_enabled = false; + config.bluetooth.enabled = true; + service->reloadConfig(SEGMENT_CONFIG); + rebootAtMsec = (millis() + DEFAULT_REBOOT_SECONDS * 1000); + } + }; + screen->showOverlayBanner(bannerOptions); +} + +void menuHandler::notificationsMenu() +{ + enum optionsNumbers { Back, BuzzerActions }; + static const char *optionsArray[] = {"Back", "Buzzer Actions"}; + static int optionsEnumArray[] = {Back, BuzzerActions}; + int options = 2; + + BannerOverlayOptions bannerOptions; + bannerOptions.message = "Notifications"; + bannerOptions.optionsArrayPtr = optionsArray; + bannerOptions.optionsCount = options; + bannerOptions.optionsEnumPtr = optionsEnumArray; + bannerOptions.bannerCallback = [](int selected) -> void { + if (selected == BuzzerActions) { + menuHandler::menuQueue = menuHandler::buzzermodemenupicker; + screen->runNow(); + } else { + menuQueue = system_base_menu; + screen->runNow(); + } + }; + screen->showOverlayBanner(bannerOptions); +} + +void menuHandler::screenOptionsMenu() +{ + // Check if brightness is supported + bool hasSupportBrightness = false; +#if defined(ST7789_CS) || defined(USE_OLED) || defined(USE_SSD1306) || defined(USE_SH1106) || defined(USE_SH1107) || HAS_TFT + hasSupportBrightness = true; +#endif + + enum optionsNumbers { Back, Brightness, ScreenColor }; + static const char *optionsArray[4] = {"Back"}; + static int optionsEnumArray[4] = {Back}; + int options = 1; + + // Only show brightness for B&W displays + if (hasSupportBrightness && !HAS_TFT) { + optionsArray[options] = "Brightness"; + optionsEnumArray[options++] = Brightness; + } + + // Only show screen color for TFT displays +#if defined(HELTEC_MESH_NODE_T114) || defined(HELTEC_VISION_MASTER_T190) || HAS_TFT + optionsArray[options] = "Screen Color"; + optionsEnumArray[options++] = ScreenColor; +#endif + + BannerOverlayOptions bannerOptions; + bannerOptions.message = "Screen Options"; + bannerOptions.optionsArrayPtr = optionsArray; + bannerOptions.optionsCount = options; + bannerOptions.optionsEnumPtr = optionsEnumArray; + bannerOptions.bannerCallback = [](int selected) -> void { + if (selected == Brightness) { + menuHandler::menuQueue = menuHandler::brightness_picker; + screen->runNow(); + } else if (selected == ScreenColor) { + menuHandler::menuQueue = menuHandler::tftcolormenupicker; + screen->runNow(); + } else { + menuQueue = system_base_menu; + screen->runNow(); + } + }; + screen->showOverlayBanner(bannerOptions); +} + +void menuHandler::powerMenu() +{ + + enum optionsNumbers { Back, Reboot, Shutdown, MUI }; + static const char *optionsArray[4] = {"Back"}; + static int optionsEnumArray[4] = {Back}; + int options = 1; + + optionsArray[options] = "Reboot"; + optionsEnumArray[options++] = Reboot; + + optionsArray[options] = "Shutdown"; + optionsEnumArray[options++] = Shutdown; + +#if HAS_TFT + optionsArray[options] = "Switch to MUI"; + optionsEnumArray[options++] = MUI; +#endif + + BannerOverlayOptions bannerOptions; + bannerOptions.message = "Reboot / Shutdown"; + bannerOptions.optionsArrayPtr = optionsArray; + bannerOptions.optionsCount = options; + bannerOptions.optionsEnumPtr = optionsEnumArray; + bannerOptions.bannerCallback = [](int selected) -> void { + if (selected == Reboot) { + menuHandler::menuQueue = menuHandler::reboot_menu; + screen->runNow(); + } else if (selected == Shutdown) { + menuHandler::menuQueue = menuHandler::shutdown_menu; + screen->runNow(); + } else if (selected == MUI) { + menuHandler::menuQueue = menuHandler::mui_picker; + screen->runNow(); + } else { + menuQueue = system_base_menu; + screen->runNow(); + } + }; + screen->showOverlayBanner(bannerOptions); +} + +void menuHandler::keyVerificationInitMenu() +{ + screen->showNodePicker("Node to Verify", 30000, + [](uint32_t selected) -> void { keyVerificationModule->sendInitialRequest(selected); }); +} + +void menuHandler::keyVerificationFinalPrompt() +{ + char message[40] = {0}; + memset(message, 0, sizeof(message)); + sprintf(message, "Verification: \n"); + keyVerificationModule->generateVerificationCode(message + 15); // send the toPhone packet + + if (screen) { + static const char *optionsArray[] = {"Reject", "Accept"}; + graphics::BannerOverlayOptions options; + options.message = message; + options.durationMs = 30000; + options.optionsArrayPtr = optionsArray; + options.optionsCount = 2; + options.notificationType = graphics::notificationTypeEnum::selection_picker; + options.bannerCallback = [=](int selected) { + if (selected == 1) { + auto remoteNodePtr = nodeDB->getMeshNode(keyVerificationModule->getCurrentRemoteNode()); + remoteNodePtr->bitfield |= NODEINFO_BITFIELD_IS_KEY_MANUALLY_VERIFIED_MASK; + } + }; + screen->showOverlayBanner(options); + } +} + +void menuHandler::handleMenuSwitch(OLEDDisplay *display) +{ + if (menuQueue != menu_none) + test_count = 0; + switch (menuQueue) { + case menu_none: + break; + case lora_picker: + LoraRegionPicker(); + break; + case TZ_picker: + TZPicker(); + break; + case twelve_hour_picker: + TwelveHourPicker(); + break; + case clock_face_picker: + ClockFacePicker(); + break; + case clock_menu: + clockMenu(); + break; + case system_base_menu: + systemBaseMenu(); + break; + case position_base_menu: + positionBaseMenu(); + break; +#if !MESHTASTIC_EXCLUDE_GPS + case gps_toggle_menu: + GPSToggleMenu(); + break; +#endif + case compass_point_north_menu: + compassNorthMenu(); + break; + case reset_node_db_menu: + resetNodeDBMenu(); + break; + case buzzermodemenupicker: + BuzzerModeMenu(); + break; + case mui_picker: + switchToMUIMenu(); + break; + case tftcolormenupicker: + TFTColorPickerMenu(display); + break; + case brightness_picker: + BrightnessPickerMenu(); + break; + case reboot_menu: + rebootMenu(); + break; + case shutdown_menu: + shutdownMenu(); + break; + case add_favorite: + addFavoriteMenu(); + break; + case remove_favorite: + removeFavoriteMenu(); + break; + case test_menu: + testMenu(); + break; + case number_test: + numberTest(); + break; + case wifi_toggle_menu: + wifiToggleMenu(); + break; + case key_verification_init: + keyVerificationInitMenu(); + break; + case key_verification_final_prompt: + keyVerificationFinalPrompt(); + break; + case bluetooth_toggle_menu: + BluetoothToggleMenu(); + break; + case notifications_menu: + notificationsMenu(); + break; + case screen_options_menu: + screenOptionsMenu(); + break; + case power_menu: + powerMenu(); + break; + case throttle_message: + screen->showSimpleBanner("Too Many Attempts\nTry again in 60 seconds.", 5000); + break; + } + menuQueue = menu_none; +} + +void menuHandler::saveUIConfig() +{ + nodeDB->saveProto("/prefs/uiconfig.proto", meshtastic_DeviceUIConfig_size, &meshtastic_DeviceUIConfig_msg, &uiconfig); +} + +} // namespace graphics + +#endif \ No newline at end of file diff --git a/src/graphics/draw/MenuHandler.h b/src/graphics/draw/MenuHandler.h new file mode 100644 index 000000000..2273dbbed --- /dev/null +++ b/src/graphics/draw/MenuHandler.h @@ -0,0 +1,82 @@ +#pragma once +#if HAS_SCREEN +#include "configuration.h" +namespace graphics +{ + +class menuHandler +{ + public: + enum screenMenus { + menu_none, + lora_picker, + TZ_picker, + twelve_hour_picker, + clock_face_picker, + clock_menu, + position_base_menu, + gps_toggle_menu, + compass_point_north_menu, + reset_node_db_menu, + buzzermodemenupicker, + mui_picker, + tftcolormenupicker, + brightness_picker, + reboot_menu, + shutdown_menu, + add_favorite, + remove_favorite, + test_menu, + number_test, + wifi_toggle_menu, + bluetooth_toggle_menu, + notifications_menu, + screen_options_menu, + power_menu, + system_base_menu, + key_verification_init, + key_verification_final_prompt, + throttle_message + }; + static screenMenus menuQueue; + + static void LoraRegionPicker(uint32_t duration = 30000); + static void handleMenuSwitch(OLEDDisplay *display); + static void clockMenu(); + static void TZPicker(); + static void TwelveHourPicker(); + static void ClockFacePicker(); + static void messageResponseMenu(); + static void homeBaseMenu(); + static void systemBaseMenu(); + static void favoriteBaseMenu(); + static void positionBaseMenu(); + static void compassNorthMenu(); + static void GPSToggleMenu(); + static void BuzzerModeMenu(); + static void switchToMUIMenu(); + static void TFTColorPickerMenu(OLEDDisplay *display); + static void nodeListMenu(); + static void resetNodeDBMenu(); + static void BrightnessPickerMenu(); + static void rebootMenu(); + static void shutdownMenu(); + static void addFavoriteMenu(); + static void removeFavoriteMenu(); + static void testMenu(); + static void numberTest(); + static void wifiBaseMenu(); + static void wifiToggleMenu(); + static void notificationsMenu(); + static void screenOptionsMenu(); + static void powerMenu(); + + private: + static void saveUIConfig(); + static void keyVerificationInitMenu(); + static void keyVerificationFinalPrompt(); + static void BluetoothToggleMenu(); +}; + +} // namespace graphics +#endif \ No newline at end of file diff --git a/src/graphics/draw/MessageRenderer.cpp b/src/graphics/draw/MessageRenderer.cpp index 707517d82..3df8a003c 100644 --- a/src/graphics/draw/MessageRenderer.cpp +++ b/src/graphics/draw/MessageRenderer.cpp @@ -56,6 +56,11 @@ namespace graphics namespace MessageRenderer { +// Simple cache based on text hash +static size_t cachedKey = 0; +static std::vector cachedLines; +static std::vector cachedHeights; + void drawStringWithEmotes(OLEDDisplay *display, int x, int y, const std::string &line, const Emote *emotes, int emoteCount) { int cursorX = x; @@ -225,6 +230,7 @@ void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16 sender); } + uint32_t now = millis(); #ifndef EXCLUDE_EMOJI // === Bounce animation setup === static uint32_t lastBounceTime = 0; @@ -232,7 +238,6 @@ void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16 const int bounceRange = 2; // Max pixels to bounce up/down const int bounceInterval = 10; // How quickly to change bounce direction (ms) - uint32_t now = millis(); if (now - lastBounceTime >= bounceInterval) { lastBounceTime = now; bounceY = (bounceY + 1) % (bounceRange * 2); @@ -246,82 +251,51 @@ void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16 display->drawString(x + 4, headerY, headerStr); // Draw separator (same as scroll version) - for (int separatorX = 0; separatorX <= (display->getStringWidth(headerStr) + 3); separatorX += 2) { - display->setPixel(separatorX, headerY + ((SCREEN_WIDTH > 128) ? 19 : 13)); + for (int separatorX = 1; separatorX <= (display->getStringWidth(headerStr) + 2); separatorX += 2) { + display->setPixel(separatorX, headerY + ((isHighResolution) ? 19 : 13)); } // Center the emote below the header line + separator + nav int remainingHeight = SCREEN_HEIGHT - (headerY + FONT_HEIGHT_SMALL) - navHeight; - int emoteY = headerY + FONT_HEIGHT_SMALL + (remainingHeight - e.height) / 2 + bounceY - bounceRange; + int emoteY = headerY + 6 + FONT_HEIGHT_SMALL + (remainingHeight - e.height) / 2 + bounceY - bounceRange; display->drawXbm((SCREEN_WIDTH - e.width) / 2, emoteY, e.width, e.height, e.bitmap); + + // Draw header at the end to sort out overlapping elements + graphics::drawCommonHeader(display, x, y, titleStr); return; } } #endif + // === Generate the cache key === + size_t currentKey = (size_t)mp.from; + currentKey ^= ((size_t)mp.to << 8); + currentKey ^= ((size_t)mp.rx_time << 16); + currentKey ^= ((size_t)mp.id << 24); - // === Word-wrap and build line list === - std::vector lines; - lines.push_back(std::string(headerStr)); // Header line is always first + if (cachedKey != currentKey) { + LOG_INFO("Message cache key is misssed cachedKey=0x%0x, currentKey=0x%x", cachedKey, currentKey); - std::string line, word; - for (int i = 0; messageBuf[i]; ++i) { - char ch = messageBuf[i]; - if (ch == '\n') { - if (!word.empty()) - line += word; - if (!line.empty()) - lines.push_back(line); - line.clear(); - word.clear(); - } else if (ch == ' ') { - line += word + ' '; - word.clear(); - } else { - word += ch; - std::string test = line + word; - if (display->getStringWidth(test.c_str()) > textWidth) { - if (!line.empty()) - lines.push_back(line); - line = word; - word.clear(); - } - } + // Cache miss - regenerate lines and heights + cachedLines = generateLines(display, headerStr, messageBuf, textWidth); + cachedHeights = calculateLineHeights(cachedLines, emotes); + cachedKey = currentKey; + } else { + // Cache hit but update the header line with current time information + cachedLines[0] = std::string(headerStr); + // The header always has a fixed height since it doesn't contain emotes + // As per calculateLineHeights logic for lines without emotes: + cachedHeights[0] = FONT_HEIGHT_SMALL - 2; + if (cachedHeights[0] < 8) + cachedHeights[0] = 8; // minimum safety } - if (!word.empty()) - line += word; - if (!line.empty()) - lines.push_back(line); // === Scrolling logic === - std::vector rowHeights; - - for (const auto &_line : lines) { - int lineHeight = FONT_HEIGHT_SMALL; - bool hasEmote = false; - - for (int i = 0; i < numEmotes; ++i) { - const Emote &e = emotes[i]; - if (_line.find(e.label) != std::string::npos) { - lineHeight = std::max(lineHeight, e.height); - hasEmote = true; - } - } - - // Apply tighter spacing if no emotes on this line - if (!hasEmote) { - lineHeight -= 2; // reduce by 2px for tighter spacing - if (lineHeight < 8) - lineHeight = 8; // minimum safety - } - - rowHeights.push_back(lineHeight); - } int totalHeight = 0; - for (size_t i = 1; i < rowHeights.size(); ++i) { - totalHeight += rowHeights[i]; + for (size_t i = 1; i < cachedHeights.size(); ++i) { + totalHeight += cachedHeights[i]; } - int usableScrollHeight = usableHeight - rowHeights[0]; // remove header height - int scrollStop = std::max(0, totalHeight - usableScrollHeight + rowHeights.back()); + int usableScrollHeight = usableHeight - cachedHeights[0]; // remove header height + int scrollStop = std::max(0, totalHeight - usableScrollHeight + cachedHeights.back()); static float scrollY = 0.0f; static uint32_t lastTime = 0, scrollStartDelay = 0, pauseStart = 0; @@ -363,28 +337,109 @@ void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16 int scrollOffset = static_cast(scrollY); int yOffset = -scrollOffset + getTextPositions(display)[1]; - for (int separatorX = 0; separatorX <= (display->getStringWidth(headerStr) + 3); separatorX += 2) { - display->setPixel(separatorX, yOffset + ((SCREEN_WIDTH > 128) ? 19 : 13)); + for (int separatorX = 1; separatorX <= (display->getStringWidth(headerStr) + 2); separatorX += 2) { + display->setPixel(separatorX, yOffset + ((isHighResolution) ? 19 : 13)); } // === Render visible lines === + renderMessageContent(display, cachedLines, cachedHeights, x, yOffset, scrollBottom, emotes, numEmotes, isInverted, isBold); + + // Draw header at the end to sort out overlapping elements + graphics::drawCommonHeader(display, x, y, titleStr); +} + +std::vector generateLines(OLEDDisplay *display, const char *headerStr, const char *messageBuf, int textWidth) +{ + std::vector lines; + lines.push_back(std::string(headerStr)); // Header line is always first + + std::string line, word; + for (int i = 0; messageBuf[i]; ++i) { + char ch = messageBuf[i]; + if ((unsigned char)messageBuf[i] == 0xE2 && (unsigned char)messageBuf[i + 1] == 0x80 && + (unsigned char)messageBuf[i + 2] == 0x99) { + ch = '\''; // plain apostrophe + i += 2; // skip over the extra UTF-8 bytes + } + if (ch == '\n') { + if (!word.empty()) + line += word; + if (!line.empty()) + lines.push_back(line); + line.clear(); + word.clear(); + } else if (ch == ' ') { + line += word + ' '; + word.clear(); + } else { + word += ch; + std::string test = line + word; + // Keep these lines for diagnostics + // LOG_INFO("Char: '%c' (0x%02X)", ch, (unsigned char)ch); + // LOG_INFO("Current String: %s", test.c_str()); + if (display->getStringWidth(test.c_str()) > textWidth) { + if (!line.empty()) + lines.push_back(line); + line = word; + word.clear(); + } + } + } + + if (!word.empty()) + line += word; + if (!line.empty()) + lines.push_back(line); + + return lines; +} + +std::vector calculateLineHeights(const std::vector &lines, const Emote *emotes) +{ + std::vector rowHeights; + + for (const auto &_line : lines) { + int lineHeight = FONT_HEIGHT_SMALL; + bool hasEmote = false; + + for (int i = 0; i < numEmotes; ++i) { + const Emote &e = emotes[i]; + if (_line.find(e.label) != std::string::npos) { + lineHeight = std::max(lineHeight, e.height); + hasEmote = true; + } + } + + // Apply tighter spacing if no emotes on this line + if (!hasEmote) { + lineHeight -= 2; // reduce by 2px for tighter spacing + if (lineHeight < 8) + lineHeight = 8; // minimum safety + } + + rowHeights.push_back(lineHeight); + } + + return rowHeights; +} + +void renderMessageContent(OLEDDisplay *display, const std::vector &lines, const std::vector &rowHeights, int x, + int yOffset, int scrollBottom, const Emote *emotes, int numEmotes, bool isInverted, bool isBold) +{ for (size_t i = 0; i < lines.size(); ++i) { int lineY = yOffset; for (size_t j = 0; j < i; ++j) lineY += rowHeights[j]; if (lineY > -rowHeights[i] && lineY < scrollBottom) { if (i == 0 && isInverted) { - display->drawString(x + 3, lineY, lines[i].c_str()); + display->drawString(x, lineY, lines[i].c_str()); if (isBold) - display->drawString(x + 4, lineY, lines[i].c_str()); + display->drawString(x, lineY, lines[i].c_str()); } else { drawStringWithEmotes(display, x, lineY, lines[i], emotes, numEmotes); } } } - - // Draw header at the end to sort out overlapping elements - graphics::drawCommonHeader(display, x, y, titleStr); } } // namespace MessageRenderer diff --git a/src/graphics/draw/MessageRenderer.h b/src/graphics/draw/MessageRenderer.h index d92b96014..c15a699f7 100644 --- a/src/graphics/draw/MessageRenderer.h +++ b/src/graphics/draw/MessageRenderer.h @@ -2,6 +2,8 @@ #include "OLEDDisplay.h" #include "OLEDDisplayUi.h" #include "graphics/emotes.h" +#include +#include namespace graphics { @@ -14,5 +16,15 @@ void drawStringWithEmotes(OLEDDisplay *display, int x, int y, const std::string /// Draws the text message frame for displaying received messages void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y); +// Function to generate lines with word wrapping +std::vector generateLines(OLEDDisplay *display, const char *headerStr, const char *messageBuf, int textWidth); + +// Function to calculate heights for each line +std::vector calculateLineHeights(const std::vector &lines, const Emote *emotes); + +// Function to render the message content +void renderMessageContent(OLEDDisplay *display, const std::vector &lines, const std::vector &rowHeights, int x, + int yOffset, int scrollBottom, const Emote *emotes, int numEmotes, bool isInverted, bool isBold); + } // namespace MessageRenderer } // namespace graphics diff --git a/src/graphics/draw/NodeListRenderer.cpp b/src/graphics/draw/NodeListRenderer.cpp index 13b71546e..d8746fb69 100644 --- a/src/graphics/draw/NodeListRenderer.cpp +++ b/src/graphics/draw/NodeListRenderer.cpp @@ -66,10 +66,10 @@ const char *getSafeNodeName(meshtastic_NodeInfoLite *node) strncpy(nodeName, name, sizeof(nodeName) - 1); nodeName[sizeof(nodeName) - 1] = '\0'; } else { - snprintf(nodeName, sizeof(nodeName), "%04X", (uint16_t)(node->num & 0xFFFF)); + snprintf(nodeName, sizeof(nodeName), "(%04X)", (uint16_t)(node->num & 0xFFFF)); } } else { - strcpy(nodeName, "?"); + snprintf(nodeName, sizeof(nodeName), "(%04X)", (uint16_t)(node->num & 0xFFFF)); } return nodeName; } @@ -80,7 +80,11 @@ const char *getCurrentModeTitle(int screenWidth) case MODE_LAST_HEARD: return "Last Heard"; case MODE_HOP_SIGNAL: - return (screenWidth > 128) ? "Hops/Signal" : "Hops/Sig"; +#ifdef USE_EINK + return "Hops/Sig"; +#else + return (isHighResolution) ? "Hops/Signal" : "Hops/Sig"; +#endif case MODE_DISTANCE: return "Distance"; default: @@ -94,50 +98,11 @@ unsigned long getModeCycleIntervalMs() return 3000; } -// Calculate bearing between two lat/lon points -float calculateBearing(double lat1, double lon1, double lat2, double lon2) -{ - double dLon = (lon2 - lon1) * DEG_TO_RAD; - double y = sin(dLon) * cos(lat2 * DEG_TO_RAD); - double x = cos(lat1 * DEG_TO_RAD) * sin(lat2 * DEG_TO_RAD) - sin(lat1 * DEG_TO_RAD) * cos(lat2 * DEG_TO_RAD) * cos(dLon); - double bearing = atan2(y, x) * RAD_TO_DEG; - return fmod(bearing + 360.0, 360.0); -} - int calculateMaxScroll(int totalEntries, int visibleRows) { return std::max(0, (totalEntries - 1) / (visibleRows * 2)); } -void retrieveAndSortNodes(std::vector &nodeList) -{ - size_t numNodes = nodeDB->getNumMeshNodes(); - for (size_t i = 0; i < numNodes; i++) { - meshtastic_NodeInfoLite *node = nodeDB->getMeshNodeByIndex(i); - if (!node || node->num == nodeDB->getNodeNum()) - continue; - - NodeEntry entry; - entry.node = node; - entry.sortValue = sinceLastSeen(node); - - nodeList.push_back(entry); - } - - // Sort nodes: favorites first, then by last heard (most recent first) - std::sort(nodeList.begin(), nodeList.end(), [](const NodeEntry &a, const NodeEntry &b) { - bool aFav = a.node->is_favorite; - bool bFav = b.node->is_favorite; - if (aFav != bFav) - return aFav; - if (a.sortValue == 0 || a.sortValue == UINT32_MAX) - return false; - if (b.sortValue == 0 || b.sortValue == UINT32_MAX) - return true; - return a.sortValue < b.sortValue; - }); -} - void drawColumnSeparator(OLEDDisplay *display, int16_t x, int16_t yStart, int16_t yEnd) { int columnWidth = display->getWidth() / 2; @@ -170,7 +135,7 @@ void drawScrollbar(OLEDDisplay *display, int visibleNodeRows, int totalEntries, void drawEntryLastHeard(OLEDDisplay *display, meshtastic_NodeInfoLite *node, int16_t x, int16_t y, int columnWidth) { bool isLeftCol = (x < SCREEN_WIDTH / 2); - int timeOffset = (SCREEN_WIDTH > 128) ? (isLeftCol ? 7 : 10) : (isLeftCol ? 3 : 7); + int timeOffset = (isHighResolution) ? (isLeftCol ? 7 : 10) : (isLeftCol ? 3 : 7); const char *nodeName = getSafeNodeName(node); @@ -191,9 +156,9 @@ void drawEntryLastHeard(OLEDDisplay *display, meshtastic_NodeInfoLite *node, int display->setTextAlignment(TEXT_ALIGN_LEFT); display->setFont(FONT_SMALL); - display->drawString(x + ((SCREEN_WIDTH > 128) ? 6 : 3), y, nodeName); + display->drawString(x + ((isHighResolution) ? 6 : 3), y, nodeName); if (node->is_favorite) { - if (SCREEN_WIDTH > 128) { + if (isHighResolution) { drawScaledXBitmap16x16(x, y + 6, smallbulletpoint_width, smallbulletpoint_height, smallbulletpoint, display); } else { display->drawXbm(x, y + 5, smallbulletpoint_width, smallbulletpoint_height, smallbulletpoint); @@ -212,8 +177,8 @@ void drawEntryHopSignal(OLEDDisplay *display, meshtastic_NodeInfoLite *node, int bool isLeftCol = (x < SCREEN_WIDTH / 2); int nameMaxWidth = columnWidth - 25; - int barsOffset = (SCREEN_WIDTH > 128) ? (isLeftCol ? 20 : 24) : (isLeftCol ? 15 : 19); - int hopOffset = (SCREEN_WIDTH > 128) ? (isLeftCol ? 21 : 29) : (isLeftCol ? 13 : 17); + int barsOffset = (isHighResolution) ? (isLeftCol ? 20 : 24) : (isLeftCol ? 15 : 19); + int hopOffset = (isHighResolution) ? (isLeftCol ? 21 : 29) : (isLeftCol ? 13 : 17); int barsXOffset = columnWidth - barsOffset; @@ -222,9 +187,9 @@ void drawEntryHopSignal(OLEDDisplay *display, meshtastic_NodeInfoLite *node, int display->setTextAlignment(TEXT_ALIGN_LEFT); display->setFont(FONT_SMALL); - display->drawStringMaxWidth(x + ((SCREEN_WIDTH > 128) ? 6 : 3), y, nameMaxWidth, nodeName); + display->drawStringMaxWidth(x + ((isHighResolution) ? 6 : 3), y, nameMaxWidth, nodeName); if (node->is_favorite) { - if (SCREEN_WIDTH > 128) { + if (isHighResolution) { drawScaledXBitmap16x16(x, y + 6, smallbulletpoint_width, smallbulletpoint_height, smallbulletpoint, display); } else { display->drawXbm(x, y + 5, smallbulletpoint_width, smallbulletpoint_height, smallbulletpoint); @@ -259,7 +224,7 @@ void drawEntryHopSignal(OLEDDisplay *display, meshtastic_NodeInfoLite *node, int void drawNodeDistance(OLEDDisplay *display, meshtastic_NodeInfoLite *node, int16_t x, int16_t y, int columnWidth) { bool isLeftCol = (x < SCREEN_WIDTH / 2); - int nameMaxWidth = columnWidth - (SCREEN_WIDTH > 128 ? (isLeftCol ? 25 : 28) : (isLeftCol ? 20 : 22)); + int nameMaxWidth = columnWidth - (isHighResolution ? (isLeftCol ? 25 : 28) : (isLeftCol ? 20 : 22)); const char *nodeName = getSafeNodeName(node); char distStr[10] = ""; @@ -314,9 +279,9 @@ void drawNodeDistance(OLEDDisplay *display, meshtastic_NodeInfoLite *node, int16 display->setTextAlignment(TEXT_ALIGN_LEFT); display->setFont(FONT_SMALL); - display->drawStringMaxWidth(x + ((SCREEN_WIDTH > 128) ? 6 : 3), y, nameMaxWidth, nodeName); + display->drawStringMaxWidth(x + ((isHighResolution) ? 6 : 3), y, nameMaxWidth, nodeName); if (node->is_favorite) { - if (SCREEN_WIDTH > 128) { + if (isHighResolution) { drawScaledXBitmap16x16(x, y + 6, smallbulletpoint_width, smallbulletpoint_height, smallbulletpoint, display); } else { display->drawXbm(x, y + 5, smallbulletpoint_width, smallbulletpoint_height, smallbulletpoint); @@ -324,8 +289,8 @@ void drawNodeDistance(OLEDDisplay *display, meshtastic_NodeInfoLite *node, int16 } if (strlen(distStr) > 0) { - int offset = (SCREEN_WIDTH > 128) ? (isLeftCol ? 7 : 10) // Offset for Wide Screens (Left Column:Right Column) - : (isLeftCol ? 4 : 7); // Offset for Narrow Screens (Left Column:Right Column) + int offset = (isHighResolution) ? (isLeftCol ? 7 : 10) // Offset for Wide Screens (Left Column:Right Column) + : (isLeftCol ? 4 : 7); // Offset for Narrow Screens (Left Column:Right Column) int rightEdge = x + columnWidth - offset; int textWidth = display->getStringWidth(distStr); display->drawString(rightEdge - textWidth, y, distStr); @@ -354,15 +319,15 @@ void drawEntryCompass(OLEDDisplay *display, meshtastic_NodeInfoLite *node, int16 bool isLeftCol = (x < SCREEN_WIDTH / 2); // Adjust max text width depending on column and screen width - int nameMaxWidth = columnWidth - (SCREEN_WIDTH > 128 ? (isLeftCol ? 25 : 28) : (isLeftCol ? 20 : 22)); + int nameMaxWidth = columnWidth - (isHighResolution ? (isLeftCol ? 25 : 28) : (isLeftCol ? 20 : 22)); const char *nodeName = getSafeNodeName(node); display->setTextAlignment(TEXT_ALIGN_LEFT); display->setFont(FONT_SMALL); - display->drawStringMaxWidth(x + ((SCREEN_WIDTH > 128) ? 6 : 3), y, nameMaxWidth, nodeName); + display->drawStringMaxWidth(x + ((isHighResolution) ? 6 : 3), y, nameMaxWidth, nodeName); if (node->is_favorite) { - if (SCREEN_WIDTH > 128) { + if (isHighResolution) { drawScaledXBitmap16x16(x, y + 6, smallbulletpoint_width, smallbulletpoint_height, smallbulletpoint, display); } else { display->drawXbm(x, y + 5, smallbulletpoint_width, smallbulletpoint_height, smallbulletpoint); @@ -377,19 +342,21 @@ void drawCompassArrow(OLEDDisplay *display, meshtastic_NodeInfoLite *node, int16 return; bool isLeftCol = (x < SCREEN_WIDTH / 2); - int arrowXOffset = (SCREEN_WIDTH > 128) ? (isLeftCol ? 22 : 24) : (isLeftCol ? 12 : 18); + int arrowXOffset = (isHighResolution) ? (isLeftCol ? 22 : 24) : (isLeftCol ? 12 : 18); int centerX = x + columnWidth - arrowXOffset; int centerY = y + FONT_HEIGHT_SMALL / 2; double nodeLat = node->position.latitude_i * 1e-7; double nodeLon = node->position.longitude_i * 1e-7; - float bearingToNode = calculateBearing(userLat, userLon, nodeLat, nodeLon); + float bearing = GeoCoord::bearing(userLat, userLon, nodeLat, nodeLon); + float bearingToNode = RAD_TO_DEG * bearing; float relativeBearing = fmod((bearingToNode - myHeading + 360), 360); float angle = relativeBearing * DEG_TO_RAD; - // Shrink size by 2px int size = FONT_HEIGHT_SMALL - 5; + CompassRenderer::drawArrowToNode(display, centerX, centerY, size, relativeBearing); + /* float halfSize = size / 2.0; // Point of the arrow @@ -414,6 +381,7 @@ void drawCompassArrow(OLEDDisplay *display, meshtastic_NodeInfoLite *node, int16 // Draw the chevron-style arrowhead display->fillTriangle(tipX, tipY, leftX, leftY, notchX, notchY); display->fillTriangle(tipX, tipY, notchX, notchY, rightX, rightY); + */ } // ============================= @@ -436,19 +404,16 @@ void drawNodeListScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t // Space below header y += COMMON_HEADER_HEIGHT; - // Fetch and display sorted node list - std::vector nodeList; - retrieveAndSortNodes(nodeList); - - int totalEntries = nodeList.size(); + int totalEntries = nodeDB->getNumMeshNodes(); int totalRowsAvailable = (display->getHeight() - y) / rowYOffset; -#ifdef USE_EINK - totalRowsAvailable -= 1; -#endif + int visibleNodeRows = totalRowsAvailable; int totalColumns = 2; int startIndex = scrollIndex * visibleNodeRows * totalColumns; + if (nodeDB->getMeshNodeByIndex(startIndex)->num == nodeDB->getNodeNum()) { + startIndex++; // skip own node + } int endIndex = std::min(startIndex + visibleNodeRows * totalColumns, totalEntries); int yOffset = 0; @@ -460,10 +425,10 @@ void drawNodeListScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t for (int i = startIndex; i < endIndex; ++i) { int xPos = x + (col * columnWidth); int yPos = y + yOffset; - renderer(display, nodeList[i].node, xPos, yPos, columnWidth); + renderer(display, nodeDB->getMeshNodeByIndex(i), xPos, yPos, columnWidth); if (extras) { - extras(display, nodeList[i].node, xPos, yPos, columnWidth, heading, lat, lon); + extras(display, nodeDB->getMeshNodeByIndex(i), xPos, yPos, columnWidth, heading, lat, lon); } lastNodeY = std::max(lastNodeY, yPos + FONT_HEIGHT_SMALL); @@ -533,7 +498,12 @@ void drawLastHeardScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_ void drawHopSignalScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) { +#ifdef USE_EINK + const char *title = "Hops/Sig"; +#else + const char *title = "Hops/Signal"; +#endif drawNodeListScreen(display, state, x, y, title, drawEntryHopSignal); } @@ -548,22 +518,24 @@ void drawNodeListWithCompasses(OLEDDisplay *display, OLEDDisplayUiState *state, { float heading = 0; bool validHeading = false; - double lat = 0; - double lon = 0; + auto ourNode = nodeDB->getMeshNode(nodeDB->getNodeNum()); + double lat = DegD(ourNode->position.latitude_i); + double lon = DegD(ourNode->position.longitude_i); + if (uiconfig.compass_mode != meshtastic_CompassMode_FREEZE_HEADING) { #if HAS_GPS - if (screen->hasHeading()) { - heading = screen->getHeading(); // degrees - validHeading = true; - } else { - heading = screen->estimatedHeading(lat, lon); - validHeading = !isnan(heading); - } + if (screen->hasHeading()) { + heading = screen->getHeading(); // degrees + validHeading = true; + } else { + heading = screen->estimatedHeading(lat, lon); + validHeading = !isnan(heading); + } #endif - if (!validHeading) - return; - + if (!validHeading) + return; + } drawNodeListScreen(display, state, x, y, "Bearings", drawEntryCompass, drawCompassArrow, heading, lat, lon); } diff --git a/src/graphics/draw/NodeListRenderer.h b/src/graphics/draw/NodeListRenderer.h index 63f0d1c69..ea8df8bd9 100644 --- a/src/graphics/draw/NodeListRenderer.h +++ b/src/graphics/draw/NodeListRenderer.h @@ -23,12 +23,6 @@ namespace NodeListRenderer typedef void (*EntryRenderer)(OLEDDisplay *, meshtastic_NodeInfoLite *, int16_t, int16_t, int); typedef void (*NodeExtrasRenderer)(OLEDDisplay *, meshtastic_NodeInfoLite *, int16_t, int16_t, int, float, double, double); -// Node entry structure -struct NodeEntry { - meshtastic_NodeInfoLite *node; - uint32_t sortValue; -}; - // Node list mode enumeration enum NodeListMode { MODE_LAST_HEARD = 0, MODE_HOP_SIGNAL = 1, MODE_DISTANCE = 2, MODE_COUNT = 3 }; @@ -57,7 +51,6 @@ void drawNodeListWithCompasses(OLEDDisplay *display, OLEDDisplayUiState *state, // Utility functions const char *getCurrentModeTitle(int screenWidth); -void retrieveAndSortNodes(std::vector &nodeList); const char *getSafeNodeName(meshtastic_NodeInfoLite *node); void drawColumns(OLEDDisplay *display, int16_t x, int16_t y, const char **fields); diff --git a/src/graphics/draw/NotificationRenderer.cpp b/src/graphics/draw/NotificationRenderer.cpp index ed5257012..7350c204f 100644 --- a/src/graphics/draw/NotificationRenderer.cpp +++ b/src/graphics/draw/NotificationRenderer.cpp @@ -26,13 +26,27 @@ extern bool hasUnreadMessage; namespace graphics { -char NotificationRenderer::inEvent = INPUT_BROKER_NONE; +InputEvent NotificationRenderer::inEvent; int8_t NotificationRenderer::curSelected = 0; char NotificationRenderer::alertBannerMessage[256] = {0}; uint32_t NotificationRenderer::alertBannerUntil = 0; // 0 is a special case meaning forever uint8_t NotificationRenderer::alertBannerOptions = 0; // last x lines are seelctable options +const char **NotificationRenderer::optionsArrayPtr = nullptr; +const int *NotificationRenderer::optionsEnumPtr = nullptr; std::function NotificationRenderer::alertBannerCallback = NULL; bool NotificationRenderer::pauseBanner = false; +notificationTypeEnum NotificationRenderer::current_notification_type = notificationTypeEnum::none; +uint32_t NotificationRenderer::numDigits = 0; +uint32_t NotificationRenderer::currentNumber = 0; + +uint32_t pow_of_10(uint32_t n) +{ + uint32_t ret = 1; + for (uint32_t i = 0; i < n; i++) { + ret *= 10; + } + return ret; +} // Used on boot when a certificate is being created void NotificationRenderer::drawSSLScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) @@ -54,179 +68,479 @@ void NotificationRenderer::drawSSLScreen(OLEDDisplay *display, OLEDDisplayUiStat } } -void NotificationRenderer::drawAlertBannerOverlay(OLEDDisplay *display, OLEDDisplayUiState *state) +void NotificationRenderer::resetBanner() { - // Exit if no message is active or duration has passed - if (!isOverlayBannerShowing()) + alertBannerMessage[0] = '\0'; + current_notification_type = notificationTypeEnum::none; + + inEvent.inputEvent = INPUT_BROKER_NONE; + inEvent.kbchar = 0; + curSelected = 0; + alertBannerOptions = 0; // last x lines are seelctable options + optionsArrayPtr = nullptr; + optionsEnumPtr = nullptr; + alertBannerCallback = NULL; + pauseBanner = false; + numDigits = 0; + currentNumber = 0; + + nodeDB->pause_sort(false); +} + +void NotificationRenderer::drawBannercallback(OLEDDisplay *display, OLEDDisplayUiState *state) +{ + if (!isOverlayBannerShowing() && alertBannerMessage[0] != '\0') + resetBanner(); + if (!isOverlayBannerShowing() || pauseBanner) + return; + switch (current_notification_type) { + case notificationTypeEnum::none: + // Do nothing - no notification to display + break; + case notificationTypeEnum::text_banner: + case notificationTypeEnum::selection_picker: + drawAlertBannerOverlay(display, state); + break; + case notificationTypeEnum::node_picker: + drawNodePicker(display, state); + break; + case notificationTypeEnum::number_picker: + drawNumberPicker(display, state); + break; + } +} + +void NotificationRenderer::drawNumberPicker(OLEDDisplay *display, OLEDDisplayUiState *state) +{ + const char *lineStarts[MAX_LINES + 1] = {0}; + uint16_t lineCount = 0; + + // Parse lines + char *alertEnd = alertBannerMessage + strnlen(alertBannerMessage, sizeof(alertBannerMessage)); + lineStarts[lineCount] = alertBannerMessage; + + // Find lines + while ((lineCount < MAX_LINES) && (lineStarts[lineCount] < alertEnd)) { + lineStarts[lineCount + 1] = std::find((char *)lineStarts[lineCount], alertEnd, '\n'); + if (lineStarts[lineCount + 1][0] == '\n') + lineStarts[lineCount + 1] += 1; + lineCount++; + } + // modulo to extract + uint8_t this_digit = (currentNumber % (pow_of_10(numDigits - curSelected))) / (pow_of_10(numDigits - curSelected - 1)); + // Handle input + if (inEvent.inputEvent == INPUT_BROKER_UP || inEvent.inputEvent == INPUT_BROKER_ALT_PRESS) { + if (this_digit == 9) { + currentNumber -= 9 * (pow_of_10(numDigits - curSelected - 1)); + } else { + currentNumber += (pow_of_10(numDigits - curSelected - 1)); + } + } else if (inEvent.inputEvent == INPUT_BROKER_DOWN || inEvent.inputEvent == INPUT_BROKER_USER_PRESS) { + if (this_digit == 0) { + currentNumber += 9 * (pow_of_10(numDigits - curSelected - 1)); + } else { + currentNumber -= (pow_of_10(numDigits - curSelected - 1)); + } + } else if (inEvent.inputEvent == INPUT_BROKER_ANYKEY) { + if (inEvent.kbchar > 47 && inEvent.kbchar < 58) { // have a digit + currentNumber -= this_digit * (pow_of_10(numDigits - curSelected - 1)); + currentNumber += (inEvent.kbchar - 48) * (pow_of_10(numDigits - curSelected - 1)); + curSelected++; + } + } else if (inEvent.inputEvent == INPUT_BROKER_SELECT || inEvent.inputEvent == INPUT_BROKER_RIGHT) { + curSelected++; + } else if (inEvent.inputEvent == INPUT_BROKER_LEFT) { + curSelected--; + } else if ((inEvent.inputEvent == INPUT_BROKER_CANCEL || inEvent.inputEvent == INPUT_BROKER_ALT_LONG) && + alertBannerUntil != 0) { + resetBanner(); + return; + } + if (curSelected == numDigits) { + alertBannerCallback(currentNumber); + resetBanner(); + return; + } + + inEvent.inputEvent = INPUT_BROKER_NONE; + if (alertBannerMessage[0] == '\0') return; - if (pauseBanner) - return; + uint16_t totalLines = lineCount + 2; + const char *linePointers[totalLines + 1] = {0}; // this is sort of a dynamic allocation + + // copy the linestarts to display to the linePointers holder + for (uint16_t i = 0; i < lineCount; i++) { + linePointers[i] = lineStarts[i]; + } + std::string digits = " "; + std::string arrowPointer = " "; + for (uint16_t i = 0; i < numDigits; i++) { + // Modulo minus modulo to return just the current number + digits += std::to_string((currentNumber % (pow_of_10(numDigits - i))) / (pow_of_10(numDigits - i - 1))) + " "; + if (curSelected == i) { + arrowPointer += "^ "; + } else { + arrowPointer += "_ "; + } + } + + linePointers[lineCount++] = digits.c_str(); + linePointers[lineCount++] = arrowPointer.c_str(); + + drawNotificationBox(display, state, linePointers, totalLines, 0); +} + +void NotificationRenderer::drawNodePicker(OLEDDisplay *display, OLEDDisplayUiState *state) +{ + static uint32_t selectedNodenum = 0; // === Layout Configuration === - constexpr uint16_t padding = 5; // Padding around text inside the box - constexpr uint16_t vPadding = 2; // Padding around text inside the box - constexpr uint8_t lineSpacing = 1; // Extra space between lines + constexpr uint16_t vPadding = 2; + alertBannerOptions = nodeDB->getNumMeshNodes() - 1; - // Search the message to determine if we need the bell added - bool needs_bell = (strstr(alertBannerMessage, "Alert Received") != nullptr); + // let the box drawing function calculate the widths? + + const char *lineStarts[MAX_LINES + 1] = {0}; + uint16_t lineCount = 0; + + // Parse lines + char *alertEnd = alertBannerMessage + strnlen(alertBannerMessage, sizeof(alertBannerMessage)); + lineStarts[lineCount] = alertBannerMessage; + + while ((lineCount < MAX_LINES) && (lineStarts[lineCount] < alertEnd)) { + lineStarts[lineCount + 1] = std::find((char *)lineStarts[lineCount], alertEnd, '\n'); + if (lineStarts[lineCount + 1][0] == '\n') + lineStarts[lineCount + 1] += 1; + lineCount++; + } + + // Handle input + if (inEvent.inputEvent == INPUT_BROKER_UP || inEvent.inputEvent == INPUT_BROKER_ALT_PRESS) { + curSelected--; + } else if (inEvent.inputEvent == INPUT_BROKER_DOWN || inEvent.inputEvent == INPUT_BROKER_USER_PRESS) { + curSelected++; + } else if (inEvent.inputEvent == INPUT_BROKER_SELECT) { + alertBannerCallback(selectedNodenum); + resetBanner(); + return; + } else if ((inEvent.inputEvent == INPUT_BROKER_CANCEL || inEvent.inputEvent == INPUT_BROKER_ALT_LONG) && + alertBannerUntil != 0) { + resetBanner(); + return; + } + + if (curSelected == -1) + curSelected = alertBannerOptions - 1; + if (curSelected == alertBannerOptions) + curSelected = 0; + + inEvent.inputEvent = INPUT_BROKER_NONE; + if (alertBannerMessage[0] == '\0') + return; + + uint16_t totalLines = lineCount + alertBannerOptions; + uint16_t screenHeight = display->height(); + uint8_t effectiveLineHeight = FONT_HEIGHT_SMALL - 3; + uint8_t visibleTotalLines = std::min(totalLines, (screenHeight - vPadding * 2) / effectiveLineHeight); + uint8_t linesShown = lineCount; + const char *linePointers[visibleTotalLines + 1] = {0}; // this is sort of a dynamic allocation + + // copy the linestarts to display to the linePointers holder + for (int i = 0; i < lineCount; i++) { + linePointers[i] = lineStarts[i]; + } + char scratchLineBuffer[visibleTotalLines - lineCount][40]; - uint8_t firstOption = 0; uint8_t firstOptionToShow = 0; + if (curSelected > 1 && alertBannerOptions > visibleTotalLines - lineCount) { + if (curSelected > alertBannerOptions - visibleTotalLines + lineCount) + firstOptionToShow = alertBannerOptions - visibleTotalLines + lineCount; + else + firstOptionToShow = curSelected - 1; + } else { + firstOptionToShow = 0; + } + int scratchLineNum = 0; + for (int i = firstOptionToShow; i < alertBannerOptions && linesShown < visibleTotalLines; i++, linesShown++) { + char temp_name[16] = {0}; + if (nodeDB->getMeshNodeByIndex(i + 1)->has_user) { + std::string sanitized = sanitizeString(nodeDB->getMeshNodeByIndex(i + 1)->user.long_name); + strncpy(temp_name, sanitized.c_str(), sizeof(temp_name) - 1); - // Setup font and alignment - display->setFont(FONT_SMALL); - display->setTextAlignment(TEXT_ALIGN_LEFT); // We will manually center per line - const int MAX_LINES = 24; + } else { + snprintf(temp_name, sizeof(temp_name), "(%04X)", (uint16_t)(nodeDB->getMeshNodeByIndex(i + 1)->num & 0xFFFF)); + } + // make temp buffer for name + // fi + if (i == curSelected) { + selectedNodenum = nodeDB->getMeshNodeByIndex(i + 1)->num; + if (isHighResolution) { + strncpy(scratchLineBuffer[scratchLineNum], "> ", 3); + strncpy(scratchLineBuffer[scratchLineNum] + 2, temp_name, 36); + strncpy(scratchLineBuffer[scratchLineNum] + strlen(temp_name) + 2, " <", 3); + } else { + strncpy(scratchLineBuffer[scratchLineNum], ">", 2); + strncpy(scratchLineBuffer[scratchLineNum] + 1, temp_name, 37); + strncpy(scratchLineBuffer[scratchLineNum] + strlen(temp_name) + 1, "<", 2); + } + scratchLineBuffer[scratchLineNum][39] = '\0'; + } else { + strncpy(scratchLineBuffer[scratchLineNum], temp_name, 36); + } + linePointers[linesShown] = scratchLineBuffer[scratchLineNum++]; + } + drawNotificationBox(display, state, linePointers, totalLines, firstOptionToShow); +} +void NotificationRenderer::drawAlertBannerOverlay(OLEDDisplay *display, OLEDDisplayUiState *state) +{ + // === Layout Configuration === + constexpr uint16_t vPadding = 2; + + uint16_t optionWidths[alertBannerOptions] = {0}; uint16_t maxWidth = 0; uint16_t arrowsWidth = display->getStringWidth("> <", 4, true); uint16_t lineWidths[MAX_LINES] = {0}; uint16_t lineLengths[MAX_LINES] = {0}; - char *lineStarts[MAX_LINES + 1]; + const char *lineStarts[MAX_LINES + 1] = {0}; uint16_t lineCount = 0; char lineBuffer[40] = {0}; - // pointer to the terminating null + + // Parse lines char *alertEnd = alertBannerMessage + strnlen(alertBannerMessage, sizeof(alertBannerMessage)); lineStarts[lineCount] = alertBannerMessage; - // loop through lines finding \n characters while ((lineCount < MAX_LINES) && (lineStarts[lineCount] < alertEnd)) { - lineStarts[lineCount + 1] = std::find(lineStarts[lineCount], alertEnd, '\n'); + lineStarts[lineCount + 1] = std::find((char *)lineStarts[lineCount], alertEnd, '\n'); lineLengths[lineCount] = lineStarts[lineCount + 1] - lineStarts[lineCount]; - if (lineStarts[lineCount + 1][0] == '\n') { - lineStarts[lineCount + 1] += 1; // Move the start pointer beyond the \n - } + if (lineStarts[lineCount + 1][0] == '\n') + lineStarts[lineCount + 1] += 1; lineWidths[lineCount] = display->getStringWidth(lineStarts[lineCount], lineLengths[lineCount], true); - if (lineWidths[lineCount] > maxWidth) { + if (lineWidths[lineCount] > maxWidth) maxWidth = lineWidths[lineCount]; - } - if (alertBannerOptions > 0 && lineCount > 0 && lineWidths[lineCount] + arrowsWidth > maxWidth) { - maxWidth = lineWidths[lineCount] + arrowsWidth; - } lineCount++; - // if we are doing a selection, add extra width for arrows } + // Measure option widths + for (int i = 0; i < alertBannerOptions; i++) { + optionWidths[i] = display->getStringWidth(optionsArrayPtr[i], strlen(optionsArrayPtr[i]), true); + if (optionWidths[i] > maxWidth) + maxWidth = optionWidths[i]; + if (optionWidths[i] + arrowsWidth > maxWidth) + maxWidth = optionWidths[i] + arrowsWidth; + } + + // Handle input if (alertBannerOptions > 0) { - // respond to input - if (inEvent == INPUT_BROKER_UP || inEvent == INPUT_BROKER_ALT_PRESS) { + if (inEvent.inputEvent == INPUT_BROKER_UP || inEvent.inputEvent == INPUT_BROKER_ALT_PRESS) { curSelected--; - } else if (inEvent == INPUT_BROKER_DOWN || inEvent == INPUT_BROKER_USER_PRESS) { + } else if (inEvent.inputEvent == INPUT_BROKER_DOWN || inEvent.inputEvent == INPUT_BROKER_USER_PRESS) { curSelected++; - } else if (inEvent == INPUT_BROKER_SELECT) { - alertBannerCallback(curSelected); - alertBannerMessage[0] = '\0'; - } else if ((inEvent == INPUT_BROKER_CANCEL || inEvent == INPUT_BROKER_ALT_LONG) && alertBannerUntil != 0) { - alertBannerMessage[0] = '\0'; + } else if (inEvent.inputEvent == INPUT_BROKER_SELECT) { + if (optionsEnumPtr != nullptr) { + alertBannerCallback(optionsEnumPtr[curSelected]); + optionsEnumPtr = nullptr; + } else { + alertBannerCallback(curSelected); + } + resetBanner(); + return; + } else if ((inEvent.inputEvent == INPUT_BROKER_CANCEL || inEvent.inputEvent == INPUT_BROKER_ALT_LONG) && + alertBannerUntil != 0) { + resetBanner(); + return; } + if (curSelected == -1) curSelected = alertBannerOptions - 1; if (curSelected == alertBannerOptions) curSelected = 0; - // compare number of options to number of lines - if (lineCount < alertBannerOptions) + } else { + if (inEvent.inputEvent == INPUT_BROKER_SELECT || inEvent.inputEvent == INPUT_BROKER_ALT_LONG || + inEvent.inputEvent == INPUT_BROKER_CANCEL) { + resetBanner(); return; - firstOption = lineCount - alertBannerOptions; - if (curSelected > 1 && alertBannerOptions > 3) { - firstOptionToShow = curSelected + firstOption - 1; - // put the selected option in the middle - } else { - firstOptionToShow = firstOption; - } - } else { // not in an alert with a callback - // TODO: check that at least a second has passed since the alert started - if (inEvent == INPUT_BROKER_SELECT || inEvent == INPUT_BROKER_ALT_LONG || inEvent == INPUT_BROKER_CANCEL) { - alertBannerMessage[0] = '\0'; // end the alert early } } - inEvent = INPUT_BROKER_NONE; + + inEvent.inputEvent = INPUT_BROKER_NONE; if (alertBannerMessage[0] == '\0') return; - // set width from longest line - uint16_t boxWidth = padding * 2 + maxWidth; - if (needs_bell) { - if (SCREEN_WIDTH > 128 && boxWidth <= 150) { - boxWidth += 26; - } - if (SCREEN_WIDTH <= 128 && boxWidth <= 100) { - boxWidth += 20; + uint16_t totalLines = lineCount + alertBannerOptions; + + uint16_t screenHeight = display->height(); + uint8_t effectiveLineHeight = FONT_HEIGHT_SMALL - 3; + uint8_t visibleTotalLines = std::min(totalLines, (screenHeight - vPadding * 2) / effectiveLineHeight); + uint8_t linesShown = lineCount; + const char *linePointers[visibleTotalLines + 1] = {0}; // this is sort of a dynamic allocation + + // copy the linestarts to display to the linePointers holder + for (int i = 0; i < lineCount; i++) { + linePointers[i] = lineStarts[i]; + } + + uint8_t firstOptionToShow = 0; + if (alertBannerOptions > 0) { + if (curSelected > 1 && alertBannerOptions > visibleTotalLines - lineCount) { + if (curSelected > alertBannerOptions - visibleTotalLines + lineCount) + firstOptionToShow = alertBannerOptions - visibleTotalLines + lineCount; + else + firstOptionToShow = curSelected - 1; + } else { + firstOptionToShow = 0; } } - // calculate max lines on screen? for now it's 4 - // set height from line count - uint16_t boxHeight; - if (lineCount <= 4) { - boxHeight = vPadding * 2 + lineCount * FONT_HEIGHT_SMALL + (lineCount - 1) * lineSpacing; + + for (int i = firstOptionToShow; i < alertBannerOptions && linesShown < visibleTotalLines; i++, linesShown++) { + if (i == curSelected) { + if (isHighResolution) { + strncpy(lineBuffer, "> ", 3); + strncpy(lineBuffer + 2, optionsArrayPtr[i], 36); + strncpy(lineBuffer + strlen(optionsArrayPtr[i]) + 2, " <", 3); + } else { + strncpy(lineBuffer, ">", 2); + strncpy(lineBuffer + 1, optionsArrayPtr[i], 37); + strncpy(lineBuffer + strlen(optionsArrayPtr[i]) + 1, "<", 2); + } + lineBuffer[39] = '\0'; + linePointers[linesShown] = lineBuffer; + } else { + linePointers[linesShown] = optionsArrayPtr[i]; + } + } + if (alertBannerOptions > 0) { + drawNotificationBox(display, state, linePointers, totalLines, firstOptionToShow, maxWidth); } else { - boxHeight = vPadding * 2 + 4 * FONT_HEIGHT_SMALL + 4 * lineSpacing; + drawNotificationBox(display, state, linePointers, totalLines, firstOptionToShow); + } +} + +void NotificationRenderer::drawNotificationBox(OLEDDisplay *display, OLEDDisplayUiState *state, const char *lines[], + uint16_t totalLines, uint8_t firstOptionToShow, uint16_t maxWidth) +{ + + bool is_picker = false; + uint16_t lineCount = 0; + // === Layout Configuration === + constexpr uint16_t hPadding = 5; + constexpr uint16_t vPadding = 2; + bool needs_bell = false; + uint16_t lineWidths[totalLines] = {0}; + uint16_t lineLengths[totalLines] = {0}; + + if (maxWidth != 0) + is_picker = true; + + // Setup font and alignment + display->setFont(FONT_SMALL); + display->setTextAlignment(TEXT_ALIGN_LEFT); + + while (lines[lineCount] != nullptr) { + auto newlinePointer = strchr(lines[lineCount], '\n'); + if (newlinePointer) + lineLengths[lineCount] = (newlinePointer - lines[lineCount]); // Check for newlines first + else // if the newline wasn't found, then pull string length from strlen + lineLengths[lineCount] = strlen(lines[lineCount]); + lineWidths[lineCount] = display->getStringWidth(lines[lineCount], lineLengths[lineCount], true); + if (!is_picker) { + needs_bell |= (strstr(alertBannerMessage, "Alert Received") != nullptr); + if (lineWidths[lineCount] > maxWidth) + maxWidth = lineWidths[lineCount]; + } + lineCount++; + } + // count lines + + uint16_t boxWidth = hPadding * 2 + maxWidth; + if (needs_bell) { + if (isHighResolution && boxWidth <= 150) + boxWidth += 26; + if (!isHighResolution && boxWidth <= 100) + boxWidth += 20; + } + + uint16_t screenHeight = display->height(); + uint8_t effectiveLineHeight = FONT_HEIGHT_SMALL - 3; + uint8_t visibleTotalLines = std::min(lineCount, (screenHeight - vPadding * 2) / effectiveLineHeight); + uint16_t contentHeight = visibleTotalLines * effectiveLineHeight; + uint16_t boxHeight = contentHeight + vPadding * 2; + if (visibleTotalLines == 1) { + boxHeight += (isHighResolution) ? 4 : 3; } int16_t boxLeft = (display->width() / 2) - (boxWidth / 2); + if (totalLines > visibleTotalLines) { + boxWidth += (isHighResolution) ? 4 : 2; + } int16_t boxTop = (display->height() / 2) - (boxHeight / 2); - // === Draw background box === + + // === Draw Box === display->setColor(BLACK); - display->fillRect(boxLeft - 1, boxTop - 1, boxWidth + 2, boxHeight + 2); // Slightly oversized box - display->fillRect(boxLeft, boxTop - 2, boxWidth, 1); // Top Line - display->fillRect(boxLeft, boxTop + boxHeight + 1, boxWidth, 1); // Bottom Line - display->fillRect(boxLeft - 2, boxTop, 1, boxHeight); // Left Line - display->fillRect(boxLeft + boxWidth + 1, boxTop, 1, boxHeight); // Right Line + display->fillRect(boxLeft - 1, boxTop - 1, boxWidth + 2, boxHeight + 2); + display->fillRect(boxLeft, boxTop - 2, boxWidth, 1); + display->fillRect(boxLeft, boxTop + boxHeight + 1, boxWidth, 1); + display->fillRect(boxLeft - 2, boxTop, 1, boxHeight); + display->fillRect(boxLeft + boxWidth + 1, boxTop, 1, boxHeight); display->setColor(WHITE); - display->drawRect(boxLeft, boxTop, boxWidth, boxHeight); // Border + display->drawRect(boxLeft, boxTop, boxWidth, boxHeight); display->setColor(BLACK); - display->fillRect(boxLeft, boxTop, 1, 1); // Top Left - display->fillRect(boxLeft + boxWidth - 1, boxTop, 1, 1); // Top Right - display->fillRect(boxLeft, boxTop + boxHeight - 1, 1, 1); // Bottom Left - display->fillRect(boxLeft + boxWidth - 1, boxTop + boxHeight - 1, 1, 1); // Bottom Right + display->fillRect(boxLeft, boxTop, 1, 1); + display->fillRect(boxLeft + boxWidth - 1, boxTop, 1, 1); + display->fillRect(boxLeft, boxTop + boxHeight - 1, 1, 1); + display->fillRect(boxLeft + boxWidth - 1, boxTop + boxHeight - 1, 1, 1); display->setColor(WHITE); - // === Draw each line centered in the box === + // === Draw Content === int16_t lineY = boxTop + vPadding; - for (int i = 0; i < lineCount; i++) { - // is this line selected? - // if so, start the buffer with -> and strncpy to the 4th location - if (i < lineCount - alertBannerOptions || alertBannerOptions == 0) { - strncpy(lineBuffer, lineStarts[i], 40); - if (lineLengths[i] > 39) - lineBuffer[39] = '\0'; - else - lineBuffer[lineLengths[i]] = '\0'; - } else if (i >= firstOptionToShow && i < firstOptionToShow + 3) { - if (i == curSelected + firstOption) { - if (lineLengths[i] > 35) - lineLengths[i] = 35; - strncpy(lineBuffer, "> ", 3); - strncpy(lineBuffer + 2, lineStarts[i], 36); - strncpy(lineBuffer + lineLengths[i] + 2, " <", 3); - lineLengths[i] += 4; - lineWidths[i] += display->getStringWidth("> <", 4, true); - if (lineLengths[i] > 35) - lineBuffer[39] = '\0'; - else - lineBuffer[lineLengths[i]] = '\0'; - } else { - strncpy(lineBuffer, lineStarts[i], 40); - if (lineLengths[i] > 39) - lineBuffer[39] = '\0'; - else - lineBuffer[lineLengths[i]] = '\0'; - } - } else { // add break for the additional lines - continue; - } - int16_t textX = boxLeft + (boxWidth - lineWidths[i]) / 2; - if (needs_bell && i == 0) { int bellY = lineY + (FONT_HEIGHT_SMALL - 8) / 2; display->drawXbm(textX - 10, bellY, 8, 8, bell_alert); display->drawXbm(textX + lineWidths[i] + 2, bellY, 8, 8, bell_alert); } + char lineBuffer[lineLengths[i] + 1]; + strncpy(lineBuffer, lines[i], lineLengths[i]); + lineBuffer[lineLengths[i]] = '\0'; + // Determine if this is a pop-up or a pick list + if (alertBannerOptions > 0 && i == 0) { + // Pick List + display->setColor(WHITE); + int background_yOffset = 1; + // Determine if we have low hanging characters + if (strchr(lineBuffer, 'p') || strchr(lineBuffer, 'g') || strchr(lineBuffer, 'y') || strchr(lineBuffer, 'j')) { + background_yOffset = -1; + } + display->fillRect(boxLeft, boxTop + 1, boxWidth, effectiveLineHeight - background_yOffset); + display->setColor(BLACK); + int yOffset = 3; + display->drawString(textX, lineY - yOffset, lineBuffer); + display->setColor(WHITE); + lineY += (effectiveLineHeight - 2 - background_yOffset); + } else { + // Pop-up + display->drawString(textX, lineY, lineBuffer); + lineY += (effectiveLineHeight); + } + } - display->drawString(textX, lineY, lineBuffer); - lineY += FONT_HEIGHT_SMALL + lineSpacing; + // === Scroll Bar (Thicker, inside box, not over title) === + if (totalLines > visibleTotalLines) { + const uint8_t scrollBarWidth = 5; + + int16_t scrollBarX = boxLeft + boxWidth - scrollBarWidth - 2; + int16_t scrollBarY = boxTop + vPadding + effectiveLineHeight; // start after title line + uint16_t scrollBarHeight = boxHeight - vPadding * 2 - effectiveLineHeight; + + float ratio = (float)visibleTotalLines / totalLines; + uint16_t indicatorHeight = std::max((int)(scrollBarHeight * ratio), 4); + float scrollRatio = (float)(firstOptionToShow + lineCount - visibleTotalLines) / (totalLines - visibleTotalLines); + uint16_t indicatorY = scrollBarY + scrollRatio * (scrollBarHeight - indicatorHeight); + + display->drawRect(scrollBarX, scrollBarY, scrollBarWidth, scrollBarHeight); + display->fillRect(scrollBarX + 1, indicatorY, scrollBarWidth - 2, indicatorHeight); } } diff --git a/src/graphics/draw/NotificationRenderer.h b/src/graphics/draw/NotificationRenderer.h index 3ed931dc6..9c30b329c 100644 --- a/src/graphics/draw/NotificationRenderer.h +++ b/src/graphics/draw/NotificationRenderer.h @@ -2,6 +2,8 @@ #include "OLEDDisplay.h" #include "OLEDDisplayUi.h" +#include "graphics/Screen.h" +#define MAX_LINES 5 namespace graphics { @@ -9,20 +11,34 @@ namespace graphics class NotificationRenderer { public: - static char inEvent; + static InputEvent inEvent; + static char inKeypress; static int8_t curSelected; static char alertBannerMessage[256]; - static uint32_t alertBannerUntil; // 0 is a special case meaning forever + static uint32_t alertBannerUntil; // 0 is a special case meaning forever + static const char **optionsArrayPtr; + static const int *optionsEnumPtr; static uint8_t alertBannerOptions; // last x lines are seelctable options static std::function alertBannerCallback; + static uint32_t numDigits; + static uint32_t currentNumber; static bool pauseBanner; + static void resetBanner(); + static void drawBannercallback(OLEDDisplay *display, OLEDDisplayUiState *state); static void drawAlertBannerOverlay(OLEDDisplay *display, OLEDDisplayUiState *state); + static void drawNumberPicker(OLEDDisplay *display, OLEDDisplayUiState *state); + static void drawNodePicker(OLEDDisplay *display, OLEDDisplayUiState *state); + static void drawNotificationBox(OLEDDisplay *display, OLEDDisplayUiState *state, const char *lines[MAX_LINES + 1], + uint16_t totalLines, uint8_t firstOptionToShow, uint16_t maxWidth = 0); + static void drawCriticalFaultFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y); static void drawSSLScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y); static void drawFrameFirmware(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y); static bool isOverlayBannerShowing(); + + static graphics::notificationTypeEnum current_notification_type; }; } // namespace graphics diff --git a/src/graphics/draw/UIRenderer.cpp b/src/graphics/draw/UIRenderer.cpp index a77d5b44b..9be8b04f4 100644 --- a/src/graphics/draw/UIRenderer.cpp +++ b/src/graphics/draw/UIRenderer.cpp @@ -18,27 +18,25 @@ #include #include -#if !MESHTASTIC_EXCLUDE_GPS - // External variables extern graphics::Screen *screen; namespace graphics { +NodeNum UIRenderer::currentFavoriteNodeNum = 0; +#if !MESHTASTIC_EXCLUDE_GPS // GeoCoord object for coordinate conversions extern GeoCoord geoCoord; // Threshold values for the GPS lock accuracy bar display extern uint32_t dopThresholds[5]; -NodeNum UIRenderer::currentFavoriteNodeNum = 0; - // Draw GPS status summary void UIRenderer::drawGps(OLEDDisplay *display, int16_t x, int16_t y, const meshtastic::GPSStatus *gps) { // Draw satellite image - if (SCREEN_WIDTH > 128) { + if (isHighResolution) { NodeListRenderer::drawScaledXBitmap16x16(x, y - 2, imgSatellite_width, imgSatellite_height, imgSatellite, display); } else { display->drawXbm(x + 1, y + 1, imgSatellite_width, imgSatellite_height, imgSatellite); @@ -58,7 +56,7 @@ void UIRenderer::drawGps(OLEDDisplay *display, int16_t x, int16_t y, const mesht } else { snprintf(textString, sizeof(textString), "%u sats", gps->getNumSatellites()); } - if (SCREEN_WIDTH > 128) { + if (isHighResolution) { display->drawString(x + 18, y, textString); } else { display->drawString(x + 11, y, textString); @@ -162,46 +160,7 @@ void UIRenderer::drawGpsCoordinates(OLEDDisplay *display, int16_t x, int16_t y, } } } - -void UIRenderer::drawBattery(OLEDDisplay *display, int16_t x, int16_t y, uint8_t *imgBuffer, - const meshtastic::PowerStatus *powerStatus) -{ - static const uint8_t powerBar[3] = {0x81, 0xBD, 0xBD}; - static const uint8_t lightning[8] = {0xA1, 0xA1, 0xA5, 0xAD, 0xB5, 0xA5, 0x85, 0x85}; - - // Clear the bar area inside the battery image - for (int i = 1; i < 14; i++) { - imgBuffer[i] = 0x81; - } - - // Fill with lightning or power bars - if (powerStatus->getIsCharging()) { - memcpy(imgBuffer + 3, lightning, 8); - } else { - for (int i = 0; i < 4; i++) { - if (powerStatus->getBatteryChargePercent() >= 25 * i) - memcpy(imgBuffer + 1 + (i * 3), powerBar, 3); - } - } - - // Slightly more conservative scaling based on screen width - int scale = 1; - - if (SCREEN_WIDTH >= 200) - scale = 2; - if (SCREEN_WIDTH >= 300) - scale = 2; // Do NOT go higher than 2 - - // Draw scaled battery image (16 columns × 8 rows) - for (int col = 0; col < 16; col++) { - uint8_t colBits = imgBuffer[col]; - for (int row = 0; row < 8; row++) { - if (colBits & (1 << row)) { - display->fillRect(x + col * scale, y + row * scale, scale, scale); - } - } - } -} +#endif // !MESHTASTIC_EXCLUDE_GPS // Draw nodes status void UIRenderer::drawNodes(OLEDDisplay *display, int16_t x, int16_t y, const meshtastic::NodeStatus *nodeStatus, int node_offset, @@ -221,19 +180,19 @@ void UIRenderer::drawNodes(OLEDDisplay *display, int16_t x, int16_t y, const mes defined(ST7789_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(HX8357_CS)) && \ !defined(DISPLAY_FORCE_SMALL_FONTS) - if (SCREEN_WIDTH > 128) { + if (isHighResolution) { NodeListRenderer::drawScaledXBitmap16x16(x, y - 1, 8, 8, imgUser, display); } else { display->drawFastImage(x, y + 3, 8, 8, imgUser); } #else - if (SCREEN_WIDTH > 128) { + if (isHighResolution) { NodeListRenderer::drawScaledXBitmap16x16(x, y - 1, 8, 8, imgUser, display); } else { display->drawFastImage(x, y + 1, 8, 8, imgUser); } #endif - int string_offset = (SCREEN_WIDTH > 128) ? 9 : 0; + int string_offset = (isHighResolution) ? 9 : 0; display->drawString(x + 10 + string_offset, y - 2, usersString); } @@ -293,12 +252,14 @@ void UIRenderer::drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *st // List of available macro Y positions in order, from top to bottom. int line = 1; // which slot to use next + std::string usernameStr; // === 1. Long Name (always try to show first) === const char *username = (node->has_user && node->user.long_name[0]) ? node->user.long_name : nullptr; - if (username && line < 5) { + if (username) { + usernameStr = sanitizeString(username); // Sanitize the incoming long_name just in case // Print node's long name (e.g. "Backpack Node") - display->drawString(x, getTextPositions(display)[line++], username); + display->drawString(x, getTextPositions(display)[line++], usernameStr.c_str()); } // === 2. Signal and Hops (combined on one line, if available) === @@ -456,8 +417,11 @@ void UIRenderer::drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *st GeoCoord::latLongToMeter(DegD(p.latitude_i), DegD(p.longitude_i), DegD(op.latitude_i), DegD(op.longitude_i)); */ float bearing = GeoCoord::bearing(DegD(op.latitude_i), DegD(op.longitude_i), DegD(p.latitude_i), DegD(p.longitude_i)); - if (!config.display.compass_north_top) + if (uiconfig.compass_mode == meshtastic_CompassMode_FREEZE_HEADING) { + myHeading = 0; + } else { bearing -= myHeading; + } display->drawCircle(compassX, compassY, compassRadius); CompassRenderer::drawCompassNorth(display, compassX, compassY, myHeading, compassRadius); @@ -476,7 +440,7 @@ void UIRenderer::drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *st const int margin = 4; // --------- PATCH FOR EINK NAV BAR (ONLY CHANGE BELOW) ----------- #if defined(USE_EINK) - const int iconSize = (SCREEN_WIDTH > 128) ? 16 : 8; + const int iconSize = (isHighResolution) ? 16 : 8; const int navBarHeight = iconSize + 6; #else const int navBarHeight = 0; @@ -497,8 +461,11 @@ void UIRenderer::drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *st int compassY = yBelowContent + availableHeight / 2; const auto &op = ourNode->position; - float myHeading = screen->hasHeading() ? screen->getHeading() * PI / 180 - : screen->estimatedHeading(DegD(op.latitude_i), DegD(op.longitude_i)); + float myHeading = 0; + if (uiconfig.compass_mode != meshtastic_CompassMode_FREEZE_HEADING) { + myHeading = screen->hasHeading() ? screen->getHeading() * PI / 180 + : screen->estimatedHeading(DegD(op.latitude_i), DegD(op.longitude_i)); + } graphics::CompassRenderer::drawCompassNorth(display, compassX, compassY, myHeading, compassRadius); const auto &p = node->position; @@ -507,7 +474,7 @@ void UIRenderer::drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *st GeoCoord::latLongToMeter(DegD(p.latitude_i), DegD(p.longitude_i), DegD(op.latitude_i), DegD(op.longitude_i)); */ float bearing = GeoCoord::bearing(DegD(op.latitude_i), DegD(op.longitude_i), DegD(p.latitude_i), DegD(p.longitude_i)); - if (!config.display.compass_north_top) + if (uiconfig.compass_mode != meshtastic_CompassMode_FREEZE_HEADING) bearing -= myHeading; graphics::CompassRenderer::drawNodeHeading(display, compassX, compassY, compassRadius * 2, bearing); @@ -570,15 +537,15 @@ void UIRenderer::drawDeviceFocused(OLEDDisplay *display, OLEDDisplayUiState *sta } else { displayLine = config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_NOT_PRESENT ? "No GPS" : "GPS off"; } - int yOffset = (SCREEN_WIDTH > 128) ? 3 : 1; - if (SCREEN_WIDTH > 128) { + int yOffset = (isHighResolution) ? 3 : 1; + if (isHighResolution) { NodeListRenderer::drawScaledXBitmap16x16(x, getTextPositions(display)[line] + yOffset - 5, imgSatellite_width, imgSatellite_height, imgSatellite, display); } else { display->drawXbm(x + 1, getTextPositions(display)[line] + yOffset, imgSatellite_width, imgSatellite_height, imgSatellite); } - int xOffset = (SCREEN_WIDTH > 128) ? 6 : 0; + int xOffset = (isHighResolution) ? 6 : 0; display->drawString(x + 11 + xOffset, getTextPositions(display)[line], displayLine); } else { UIRenderer::drawGps(display, 0, getTextPositions(display)[line], gpsStatus); @@ -602,17 +569,21 @@ void UIRenderer::drawDeviceFocused(OLEDDisplay *display, OLEDDisplayUiState *sta char chUtilPercentage[10]; snprintf(chUtilPercentage, sizeof(chUtilPercentage), "%2.0f%%", airTime->channelUtilizationPercent()); - int chUtil_x = (SCREEN_WIDTH > 128) ? display->getStringWidth(chUtil) + 10 : display->getStringWidth(chUtil) + 5; + int chUtil_x = (isHighResolution) ? display->getStringWidth(chUtil) + 10 : display->getStringWidth(chUtil) + 5; int chUtil_y = getTextPositions(display)[line] + 3; - int chutil_bar_width = (SCREEN_WIDTH > 128) ? 100 : 50; + int chutil_bar_width = (isHighResolution) ? 100 : 50; if (!config.bluetooth.enabled) { - chutil_bar_width = (SCREEN_WIDTH > 128) ? 80 : 40; +#if defined(USE_EINK) + chutil_bar_width = (isHighResolution) ? 50 : 30; +#else + chutil_bar_width = (isHighResolution) ? 80 : 40; +#endif } - int chutil_bar_height = (SCREEN_WIDTH > 128) ? 12 : 7; - int extraoffset = (SCREEN_WIDTH > 128) ? 6 : 3; + int chutil_bar_height = (isHighResolution) ? 12 : 7; + int extraoffset = (isHighResolution) ? 6 : 3; if (!config.bluetooth.enabled) { - extraoffset = (SCREEN_WIDTH > 128) ? 6 : 1; + extraoffset = (isHighResolution) ? 6 : 1; } int chutil_percent = airTime->channelUtilizationPercent(); @@ -672,21 +643,20 @@ void UIRenderer::drawDeviceFocused(OLEDDisplay *display, OLEDDisplayUiState *sta // === Fourth & Fifth Rows: Node Identity === int textWidth = 0; int nameX = 0; - int yOffset = (SCREEN_WIDTH > 128) ? 0 : 5; + int yOffset = (isHighResolution) ? 0 : 5; const char *longName = nullptr; + std::string longNameStr; + meshtastic_NodeInfoLite *ourNode = nodeDB->getMeshNode(nodeDB->getNodeNum()); if (ourNode && ourNode->has_user && strlen(ourNode->user.long_name) > 0) { - longName = ourNode->user.long_name; + longNameStr = sanitizeString(ourNode->user.long_name); } - uint8_t dmac[6]; char shortnameble[35]; - getMacAddr(dmac); - snprintf(screen->ourId, sizeof(screen->ourId), "%02x%02x", dmac[4], dmac[5]); snprintf(shortnameble, sizeof(shortnameble), "%s", graphics::UIRenderer::haveGlyphs(owner.short_name) ? owner.short_name : ""); char combinedName[50]; - snprintf(combinedName, sizeof(combinedName), "%s (%s)", longName, shortnameble); + snprintf(combinedName, sizeof(combinedName), "%s (%s)", longNameStr.empty() ? "" : longNameStr.c_str(), shortnameble); if (SCREEN_WIDTH - (display->getStringWidth(longName) + display->getStringWidth(shortnameble)) > 10) { size_t len = strlen(combinedName); if (len >= 3 && strcmp(combinedName + len - 3, " ()") == 0) { @@ -700,7 +670,7 @@ void UIRenderer::drawDeviceFocused(OLEDDisplay *display, OLEDDisplayUiState *sta // === LongName Centered === textWidth = display->getStringWidth(longName); nameX = (SCREEN_WIDTH - textWidth) / 2; - display->drawString(nameX, getTextPositions(display)[line++], longName); + display->drawString(nameX, getTextPositions(display)[line++], longNameStr.c_str()); // === ShortName Centered === textWidth = display->getStringWidth(shortnameble); @@ -808,44 +778,42 @@ void UIRenderer::drawScreensaverOverlay(OLEDDisplay *display, OLEDDisplayUiState { LOG_DEBUG("Draw screensaver overlay"); - EINK_ADD_FRAMEFLAG(display, COSMETIC); // Take the opportunity for a full-refresh + EINK_ADD_FRAMEFLAG(display, COSMETIC); // Full refresh for screensaver // Config display->setFont(FONT_SMALL); display->setTextAlignment(TEXT_ALIGN_LEFT); const char *pauseText = "Screen Paused"; const char *idText = owner.short_name; - const bool useId = haveGlyphs(idText); // This bool is used to hide the idText box if we can't render the short name - constexpr uint16_t padding = 5; + const bool useId = haveGlyphs(idText); + constexpr uint8_t padding = 2; constexpr uint8_t dividerGap = 1; - constexpr uint8_t imprecision = 5; // How far the box origins can drift from center. Combat burn-in. - // Dimensions - const uint16_t idTextWidth = display->getStringWidth(idText, strlen(idText), true); // "true": handle utf8 chars + // Text widths + const uint16_t idTextWidth = display->getStringWidth(idText, strlen(idText), true); const uint16_t pauseTextWidth = display->getStringWidth(pauseText, strlen(pauseText)); - const uint16_t boxWidth = padding + (useId ? idTextWidth + padding + padding : 0) + pauseTextWidth + padding; - const uint16_t boxHeight = padding + FONT_HEIGHT_SMALL + padding; + const uint16_t boxWidth = padding + (useId ? idTextWidth + padding : 0) + pauseTextWidth + padding; + const uint16_t boxHeight = FONT_HEIGHT_SMALL + (padding * 2); - // Position - const int16_t boxLeft = (display->width() / 2) - (boxWidth / 2) + random(-imprecision, imprecision + 1); - // const int16_t boxRight = boxLeft + boxWidth - 1; - const int16_t boxTop = (display->height() / 2) - (boxHeight / 2 + random(-imprecision, imprecision + 1)); - const int16_t boxBottom = boxTop + boxHeight - 1; + // Flush with bottom + const int16_t boxLeft = (display->width() / 2) - (boxWidth / 2); + const int16_t boxTop = display->height() - boxHeight; + const int16_t boxBottom = display->height() - 1; const int16_t idTextLeft = boxLeft + padding; const int16_t idTextTop = boxTop + padding; - const int16_t pauseTextLeft = boxLeft + (useId ? padding + idTextWidth + padding : 0) + padding; + const int16_t pauseTextLeft = boxLeft + (useId ? idTextWidth + (padding * 2) : 0) + padding; const int16_t pauseTextTop = boxTop + padding; const int16_t dividerX = boxLeft + padding + idTextWidth + padding; - const int16_t dividerTop = boxTop + 1 + dividerGap; - const int16_t dividerBottom = boxBottom - 1 - dividerGap; + const int16_t dividerTop = boxTop + dividerGap; + const int16_t dividerBottom = boxBottom - dividerGap; // Draw: box display->setColor(EINK_WHITE); - display->fillRect(boxLeft - 1, boxTop - 1, boxWidth + 2, boxHeight + 2); // Clear a slightly oversized area for the box + display->fillRect(boxLeft, boxTop, boxWidth, boxHeight); display->setColor(EINK_BLACK); display->drawRect(boxLeft, boxTop, boxWidth, boxHeight); - // Draw: Text + // Draw: text if (useId) display->drawString(idTextLeft, idTextTop, idText); display->drawString(pauseTextLeft, pauseTextTop, pauseText); @@ -920,15 +888,15 @@ void UIRenderer::drawCompassAndLocationScreen(OLEDDisplay *display, OLEDDisplayU } else { displayLine = config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_NOT_PRESENT ? "No GPS" : "GPS off"; } - int yOffset = (SCREEN_WIDTH > 128) ? 3 : 1; - if (SCREEN_WIDTH > 128) { + int yOffset = (isHighResolution) ? 3 : 1; + if (isHighResolution) { NodeListRenderer::drawScaledXBitmap16x16(x, getTextPositions(display)[line] + yOffset - 5, imgSatellite_width, imgSatellite_height, imgSatellite, display); } else { display->drawXbm(x + 1, getTextPositions(display)[line] + yOffset, imgSatellite_width, imgSatellite_height, imgSatellite); } - int xOffset = (SCREEN_WIDTH > 128) ? 6 : 0; + int xOffset = (isHighResolution) ? 6 : 0; display->drawString(x + 11 + xOffset, getTextPositions(display)[line++], displayLine); } else { UIRenderer::drawGps(display, 0, getTextPositions(display)[line++], gpsStatus); @@ -941,15 +909,18 @@ void UIRenderer::drawCompassAndLocationScreen(OLEDDisplay *display, OLEDDisplayU int32_t(gpsStatus->getAltitude())); // === Determine Compass Heading === - float heading; + float heading = 0; bool validHeading = false; - - if (screen->hasHeading()) { - heading = radians(screen->getHeading()); + if (uiconfig.compass_mode == meshtastic_CompassMode_FREEZE_HEADING) { validHeading = true; } else { - heading = screen->estimatedHeading(geoCoord.getLatitude() * 1e-7, geoCoord.getLongitude() * 1e-7); - validHeading = !isnan(heading); + if (screen->hasHeading()) { + heading = radians(screen->getHeading()); + validHeading = true; + } else { + heading = screen->estimatedHeading(geoCoord.getLatitude() * 1e-7, geoCoord.getLongitude() * 1e-7); + validHeading = !isnan(heading); + } } // If GPS is off, no need to display these parts @@ -1005,7 +976,9 @@ void UIRenderer::drawCompassAndLocationScreen(OLEDDisplay *display, OLEDDisplayU display->drawCircle(compassX, compassY, compassRadius); // "N" label - float northAngle = -heading; + float northAngle = 0; + if (uiconfig.compass_mode != meshtastic_CompassMode_FIXED_RING) + northAngle = -heading; float radius = compassRadius; int16_t nX = compassX + (radius - 1) * sin(northAngle); int16_t nY = compassY - (radius - 1) * cos(northAngle); @@ -1046,7 +1019,9 @@ void UIRenderer::drawCompassAndLocationScreen(OLEDDisplay *display, OLEDDisplayU display->drawCircle(compassX, compassY, compassRadius); // "N" label - float northAngle = -heading; + float northAngle = 0; + if (uiconfig.compass_mode != meshtastic_CompassMode_FIXED_RING) + northAngle = -heading; float radius = compassRadius; int16_t nX = compassX + (radius - 1) * sin(northAngle); int16_t nY = compassY - (radius - 1) * cos(northAngle); @@ -1069,9 +1044,16 @@ void UIRenderer::drawCompassAndLocationScreen(OLEDDisplay *display, OLEDDisplayU void UIRenderer::drawOEMIconScreen(const char *upperMsg, OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) { static const uint8_t xbm[] = USERPREFS_OEM_IMAGE_DATA; - display->drawXbm(x + (SCREEN_WIDTH - USERPREFS_OEM_IMAGE_WIDTH) / 2, - y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - USERPREFS_OEM_IMAGE_HEIGHT) / 2 + 2, USERPREFS_OEM_IMAGE_WIDTH, - USERPREFS_OEM_IMAGE_HEIGHT, xbm); + if (isHighResolution) { + display->drawXbm(x + (SCREEN_WIDTH - USERPREFS_OEM_IMAGE_WIDTH) / 2, + y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - USERPREFS_OEM_IMAGE_HEIGHT) / 2 + 2, USERPREFS_OEM_IMAGE_WIDTH, + USERPREFS_OEM_IMAGE_HEIGHT, xbm); + } else { + + display->drawXbm(x + (SCREEN_WIDTH - USERPREFS_OEM_IMAGE_WIDTH) / 2, + y + (SCREEN_HEIGHT - USERPREFS_OEM_IMAGE_HEIGHT) / 2 + 2, USERPREFS_OEM_IMAGE_WIDTH, + USERPREFS_OEM_IMAGE_HEIGHT, xbm); + } switch (USERPREFS_OEM_FONT_SIZE) { case 0: @@ -1087,7 +1069,9 @@ void UIRenderer::drawOEMIconScreen(const char *upperMsg, OLEDDisplay *display, O display->setTextAlignment(TEXT_ALIGN_LEFT); const char *title = USERPREFS_OEM_TEXT; - display->drawString(x + getStringCenteredX(title), y + SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM, title); + if (isHighResolution) { + display->drawString(x + getStringCenteredX(title), y + SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM, title); + } display->setFont(FONT_SMALL); // Draw region in upper left @@ -1114,18 +1098,6 @@ void UIRenderer::drawOEMBootScreen(OLEDDisplay *display, OLEDDisplayUiState *sta #endif -// Function overlay for showing mute/buzzer modifiers etc. -void UIRenderer::drawFunctionOverlay(OLEDDisplay *display, OLEDDisplayUiState *state) -{ - // LOG_DEBUG("Draw function overlay"); - if (functionSymbol.begin() != functionSymbol.end()) { - char buf[64]; - display->setFont(FONT_SMALL); - snprintf(buf, sizeof(buf), "%s", functionSymbolString.c_str()); - display->drawString(SCREEN_WIDTH - display->getStringWidth(buf), SCREEN_HEIGHT - FONT_HEIGHT_SMALL, buf); - } -} - // Navigation bar overlay implementation static int8_t lastFrameIndex = -1; static uint32_t lastFrameChangeTime = 0; @@ -1141,10 +1113,9 @@ void UIRenderer::drawNavigationBar(OLEDDisplay *display, OLEDDisplayUiState *sta lastFrameChangeTime = millis(); } - const bool useBigIcons = (SCREEN_WIDTH > 128); - const int iconSize = useBigIcons ? 16 : 8; - const int spacing = useBigIcons ? 8 : 4; - const int bigOffset = useBigIcons ? 1 : 0; + const int iconSize = isHighResolution ? 16 : 8; + const int spacing = isHighResolution ? 8 : 4; + const int bigOffset = isHighResolution ? 1 : 0; const size_t totalIcons = screen->indicatorIcons.size(); if (totalIcons == 0) @@ -1158,14 +1129,35 @@ void UIRenderer::drawNavigationBar(OLEDDisplay *display, OLEDDisplayUiState *sta const int totalWidth = (pageEnd - pageStart) * iconSize + (pageEnd - pageStart - 1) * spacing; const int xStart = (SCREEN_WIDTH - totalWidth) / 2; - // Only show bar briefly after switching frames (unless on E-Ink) + // Only show bar briefly after switching frames + static uint32_t navBarLastShown = 0; + static bool cosmeticRefreshDone = false; + + bool navBarVisible = millis() - lastFrameChangeTime <= ICON_DISPLAY_DURATION_MS; + int y = navBarVisible ? (SCREEN_HEIGHT - iconSize - 1) : SCREEN_HEIGHT; + #if defined(USE_EINK) - int y = SCREEN_HEIGHT - iconSize - 1; -#else - int y = SCREEN_HEIGHT - iconSize - 1; - if (millis() - lastFrameChangeTime > ICON_DISPLAY_DURATION_MS) { - y = SCREEN_HEIGHT; + static bool navBarPrevVisible = false; + + if (navBarVisible && !navBarPrevVisible) { + EINK_ADD_FRAMEFLAG(display, DEMAND_FAST); // Fast refresh when showing nav bar + cosmeticRefreshDone = false; + navBarLastShown = millis(); } + + if (!navBarVisible && navBarPrevVisible) { + EINK_ADD_FRAMEFLAG(display, DEMAND_FAST); // Fast refresh when hiding nav bar + navBarLastShown = millis(); // Mark when it disappeared + } + + if (!navBarVisible && navBarLastShown != 0 && !cosmeticRefreshDone) { + if (millis() - navBarLastShown > 10000) { // 10s after hidden + EINK_ADD_FRAMEFLAG(display, COSMETIC); // One-time ghost cleanup + cosmeticRefreshDone = true; + } + } + + navBarPrevVisible = navBarVisible; #endif // Pre-calculate bounding rect @@ -1191,7 +1183,7 @@ void UIRenderer::drawNavigationBar(OLEDDisplay *display, OLEDDisplayUiState *sta display->setColor(BLACK); } - if (useBigIcons) { + if (isHighResolution) { NodeListRenderer::drawScaledXBitmap16x16(x, y, 8, 8, icon, display); } else { display->drawXbm(x, y, iconSize, iconSize, icon); @@ -1236,5 +1228,4 @@ std::string UIRenderer::drawTimeDelta(uint32_t days, uint32_t hours, uint32_t mi } // namespace graphics -#endif // !MESHTASTIC_EXCLUDE_GPS #endif // HAS_SCREEN \ No newline at end of file diff --git a/src/graphics/draw/UIRenderer.h b/src/graphics/draw/UIRenderer.h index 21e4aef61..9e5e8c4b4 100644 --- a/src/graphics/draw/UIRenderer.h +++ b/src/graphics/draw/UIRenderer.h @@ -32,8 +32,6 @@ class UIRenderer { public: // Common UI elements - static void drawBattery(OLEDDisplay *display, int16_t x, int16_t y, uint8_t *imgBuffer, - const meshtastic::PowerStatus *powerStatus); static void drawNodes(OLEDDisplay *display, int16_t x, int16_t y, const meshtastic::NodeStatus *nodeStatus, int node_offset = 0, bool show_total = true, String additional_words = ""); @@ -49,9 +47,6 @@ class UIRenderer // Overlay and special screens static void drawFrameText(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y, const char *text); - // Function overlay for showing mute/buzzer modifiers etc. - static void drawFunctionOverlay(OLEDDisplay *display, OLEDDisplayUiState *state); - // Navigation bar overlay static void drawNavigationBar(OLEDDisplay *display, OLEDDisplayUiState *state); diff --git a/src/graphics/emotes.cpp b/src/graphics/emotes.cpp index 205d5c660..e1a105d20 100644 --- a/src/graphics/emotes.cpp +++ b/src/graphics/emotes.cpp @@ -11,11 +11,11 @@ const Emote emotes[] = { {"\U0001F44E", thumbdown, thumbs_width, thumbs_height}, // 👎 Thumbs Down // --- Smileys (Multiple Unicode Aliases) --- - {"\U0001F60A", smiley, smiley_width, smiley_height}, // 😊 Smiling Face with Smiling Eyes - {"\U0001F600", smiley, smiley_width, smiley_height}, // 😀 Grinning Face - {"\U0001F642", smiley, smiley_width, smiley_height}, // 🙂 Slightly Smiling Face - {"\U0001F609", smiley, smiley_width, smiley_height}, // 😉 Winking Face - {"\U0001F601", smiley, smiley_width, smiley_height}, // 😁 Grinning Face with Smiling Eyes + {"\U0001F60A", Smiling_Eyes, Smiling_Eyes_width, Smiling_Eyes_height}, // 😊 Smiling Eyes + {"\U0001F600", Grinning, Grinning_width, Grinning_height}, // 😀 Grinning Face + {"\U0001F642", Slightly_Smiling, Slightly_Smiling_width, Slightly_Smiling_height}, // 🙂 Slightly Smiling Face + {"\U0001F609", Winking_Face, Winking_Face_width, Winking_Face_height}, // 😉 Winking Face + {"\U0001F601", Grinning_Smiling_Eyes, Grinning_Smiling_Eyes_width, Grinning_Smiling_Eyes_height}, // 😁 Grinning Smiling Eyes // --- Question/Alert --- {"\u2753", question, question_width, question_height}, // ❓ Question Mark @@ -23,10 +23,11 @@ const Emote emotes[] = { // --- Laughing Faces --- {"\U0001F602", haha, haha_width, haha_height}, // 😂 Face with Tears of Joy - {"\U0001F923", haha, haha_width, haha_height}, // 🤣 Rolling on the Floor Laughing - {"\U0001F606", haha, haha_width, haha_height}, // 😆 Smiling with Open Mouth and Closed Eyes - {"\U0001F605", haha, haha_width, haha_height}, // 😅 Smiling with Sweat - {"\U0001F604", haha, haha_width, haha_height}, // 😄 Grinning Face with Smiling Eyes + {"\U0001F923", ROFL, ROFL_width, ROFL_height}, // 🤣 Rolling on the Floor Laughing + {"\U0001F606", Smiling_Closed_Eyes, Smiling_Closed_Eyes_width, Smiling_Closed_Eyes_height}, // 😆 Smiling Closed Eyes + {"\U0001F605", haha, haha_width, haha_height}, // 😅 Smiling with Sweat + {"\U0001F604", Grinning_SmilingEyes2, Grinning_SmilingEyes2_width, + Grinning_SmilingEyes2_height}, // 😄 Grinning Face with Smiling Eyes // --- Gestures and People --- {"\U0001F44B", wave_icon, wave_icon_width, wave_icon_height}, // 👋 Waving Hand @@ -78,13 +79,45 @@ const unsigned char thumbdown[] PROGMEM = { 0x80, 0x09, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, }; -const unsigned char smiley[] PROGMEM = { - 0x00, 0xfe, 0x0f, 0x00, 0x80, 0x01, 0x30, 0x00, 0x40, 0x00, 0xc0, 0x00, 0x20, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x02, - 0x08, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x10, 0x02, 0x0e, 0x0e, 0x10, 0x02, 0x09, 0x12, 0x10, - 0x01, 0x09, 0x12, 0x20, 0x01, 0x0f, 0x1e, 0x20, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, - 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, 0x81, 0x00, 0x20, 0x20, - 0x82, 0x00, 0x20, 0x10, 0x02, 0x01, 0x10, 0x10, 0x04, 0x02, 0x08, 0x08, 0x04, 0xfc, 0x07, 0x08, 0x08, 0x00, 0x00, 0x04, - 0x10, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x01, 0x40, 0x00, 0xc0, 0x00, 0x80, 0x01, 0x30, 0x00, 0x00, 0xfe, 0x0f, 0x00}; +const unsigned char Smiling_Eyes[] PROGMEM = { + 0x00, 0xf8, 0x03, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0xc0, 0xff, 0xff, 0xc0, 0xe0, 0xff, 0xff, 0xc1, + 0xf0, 0xff, 0xff, 0xc3, 0xf8, 0xff, 0xff, 0xc7, 0xf8, 0xff, 0xff, 0xcf, 0xfc, 0xff, 0xff, 0xcf, 0xfc, 0xff, 0xff, 0xcf, + 0x7e, 0xf8, 0xc3, 0xdf, 0x3e, 0xf0, 0x81, 0xdf, 0xbf, 0xf7, 0xbd, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f, 0xff, 0x3f, 0xff, + 0x6f, 0xff, 0xdf, 0xfe, 0x6f, 0xff, 0xdf, 0xfe, 0x9f, 0xff, 0x3f, 0xff, 0xfe, 0xff, 0xff, 0xdf, 0x7e, 0xff, 0xdf, 0xdf, + 0x7c, 0xff, 0xdf, 0xcf, 0xfc, 0xfe, 0xef, 0xcf, 0xf8, 0xf9, 0xf7, 0xc7, 0xf8, 0x03, 0xf8, 0xc7, 0xf0, 0xff, 0xff, 0xc3, + 0xe0, 0xff, 0xff, 0xc1, 0xc0, 0xff, 0xff, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x00, 0xf8, 0x07, 0xc0}; + +const unsigned char Grinning[] PROGMEM = { + 0x00, 0xf8, 0x03, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0xc0, 0xff, 0xff, 0xc0, 0xe0, 0xff, 0xff, 0xc1, + 0xf0, 0xff, 0xff, 0xc3, 0xf8, 0xff, 0xff, 0xc7, 0xf8, 0xff, 0xff, 0xcf, 0xfc, 0xf9, 0xf3, 0xcf, 0xfc, 0xf0, 0xe1, 0xcf, + 0xfe, 0xf0, 0xe1, 0xdf, 0xfe, 0xf0, 0xe1, 0xdf, 0xff, 0xf0, 0xe1, 0xff, 0xff, 0xf9, 0xf3, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x80, 0xff, 0xbe, 0xff, 0xbf, 0xdf, 0x7e, 0x00, 0xc0, 0xdf, + 0x7c, 0x00, 0xc0, 0xcf, 0xfc, 0x00, 0xe0, 0xcf, 0xf8, 0x01, 0xf0, 0xc7, 0xf8, 0x03, 0xf8, 0xc7, 0xf0, 0xff, 0xff, 0xc3, + 0xe0, 0xff, 0xff, 0xc1, 0xc0, 0xff, 0xff, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x00, 0xf8, 0x03, 0xc0}; + +const unsigned char Slightly_Smiling[] PROGMEM = { + 0x00, 0xf8, 0x03, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0xc0, 0xff, 0xff, 0xc0, 0xe0, 0xff, 0xff, 0xc1, + 0xf0, 0xff, 0xff, 0xc3, 0xf8, 0xff, 0xff, 0xc7, 0xf8, 0xff, 0xff, 0xcf, 0xfc, 0xf9, 0xf3, 0xcf, 0xfc, 0xf0, 0xe1, 0xcf, + 0xfe, 0xf0, 0xe1, 0xdf, 0xfe, 0xf0, 0xe1, 0xdf, 0xff, 0xf0, 0xe1, 0xff, 0xff, 0xf9, 0xf3, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xdf, 0x7e, 0xff, 0xdf, 0xdf, + 0x7c, 0xff, 0xdf, 0xcf, 0xfc, 0xfe, 0xef, 0xcf, 0xf8, 0xf9, 0xf7, 0xc7, 0xf8, 0x03, 0xf8, 0xc7, 0xf0, 0xff, 0xff, 0xc3, + 0xe0, 0xff, 0xff, 0xc1, 0xc0, 0xff, 0xff, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x00, 0xf8, 0x03, 0xc0}; + +const unsigned char Winking_Face[] PROGMEM = { + 0x00, 0xf8, 0x03, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0xc0, 0xff, 0xff, 0xc0, 0xe0, 0xff, 0xff, 0xc1, + 0xf0, 0xf0, 0xff, 0xc3, 0x78, 0xef, 0xc3, 0xc7, 0xb8, 0xdf, 0xbd, 0xcf, 0xfc, 0xf9, 0x7f, 0xcf, 0xfc, 0xf0, 0xff, 0xcf, + 0xfe, 0xf0, 0xc3, 0xdf, 0xfe, 0xf0, 0x81, 0xdf, 0xff, 0xf0, 0xbf, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xdf, 0x7e, 0xff, 0xdf, 0xdf, + 0x7c, 0xff, 0xdf, 0xcf, 0xfc, 0xfe, 0xef, 0xcf, 0xf8, 0xf9, 0xf7, 0xc7, 0xf8, 0x03, 0xf8, 0xc7, 0xf0, 0xff, 0xff, 0xc3, + 0xe0, 0xff, 0xff, 0xc1, 0xc0, 0xff, 0xff, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x00, 0xf8, 0x07, 0xc0}; + +const unsigned char Grinning_Smiling_Eyes[] PROGMEM = { + 0x00, 0xf8, 0x03, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0xc0, 0xff, 0xff, 0xc0, 0xe0, 0xff, 0xff, 0xc1, + 0xf0, 0xff, 0xff, 0xc3, 0xf8, 0xff, 0xff, 0xc7, 0xf8, 0xff, 0xff, 0xcf, 0xfc, 0xf8, 0xe3, 0xcf, 0x7c, 0xf7, 0xdd, 0xcf, + 0xbe, 0xef, 0xbe, 0xdf, 0xbe, 0xef, 0xbe, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0xff, 0x5e, 0x55, 0x55, 0xdf, 0x5e, 0x55, 0x55, 0xdf, + 0x3c, 0x00, 0x80, 0xcf, 0x7c, 0x55, 0xd5, 0xcf, 0xf8, 0x54, 0xe5, 0xc7, 0xf8, 0x03, 0xf8, 0xc7, 0xf0, 0xff, 0xff, 0xc3, + 0xe0, 0xff, 0xff, 0xc1, 0xc0, 0xff, 0xff, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x00, 0xf8, 0x03, 0xc0}; const unsigned char question[] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x80, 0xFF, 0x01, 0x00, 0xC0, 0xFF, 0x07, 0x00, 0xE0, 0xFF, 0x07, 0x00, @@ -104,31 +137,52 @@ const unsigned char bang[] PROGMEM = { }; const unsigned char haha[] PROGMEM = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x01, 0x00, - 0x00, 0xFC, 0x0F, 0x00, 0x00, 0x1F, 0x3E, 0x00, 0x80, 0x03, 0x70, 0x00, 0xC0, 0x01, 0xE0, 0x00, 0xC0, 0x00, 0xC2, 0x00, - 0x60, 0x00, 0x03, 0x00, 0x60, 0x00, 0xC1, 0x1F, 0x60, 0x80, 0x8F, 0x31, 0x30, 0x0E, 0x80, 0x31, 0x30, 0x10, 0x30, 0x1F, - 0x30, 0x08, 0x58, 0x00, 0x30, 0x04, 0x6C, 0x03, 0x60, 0x00, 0xF3, 0x01, 0x60, 0xC0, 0xFC, 0x01, 0x80, 0x38, 0xBF, 0x01, - 0xE0, 0xC5, 0xDF, 0x00, 0xB0, 0xF9, 0xEF, 0x00, 0x30, 0xF1, 0x73, 0x00, 0xB0, 0x1D, 0x3E, 0x00, 0xF0, 0xFD, 0x0F, 0x00, - 0xE0, 0xE0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; + 0x00, 0xf8, 0x03, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0xc0, 0xff, 0x7f, 0xc0, 0xe0, 0xf9, 0xf3, 0xc0, + 0xf0, 0xfe, 0xef, 0xc1, 0x38, 0xff, 0x9f, 0xc3, 0xd8, 0xff, 0x7f, 0xc3, 0xfc, 0xf8, 0xe3, 0xc7, 0x7c, 0xf7, 0xdd, 0xcf, + 0xbe, 0xef, 0xbe, 0xcf, 0xfe, 0xff, 0xff, 0xcf, 0xef, 0xff, 0xff, 0xde, 0xe7, 0xff, 0xff, 0xdc, 0xeb, 0xff, 0xff, 0xda, + 0xed, 0xff, 0xff, 0xd6, 0xee, 0xff, 0xff, 0xce, 0x36, 0x00, 0x80, 0xcd, 0xb8, 0xff, 0xbf, 0xc3, 0x7e, 0x00, 0xc0, 0xdf, + 0x7c, 0x00, 0xc0, 0xcf, 0xfc, 0x00, 0xe0, 0xcf, 0xf8, 0x01, 0xf0, 0xc7, 0xf8, 0x03, 0xf8, 0xc7, 0xf0, 0xff, 0xff, 0xc3, + 0xe0, 0xff, 0xff, 0xc1, 0xc0, 0xff, 0xff, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x00, 0xf8, 0x03, 0xc0}; + +const unsigned char ROFL[] PROGMEM = { + 0x00, 0x00, 0x00, 0xc0, 0x00, 0xfc, 0x07, 0xc0, 0x00, 0xff, 0x1f, 0xc0, 0x80, 0xff, 0x7f, 0xc0, 0xc0, 0xff, 0xff, 0xc0, + 0xe0, 0x9f, 0xff, 0xc1, 0xf0, 0x9f, 0xff, 0xc0, 0xf8, 0x9f, 0x7f, 0xcb, 0xf8, 0x9f, 0xbf, 0xcb, 0xfc, 0x9f, 0xdf, 0xdb, + 0xfc, 0x1f, 0x08, 0xdc, 0xfe, 0x1f, 0xf8, 0xfe, 0xfe, 0xff, 0xff, 0xfe, 0x1e, 0xf0, 0x7f, 0xfe, 0x1e, 0xf0, 0xbf, 0xfe, + 0xfe, 0xf3, 0xdf, 0xfe, 0xfe, 0xf3, 0x6f, 0xfe, 0xfe, 0xf3, 0x37, 0xfe, 0xfe, 0xeb, 0x1b, 0xfe, 0xfc, 0xef, 0x0d, 0xde, + 0xfc, 0xe7, 0x06, 0xcf, 0xf8, 0x6b, 0x83, 0xcf, 0xf8, 0x0d, 0xc0, 0xc7, 0xf0, 0xed, 0xff, 0xc7, 0xe0, 0xee, 0xff, 0xc3, + 0xc0, 0xee, 0xff, 0xc1, 0x80, 0xee, 0xff, 0xc0, 0x00, 0xe6, 0x3f, 0xc0, 0x00, 0xf0, 0x0f, 0xc0, 0x00, 0x00, 0x00, 0xc0}; + +const unsigned char Smiling_Closed_Eyes[] PROGMEM = { + 0x00, 0xf8, 0x03, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0xc0, 0xff, 0xff, 0xc0, 0xe0, 0xff, 0xff, 0xc1, + 0xf0, 0xff, 0xff, 0xc3, 0xf8, 0xff, 0xff, 0xc7, 0xf8, 0xff, 0xff, 0xcf, 0x7c, 0xfe, 0xcf, 0xcf, 0xfc, 0xfc, 0xe7, 0xcf, + 0xfe, 0xf9, 0xf3, 0xdf, 0xfe, 0xf3, 0xf9, 0xdf, 0xff, 0xf9, 0xf3, 0xff, 0xff, 0xfc, 0xe7, 0xff, 0x7f, 0xfe, 0xcf, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x80, 0xff, 0xbe, 0xff, 0xbf, 0xdf, 0x7e, 0x00, 0xc0, 0xdf, + 0x7c, 0x00, 0xc0, 0xcf, 0xfc, 0x00, 0xe0, 0xcf, 0xf8, 0x01, 0xf0, 0xc7, 0xf8, 0x03, 0xf8, 0xc7, 0xf0, 0xff, 0xff, 0xc3, + 0xe0, 0xff, 0xff, 0xc1, 0xc0, 0xff, 0xff, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x00, 0xf8, 0x03, 0xc0}; + +const unsigned char Grinning_SmilingEyes2[] PROGMEM = { + 0x00, 0xf8, 0x03, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0xc0, 0xff, 0x7f, 0xc0, 0xe0, 0xff, 0xff, 0xc0, + 0xf0, 0xff, 0xff, 0xc1, 0xf8, 0xff, 0xff, 0xc3, 0xf8, 0xff, 0xff, 0xc3, 0xfc, 0xf8, 0xe3, 0xc7, 0x7c, 0xf7, 0xdd, 0xc7, + 0xbe, 0xef, 0xbe, 0xcf, 0xfe, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xdf, + 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xdf, 0x3f, 0x00, 0x80, 0xdf, 0xbe, 0xff, 0xbf, 0xcf, 0x7e, 0x00, 0xc0, 0xcf, + 0x7c, 0x00, 0xc0, 0xc7, 0xfc, 0x00, 0xe0, 0xc7, 0xf8, 0x01, 0xf0, 0xc3, 0xf8, 0x03, 0xf8, 0xc3, 0xf0, 0xff, 0xff, 0xc1, + 0xe0, 0xff, 0xff, 0xc0, 0xc0, 0xff, 0x7f, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x00, 0xf8, 0x03, 0xc0}; const unsigned char wave_icon[] PROGMEM = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xC0, 0x00, - 0x00, 0x0C, 0x9C, 0x01, 0x80, 0x17, 0x20, 0x01, 0x80, 0x26, 0x46, 0x02, 0x80, 0x44, 0x88, 0x02, 0xC0, 0x89, 0x8A, 0x02, - 0x40, 0x93, 0x8B, 0x02, 0x40, 0x26, 0x13, 0x00, 0x80, 0x44, 0x16, 0x00, 0xC0, 0x89, 0x24, 0x00, 0x40, 0x93, 0x60, 0x00, - 0x40, 0x26, 0x40, 0x00, 0x80, 0x0C, 0x80, 0x00, 0x00, 0x09, 0x80, 0x00, 0x00, 0x02, 0x80, 0x00, 0x40, 0x06, 0x80, 0x00, - 0x50, 0x0C, 0x80, 0x00, 0x50, 0x08, 0x40, 0x00, 0x90, 0x10, 0x20, 0x00, 0xB0, 0x21, 0x10, 0x00, 0x20, 0x47, 0x18, 0x00, - 0x40, 0x80, 0x0F, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; + 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x7f, 0xc0, 0x00, 0x00, 0xc0, 0xc1, 0x00, 0x00, 0x00, 0xc7, + 0x00, 0x00, 0x1e, 0xcc, 0x00, 0x00, 0x30, 0xc8, 0x00, 0x00, 0x60, 0xd8, 0x00, 0x08, 0xc0, 0xd0, 0x00, 0x1a, 0x81, 0xd1, + 0x00, 0x36, 0x03, 0xd3, 0x80, 0x6d, 0x06, 0xd2, 0x00, 0xdb, 0x0c, 0xc2, 0x80, 0xb6, 0x1d, 0xc0, 0x80, 0x6d, 0x1f, 0xc0, + 0x00, 0xdb, 0x3f, 0xc0, 0x00, 0xf6, 0x7f, 0xc0, 0x00, 0xfc, 0x7f, 0xc0, 0x08, 0xf8, 0x7f, 0xc0, 0x48, 0xf0, 0x7f, 0xc0, + 0x48, 0xe0, 0x7f, 0xc0, 0xc8, 0xc0, 0x3f, 0xc0, 0x98, 0x81, 0x1f, 0xc0, 0x10, 0x03, 0x00, 0xc0, 0x30, 0x0e, 0x00, 0xc0, + 0x20, 0x38, 0x00, 0xc0, 0xe0, 0x00, 0x00, 0xc0, 0x80, 0x07, 0x00, 0xc0, 0x00, 0x1e, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0}; const unsigned char cowboy[] PROGMEM = { - 0x00, 0xF0, 0x03, 0x00, 0x00, 0xFC, 0x0F, 0x00, 0x00, 0xFE, 0x1F, 0x00, 0x00, 0xFF, 0x3F, 0x00, 0x3C, 0xFE, 0x1F, 0x0F, - 0xFE, 0xFE, 0xDF, 0x1F, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0x3F, - 0x3E, 0xC0, 0x00, 0x1F, 0x1E, 0x00, 0x00, 0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x08, 0x0E, 0x1C, 0x04, 0x00, 0x0E, 0x1C, 0x00, - 0x04, 0x0E, 0x1C, 0x08, 0x04, 0x0E, 0x1C, 0x08, 0x04, 0x04, 0x08, 0x08, 0x04, 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x08, - 0x8C, 0x07, 0x70, 0x0C, 0x88, 0xFC, 0x4F, 0x04, 0x88, 0x01, 0x40, 0x04, 0x90, 0xFF, 0x7F, 0x02, 0x30, 0x03, 0x30, 0x03, - 0x60, 0x0E, 0x9C, 0x01, 0xC0, 0xF8, 0xC7, 0x00, 0x80, 0x01, 0x60, 0x00, 0x00, 0x0E, 0x1C, 0x00, 0x00, 0xF8, 0x07, 0x00, -}; + 0x00, 0x0c, 0x0c, 0xc0, 0x00, 0x02, 0x10, 0xc0, 0x00, 0x01, 0x20, 0xc0, 0xbc, 0x00, 0x40, 0xcf, 0xc2, 0x01, 0xe0, 0xd0, + 0x01, 0x01, 0x20, 0xe0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, + 0xc1, 0x3f, 0xff, 0xe0, 0xe1, 0xff, 0xff, 0xe1, 0xf2, 0xf3, 0xf3, 0xd3, 0xf4, 0xf1, 0xe3, 0xcb, 0xfc, 0xf1, 0xe3, 0xc7, + 0xf8, 0xf1, 0xe3, 0xc7, 0xf8, 0xf1, 0xe3, 0xc7, 0xf8, 0xfb, 0xf7, 0xc7, 0xf8, 0xff, 0xff, 0xc7, 0xf8, 0xff, 0xff, 0xc7, + 0x70, 0xf8, 0x8f, 0xc3, 0x70, 0x03, 0xb0, 0xc3, 0x70, 0xfe, 0xbf, 0xc3, 0x60, 0x00, 0x80, 0xc1, 0xc0, 0x00, 0xc0, 0xc0, + 0x80, 0x01, 0x60, 0xc0, 0x00, 0x07, 0x38, 0xc0, 0x00, 0xfe, 0x1f, 0xc0, 0x00, 0xf0, 0x03, 0xc0, 0x00, 0x00, 0x00, 0xc0}; const unsigned char deadmau5[] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x07, 0x00, @@ -181,13 +235,12 @@ const unsigned char fog[] PROGMEM = { }; const unsigned char devil[] PROGMEM = { - 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x10, 0x03, 0xC0, 0x01, 0x38, 0x07, 0x7C, 0x0F, 0x38, 0x1F, 0x03, 0x30, 0x1E, - 0xFE, 0x01, 0xE0, 0x1F, 0x7E, 0x00, 0x80, 0x1F, 0x3C, 0x00, 0x00, 0x0F, 0x1C, 0x00, 0x00, 0x0E, 0x18, 0x00, 0x00, 0x06, - 0x08, 0x00, 0x00, 0x04, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x0E, 0x1C, 0x0C, - 0x0C, 0x18, 0x06, 0x0C, 0x0C, 0x1C, 0x06, 0x0C, 0x0C, 0x1C, 0x0E, 0x0C, 0x0C, 0x1C, 0x0E, 0x0C, 0x0C, 0x0C, 0x06, 0x0C, - 0x08, 0x00, 0x00, 0x06, 0x18, 0x02, 0x10, 0x06, 0x10, 0x0C, 0x0C, 0x03, 0x30, 0xF8, 0x07, 0x03, 0x60, 0xE0, 0x80, 0x01, - 0xC0, 0x00, 0xC0, 0x00, 0x80, 0x01, 0x70, 0x00, 0x00, 0x06, 0x1C, 0x00, 0x00, 0xF0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, -}; + 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0xf0, 0x0f, 0xfc, 0x0f, 0xfc, + 0x3f, 0xff, 0x3f, 0xff, 0xfe, 0xff, 0xff, 0xdf, 0xfe, 0xff, 0xff, 0xdf, 0xfe, 0xff, 0xff, 0xdf, 0xfc, 0xff, 0xff, 0xcf, + 0xfc, 0xff, 0xff, 0xcf, 0xf8, 0xff, 0xff, 0xc7, 0xf0, 0xff, 0xff, 0xc3, 0xf0, 0xff, 0xff, 0xc3, 0xf0, 0xf1, 0xe3, 0xc3, + 0xf0, 0xe7, 0xf9, 0xc3, 0xf0, 0xe7, 0xf9, 0xc3, 0xf0, 0xe3, 0xf1, 0xc3, 0xf0, 0xe3, 0xf1, 0xc3, 0xf0, 0xe7, 0xf9, 0xc3, + 0xf0, 0xff, 0xff, 0xc3, 0xe0, 0xfd, 0xef, 0xc1, 0xe0, 0xf3, 0xf3, 0xc1, 0xc0, 0x07, 0xf8, 0xc0, 0x80, 0x1f, 0x7e, 0xc0, + 0x00, 0xff, 0x3f, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x00, 0xf8, 0x03, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0}; const unsigned char heart[] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0xC0, 0x03, 0xF0, 0x00, 0xF8, 0x0F, 0xFC, 0x07, 0xFC, 0x1F, 0x06, 0x0E, 0xFE, 0x3F, 0x03, 0x18, @@ -199,13 +252,12 @@ const unsigned char heart[] PROGMEM = { }; const unsigned char poo[] PROGMEM = { - 0x00, 0x1C, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0xEC, 0x01, 0x00, 0x00, 0x8C, 0x07, 0x00, 0x00, 0x0C, 0x06, 0x00, - 0x00, 0x24, 0x0C, 0x00, 0x00, 0x34, 0x08, 0x00, 0x00, 0x1F, 0x08, 0x00, 0xC0, 0x0F, 0x08, 0x00, 0xC0, 0x00, 0x3C, 0x00, - 0x60, 0x00, 0x7C, 0x00, 0x60, 0x00, 0xC6, 0x00, 0x20, 0x00, 0xCB, 0x00, 0xA0, 0xC7, 0xFF, 0x00, 0xE0, 0x7F, 0xF7, 0x00, - 0xF0, 0x18, 0xE3, 0x03, 0x78, 0x18, 0x41, 0x03, 0x6C, 0x9B, 0x5D, 0x06, 0x64, 0x9B, 0x5D, 0x04, 0x44, 0x1A, 0x41, 0x04, - 0x4C, 0xD8, 0x63, 0x06, 0xF8, 0xFC, 0x36, 0x06, 0xFE, 0x0F, 0x9C, 0x1F, 0x07, 0x03, 0xC0, 0x30, 0x03, 0x00, 0x78, 0x20, - 0x01, 0x00, 0x1F, 0x20, 0x03, 0xE0, 0x03, 0x20, 0x07, 0x7E, 0x04, 0x30, 0xFE, 0x0F, 0xFC, 0x1F, 0xF0, 0x00, 0xF0, 0x0F, -}; + 0x00, 0x1c, 0x00, 0xc0, 0x00, 0x7c, 0x00, 0xc0, 0x00, 0xfc, 0x00, 0xc0, 0x00, 0x7c, 0x03, 0xc0, 0x00, 0xbe, 0x03, 0xc0, + 0x00, 0xdf, 0x0f, 0xc0, 0x80, 0xcf, 0x0f, 0xc0, 0xc0, 0xf1, 0x0f, 0xc0, 0x60, 0xfc, 0x0f, 0xc0, 0x30, 0xff, 0x07, 0xc0, + 0x90, 0xff, 0x3b, 0xc0, 0xc0, 0xff, 0x7d, 0xc0, 0xf8, 0xff, 0xfc, 0xc0, 0xf8, 0x3f, 0xf0, 0xc0, 0x78, 0x88, 0xc0, 0xc0, + 0x20, 0xe3, 0x18, 0xc0, 0x98, 0xe7, 0xbc, 0xc1, 0x9c, 0x64, 0xa4, 0xc3, 0x9e, 0x64, 0xa4, 0xc7, 0xbe, 0xe4, 0xa4, 0xc7, + 0xbc, 0x27, 0xbc, 0xc7, 0x38, 0x03, 0xd9, 0xc3, 0x00, 0xf0, 0x63, 0xc0, 0xf8, 0xfc, 0x3f, 0xcf, 0xfc, 0xff, 0x87, 0xdf, + 0xfe, 0xff, 0xe0, 0xdf, 0xfc, 0x1f, 0xfe, 0xdf, 0xf8, 0x07, 0xf8, 0xcf, 0xf0, 0x03, 0xe0, 0xc7, 0x00, 0x00, 0x00, 0xc0}; const unsigned char bell_icon[] PROGMEM = { 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b11110000, diff --git a/src/graphics/emotes.h b/src/graphics/emotes.h index 5640ac04a..30b164cbc 100644 --- a/src/graphics/emotes.h +++ b/src/graphics/emotes.h @@ -22,9 +22,25 @@ extern const int numEmotes; extern const unsigned char thumbup[] PROGMEM; extern const unsigned char thumbdown[] PROGMEM; -#define smiley_height 30 -#define smiley_width 30 -extern const unsigned char smiley[] PROGMEM; +#define Smiling_Eyes_height 30 +#define Smiling_Eyes_width 30 +extern const unsigned char Smiling_Eyes[] PROGMEM; + +#define Grinning_height 30 +#define Grinning_width 30 +extern const unsigned char Grinning[] PROGMEM; + +#define Slightly_Smiling_height 30 +#define Slightly_Smiling_width 30 +extern const unsigned char Slightly_Smiling[] PROGMEM; + +#define Winking_Face_height 30 +#define Winking_Face_width 30 +extern const unsigned char Winking_Face[] PROGMEM; + +#define Grinning_Smiling_Eyes_height 30 +#define Grinning_Smiling_Eyes_width 30 +extern const unsigned char Grinning_Smiling_Eyes[] PROGMEM; #define question_height 25 #define question_width 25 @@ -38,6 +54,18 @@ extern const unsigned char bang[] PROGMEM; #define haha_width 30 extern const unsigned char haha[] PROGMEM; +#define ROFL_height 30 +#define ROFL_width 30 +extern const unsigned char ROFL[] PROGMEM; + +#define Smiling_Closed_Eyes_height 30 +#define Smiling_Closed_Eyes_width 30 +extern const unsigned char Smiling_Closed_Eyes[] PROGMEM; + +#define Grinning_SmilingEyes2_height 30 +#define Grinning_SmilingEyes2_width 30 +extern const unsigned char Grinning_SmilingEyes2[] PROGMEM; + #define wave_icon_height 30 #define wave_icon_width 30 extern const unsigned char wave_icon[] PROGMEM; diff --git a/src/graphics/images.h b/src/graphics/images.h index e9c2f00ea..beef3a1b2 100644 --- a/src/graphics/images.h +++ b/src/graphics/images.h @@ -12,7 +12,10 @@ const uint8_t imgSatellite[] PROGMEM = { 0b00000000, 0b00000000, 0b00000000, 0b00011000, 0b11011011, 0b11111111, 0b11011011, 0b00011000, }; -const uint8_t imgUSB[] PROGMEM = {0x60, 0x60, 0x30, 0x18, 0x18, 0x18, 0x24, 0x42, 0x42, 0x42, 0x42, 0x7E, 0x24, 0x24, 0x24, 0x3C}; +const uint8_t imgUSB[] PROGMEM = {0x00, 0xfc, 0xf0, 0xfc, 0x88, 0xff, 0x86, 0xfe, 0x85, 0xfe, 0x89, 0xff, 0xf1, 0xfc, 0x00, 0xfc}; +const uint8_t imgUSB_HighResolution[] PROGMEM = {0x00, 0x3e, 0xf8, 0x80, 0x43, 0xf8, 0xc0, 0xc2, 0xff, 0x60, 0x42, 0xfc, + 0x3c, 0xc2, 0xff, 0x22, 0x42, 0xf8, 0x3d, 0x42, 0xf8, 0x22, 0xc2, 0xff, + 0x61, 0x42, 0xfc, 0xc0, 0xc2, 0xff, 0x80, 0x43, 0xf8, 0x00, 0x3e, 0xf8}; const uint8_t imgPower[] PROGMEM = {0x40, 0x40, 0x40, 0x58, 0x48, 0x08, 0x08, 0x08, 0x1C, 0x22, 0x22, 0x41, 0x7F, 0x22, 0x22, 0x22}; const uint8_t imgUser[] PROGMEM = {0x3C, 0x42, 0x99, 0xA5, 0xA5, 0x99, 0x42, 0x3C}; @@ -23,9 +26,6 @@ const uint8_t bluetoothConnectedIcon[36] PROGMEM = {0xfe, 0x01, 0xff, 0x03, 0x03 0xf3, 0x3f, 0x33, 0x30, 0x33, 0x33, 0x33, 0x33, 0x03, 0x33, 0xff, 0x33, 0xfe, 0x31, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0xf0, 0x3f, 0xe0, 0x1f}; -// This image definition is here instead of images.h because it's modified dynamically by the drawBattery function -static uint8_t imgBattery[16] = {0xFF, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xE7, 0x3C}; - #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(ILI9488_CS) || ARCH_PORTDUINO) && \ !defined(DISPLAY_FORCE_SMALL_FONTS) @@ -45,19 +45,15 @@ const uint8_t imgSF[] PROGMEM = {0xd2, 0xb7, 0xad, 0xbb, 0x92, 0x01, 0xfd, 0xfd, // === Horizontal battery === // Basic battery design and all related pieces -const unsigned char batteryBitmap_h[] PROGMEM = { - 0b11111110, 0b00000000, 0b11110000, 0b00000111, 0b00000001, 0b00000000, 0b00000000, 0b00001000, 0b00000001, 0b00000000, - 0b00000000, 0b00001000, 0b00000001, 0b00000000, 0b00000000, 0b00001000, 0b00000001, 0b00000000, 0b00000000, 0b00001000, - 0b00000001, 0b00000000, 0b00000000, 0b00011000, 0b00000001, 0b00000000, 0b00000000, 0b00011000, 0b00000001, 0b00000000, - 0b00000000, 0b00011000, 0b00000001, 0b00000000, 0b00000000, 0b00011000, 0b00000001, 0b00000000, 0b00000000, 0b00011000, - 0b00000001, 0b00000000, 0b00000000, 0b00001000, 0b00000001, 0b00000000, 0b00000000, 0b00001000, 0b00000001, 0b00000000, - 0b00000000, 0b00001000, 0b00000001, 0b00000000, 0b00000000, 0b00001000, 0b11111110, 0b00000000, 0b11110000, 0b00000111}; +const unsigned char batteryBitmap_h_bottom[] PROGMEM = { + 0b00011110, 0b00000000, 0b00000001, 0b00000000, 0b00000001, 0b00000000, 0b00000001, 0b00000000, 0b00000001, + 0b00000000, 0b00000001, 0b00000000, 0b00000001, 0b00000000, 0b00000001, 0b00000000, 0b00000001, 0b00000000, + 0b00000001, 0b00000000, 0b00000001, 0b00000000, 0b00000001, 0b00000000, 0b00011110, 0b00000000}; -// This is the left and right bars for the fill in -const unsigned char batteryBitmap_sidegaps_h[] PROGMEM = { - 0b11111111, 0b00001111, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b11111111, 0b00001111}; +const unsigned char batteryBitmap_h_top[] PROGMEM = { + 0b00111100, 0b00000000, 0b01000000, 0b00000000, 0b01000000, 0b00000000, 0b01000000, 0b00000000, 0b01000000, + 0b00000000, 0b11000000, 0b00000000, 0b11000000, 0b00000000, 0b11000000, 0b00000000, 0b01000000, 0b00000000, + 0b01000000, 0b00000000, 0b01000000, 0b00000000, 0b01000000, 0b00000000, 0b00111100, 0b00000000}; // Lightning Bolt const unsigned char lightning_bolt_h[] PROGMEM = { @@ -280,11 +276,16 @@ const uint8_t bluetoothdisabled[] PROGMEM = {0b11101100, 0b01010100, 0b01001100, const uint8_t smallbulletpoint[] PROGMEM = {0b00000011, 0b00000011, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000}; -// Clock -#define icon_clock_width 8 -#define icon_clock_height 8 -const uint8_t icon_clock[] PROGMEM = {0b00111100, 0b01000010, 0b10000101, 0b10101001, - 0b10010001, 0b10000001, 0b01000010, 0b00111100}; +// Digital Clock +#define digital_icon_clock_width 8 +#define digital_icon_clock_height 8 +const uint8_t digital_icon_clock[] PROGMEM = {0b00111100, 0b01000010, 0b10000101, 0b10101001, + 0b10010001, 0b10000001, 0b01000010, 0b00111100}; +// Analog Clock +#define analog_icon_clock_width 8 +#define analog_icon_clock_height 8 +const uint8_t analog_icon_clock[] PROGMEM = {0b11111111, 0b01000010, 0b00100100, 0b00011000, + 0b00100100, 0b01000010, 0b01000010, 0b11111111}; #include "img/icon.xbm" static_assert(sizeof(icon_bits) >= 0, "Silence unused variable warning"); \ No newline at end of file diff --git a/src/graphics/niche/Drivers/EInk/E0213A367.cpp b/src/graphics/niche/Drivers/EInk/E0213A367.cpp new file mode 100644 index 000000000..f19cb4ff7 --- /dev/null +++ b/src/graphics/niche/Drivers/EInk/E0213A367.cpp @@ -0,0 +1,84 @@ +#include "./E0213A367.h" + +#ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS + +using namespace NicheGraphics::Drivers; + +// Map the display controller IC's output to the connected panel +void E0213A367::configScanning() +{ + // "Driver output control" + // Scan gates from 0 to 249 (vertical resolution 250px) + sendCommand(0x01); + sendData(0xF9); + sendData(0x00); +} + +// Specify which information is used to control the sequence of voltages applied to move the pixels +void E0213A367::configWaveform() +{ + // This command (0x37) is poorly documented + // As of July 2025, the datasheet for this display's controller IC is unavailable + // The values are supplied by Heltec, who presumably have privileged access to information from the display manufacturer + // Datasheet for the similar SSD1680 IC hints at the function of this command: + + // "Spare VCOM OTP selection": + // Unclear why 0x40 is set. Sane values for related SSD1680 seem to be 0x80 or 0x00. + // Maybe value is redundant? No noticeable impact when set to 0x00. + // We'll leave it set to 0x40, following Heltec's lead, just in case. + + // "Display Mode" + // Seems to specify whether a waveform stored in OTP should use display mode 1 or 2 (full refresh or differential refresh) + + // Unusual that waveforms are programmed to OTP, but this meta information is not ..? + + sendCommand(0x37); // "Write Register for Display Option" ? + sendData(0x40); // "Spare VCOM OTP selection" ? + sendData(0x80); // "Display Mode for WS[7:0]" ? + sendData(0x03); // "Display Mode for WS[15:8]" ? + sendData(0x0E); // "Display Mode [23:16]" ? + + switch (updateType) { + case FAST: + sendCommand(0x3C); // Border waveform: + sendData(0x81); // As specified by Heltec. Actually VCOM (0x80)?. Bit 0 seems redundant here. + break; + case FULL: + default: + sendCommand(0x3C); // Border waveform: + sendData(0x01); // Follow LUT 1 (blink same as white pixels) + break; + } +} + +// Tell controller IC which operations to run +void E0213A367::configUpdateSequence() +{ + switch (updateType) { + case FAST: + sendCommand(0x22); // Set "update sequence" + sendData(0xFF); // Will load LUT from OTP memory, Display mode 2 "differential refresh" + break; + case FULL: + default: + sendCommand(0x22); // Set "update sequence" + sendData(0xF7); // Will load LUT from OTP memory, Display mode 1 "full refresh" + break; + } +} + +// Once the refresh operation has been started, +// begin periodically polling the display to check for completion, using the normal Meshtastic threading code +// Only used when refresh is "async" +void E0213A367::detachFromUpdate() +{ + switch (updateType) { + case FAST: + return beginPolling(50, 500); // At least 500ms for fast refresh + case FULL: + default: + return beginPolling(100, 1500); // At least 1.5 seconds for full refresh + } +} + +#endif // MESHTASTIC_INCLUDE_NICHE_GRAPHICS \ No newline at end of file diff --git a/src/graphics/niche/Drivers/EInk/E0213A367.h b/src/graphics/niche/Drivers/EInk/E0213A367.h new file mode 100644 index 000000000..a36fcb407 --- /dev/null +++ b/src/graphics/niche/Drivers/EInk/E0213A367.h @@ -0,0 +1,41 @@ +/* + +E-Ink display driver + - SSD1682 + - Manufacturer: SEEKINK + - Size: 2.13 inch + - Resolution: 122px x 255px + - Flex connector marking: HINK-E0213A162-A1 (hidden, printed on reverse) + +*/ + +#pragma once + +#ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS + +#include "configuration.h" + +#include "./SSD1682.h" + +namespace NicheGraphics::Drivers +{ +class E0213A367 : public SSD1682 +{ + // Display properties + private: + static constexpr uint32_t width = 122; + static constexpr uint32_t height = 250; + static constexpr UpdateTypes supported = (UpdateTypes)(FULL | FAST); + + public: + E0213A367() : SSD1682(width, height, supported, 0) {} + + protected: + void configScanning() override; + void configWaveform() override; + void configUpdateSequence() override; + void detachFromUpdate() override; +}; + +} // namespace NicheGraphics::Drivers +#endif // MESHTASTIC_INCLUDE_NICHE_GRAPHICS \ No newline at end of file diff --git a/src/graphics/niche/Drivers/EInk/SSD1682.cpp b/src/graphics/niche/Drivers/EInk/SSD1682.cpp new file mode 100644 index 000000000..c3d7f7786 --- /dev/null +++ b/src/graphics/niche/Drivers/EInk/SSD1682.cpp @@ -0,0 +1,41 @@ +#include "./SSD1682.h" + +#ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS + +using namespace NicheGraphics::Drivers; + +SSD1682::SSD1682(uint16_t width, uint16_t height, EInk::UpdateTypes supported, uint8_t bufferOffsetX) + : SSD16XX(width, height, supported, bufferOffsetX) +{ +} + +// SSD1682 only accepts single-byte x and y values +// This causes an incompatibility with the default SSD16XX::configFullscreen +void SSD1682::configFullscreen() +{ + // Define the boundaries of the "fullscreen" region, for the controller IC + static const uint8_t sx = bufferOffsetX; // Notice the offset + static const uint8_t sy = 0; + static const uint8_t ex = bufferRowSize + bufferOffsetX - 1; // End is "max index", not "count". Minus 1 handles this + static const uint8_t ey = height; + + // Data entry mode - Left to Right, Top to Bottom + sendCommand(0x11); + sendData(0x03); + + // Select controller IC memory region to display a fullscreen image + sendCommand(0x44); // Memory X start - end + sendData(sx); + sendData(ex); + sendCommand(0x45); // Memory Y start - end + sendData(sy); + sendData(ey); + + // Place the cursor at the start of this memory region, ready to send image data x=0 y=0 + sendCommand(0x4E); // Memory cursor X + sendData(sx); + sendCommand(0x4F); // Memory cursor y + sendData(sy); +} + +#endif \ No newline at end of file diff --git a/src/graphics/niche/Drivers/EInk/SSD1682.h b/src/graphics/niche/Drivers/EInk/SSD1682.h new file mode 100644 index 000000000..ba3008537 --- /dev/null +++ b/src/graphics/niche/Drivers/EInk/SSD1682.h @@ -0,0 +1,31 @@ +/* + +E-Ink base class for displays based on SSD1682 + +SSD1682 has a few quirks. We're implementing them here in a new base class, +to avoid re-implementing them every time we need to add a new SSD1682-based display. + +*/ + +#pragma once + +#ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS + +#include "configuration.h" + +#include "./SSD16XX.h" + +namespace NicheGraphics::Drivers +{ + +class SSD1682 : public SSD16XX +{ + public: + SSD1682(uint16_t width, uint16_t height, EInk::UpdateTypes supported, uint8_t bufferOffsetX = 0); + virtual void configFullscreen(); // Select memory region on controller IC + virtual void deepSleep() {} // Not usable (image memory not retained) +}; + +} // namespace NicheGraphics::Drivers + +#endif // MESHTASTIC_INCLUDE_NICHE_GRAPHICS \ No newline at end of file diff --git a/src/graphics/niche/Fonts/FreeSans12pt_Win1250.h b/src/graphics/niche/Fonts/FreeSans12pt_Win1250.h new file mode 100644 index 000000000..66edcc6ad --- /dev/null +++ b/src/graphics/niche/Fonts/FreeSans12pt_Win1250.h @@ -0,0 +1,527 @@ +// trunk-ignore-all(clang-format) +#pragma once +/* PROPERTIES + +FONT_NAME FreeSans12pt_Win1250 +*/ +const uint8_t FreeSans12pt_Win1250Bitmaps[] PROGMEM = { +/* 0x01 */ 0x00, 0x30, 0x00, 0x09, 0x00, 0x01, 0x20, 0x00, 0x24, 0x00, 0x04, 0x80, 0x01, 0x90, 0x00, 0x62, 0x00, 0x30, 0xFE, 0x04, 0x10, 0x5F, 0x02, 0x0B, 0x00, 0x7F, 0xE0, 0x0C, 0x1C, 0x02, 0x83, 0x81, 0x9F, 0xF0, 0x02, 0x1E, 0x00, 0x41, 0xC0, 0x0E, 0x7F, 0x81, 0x78, 0x18, 0x62, 0x00, 0xFF, 0xC0, +/* 0x02 */ 0x00, 0xFF, 0x80, 0x61, 0x13, 0xF0, 0x62, 0x60, 0x07, 0xFC, 0x00, 0x83, 0x80, 0x10, 0xF0, 0x33, 0xF6, 0x01, 0x41, 0xC0, 0x18, 0x38, 0x03, 0xFF, 0xE0, 0x47, 0x02, 0x08, 0x20, 0x61, 0xC4, 0x06, 0x17, 0x00, 0x22, 0x00, 0x02, 0x40, 0x00, 0x48, 0x00, 0x09, 0x00, 0x01, 0x20, 0x00, 0x3C, 0x00, +/* 0x03 */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x00, 0x02, 0x30, 0x00, 0x09, 0x04, 0x08, 0x48, 0x70, 0xE1, 0xC3, 0x87, 0x0E, 0x08, 0x10, 0x70, 0x00, 0x03, 0x80, 0x00, 0x14, 0x00, 0x00, 0xA1, 0x81, 0x8D, 0x87, 0xF0, 0x44, 0x00, 0x06, 0x30, 0x00, 0x60, 0xC0, 0x06, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00, +/* 0x04 */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x00, 0x02, 0x30, 0x00, 0x09, 0x10, 0x02, 0x48, 0xE0, 0x61, 0xC1, 0xCC, 0x0E, 0x78, 0x1C, 0x70, 0x00, 0x03, 0x80, 0x00, 0x14, 0xFF, 0xFC, 0xA6, 0x00, 0xCD, 0x9F, 0xFE, 0x44, 0x71, 0xE6, 0x30, 0xFC, 0x60, 0xC0, 0x06, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00, +/* 0x05 */ 0x00, 0x18, 0x00, 0x00, 0x40, 0x01, 0x90, 0x01, 0xF4, 0x08, 0x12, 0x23, 0xC1, 0x91, 0x2C, 0x1C, 0x8A, 0xC3, 0x64, 0x64, 0x13, 0x22, 0x41, 0x98, 0x26, 0x2C, 0xC4, 0x22, 0x60, 0x42, 0x13, 0x04, 0x30, 0x80, 0x61, 0xA4, 0x02, 0x18, 0x20, 0x03, 0x41, 0x00, 0x20, 0x08, 0x02, 0x00, 0x60, 0x40, 0x03, 0xF8, +/* 0x06 */ 0x00, 0x10, 0x00, 0x03, 0x00, 0x1C, 0x48, 0x00, 0xB4, 0x80, 0x09, 0xF9, 0xC0, 0xE0, 0xE4, 0x0C, 0x02, 0x8F, 0x80, 0x38, 0x88, 0x01, 0x0D, 0x00, 0x18, 0x30, 0x01, 0x60, 0x80, 0x13, 0x18, 0x03, 0xF2, 0xC0, 0x20, 0x26, 0x06, 0x07, 0xFF, 0xA0, 0x02, 0x39, 0x00, 0x14, 0x70, 0x01, 0xC3, 0x00, 0x18, 0x00, +/* 0x07 */ +/* 0x08 */ 0x00, 0x1F, 0x80, 0x00, 0x60, 0x80, 0x01, 0x00, 0x80, 0x06, 0x00, 0x80, 0x3C, 0x01, 0x01, 0x8C, 0x02, 0x02, 0x08, 0x04, 0x04, 0x08, 0x0C, 0x38, 0x00, 0x04, 0x80, 0x00, 0x06, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x2E, 0xC0, 0x01, 0x83, 0x7E, 0x0C, 0x10, 0x37, 0xE2, 0x61, 0x00, 0x0C, 0xC6, 0x10, 0x98, 0x0C, 0x63, 0x00, 0x00, 0xC6, 0x00, +/* 0x09 */ 0x00, 0x1F, 0x80, 0x00, 0x60, 0x80, 0x01, 0x00, 0x80, 0x06, 0x00, 0x80, 0x3C, 0x01, 0x01, 0x8C, 0x02, 0x02, 0x08, 0x04, 0x04, 0x08, 0x0C, 0x38, 0x00, 0x04, 0x80, 0x00, 0x06, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x2E, 0xC0, 0x01, 0x83, 0x7E, 0x0C, 0x00, 0x37, 0xE0, +/* 0x0A */ +/* 0x0B */ 0x1F, 0x07, 0xC1, 0x86, 0x41, 0x10, 0x0C, 0x04, 0x80, 0x40, 0x18, 0x00, 0x00, 0xC0, 0x00, 0x06, 0x00, 0x00, 0x30, 0x00, 0x01, 0x40, 0x00, 0x0A, 0x00, 0x00, 0x88, 0x00, 0x04, 0x40, 0x00, 0x41, 0x00, 0x02, 0x04, 0x00, 0x20, 0x20, 0x02, 0x00, 0x80, 0x20, 0x02, 0x02, 0x00, 0x08, 0x20, 0x00, 0x22, 0x00, 0x00, 0xE0, 0x00, +/* 0x0C */ 0x01, 0x00, 0x00, 0x38, 0x00, 0x04, 0xC0, 0x01, 0x08, 0x00, 0x18, 0x80, 0x1C, 0x10, 0x02, 0x07, 0x80, 0x81, 0x10, 0x1F, 0xC2, 0x02, 0x00, 0x60, 0x80, 0x1A, 0x20, 0x1C, 0x42, 0x1C, 0x08, 0xFE, 0x03, 0xA0, 0x01, 0x8C, 0x01, 0xC1, 0x43, 0xD0, 0x27, 0x81, 0xF8, +/* 0x0D */ +/* 0x0E */ 0x00, 0xE0, 0x00, 0x11, 0x00, 0x01, 0x10, 0x00, 0x0B, 0x00, 0x03, 0xF8, 0x00, 0x60, 0x60, 0x09, 0x02, 0x00, 0xA0, 0x10, 0x16, 0x01, 0x01, 0x40, 0x10, 0x10, 0x01, 0x01, 0x00, 0x08, 0x10, 0x00, 0x82, 0x1F, 0x08, 0x3F, 0x90, 0x44, 0x00, 0x06, 0xBF, 0xFF, 0xAF, 0xF0, 0xFF, 0xFF, 0x0F, 0xE3, 0xFB, 0xFC, +/* 0x0F */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x40, 0x12, 0x34, 0x00, 0x69, 0x40, 0x01, 0x49, 0xE0, 0xF1, 0xCD, 0x06, 0x8E, 0x28, 0x14, 0x71, 0x40, 0xA3, 0x8B, 0xFD, 0x14, 0x50, 0x68, 0xA2, 0x81, 0x4D, 0x97, 0xFA, 0x44, 0xBF, 0xD6, 0x31, 0x02, 0xE0, 0xC8, 0x16, 0x08, 0x61, 0x08, 0x21, 0xF0, 0x80, 0xF8, 0x78, 0x00, +/* 0x10 */ 0x00, 0xF0, 0x00, 0x3A, 0x00, 0x07, 0xC0, 0x00, 0xA8, 0x00, 0x1F, 0x00, 0x02, 0xB0, 0x00, 0x52, 0x00, 0x0A, 0x40, 0x02, 0x48, 0x00, 0x49, 0x00, 0x09, 0x30, 0x01, 0x22, 0x01, 0xC4, 0x70, 0xF0, 0x85, 0xE1, 0x10, 0x88, 0x37, 0x20, 0x03, 0x9C, 0x00, 0x37, 0x00, 0x06, 0x40, 0x01, 0x86, 0x00, +/* 0x11 */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x60, 0x02, 0x36, 0x00, 0x09, 0x04, 0x0C, 0x48, 0x60, 0xC1, 0xC3, 0x0F, 0x0E, 0x00, 0x08, 0x70, 0x00, 0x23, 0x80, 0x63, 0x84, 0x01, 0x9F, 0x20, 0x0C, 0xFD, 0x80, 0x27, 0xE4, 0x03, 0x3F, 0x30, 0x33, 0xE0, 0xC0, 0x00, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00, +/* 0x12 */ 0x00, 0xC2, 0x00, 0x1C, 0x24, 0x02, 0x18, 0x60, 0x64, 0x02, 0x02, 0x40, 0x20, 0x00, 0xF2, 0x03, 0x89, 0xE0, 0x7C, 0x80, 0x0E, 0x25, 0x80, 0xE1, 0x00, 0x1A, 0x08, 0x71, 0xB0, 0xC4, 0x39, 0x84, 0xC2, 0xCC, 0x40, 0x76, 0x7C, 0x05, 0xBB, 0x80, 0x4C, 0xE0, 0x0A, 0x78, 0x00, 0x9C, 0x00, 0x0F, 0x00, 0x00, +/* 0x13 */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x00, 0x02, 0x30, 0x00, 0x09, 0x00, 0x00, 0x48, 0x60, 0xC1, 0xC6, 0xC9, 0x0E, 0x00, 0x00, 0x70, 0x00, 0x03, 0x80, 0x00, 0x14, 0xFF, 0xF8, 0xA6, 0x00, 0xCD, 0x9F, 0xFE, 0x44, 0x71, 0xE6, 0x30, 0xFC, 0x60, 0xC0, 0x06, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00, +/* 0x14 */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x20, 0x22, 0x33, 0x01, 0x89, 0x20, 0x02, 0x48, 0x60, 0xE1, 0xC8, 0x80, 0x8E, 0x46, 0x46, 0x72, 0x32, 0x33, 0x9F, 0x9F, 0x94, 0x78, 0x78, 0xA0, 0x00, 0x0D, 0x80, 0x00, 0x44, 0x0E, 0x06, 0x30, 0x00, 0x60, 0xC0, 0x06, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00, +/* 0x15 */ 0x03, 0xFC, 0x20, 0x38, 0x1C, 0x81, 0x80, 0x1D, 0x08, 0x00, 0x32, 0x60, 0x00, 0x89, 0x00, 0x02, 0x18, 0x00, 0x08, 0x61, 0xC3, 0x22, 0x8D, 0x93, 0x72, 0x00, 0x00, 0x48, 0x00, 0x01, 0x20, 0x00, 0x04, 0x9F, 0xFF, 0x92, 0x60, 0x0E, 0x44, 0xFF, 0xF2, 0x11, 0xC3, 0x88, 0x21, 0xF8, 0x40, 0x40, 0x02, 0x00, 0xC0, 0x30, 0x00, 0xFF, 0x00, +/* 0x16 */ 0x03, 0x80, 0x03, 0xC0, 0x01, 0xE0, 0x01, 0xE0, 0x03, 0xF0, 0x03, 0xF0, 0x27, 0xF0, 0x6F, 0x70, 0x6E, 0x60, 0xFC, 0x60, 0xFC, 0x7E, 0xFC, 0x7E, 0xFC, 0x3F, 0xF4, 0x1F, 0xF4, 0x1F, 0xF0, 0x0E, 0x70, 0x0E, 0x30, 0x1C, 0x38, 0x38, 0x0F, 0xF0, +/* 0x17 */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x00, 0x02, 0x30, 0x00, 0x09, 0x00, 0x00, 0x48, 0x00, 0x21, 0xC0, 0x02, 0x8E, 0x20, 0xF4, 0x70, 0x84, 0x11, 0x82, 0x40, 0x84, 0x01, 0x03, 0x20, 0x0F, 0x85, 0x80, 0x03, 0x04, 0x00, 0x04, 0x30, 0x78, 0x10, 0xC0, 0x06, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00, +/* 0x18 */ 0x00, 0xFC, 0x00, 0x02, 0x06, 0x00, 0x08, 0x24, 0x00, 0x21, 0xA4, 0x00, 0x4C, 0x48, 0x00, 0xA0, 0x50, 0x01, 0x92, 0x60, 0x03, 0x24, 0xC0, 0x06, 0x01, 0x81, 0x28, 0x03, 0x49, 0x6C, 0xC4, 0xAD, 0xD8, 0x16, 0xA4, 0xCC, 0xC4, 0x44, 0x86, 0x13, 0x05, 0x00, 0x28, 0x0A, 0x00, 0x50, 0x14, 0x00, 0x90, 0x48, 0x01, 0x20, 0x90, 0x02, 0x41, 0x20, 0x00, 0x00, +/* 0x19 */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x00, 0x02, 0x30, 0x00, 0x09, 0x00, 0x00, 0x49, 0xC3, 0x81, 0xC0, 0x00, 0x0E, 0x78, 0xF0, 0x77, 0xEF, 0xC3, 0xA7, 0x4E, 0x15, 0x0A, 0x10, 0xA7, 0x8F, 0x0D, 0x80, 0x00, 0x44, 0x00, 0x06, 0x33, 0xF0, 0x60, 0xC0, 0x06, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00, +/* 0x1A */ 0xFF, 0xFF, 0x00, 0x06, 0x00, 0x0C, 0x3E, 0x18, 0x82, 0x32, 0x02, 0x64, 0x04, 0xC8, 0x09, 0x80, 0x23, 0x00, 0x86, 0x02, 0x0C, 0x08, 0x18, 0x10, 0x30, 0x00, 0x60, 0x00, 0xC0, 0x81, 0x80, 0x03, 0x00, 0x07, 0xFF, 0xF8, +/* 0x1B */ 0x00, 0xFE, 0x00, 0x03, 0x81, 0x80, 0x04, 0x00, 0x60, 0x08, 0x00, 0x30, 0x10, 0x00, 0x10, 0x30, 0x07, 0x88, 0x23, 0xC8, 0x08, 0x22, 0x00, 0x04, 0x60, 0x00, 0x44, 0x60, 0x00, 0x84, 0x63, 0x03, 0x04, 0x61, 0xFC, 0x04, 0x6B, 0x00, 0x9E, 0xA5, 0x01, 0x6A, 0xD5, 0x01, 0x43, 0xA8, 0x81, 0x05, 0xD0, 0x82, 0x0A, 0xA0, 0x82, 0x05, 0xC0, 0x82, 0x02, 0x61, 0xFF, 0x0C, 0x1E, 0x00, 0xF0, +/* 0x1C */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x30, 0x02, 0x32, 0x00, 0x09, 0x00, 0x00, 0x48, 0x20, 0x61, 0xC3, 0x84, 0x0E, 0x1C, 0x78, 0x70, 0x40, 0x03, 0x80, 0x00, 0x14, 0x00, 0x00, 0xA0, 0x03, 0x0D, 0x83, 0xF0, 0x44, 0x00, 0x06, 0x30, 0x00, 0x60, 0xC0, 0x06, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00, +/* 0x1D */ 0x01, 0xFE, 0x00, 0x3A, 0x1C, 0x03, 0x00, 0x30, 0x23, 0x1E, 0xC3, 0x38, 0x03, 0x10, 0xC3, 0x09, 0x00, 0x18, 0x68, 0x00, 0xC1, 0x40, 0x00, 0x0A, 0x07, 0x80, 0x50, 0x46, 0x02, 0x80, 0x00, 0x1A, 0x1E, 0x00, 0xCB, 0x10, 0x0D, 0x03, 0x00, 0x48, 0x60, 0x06, 0x40, 0x00, 0x22, 0x0C, 0x02, 0x10, 0x60, 0x60, 0x43, 0xFC, 0x01, 0xE0, 0x00, 0x00, +/* 0x1E */ 0x01, 0xF0, 0x00, 0xEA, 0xC0, 0x31, 0x5F, 0x04, 0x5F, 0x88, 0x80, 0xA0, 0x48, 0x0E, 0x02, 0x8F, 0x40, 0x3C, 0x10, 0x21, 0x66, 0x87, 0x15, 0x98, 0x71, 0x41, 0x02, 0x14, 0x00, 0x01, 0x40, 0x00, 0x14, 0x00, 0x01, 0x21, 0xFE, 0x12, 0x00, 0x02, 0x10, 0x00, 0x60, 0x80, 0x0C, 0x06, 0x01, 0x80, 0x3F, 0xE0, +/* 0x1F */ 0x0E, 0x00, 0x13, 0x00, 0x23, 0x00, 0xF3, 0x01, 0x31, 0x01, 0x11, 0x03, 0xD3, 0x06, 0xF2, 0x30, 0x34, 0xC7, 0x25, 0x33, 0x2B, 0xC2, 0x57, 0x04, 0x3A, 0x08, 0x72, 0x30, 0xA3, 0xC3, 0x40, 0x04, 0x40, 0x18, 0x40, 0x60, 0x7F, 0x80, +/* ' ' 0x20 */ +/* '!' 0x21 */ 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, +/* '"' 0x22 */ 0xCF, 0x3C, 0xF3, 0x8A, 0x20, +/* '#' 0x23 */ 0x06, 0x30, 0x31, 0x03, 0x18, 0x18, 0xC7, 0xFF, 0xBF, 0xFC, 0x31, 0x01, 0x18, 0x18, 0xC7, 0xFF, 0xBF, 0xFC, 0x31, 0x01, 0x18, 0x18, 0xC0, 0xC6, 0x06, 0x30, +/* '$' 0x24 */ 0x04, 0x03, 0xE1, 0xFF, 0x72, 0x7C, 0x47, 0x88, 0xF1, 0x07, 0xA0, 0x7E, 0x03, 0xF0, 0x17, 0x02, 0x7C, 0x47, 0x88, 0xF1, 0x1B, 0x26, 0x7F, 0xC3, 0xE0, 0x10, 0x02, 0x00, +/* '%' 0x25 */ 0x00, 0x06, 0x03, 0xC0, 0x40, 0x7E, 0x0C, 0x0E, 0x70, 0x80, 0xC3, 0x18, 0x0C, 0x31, 0x00, 0xE7, 0x30, 0x07, 0xE6, 0x00, 0x3C, 0x40, 0x00, 0x0C, 0x7C, 0x00, 0x8F, 0xE0, 0x19, 0xC7, 0x01, 0x18, 0x30, 0x31, 0x83, 0x02, 0x1C, 0x70, 0x40, 0xFE, 0x04, 0x07, 0xC0, +/* '&' 0x26 */ 0x0F, 0x00, 0x7E, 0x03, 0x9C, 0x0C, 0x30, 0x30, 0xC0, 0xE7, 0x01, 0xF8, 0x03, 0x80, 0x3E, 0x01, 0xCC, 0x6E, 0x39, 0xB0, 0x7C, 0xC0, 0xF3, 0x03, 0xCE, 0x1F, 0x9F, 0xE6, 0x3E, 0x1C, +/* ''' 0x27 */ 0xFF, 0xA0, +/* '(' 0x28 */ 0x08, 0x8C, 0x46, 0x31, 0x98, 0xC6, 0x31, 0x8C, 0x63, 0x08, 0x63, 0x08, 0x61, 0x0C, 0x20, +/* ')' 0x29 */ 0x82, 0x18, 0xC3, 0x18, 0xC3, 0x18, 0xC6, 0x31, 0x8C, 0x62, 0x31, 0x88, 0xC4, 0x62, 0x00, +/* '*' 0x2A */ 0x10, 0x23, 0x5B, 0xE3, 0x8D, 0x91, 0x00, +/* '+' 0x2B */ 0x0C, 0x03, 0x00, 0xC0, 0x30, 0xFF, 0xFF, 0xF0, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, +/* ',' 0x2C */ 0xF5, 0x60, +/* '-' 0x2D */ 0xFF, 0xF0, +/* '.' 0x2E */ 0xF0, +/* '/' 0x2F */ 0x02, 0x0C, 0x10, 0x20, 0xC1, 0x02, 0x0C, 0x10, 0x20, 0xC1, 0x02, 0x0C, 0x10, 0x20, 0xC1, 0x00, +/* '0' 0x30 */ 0x1F, 0x07, 0xF1, 0xC7, 0x30, 0x6C, 0x0F, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3E, 0x0E, 0xC1, 0x9C, 0x71, 0xFC, 0x1F, 0x00, +/* '1' 0x31 */ 0x08, 0xCF, 0xFF, 0x8C, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x18, +/* '2' 0x32 */ 0x1F, 0x0F, 0xF9, 0x87, 0x60, 0x7C, 0x06, 0x00, 0xC0, 0x18, 0x07, 0x01, 0xC0, 0xF0, 0x78, 0x1C, 0x06, 0x00, 0xC0, 0x30, 0x07, 0xFF, 0xFF, 0xE0, +/* '3' 0x33 */ 0x3F, 0x0F, 0xF3, 0x87, 0x60, 0x6C, 0x0C, 0x01, 0x80, 0x60, 0x78, 0x0F, 0x80, 0x18, 0x01, 0x80, 0x3C, 0x07, 0x80, 0xD8, 0x73, 0xFC, 0x3F, 0x00, +/* '4' 0x34 */ 0x01, 0x80, 0x70, 0x0E, 0x03, 0xC0, 0xD8, 0x1B, 0x06, 0x61, 0x8C, 0x21, 0x8C, 0x33, 0x06, 0x7F, 0xFF, 0xFE, 0x03, 0x00, 0x60, 0x0C, 0x01, 0x80, +/* '5' 0x35 */ 0x3F, 0xCF, 0xF9, 0x80, 0x30, 0x06, 0x00, 0xDE, 0x1F, 0xE7, 0x0E, 0x00, 0xE0, 0x0C, 0x01, 0x80, 0x30, 0x07, 0x81, 0xB8, 0x73, 0xFC, 0x1F, 0x00, +/* '6' 0x36 */ 0x0F, 0x07, 0xF9, 0xC3, 0x30, 0x74, 0x01, 0x80, 0x33, 0xC7, 0xFE, 0xF1, 0xDC, 0x1F, 0x01, 0xE0, 0x3C, 0x06, 0xC1, 0xDC, 0x71, 0xFC, 0x1F, 0x00, +/* '7' 0x37 */ 0xFF, 0xFF, 0xFC, 0x01, 0x00, 0x60, 0x18, 0x02, 0x00, 0xC0, 0x30, 0x06, 0x01, 0x80, 0x30, 0x04, 0x01, 0x80, 0x30, 0x06, 0x01, 0x80, 0x30, 0x00, +/* '8' 0x38 */ 0x1F, 0x07, 0xF1, 0xC7, 0x30, 0x66, 0x0C, 0xC1, 0x8C, 0x61, 0xF8, 0x3F, 0x8E, 0x3B, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xD8, 0x31, 0xFC, 0x1F, 0x00, +/* '9' 0x39 */ 0x1F, 0x07, 0xF1, 0xC7, 0x70, 0x6C, 0x07, 0x80, 0xF0, 0x1E, 0x07, 0x61, 0xEF, 0xFC, 0x79, 0x80, 0x30, 0x05, 0xC1, 0x98, 0x73, 0xFC, 0x1E, 0x00, +/* ':' 0x3A */ 0xF0, 0x00, 0x03, 0xC0, +/* ';' 0x3B */ 0xF0, 0x00, 0x0F, 0x56, +/* '<' 0x3C */ 0x00, 0x70, 0x1E, 0x0F, 0x83, 0xC0, 0xF0, 0x0E, 0x00, 0x7C, 0x00, 0xF0, 0x03, 0xC0, 0x0F, 0x00, 0x10, +/* '=' 0x3D */ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, +/* '>' 0x3E */ 0xE0, 0x07, 0x80, 0x1F, 0x00, 0x7C, 0x00, 0xF0, 0x07, 0x01, 0xE0, 0xF0, 0x3C, 0x0F, 0x00, 0x80, 0x00, +/* '?' 0x3F */ 0x3F, 0x1F, 0xEE, 0x1F, 0x03, 0xC0, 0xC0, 0x30, 0x0C, 0x06, 0x03, 0x81, 0xC0, 0xE0, 0x30, 0x0C, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x03, 0x00, +/* '@' 0x40 */ 0x00, 0xFE, 0x00, 0x0F, 0xFE, 0x00, 0xF0, 0x3E, 0x07, 0x00, 0x3C, 0x38, 0x00, 0x38, 0xC1, 0xE0, 0x66, 0x0F, 0xD9, 0xD8, 0x61, 0xC3, 0xC3, 0x07, 0x0F, 0x1C, 0x1C, 0x3C, 0x60, 0x60, 0xF1, 0x81, 0x83, 0xC6, 0x06, 0x1B, 0x18, 0x38, 0xEE, 0x71, 0xE7, 0x18, 0xFD, 0xF8, 0x71, 0xE7, 0xC0, 0xE0, 0x00, 0x01, 0xE0, 0x00, 0x01, 0xFF, 0xC0, 0x01, 0xFC, 0x00, +/* 'A' 0x41 */ 0x07, 0x80, 0x1E, 0x00, 0x78, 0x03, 0xF0, 0x0C, 0xC0, 0x33, 0x01, 0xCE, 0x06, 0x18, 0x18, 0x60, 0xE1, 0xC3, 0x03, 0x0F, 0xFC, 0x7F, 0xF9, 0x80, 0x66, 0x01, 0xB8, 0x07, 0xC0, 0x0F, 0x00, 0x30, +/* 'B' 0x42 */ 0xFF, 0xC7, 0xFF, 0x30, 0x1D, 0x80, 0x6C, 0x03, 0x60, 0x1B, 0x00, 0xD8, 0x0C, 0xFF, 0xC7, 0xFF, 0x30, 0x0D, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x06, 0xFF, 0xF7, 0xFE, 0x00, +/* 'C' 0x43 */ 0x07, 0xE0, 0x3F, 0xF0, 0xE0, 0x73, 0x80, 0x76, 0x00, 0x6C, 0x00, 0x30, 0x00, 0x60, 0x00, 0xC0, 0x01, 0x80, 0x03, 0x00, 0x06, 0x00, 0x0E, 0x00, 0x6C, 0x00, 0xDC, 0x03, 0x1E, 0x0E, 0x1F, 0xF8, 0x0F, 0xC0, +/* 'D' 0x44 */ 0xFF, 0xC3, 0xFF, 0x8C, 0x07, 0x30, 0x0E, 0xC0, 0x1B, 0x00, 0x7C, 0x00, 0xF0, 0x03, 0xC0, 0x0F, 0x00, 0x3C, 0x00, 0xF0, 0x03, 0xC0, 0x1F, 0x00, 0x6C, 0x03, 0xB0, 0x1C, 0xFF, 0xE3, 0xFE, 0x00, +/* 'E' 0x45 */ 0xFF, 0xFF, 0xFF, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xFF, 0xEF, 0xFE, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xFF, 0xFF, 0xFF, +/* 'F' 0x46 */ 0xFF, 0xFF, 0xFF, 0x00, 0x60, 0x0C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xFF, 0xDF, 0xFB, 0x00, 0x60, 0x0C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xC0, 0x18, 0x00, +/* 'G' 0x47 */ 0x07, 0xF0, 0x1F, 0xFC, 0x3C, 0x1E, 0x70, 0x07, 0x60, 0x03, 0xE0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x7F, 0xC0, 0x7F, 0xC0, 0x03, 0xC0, 0x03, 0x60, 0x03, 0x60, 0x07, 0x30, 0x0F, 0x3C, 0x1F, 0x1F, 0xFB, 0x07, 0xE1, +/* 'H' 0x48 */ 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xFF, 0xFF, 0xFF, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xC0, +/* 'I' 0x49 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, +/* 'J' 0x4A */ 0x01, 0x80, 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x80, 0xC0, 0x60, 0x3C, 0x1E, 0x0F, 0x07, 0xC7, 0x7F, 0x1F, 0x00, +/* 'K' 0x4B */ 0xC0, 0x3E, 0x03, 0xB0, 0x39, 0x83, 0x8C, 0x38, 0x63, 0x83, 0x38, 0x19, 0xC0, 0xDE, 0x07, 0xB8, 0x38, 0xE1, 0x83, 0x0C, 0x1C, 0x60, 0x73, 0x01, 0x98, 0x0E, 0xC0, 0x3E, 0x00, 0xC0, +/* 'L' 0x4C */ 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xFF, 0xFF, 0xF0, +/* 'M' 0x4D */ 0xE0, 0x07, 0xE0, 0x07, 0xF0, 0x0F, 0xF0, 0x0F, 0xD0, 0x0F, 0xD8, 0x1B, 0xD8, 0x1B, 0xD8, 0x1B, 0xCC, 0x33, 0xCC, 0x33, 0xCC, 0x33, 0xC6, 0x63, 0xC6, 0x63, 0xC6, 0x63, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC1, 0x83, +/* 'N' 0x4E */ 0xE0, 0x1F, 0x00, 0xFC, 0x07, 0xE0, 0x3D, 0x81, 0xEE, 0x0F, 0x30, 0x79, 0xC3, 0xC6, 0x1E, 0x18, 0xF0, 0xE7, 0x83, 0x3C, 0x1D, 0xE0, 0x6F, 0x01, 0xF8, 0x0F, 0xC0, 0x3E, 0x01, 0xC0, +/* 'O' 0x4F */ 0x07, 0xF0, 0x0F, 0xFE, 0x0F, 0x07, 0x86, 0x00, 0xC6, 0x00, 0x33, 0x00, 0x1B, 0x00, 0x07, 0x80, 0x03, 0xC0, 0x01, 0xE0, 0x00, 0xF0, 0x00, 0x78, 0x00, 0x36, 0x00, 0x33, 0x00, 0x18, 0xC0, 0x18, 0x78, 0x3C, 0x1F, 0xFC, 0x03, 0xF8, 0x00, +/* 'P' 0x50 */ 0xFF, 0x8F, 0xFE, 0xC0, 0x6C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x06, 0xFF, 0xEF, 0xFC, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, +/* 'Q' 0x51 */ 0x07, 0xF0, 0x0F, 0xFE, 0x0F, 0x07, 0x86, 0x00, 0xC6, 0x00, 0x33, 0x00, 0x1B, 0x00, 0x07, 0x80, 0x03, 0xC0, 0x01, 0xE0, 0x00, 0xF0, 0x00, 0x78, 0x00, 0x36, 0x00, 0x33, 0x01, 0x98, 0xC0, 0xFC, 0x78, 0x3C, 0x1F, 0xFF, 0x03, 0xF9, 0x80, 0x00, 0x40, +/* 'R' 0x52 */ 0xFF, 0xE3, 0xFF, 0xCC, 0x03, 0xB0, 0x06, 0xC0, 0x1B, 0x00, 0x6C, 0x01, 0xB0, 0x0C, 0xFF, 0xE3, 0xFF, 0xCC, 0x03, 0xB0, 0x06, 0xC0, 0x1B, 0x00, 0x6C, 0x01, 0xB0, 0x06, 0xC0, 0x1B, 0x00, 0x70, +/* 'S' 0x53 */ 0x0F, 0xE0, 0x7F, 0xC3, 0x83, 0x98, 0x07, 0x60, 0x0D, 0x80, 0x07, 0x00, 0x1E, 0x00, 0x3F, 0x80, 0x3F, 0xC0, 0x0F, 0x80, 0x07, 0xC0, 0x0F, 0x00, 0x3E, 0x00, 0xDE, 0x0E, 0x3F, 0xF0, 0x3F, 0x80, +/* 'T' 0x54 */ 0xFF, 0xFF, 0xFF, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, +/* 'U' 0x55 */ 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x80, 0xEE, 0x0E, 0x3F, 0xE0, 0xFC, 0x00, +/* 'V' 0x56 */ 0xC0, 0x0F, 0x00, 0x7E, 0x01, 0x98, 0x06, 0x60, 0x39, 0xC0, 0xC3, 0x03, 0x0C, 0x1C, 0x38, 0x60, 0x61, 0x81, 0x8E, 0x07, 0x30, 0x0C, 0xC0, 0x37, 0x00, 0xF8, 0x01, 0xE0, 0x07, 0x80, 0x1C, 0x00, +/* 'W' 0x57 */ 0xE0, 0x30, 0x1D, 0x80, 0xE0, 0x76, 0x07, 0x81, 0xDC, 0x1E, 0x06, 0x70, 0x7C, 0x18, 0xC1, 0xB0, 0xE3, 0x0C, 0xC3, 0x8C, 0x33, 0x0C, 0x38, 0xC6, 0x30, 0x67, 0x18, 0xC1, 0x98, 0x67, 0x06, 0x61, 0xD8, 0x1D, 0x83, 0x60, 0x3C, 0x0D, 0x80, 0xF0, 0x3E, 0x03, 0xC0, 0x70, 0x0F, 0x01, 0xC0, 0x18, 0x07, 0x00, +/* 'X' 0x58 */ 0xE0, 0x1D, 0x80, 0xE7, 0x03, 0x0E, 0x1C, 0x18, 0x60, 0x73, 0x00, 0xFC, 0x01, 0xE0, 0x07, 0x00, 0x1E, 0x00, 0xF8, 0x03, 0x30, 0x1C, 0xE0, 0xE1, 0x83, 0x07, 0x1C, 0x0E, 0xE0, 0x1B, 0x00, 0x70, +/* 'Y' 0x59 */ 0xC0, 0x0F, 0x80, 0x76, 0x01, 0x9C, 0x0C, 0x38, 0x70, 0x61, 0x81, 0xCE, 0x03, 0x30, 0x0F, 0x80, 0x1E, 0x00, 0x30, 0x00, 0xC0, 0x03, 0x00, 0x0C, 0x00, 0x30, 0x00, 0xC0, 0x03, 0x00, 0x0C, 0x00, +/* 'Z' 0x5A */ 0xFF, 0xFF, 0xFF, 0xC0, 0x0E, 0x00, 0xE0, 0x0E, 0x00, 0x60, 0x07, 0x00, 0x70, 0x07, 0x00, 0x30, 0x03, 0x80, 0x38, 0x03, 0x80, 0x18, 0x01, 0xC0, 0x1C, 0x00, 0xFF, 0xFF, 0xFF, 0xC0, +/* '[' 0x5B */ 0xFF, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCF, 0xF0, +/* '\' 0x5C */ 0x81, 0x81, 0x02, 0x06, 0x04, 0x08, 0x18, 0x10, 0x20, 0x60, 0x40, 0x81, 0x81, 0x02, 0x06, 0x04, +/* ']' 0x5D */ 0xFF, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0xF0, +/* '^' 0x5E */ 0x0C, 0x0E, 0x05, 0x86, 0xC3, 0x21, 0x19, 0x8C, 0x83, 0xC1, 0x80, +/* '_' 0x5F */ 0xFF, 0xFE, +/* '`' 0x60 */ 0xE3, 0x8C, 0x30, +/* 'a' 0x61 */ 0x3F, 0x07, 0xF8, 0xE1, 0xCC, 0x0C, 0x00, 0xC0, 0x1C, 0x3F, 0xCF, 0x8C, 0xC0, 0xCC, 0x0C, 0xE3, 0xC7, 0xEF, 0x3C, 0x70, +/* 'b' 0x62 */ 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0xF8, 0xDF, 0xCF, 0x0E, 0xE0, 0x7C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xE0, 0x6F, 0x0E, 0xDF, 0xCC, 0xF8, +/* 'c' 0x63 */ 0x1F, 0x0F, 0xE6, 0x1F, 0x83, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x38, 0x37, 0x1C, 0xFE, 0x1F, 0x00, +/* 'd' 0x64 */ 0x00, 0x60, 0x0C, 0x01, 0x80, 0x30, 0x06, 0x3C, 0xCF, 0xFB, 0x8F, 0xE0, 0xF8, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF8, 0x3B, 0x8F, 0x3F, 0x63, 0xCC, +/* 'e' 0x65 */ 0x1F, 0x07, 0xF1, 0xC7, 0x70, 0x3C, 0x07, 0xFF, 0xFF, 0xFE, 0x00, 0xC0, 0x1C, 0x0D, 0xC3, 0x1F, 0xC1, 0xF0, +/* 'f' 0x66 */ 0x3B, 0xD8, 0xC6, 0x7F, 0xEC, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x00, +/* 'g' 0x67 */ 0x1E, 0x67, 0xFD, 0xC7, 0xF0, 0x7C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x7C, 0x1D, 0xC7, 0x9F, 0xB1, 0xE6, 0x00, 0xC0, 0x3E, 0x0E, 0x7F, 0xC7, 0xE0, +/* 'h' 0x68 */ 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x33, 0xCD, 0xFB, 0xC7, 0xE0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x30, +/* 'i' 0x69 */ 0xF0, 0x3F, 0xFF, 0xFF, 0xF0, +/* 'j' 0x6A */ 0x33, 0x00, 0x03, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0xE0, +/* 'k' 0x6B */ 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x6C, 0x33, 0x18, 0xCC, 0x37, 0x0F, 0xC3, 0xB8, 0xC6, 0x31, 0xCC, 0x3B, 0x06, 0xC1, 0xF0, 0x30, +/* 'l' 0x6C */ 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, +/* 'm' 0x6D */ 0xCF, 0x1F, 0x6F, 0xDF, 0xFC, 0x78, 0xFC, 0x18, 0x3C, 0x0C, 0x1E, 0x06, 0x0F, 0x03, 0x07, 0x81, 0x83, 0xC0, 0xC1, 0xE0, 0x60, 0xF0, 0x30, 0x78, 0x18, 0x3C, 0x0C, 0x18, +/* 'n' 0x6E */ 0xCF, 0x37, 0xEF, 0x1F, 0x83, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xC0, +/* 'o' 0x6F */ 0x1F, 0x07, 0xF1, 0xC7, 0x70, 0x7C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x7C, 0x1D, 0xC7, 0x1F, 0xC1, 0xF0, +/* 'p' 0x70 */ 0xCF, 0x8D, 0xFC, 0xF0, 0xEE, 0x06, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3E, 0x06, 0xF0, 0xEF, 0xFC, 0xCF, 0x8C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x00, +/* 'q' 0x71 */ 0x1E, 0x67, 0xFD, 0xC7, 0xF0, 0x7C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x7C, 0x1D, 0xC7, 0x9F, 0xF1, 0xE6, 0x00, 0xC0, 0x18, 0x03, 0x00, 0x60, +/* 'r' 0x72 */ 0xCF, 0x7F, 0x38, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC0, +/* 's' 0x73 */ 0x3E, 0x1F, 0xEE, 0x1B, 0x00, 0xC0, 0x3C, 0x07, 0xF0, 0x3F, 0x01, 0xF0, 0x3E, 0x1D, 0xFE, 0x3F, 0x00, +/* 't' 0x74 */ 0x63, 0x19, 0xFF, 0xB1, 0x8C, 0x63, 0x18, 0xC6, 0x31, 0xE7, +/* 'u' 0x75 */ 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x7E, 0x3D, 0xFB, 0x3C, 0xC0, +/* 'v' 0x76 */ 0xE0, 0x6C, 0x0D, 0x81, 0xB8, 0x63, 0x0C, 0x61, 0x8E, 0x60, 0xCC, 0x19, 0x83, 0xE0, 0x3C, 0x07, 0x00, 0xE0, +/* 'w' 0x77 */ 0xC1, 0xC1, 0xB0, 0xE1, 0xD8, 0x70, 0xCC, 0x2C, 0x66, 0x36, 0x31, 0x9B, 0x18, 0xCD, 0x98, 0x64, 0x6C, 0x16, 0x36, 0x0F, 0x1A, 0x07, 0x8F, 0x03, 0x83, 0x80, 0xC1, 0xC0, +/* 'x' 0x78 */ 0xC1, 0xF8, 0x66, 0x30, 0xCC, 0x3E, 0x07, 0x00, 0xC0, 0x78, 0x36, 0x0C, 0xC6, 0x3B, 0x06, 0xC0, 0xC0, +/* 'y' 0x79 */ 0xE0, 0x6C, 0x0D, 0x83, 0x38, 0x63, 0x0C, 0x63, 0x0C, 0x60, 0xCC, 0x1B, 0x03, 0x60, 0x3C, 0x07, 0x00, 0xE0, 0x18, 0x03, 0x00, 0xE0, 0x78, 0x0E, 0x00, +/* 'z' 0x7A */ 0xFF, 0xFF, 0xF0, 0x18, 0x0C, 0x07, 0x03, 0x81, 0xC0, 0x60, 0x30, 0x18, 0x0E, 0x03, 0xFF, 0xFF, 0xC0, +/* '{' 0x7B */ 0x19, 0xCC, 0x63, 0x18, 0xC6, 0x31, 0x99, 0x86, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x1C, 0x60, +/* '|' 0x7C */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, +/* '}' 0x7D */ 0xC7, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x0C, 0x33, 0x31, 0x8C, 0x63, 0x18, 0xC6, 0x73, 0x00, +/* '~' 0x7E */ 0x70, 0x3E, 0x09, 0xE4, 0x1F, 0x03, 0x80, +/* 0x7F */ +/* 0x80 */ 0x01, 0xF0, 0x1F, 0xF0, 0xE0, 0xC7, 0x00, 0x18, 0x00, 0xC0, 0x07, 0xFF, 0x3F, 0xFC, 0x30, 0x01, 0xFF, 0x8F, 0xFC, 0x0C, 0x00, 0x18, 0x00, 0x70, 0x00, 0xE0, 0x81, 0xFE, 0x03, 0xF0, +/* 0x81 */ +/* 0x82 */ 0xF5, 0x80, +/* 0x83 */ +/* 0x84 */ 0xCF, 0x34, 0x51, 0x88, +/* 0x85 */ 0xC6, 0x3C, 0x63, +/* 0x86 */ 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x3F, 0xFF, 0xFC, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x00, +/* 0x87 */ 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x3F, 0xFF, 0xFC, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x0F, 0xFF, 0xFF, 0x0C, 0x03, 0x00, 0xC0, 0x30, +/* 0x88 */ +/* 0x89 */ 0x38, 0x18, 0x00, 0xF8, 0x30, 0x03, 0x18, 0xC0, 0x04, 0x11, 0x80, 0x0C, 0x66, 0x00, 0x0F, 0x8C, 0x00, 0x0E, 0x30, 0x00, 0x00, 0x40, 0x00, 0x01, 0x80, 0x00, 0x06, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x31, 0xC0, 0xE0, 0x67, 0xC3, 0xC1, 0x98, 0xCC, 0xC3, 0x20, 0x90, 0x8C, 0x63, 0x33, 0x10, 0x7C, 0x3C, 0x60, 0x70, 0x38, +/* 0x8A */ 0x0C, 0x40, 0x1F, 0x00, 0x38, 0x03, 0xF8, 0x1F, 0xF0, 0xE0, 0xE6, 0x01, 0xD8, 0x03, 0x60, 0x01, 0xC0, 0x07, 0x80, 0x0F, 0xE0, 0x0F, 0xF0, 0x03, 0xE0, 0x01, 0xF0, 0x03, 0xC0, 0x0F, 0x80, 0x37, 0x83, 0x8F, 0xFC, 0x0F, 0xE0, +/* 0x8B */ 0x2F, 0x49, 0x99, +/* 0x8C */ 0x01, 0x80, 0x0C, 0x00, 0x60, 0x00, 0x00, 0x0F, 0xE0, 0x7F, 0xC3, 0x83, 0x98, 0x07, 0x60, 0x0D, 0x80, 0x07, 0x00, 0x1E, 0x00, 0x3F, 0x80, 0x3F, 0xC0, 0x0F, 0x80, 0x07, 0xC0, 0x0F, 0x00, 0x3E, 0x00, 0xDE, 0x0E, 0x3F, 0xF0, 0x3F, 0x80, +/* 0x8D */ 0x0C, 0xC0, 0xF8, 0x07, 0x0F, 0xFF, 0xFF, 0xF0, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, +/* 0x8E */ 0x0C, 0xC0, 0x3C, 0x00, 0xE1, 0xFF, 0xFF, 0xFF, 0x80, 0x1C, 0x01, 0xC0, 0x1C, 0x00, 0xC0, 0x0E, 0x00, 0xE0, 0x0E, 0x00, 0x60, 0x07, 0x00, 0x70, 0x07, 0x00, 0x30, 0x03, 0x80, 0x38, 0x01, 0xFF, 0xFF, 0xFF, 0x80, +/* 0x8F */ 0x01, 0x80, 0x18, 0x01, 0x80, 0x00, 0x0F, 0xFF, 0xFF, 0xFC, 0x00, 0xE0, 0x0E, 0x00, 0xE0, 0x06, 0x00, 0x70, 0x07, 0x00, 0x70, 0x03, 0x00, 0x38, 0x03, 0x80, 0x38, 0x01, 0x80, 0x1C, 0x01, 0xC0, 0x0F, 0xFF, 0xFF, 0xFC, +/* 0x90 */ +/* 0x91 */ 0x6A, 0xF0, +/* 0x92 */ 0xF5, 0x60, +/* 0x93 */ 0x4E, 0x28, 0xA2, 0xCF, 0x30, +/* 0x94 */ 0xCF, 0x34, 0x51, 0x4E, 0x20, +/* 0x95 */ 0x7B, 0xFF, 0xFF, 0xFD, 0xE0, +/* 0x96 */ 0xFF, 0xFF, 0xF0, +/* 0x97 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, +/* 0x98 */ +/* 0x99 */ 0xFF, 0x70, 0x1F, 0xFD, 0xC0, 0x71, 0x87, 0x83, 0xC6, 0x1E, 0x0F, 0x18, 0x68, 0x3C, 0x61, 0xB1, 0xB1, 0x86, 0xC6, 0xC6, 0x19, 0x1B, 0x18, 0x66, 0xCC, 0x61, 0x9B, 0x31, 0x86, 0x3C, 0xC6, 0x18, 0xE3, 0x18, 0x63, 0x8C, +/* 0x9A */ 0x63, 0x0D, 0x83, 0x60, 0x70, 0x00, 0x0F, 0x87, 0xFB, 0x86, 0xC0, 0x30, 0x0F, 0x01, 0xFC, 0x0F, 0xC0, 0x7C, 0x0F, 0x87, 0x7F, 0x8F, 0xC0, +/* 0x9B */ 0x99, 0x92, 0xF4, +/* 0x9C */ 0x07, 0x03, 0x80, 0xC0, 0x60, 0x00, 0x0F, 0x87, 0xFB, 0x86, 0xC0, 0x30, 0x0F, 0x01, 0xFC, 0x0F, 0xC0, 0x7C, 0x0F, 0x87, 0x7F, 0x8F, 0xC0, +/* 0x9D */ 0x03, 0x06, 0x66, 0x64, 0x60, 0xF8, 0xF8, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x38, +/* 0x9E */ 0x63, 0x0C, 0x83, 0x60, 0x70, 0x00, 0x3F, 0xFF, 0xFC, 0x06, 0x03, 0x01, 0xC0, 0xE0, 0x70, 0x18, 0x0C, 0x06, 0x03, 0x80, 0xFF, 0xFF, 0xF0, +/* 0x9F */ 0x07, 0x01, 0x80, 0xC0, 0x20, 0x00, 0x3F, 0xFF, 0xFC, 0x06, 0x03, 0x01, 0xC0, 0xE0, 0x70, 0x18, 0x0C, 0x06, 0x03, 0x80, 0xFF, 0xFF, 0xF0, +/* 0xA0 */ +/* 0xA1 */ 0xC6, 0xD9, 0xB1, 0xC0, +/* 0xA2 */ 0x83, 0x8D, 0xF1, 0xC0, +/* 0xA3 */ 0x30, 0x01, 0x80, 0x0C, 0x00, 0x60, 0x03, 0x00, 0x18, 0x80, 0xCC, 0x06, 0xC0, 0x3C, 0x01, 0xC0, 0x3C, 0x01, 0x60, 0x03, 0x00, 0x18, 0x00, 0xC0, 0x06, 0x00, 0x3F, 0xF9, 0xFF, 0xC0, +/* 0xA4 */ 0xDD, 0xFF, 0xD8, 0xD8, 0x3C, 0x1E, 0x0F, 0x8D, 0xFF, 0xDD, 0x80, +/* 0xA5 */ 0x03, 0x80, 0x03, 0xC0, 0x07, 0xC0, 0x07, 0xC0, 0x04, 0xE0, 0x0C, 0xE0, 0x0C, 0xE0, 0x08, 0x70, 0x18, 0x70, 0x18, 0x70, 0x10, 0x38, 0x3F, 0xF8, 0x3F, 0xF8, 0x30, 0x1C, 0x70, 0x0C, 0x60, 0x0C, 0x60, 0x0E, 0xE0, 0x06, 0x00, 0x0E, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x0F, +/* 0xA6 */ 0xFF, 0xFF, 0xF0, 0x3F, 0xFF, 0xFC, +/* 0xA7 */ 0x0F, 0x03, 0xF0, 0xE7, 0x18, 0x63, 0x0C, 0x70, 0x07, 0x03, 0xF8, 0xC3, 0x98, 0x3B, 0x03, 0xF0, 0x37, 0x06, 0x78, 0xC7, 0xB0, 0x7C, 0x03, 0x80, 0x39, 0x83, 0x30, 0x67, 0x1C, 0x7F, 0x07, 0xC0, +/* 0xA8 */ 0xCF, 0x30, +/* 0xA9 */ 0x03, 0xF0, 0x03, 0xFF, 0x01, 0xE0, 0xE0, 0xE3, 0x1C, 0x73, 0xF3, 0x99, 0x86, 0x6C, 0xC1, 0x8F, 0x30, 0x03, 0xCC, 0x00, 0xF3, 0x00, 0x3C, 0xC1, 0x8D, 0x98, 0x66, 0x77, 0xF3, 0x8E, 0x79, 0xC1, 0xC0, 0xE0, 0x3F, 0xF0, 0x03, 0xF0, 0x00, +/* 0xAA */ 0x0F, 0xC0, 0xFF, 0xC3, 0x03, 0x98, 0x07, 0x60, 0x0D, 0x80, 0x07, 0x00, 0x1E, 0x00, 0x3F, 0x80, 0x3F, 0xC0, 0x0F, 0x80, 0x07, 0xC0, 0x0F, 0x00, 0x3E, 0x00, 0xDC, 0x0E, 0x3F, 0xF0, 0x3F, 0x00, 0x20, 0x01, 0xE0, 0x01, 0x80, 0x06, 0x00, 0xF0, 0x00, +/* 0xAB */ 0x21, 0x63, 0xE7, 0x84, 0x84, 0xE7, 0x63, 0x21, +/* 0xAC */ 0xFF, 0xFF, 0xFF, 0x00, 0x30, 0x03, 0x00, 0x30, 0x03, +/* 0xAD */ 0xFF, 0xF0, +/* 0xAE */ 0x03, 0xF0, 0x03, 0xFF, 0x01, 0xE0, 0xE0, 0xFF, 0x1C, 0x7F, 0xF3, 0x9B, 0x04, 0x6C, 0xC1, 0x8F, 0x30, 0x43, 0xCF, 0xF0, 0xF3, 0xFC, 0x3C, 0xC1, 0x0D, 0xB0, 0x66, 0x7C, 0x1B, 0x8F, 0x07, 0xC1, 0xC0, 0xE0, 0x3F, 0xF0, 0x03, 0xF0, 0x00, +/* 0xAF */ 0x03, 0x00, 0x18, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x80, 0x1C, 0x01, 0xC0, 0x1C, 0x00, 0xC0, 0x0E, 0x00, 0xE0, 0x0E, 0x00, 0x60, 0x07, 0x00, 0x70, 0x07, 0x00, 0x30, 0x03, 0x80, 0x38, 0x01, 0xFF, 0xFF, 0xFF, 0x80, +/* 0xB0 */ 0x38, 0xFB, 0x1C, 0x18, 0x38, 0xDF, 0x1C, +/* 0xB1 */ 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x7F, 0xE7, 0xFE, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xF0, +/* 0xB2 */ 0x76, 0x31, 0x87, 0x80, +/* 0xB3 */ 0x66, 0x66, 0x66, 0x67, 0x7E, 0xE6, 0x66, 0x66, 0x66, +/* 0xB4 */ 0x3B, 0x99, 0x80, +/* 0xB5 */ 0xC0, 0xCC, 0x0C, 0xC0, 0xCC, 0x0C, 0xC0, 0xCC, 0x0C, 0xC0, 0xCC, 0x0C, 0xC0, 0xCC, 0x1C, 0xE3, 0xCF, 0xEF, 0xFC, 0x7C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x00, +/* 0xB6 */ 0x1F, 0xE7, 0xFD, 0xF3, 0x7E, 0x6F, 0xCD, 0xF9, 0xBF, 0x37, 0xE6, 0x7C, 0xCF, 0x98, 0xF3, 0x06, 0x60, 0xCC, 0x19, 0x83, 0x30, 0x66, 0x0C, 0xC1, 0x98, 0x33, 0x06, 0x60, 0xCC, +/* 0xB7 */ 0xF0, +/* 0xB8 */ 0x10, 0xF0, 0xE3, 0x78, +/* 0xB9 */ 0x1F, 0x01, 0xFC, 0x1C, 0x70, 0xC1, 0x80, 0x0C, 0x00, 0xE0, 0xFF, 0x1F, 0x18, 0xC0, 0xC6, 0x06, 0x38, 0x70, 0xFF, 0xE3, 0xC7, 0x00, 0x30, 0x03, 0x00, 0x18, 0x00, 0xC0, 0x03, 0xC0, +/* 0xBA */ 0x3F, 0x1F, 0xEE, 0x1B, 0x00, 0xC0, 0x3C, 0x07, 0xF0, 0x3E, 0x01, 0xF0, 0x3C, 0x0D, 0xDE, 0x7F, 0x02, 0x01, 0xE0, 0x18, 0x46, 0x0F, 0x00, +/* 0xBB */ 0x88, 0xC6, 0xE7, 0x21, 0x21, 0xE7, 0xC6, 0x88, +/* 0xBC */ 0xC3, 0x31, 0x8C, 0x63, 0x10, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xFF, 0xFF, 0xF0, +/* 0xBD */ 0x77, 0x66, 0xCC, 0xC8, +/* 0xBE */ 0xC7, 0x9B, 0x36, 0xCC, 0x18, 0x30, 0x60, 0xC1, 0x83, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x80, +/* 0xBF */ 0x0C, 0x03, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x18, 0x0C, 0x07, 0x03, 0x81, 0xC0, 0x60, 0x30, 0x18, 0x0E, 0x03, 0xFF, 0xFF, 0xC0, +/* 0xC0 */ 0x03, 0x80, 0x18, 0x00, 0x40, 0x00, 0x00, 0xFF, 0xE3, 0xFF, 0xCC, 0x03, 0xB0, 0x06, 0xC0, 0x1B, 0x00, 0x6C, 0x01, 0xB0, 0x0C, 0xFF, 0xE3, 0xFF, 0xCC, 0x03, 0xB0, 0x06, 0xC0, 0x1B, 0x00, 0x6C, 0x01, 0xB0, 0x06, 0xC0, 0x1B, 0x00, 0x70, +/* 0xC1 */ 0x01, 0xC0, 0x0C, 0x00, 0x20, 0x00, 0x00, 0x07, 0x80, 0x1E, 0x00, 0x78, 0x03, 0xF0, 0x0C, 0xC0, 0x33, 0x01, 0xCE, 0x06, 0x18, 0x18, 0x60, 0xE1, 0xC3, 0x03, 0x0F, 0xFC, 0x7F, 0xF9, 0x80, 0x66, 0x01, 0xB8, 0x07, 0xC0, 0x0F, 0x00, 0x30, +/* 0xC2 */ 0x07, 0x00, 0x3E, 0x01, 0x8C, 0x00, 0x00, 0x07, 0x80, 0x1E, 0x00, 0x78, 0x03, 0xF0, 0x0C, 0xC0, 0x33, 0x01, 0xCE, 0x06, 0x18, 0x18, 0x60, 0xE1, 0xC3, 0x03, 0x0F, 0xFC, 0x7F, 0xF9, 0x80, 0x66, 0x01, 0xB8, 0x07, 0xC0, 0x0F, 0x00, 0x30, +/* 0xC3 */ 0x10, 0x40, 0x63, 0x00, 0xF8, 0x01, 0xE0, 0x07, 0x80, 0x1E, 0x00, 0x78, 0x03, 0xF0, 0x0C, 0xC0, 0x33, 0x01, 0xCE, 0x06, 0x18, 0x18, 0x60, 0xE1, 0xC3, 0x03, 0x0F, 0xFC, 0x7F, 0xF9, 0x80, 0x66, 0x01, 0xB8, 0x07, 0xC0, 0x0F, 0x00, 0x30, +/* 0xC4 */ 0x0C, 0xC0, 0x33, 0x00, 0x00, 0x01, 0xE0, 0x07, 0x80, 0x1E, 0x00, 0xFC, 0x03, 0x30, 0x0C, 0xC0, 0x73, 0x81, 0x86, 0x06, 0x18, 0x38, 0x70, 0xC0, 0xC3, 0xFF, 0x1F, 0xFE, 0x60, 0x19, 0x80, 0x6E, 0x01, 0xF0, 0x03, 0xC0, 0x0C, +/* 0xC5 */ 0x18, 0x0C, 0x06, 0x00, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xFF, 0xFF, 0xF0, +/* 0xC6 */ 0x00, 0xC0, 0x03, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x7E, 0x03, 0xFF, 0x0E, 0x07, 0x38, 0x07, 0x60, 0x06, 0xC0, 0x03, 0x00, 0x06, 0x00, 0x0C, 0x00, 0x18, 0x00, 0x30, 0x00, 0x60, 0x00, 0xE0, 0x06, 0xC0, 0x0D, 0xC0, 0x31, 0xE0, 0xE1, 0xFF, 0x80, 0xFC, 0x00, +/* 0xC7 */ 0x07, 0xE0, 0x3F, 0xF0, 0xE0, 0x73, 0x80, 0x66, 0x00, 0x7C, 0x00, 0x30, 0x00, 0x60, 0x00, 0xC0, 0x01, 0x80, 0x03, 0x00, 0x06, 0x00, 0x0E, 0x00, 0x6C, 0x01, 0xDC, 0x03, 0x1C, 0x1E, 0x1F, 0xF8, 0x0F, 0xC0, 0x08, 0x00, 0x1E, 0x00, 0x0C, 0x01, 0x18, 0x01, 0xE0, 0x00, +/* 0xC8 */ 0x06, 0x30, 0x07, 0xC0, 0x07, 0x00, 0x3F, 0x01, 0xFF, 0x87, 0x03, 0x9C, 0x03, 0xB0, 0x03, 0x60, 0x01, 0x80, 0x03, 0x00, 0x06, 0x00, 0x0C, 0x00, 0x18, 0x00, 0x30, 0x00, 0x70, 0x03, 0x60, 0x06, 0xE0, 0x18, 0xF0, 0x70, 0xFF, 0xC0, 0x7E, 0x00, +/* 0xC9 */ 0x07, 0x00, 0x60, 0x0C, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xFF, 0xEF, 0xFE, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xFF, 0xFF, 0xFF, +/* 0xCA */ 0xFF, 0xE7, 0xFF, 0x30, 0x01, 0x80, 0x0C, 0x00, 0x60, 0x03, 0x00, 0x18, 0x00, 0xFF, 0xE7, 0xFF, 0x30, 0x01, 0x80, 0x0C, 0x00, 0x60, 0x03, 0x00, 0x18, 0x00, 0xFF, 0xF7, 0xFF, 0x80, 0x18, 0x01, 0x80, 0x0C, 0x00, 0x60, 0x01, 0xE0, +/* 0xCB */ 0x19, 0x81, 0x98, 0x00, 0x0F, 0xFF, 0xFF, 0xFC, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0F, 0xFE, 0xFF, 0xEC, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0F, 0xFF, 0xFF, 0xF0, +/* 0xCC */ 0x08, 0xC0, 0xF8, 0x07, 0x0F, 0xFF, 0xFF, 0xFC, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0F, 0xFE, 0xFF, 0xEC, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0F, 0xFF, 0xFF, 0xF0, +/* 0xCD */ 0x36, 0xC0, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, +/* 0xCE */ 0x39, 0xFC, 0x40, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC0, +/* 0xCF */ 0x18, 0xC0, 0x3E, 0x00, 0x70, 0x3F, 0xF0, 0xFF, 0xE3, 0x01, 0xCC, 0x03, 0xB0, 0x06, 0xC0, 0x1F, 0x00, 0x3C, 0x00, 0xF0, 0x03, 0xC0, 0x0F, 0x00, 0x3C, 0x00, 0xF0, 0x07, 0xC0, 0x1B, 0x00, 0xEC, 0x07, 0x3F, 0xF8, 0xFF, 0x80, +/* 0xD0 */ 0x7F, 0xE0, 0xFF, 0xE1, 0x80, 0xE3, 0x00, 0xE6, 0x00, 0xCC, 0x01, 0xD8, 0x01, 0xB0, 0x03, 0xFE, 0x07, 0xFC, 0x0D, 0x80, 0x1B, 0x00, 0x36, 0x00, 0x6C, 0x01, 0x98, 0x07, 0x30, 0x1C, 0x7F, 0xF0, 0xFF, 0xC0, +/* 0xD1 */ 0x01, 0x80, 0x18, 0x01, 0x80, 0x00, 0x0E, 0x01, 0xF0, 0x0F, 0xC0, 0x7E, 0x03, 0xD8, 0x1E, 0xE0, 0xF3, 0x07, 0x9C, 0x3C, 0x61, 0xE1, 0x8F, 0x0E, 0x78, 0x33, 0xC1, 0xDE, 0x06, 0xF0, 0x1F, 0x80, 0xFC, 0x03, 0xE0, 0x1C, +/* 0xD2 */ 0x0C, 0xC0, 0x3C, 0x00, 0xE1, 0xC0, 0x3E, 0x01, 0xF8, 0x0F, 0xC0, 0x7B, 0x03, 0xDC, 0x1E, 0x60, 0xF3, 0x87, 0x8C, 0x3C, 0x31, 0xE1, 0xCF, 0x06, 0x78, 0x3B, 0xC0, 0xDE, 0x03, 0xF0, 0x1F, 0x80, 0x7C, 0x03, 0x80, +/* 0xD3 */ 0x00, 0xE0, 0x00, 0x60, 0x00, 0x40, 0x00, 0x00, 0x00, 0x7F, 0x00, 0xFF, 0xE0, 0xF0, 0x78, 0x60, 0x0C, 0x60, 0x03, 0x30, 0x01, 0xB0, 0x00, 0x78, 0x00, 0x3C, 0x00, 0x1E, 0x00, 0x0F, 0x00, 0x07, 0x80, 0x03, 0x60, 0x03, 0x30, 0x01, 0x8C, 0x01, 0x87, 0x83, 0xC1, 0xFF, 0xC0, 0x3F, 0x80, +/* 0xD4 */ 0x03, 0xC0, 0x01, 0xE0, 0x01, 0x98, 0x00, 0x00, 0x00, 0x7F, 0x00, 0xFF, 0xE0, 0xF0, 0x78, 0x60, 0x0C, 0x60, 0x03, 0x30, 0x01, 0xB0, 0x00, 0x78, 0x00, 0x3C, 0x00, 0x1E, 0x00, 0x0F, 0x00, 0x07, 0x80, 0x03, 0x60, 0x03, 0x30, 0x01, 0x8C, 0x01, 0x87, 0x83, 0xC1, 0xFF, 0xC0, 0x3F, 0x80, +/* 0xD5 */ 0x03, 0xB8, 0x01, 0x98, 0x00, 0x98, 0x00, 0x00, 0x00, 0x7F, 0x00, 0xFF, 0xE0, 0xF0, 0x78, 0x60, 0x0C, 0x60, 0x03, 0x30, 0x01, 0xB0, 0x00, 0x78, 0x00, 0x3C, 0x00, 0x1E, 0x00, 0x0F, 0x00, 0x07, 0x80, 0x03, 0x60, 0x03, 0x30, 0x01, 0x8C, 0x01, 0x87, 0x83, 0xC1, 0xFF, 0xC0, 0x3F, 0x80, +/* 0xD6 */ 0x06, 0x30, 0x03, 0x18, 0x00, 0x00, 0x00, 0xFE, 0x01, 0xFF, 0xC1, 0xE0, 0xF0, 0xC0, 0x18, 0xC0, 0x06, 0x60, 0x03, 0x60, 0x00, 0xF0, 0x00, 0x78, 0x00, 0x3C, 0x00, 0x1E, 0x00, 0x0F, 0x00, 0x06, 0xC0, 0x06, 0x60, 0x03, 0x18, 0x03, 0x0F, 0x07, 0x83, 0xFF, 0x80, 0x7F, 0x00, +/* 0xD7 */ 0x81, 0xC3, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0xC3, 0x81, +/* 0xD8 */ 0x0C, 0xC0, 0x1E, 0x00, 0x78, 0x3F, 0xF8, 0xFF, 0xF3, 0x00, 0xEC, 0x01, 0xB0, 0x06, 0xC0, 0x1B, 0x00, 0x6C, 0x03, 0x3F, 0xF8, 0xFF, 0xF3, 0x00, 0xEC, 0x01, 0xB0, 0x06, 0xC0, 0x1B, 0x00, 0x6C, 0x01, 0xB0, 0x06, 0xC0, 0x1C, +/* 0xD9 */ 0x03, 0x00, 0x7C, 0x03, 0x70, 0x19, 0x80, 0xF8, 0x03, 0xC3, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3E, 0x03, 0xB8, 0x38, 0xFF, 0x83, 0xF0, +/* 0xDA */ 0x03, 0x80, 0x18, 0x01, 0x80, 0x00, 0x0C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF8, 0x0E, 0xE0, 0xE3, 0xFE, 0x0F, 0xC0, +/* 0xDB */ 0x0E, 0xE0, 0x66, 0x03, 0x60, 0x00, 0x0C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF8, 0x0E, 0xE0, 0xE3, 0xFE, 0x0F, 0xC0, +/* 0xDC */ 0x0C, 0xC0, 0x66, 0x00, 0x01, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1F, 0x01, 0xDC, 0x1C, 0x7F, 0xC1, 0xF8, 0x00, +/* 0xDD */ 0x01, 0x80, 0x0C, 0x00, 0x60, 0x00, 0x00, 0xC0, 0x0F, 0x80, 0x76, 0x01, 0x9C, 0x0C, 0x38, 0x70, 0x61, 0x81, 0xCE, 0x03, 0x30, 0x0F, 0x80, 0x1E, 0x00, 0x30, 0x00, 0xC0, 0x03, 0x00, 0x0C, 0x00, 0x30, 0x00, 0xC0, 0x03, 0x00, 0x0C, 0x00, +/* 0xDE */ 0xFF, 0xFF, 0xFF, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x04, 0x00, 0x78, 0x01, 0x81, 0x18, 0x0F, 0x00, +/* 0xDF */ 0x1F, 0x0F, 0xF3, 0x87, 0x60, 0x6C, 0x0D, 0x81, 0xB0, 0x66, 0x38, 0xC7, 0xD8, 0x1B, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x3E, 0x0E, 0xCF, 0x99, 0xE0, +/* 0xE0 */ 0x0C, 0x61, 0x8C, 0x03, 0x3D, 0xFC, 0xE3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x00, +/* 0xE1 */ 0x07, 0x00, 0x60, 0x0C, 0x01, 0x80, 0x00, 0x03, 0xF0, 0x7F, 0x8E, 0x1C, 0xC0, 0xC0, 0x0C, 0x01, 0xC3, 0xFC, 0xF8, 0xCC, 0x0C, 0xC0, 0xCE, 0x3C, 0x7E, 0xF3, 0xC7, +/* 0xE2 */ 0x0C, 0x01, 0xE0, 0x1B, 0x03, 0x30, 0x00, 0x03, 0xF0, 0x7F, 0x8E, 0x1C, 0xC0, 0xC0, 0x0C, 0x01, 0xC3, 0xFC, 0xF8, 0xCC, 0x0C, 0xC0, 0xCE, 0x3C, 0x7E, 0xF3, 0xC7, +/* 0xE3 */ 0x20, 0x82, 0x10, 0x3F, 0x01, 0xE0, 0x00, 0x03, 0xF0, 0x7F, 0x8E, 0x1C, 0xC0, 0xC0, 0x0C, 0x01, 0xC3, 0xFC, 0xF8, 0xCC, 0x0C, 0xC0, 0xCE, 0x3C, 0x7E, 0xF3, 0xC7, +/* 0xE4 */ 0x19, 0x81, 0x98, 0x00, 0x00, 0x00, 0x3F, 0x07, 0xF8, 0xE1, 0xCC, 0x0C, 0x00, 0xC0, 0x1C, 0x3F, 0xCF, 0x8C, 0xC0, 0xCC, 0x0C, 0xE3, 0xC7, 0xEF, 0x3C, 0x70, +/* 0xE5 */ 0x3B, 0x30, 0x06, 0x31, 0x8C, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x18, 0xC6, 0x30, +/* 0xE6 */ 0x07, 0x01, 0x80, 0xC0, 0x20, 0x00, 0x07, 0xC3, 0xF9, 0x87, 0xE0, 0xF0, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0E, 0x0D, 0xC7, 0x3F, 0x87, 0xC0, +/* 0xE7 */ 0x1F, 0x0F, 0xE7, 0x1D, 0x83, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x38, 0x37, 0x1C, 0xFE, 0x1F, 0x02, 0x00, 0xE0, 0x0C, 0x23, 0x07, 0x80, +/* 0xE8 */ 0x21, 0x0C, 0xC1, 0xE0, 0x78, 0x00, 0x07, 0xC3, 0xF9, 0x87, 0xE0, 0xF0, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0E, 0x0D, 0xC7, 0x3F, 0x87, 0xC0, +/* 0xE9 */ 0x03, 0x00, 0xC0, 0x30, 0x04, 0x00, 0x00, 0x3E, 0x0F, 0xE3, 0x8E, 0xE0, 0x78, 0x0F, 0xFF, 0xFF, 0xFC, 0x01, 0x80, 0x38, 0x1B, 0x86, 0x3F, 0x83, 0xE0, +/* 0xEA */ 0x1F, 0x07, 0xF1, 0x87, 0x60, 0x6C, 0x07, 0xFF, 0xFF, 0xFE, 0x00, 0xC0, 0x1C, 0x1D, 0x87, 0x1F, 0xC1, 0xF8, 0x06, 0x01, 0x80, 0x30, 0x06, 0x00, 0x78, +/* 0xEB */ 0x31, 0x86, 0x30, 0x00, 0x00, 0x01, 0xF0, 0x7F, 0x1C, 0x77, 0x03, 0xC0, 0x7F, 0xFF, 0xFF, 0xE0, 0x0C, 0x01, 0xC0, 0xDC, 0x31, 0xFC, 0x1F, 0x00, +/* 0xEC */ 0x31, 0x82, 0x60, 0x6C, 0x07, 0x00, 0x00, 0x3E, 0x0F, 0xE3, 0x8E, 0xE0, 0x78, 0x0F, 0xFF, 0xFF, 0xFC, 0x01, 0x80, 0x38, 0x1B, 0x86, 0x3F, 0x83, 0xE0, +/* 0xED */ 0x39, 0x99, 0x80, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x18, 0xC6, 0x31, 0x80, +/* 0xEE */ 0x71, 0xED, 0xA3, 0x00, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC0, +/* 0xEF */ 0x00, 0x67, 0x00, 0x66, 0x00, 0x64, 0x00, 0x6C, 0x00, 0x60, 0x1E, 0x60, 0x3F, 0xE0, 0x71, 0xE0, 0xE0, 0xE0, 0xC0, 0x60, 0xC0, 0x60, 0xC0, 0x60, 0xC0, 0x60, 0xC0, 0x60, 0xE0, 0xE0, 0x71, 0xE0, 0x3F, 0x60, 0x1E, 0x60, +/* 0xF0 */ 0x00, 0x60, 0x06, 0x03, 0xF0, 0x06, 0x00, 0x61, 0xE6, 0x3F, 0xE7, 0x1E, 0xE0, 0xEC, 0x06, 0xC0, 0x6C, 0x06, 0xC0, 0x6C, 0x06, 0xE0, 0xE7, 0x1E, 0x3F, 0xE1, 0xE6, +/* 0xF1 */ 0x03, 0x81, 0xC0, 0x60, 0x30, 0x00, 0x33, 0xCD, 0xFB, 0xC7, 0xE0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x30, +/* 0xF2 */ 0x31, 0x84, 0xC1, 0xA0, 0x38, 0x00, 0x33, 0xCD, 0xFB, 0xC7, 0xE0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x30, +/* 0xF3 */ 0x07, 0x00, 0xC0, 0x30, 0x04, 0x00, 0x00, 0x3E, 0x0F, 0xE3, 0x8E, 0xE0, 0xF8, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF8, 0x3B, 0x8E, 0x3F, 0x83, 0xE0, +/* 0xF4 */ 0x0C, 0x03, 0xC0, 0xD8, 0x19, 0x80, 0x00, 0x3E, 0x0F, 0xE3, 0x8E, 0xE0, 0xF8, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF8, 0x3B, 0x8E, 0x3F, 0x83, 0xE0, +/* 0xF5 */ 0x0C, 0xC3, 0xB8, 0x66, 0x0D, 0x80, 0x00, 0x3E, 0x0F, 0xE3, 0x8E, 0xE0, 0xF8, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF8, 0x3B, 0x8E, 0x3F, 0x83, 0xE0, +/* 0xF6 */ 0x31, 0x86, 0x30, 0x00, 0x00, 0x01, 0xF0, 0x7F, 0x1C, 0x77, 0x07, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0xC1, 0xDC, 0x71, 0xFC, 0x1F, 0x00, +/* 0xF7 */ 0x06, 0x00, 0x60, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x06, 0x00, +/* 0xF8 */ 0xC7, 0x37, 0x8E, 0x03, 0x3D, 0xFC, 0xE3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x00, +/* 0xF9 */ 0x0E, 0x07, 0xC1, 0xB8, 0x6C, 0x1F, 0x03, 0x8C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x07, 0xE3, 0xDF, 0xB3, 0xCC, +/* 0xFA */ 0x03, 0x01, 0x80, 0x60, 0x30, 0x00, 0x30, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x1F, 0x8F, 0x7E, 0xCF, 0x30, +/* 0xFB */ 0x1D, 0xC6, 0x61, 0xB0, 0xCC, 0x00, 0x30, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x1F, 0x8F, 0x7E, 0xCF, 0x30, +/* 0xFC */ 0x31, 0x8C, 0x60, 0x00, 0x00, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x7E, 0x3D, 0xFB, 0x3C, 0xC0, +/* 0xFD */ 0x03, 0x80, 0x60, 0x18, 0x06, 0x00, 0x01, 0xC0, 0xD8, 0x1B, 0x06, 0x70, 0xC6, 0x18, 0xC6, 0x18, 0xC1, 0x98, 0x36, 0x06, 0xC0, 0x78, 0x0E, 0x01, 0xC0, 0x30, 0x06, 0x01, 0xC0, 0xF0, 0x1C, 0x00, +/* 0xFE */ 0x61, 0x86, 0x3E, 0xF9, 0x86, 0x18, 0x61, 0x86, 0x18, 0x61, 0x87, 0x8E, 0x10, 0x83, 0xC3, 0x78, +/* 0xFF */ 0xF0, +}; + +const GFXglyph FreeSans12pt_Win1250Glyphs[] PROGMEM = { +/* 0x01 */ { 0, 19, 20, 21, 1, -17 }, +/* 0x02 */ { 48, 19, 20, 21, 1, -17 }, +/* 0x03 */ { 96, 21, 20, 23, 1, -17 }, +/* 0x04 */ { 149, 21, 20, 23, 1, -17 }, +/* 0x05 */ { 202, 20, 20, 22, 1, -17 }, +/* 0x06 */ { 252, 20, 20, 22, 1, -17 }, +/* 0x07 */ { 302, 0, 0, 8, 0, 0 }, +/* 0x08 */ { 302, 23, 20, 25, 1, -17 }, +/* 0x09 */ { 360, 23, 16, 25, 1, -16 }, +/* 0x0A */ { 406, 0, 0, 8, 0, 0 }, +/* 0x0B */ { 406, 21, 20, 23, 1, -17 }, +/* 0x0C */ { 459, 19, 18, 21, 1, -15 }, +/* 0x0D */ { 502, 0, 0, 8, 0, 0 }, +/* 0x0E */ { 502, 20, 20, 22, 1, -17 }, +/* 0x0F */ { 552, 21, 21, 23, 1, -18 }, +/* 0x10 */ { 608, 19, 20, 21, 1, -17 }, +/* 0x11 */ { 656, 21, 20, 23, 1, -17 }, +/* 0x12 */ { 709, 20, 20, 22, 1, -17 }, +/* 0x13 */ { 759, 21, 20, 23, 1, -17 }, +/* 0x14 */ { 812, 21, 20, 23, 1, -17 }, +/* 0x15 */ { 865, 22, 20, 24, 1, -17 }, +/* 0x16 */ { 920, 16, 20, 18, 1, -17 }, +/* 0x17 */ { 960, 21, 20, 23, 1, -17 }, +/* 0x18 */ { 1013, 23, 20, 25, 1, -17 }, +/* 0x19 */ { 1071, 21, 20, 23, 1, -17 }, +/* 0x1A */ { 1124, 15, 19, 17, 1, -16 }, +/* 0x1B */ { 1160, 24, 21, 26, 1, -18 }, +/* 0x1C */ { 1223, 21, 20, 23, 1, -17 }, +/* 0x1D */ { 1276, 21, 21, 23, 1, -18 }, +/* 0x1E */ { 1332, 20, 20, 22, 1, -17 }, +/* 0x1F */ { 1382, 15, 20, 17, 1, -17 }, +/* ' ' 0x20 */ { 1420, 0, 0, 6, 0, 0 }, +/* '!' 0x21 */ { 1420, 2, 18, 8, 3, -16 }, +/* '"' 0x22 */ { 1425, 6, 6, 8, 1, -15 }, +/* '#' 0x23 */ { 1430, 13, 16, 13, 0, -14 }, +/* '$' 0x24 */ { 1456, 11, 20, 13, 1, -16 }, +/* '%' 0x25 */ { 1484, 20, 17, 21, 1, -15 }, +/* '&' 0x26 */ { 1527, 14, 17, 16, 1, -15 }, +/* ''' 0x27 */ { 1557, 2, 6, 5, 1, -15 }, +/* '(' 0x28 */ { 1559, 5, 23, 8, 2, -16 }, +/* ')' 0x29 */ { 1574, 5, 23, 8, 1, -16 }, +/* '*' 0x2A */ { 1589, 7, 7, 9, 1, -16 }, +/* '+' 0x2B */ { 1596, 10, 11, 14, 2, -9 }, +/* ',' 0x2C */ { 1610, 2, 6, 7, 2, 0 }, +/* '-' 0x2D */ { 1612, 6, 2, 8, 1, -6 }, +/* '.' 0x2E */ { 1614, 2, 2, 6, 2, 0 }, +/* '/' 0x2F */ { 1615, 7, 18, 7, 0, -16 }, +/* '0' 0x30 */ { 1631, 11, 17, 13, 1, -15 }, +/* '1' 0x31 */ { 1655, 5, 17, 13, 3, -15 }, +/* '2' 0x32 */ { 1666, 11, 17, 13, 1, -15 }, +/* '3' 0x33 */ { 1690, 11, 17, 13, 1, -15 }, +/* '4' 0x34 */ { 1714, 11, 17, 13, 1, -15 }, +/* '5' 0x35 */ { 1738, 11, 17, 13, 1, -15 }, +/* '6' 0x36 */ { 1762, 11, 17, 13, 1, -15 }, +/* '7' 0x37 */ { 1786, 11, 17, 13, 1, -15 }, +/* '8' 0x38 */ { 1810, 11, 17, 13, 1, -15 }, +/* '9' 0x39 */ { 1834, 11, 17, 13, 1, -15 }, +/* ':' 0x3A */ { 1858, 2, 13, 6, 2, -11 }, +/* ';' 0x3B */ { 1862, 2, 16, 6, 2, -10 }, +/* '<' 0x3C */ { 1866, 12, 11, 14, 1, -9 }, +/* '=' 0x3D */ { 1883, 12, 6, 14, 1, -7 }, +/* '>' 0x3E */ { 1892, 12, 11, 14, 1, -9 }, +/* '?' 0x3F */ { 1909, 10, 18, 13, 2, -16 }, +/* '@' 0x40 */ { 1932, 22, 21, 24, 1, -16 }, +/* 'A' 0x41 */ { 1990, 14, 18, 16, 1, -16 }, +/* 'B' 0x42 */ { 2022, 13, 18, 16, 2, -16 }, +/* 'C' 0x43 */ { 2052, 15, 18, 17, 1, -16 }, +/* 'D' 0x44 */ { 2086, 14, 18, 17, 2, -16 }, +/* 'E' 0x45 */ { 2118, 12, 18, 15, 2, -16 }, +/* 'F' 0x46 */ { 2145, 11, 18, 14, 2, -16 }, +/* 'G' 0x47 */ { 2170, 16, 18, 18, 1, -16 }, +/* 'H' 0x48 */ { 2206, 13, 18, 17, 2, -16 }, +/* 'I' 0x49 */ { 2236, 2, 18, 7, 2, -16 }, +/* 'J' 0x4A */ { 2241, 9, 18, 13, 1, -16 }, +/* 'K' 0x4B */ { 2262, 13, 18, 16, 2, -16 }, +/* 'L' 0x4C */ { 2292, 10, 18, 14, 2, -16 }, +/* 'M' 0x4D */ { 2315, 16, 18, 20, 2, -16 }, +/* 'N' 0x4E */ { 2351, 13, 18, 18, 2, -16 }, +/* 'O' 0x4F */ { 2381, 17, 18, 19, 1, -16 }, +/* 'P' 0x50 */ { 2420, 12, 18, 16, 2, -16 }, +/* 'Q' 0x51 */ { 2447, 17, 19, 19, 1, -16 }, +/* 'R' 0x52 */ { 2488, 14, 18, 17, 2, -16 }, +/* 'S' 0x53 */ { 2520, 14, 18, 16, 1, -16 }, +/* 'T' 0x54 */ { 2552, 12, 18, 15, 1, -16 }, +/* 'U' 0x55 */ { 2579, 13, 18, 17, 2, -16 }, +/* 'V' 0x56 */ { 2609, 14, 18, 15, 1, -16 }, +/* 'W' 0x57 */ { 2641, 22, 18, 22, 0, -16 }, +/* 'X' 0x58 */ { 2691, 14, 18, 16, 1, -16 }, +/* 'Y' 0x59 */ { 2723, 14, 18, 16, 1, -16 }, +/* 'Z' 0x5A */ { 2755, 13, 18, 15, 1, -16 }, +/* '[' 0x5B */ { 2785, 4, 23, 7, 2, -16 }, +/* '\' 0x5C */ { 2797, 7, 18, 7, 0, -16 }, +/* ']' 0x5D */ { 2813, 4, 23, 7, 1, -16 }, +/* '^' 0x5E */ { 2825, 9, 9, 11, 1, -15 }, +/* '_' 0x5F */ { 2836, 15, 1, 13, -1, 5 }, +/* '`' 0x60 */ { 2838, 5, 4, 6, 1, -16 }, +/* 'a' 0x61 */ { 2841, 12, 13, 13, 1, -11 }, +/* 'b' 0x62 */ { 2861, 12, 18, 13, 1, -16 }, +/* 'c' 0x63 */ { 2888, 10, 13, 12, 1, -11 }, +/* 'd' 0x64 */ { 2905, 11, 18, 13, 1, -16 }, +/* 'e' 0x65 */ { 2930, 11, 13, 13, 1, -11 }, +/* 'f' 0x66 */ { 2948, 5, 18, 7, 1, -16 }, +/* 'g' 0x67 */ { 2960, 11, 18, 13, 1, -11 }, +/* 'h' 0x68 */ { 2985, 10, 18, 13, 1, -16 }, +/* 'i' 0x69 */ { 3008, 2, 18, 5, 2, -16 }, +/* 'j' 0x6A */ { 3013, 4, 23, 6, 0, -16 }, +/* 'k' 0x6B */ { 3025, 10, 18, 12, 1, -16 }, +/* 'l' 0x6C */ { 3048, 2, 18, 5, 1, -16 }, +/* 'm' 0x6D */ { 3053, 17, 13, 19, 1, -11 }, +/* 'n' 0x6E */ { 3081, 10, 13, 13, 1, -11 }, +/* 'o' 0x6F */ { 3098, 11, 13, 13, 1, -11 }, +/* 'p' 0x70 */ { 3116, 12, 17, 13, 1, -11 }, +/* 'q' 0x71 */ { 3142, 11, 17, 13, 1, -11 }, +/* 'r' 0x72 */ { 3166, 6, 13, 8, 1, -11 }, +/* 's' 0x73 */ { 3176, 10, 13, 12, 1, -11 }, +/* 't' 0x74 */ { 3193, 5, 16, 7, 1, -14 }, +/* 'u' 0x75 */ { 3203, 10, 13, 13, 1, -11 }, +/* 'v' 0x76 */ { 3220, 11, 13, 12, 0, -11 }, +/* 'w' 0x77 */ { 3238, 17, 13, 17, 0, -11 }, +/* 'x' 0x78 */ { 3266, 10, 13, 11, 1, -11 }, +/* 'y' 0x79 */ { 3283, 11, 18, 11, 0, -11 }, +/* 'z' 0x7A */ { 3308, 10, 13, 12, 1, -11 }, +/* '{' 0x7B */ { 3325, 5, 23, 8, 1, -16 }, +/* '|' 0x7C */ { 3340, 2, 23, 6, 2, -16 }, +/* '}' 0x7D */ { 3346, 5, 23, 8, 2, -16 }, +/* '~' 0x7E */ { 3361, 10, 5, 12, 1, -9 }, +/* 0x7F */ { 3368, 0, 0, 0, 0, 0 }, +/* 0x80 */ { 3368, 14, 17, 16, 1, -17 }, +/* 0x81 */ { 3398, 0, 0, 8, 0, 0 }, +/* 0x82 */ { 3398, 2, 5, 6, 2, -2 }, +/* 0x83 */ { 3400, 0, 0, 8, 0, 0 }, +/* 0x84 */ { 3400, 6, 5, 10, 2, -2 }, +/* 0x85 */ { 3404, 12, 2, 16, 2, -2 }, +/* 0x86 */ { 3407, 10, 21, 13, 2, -17 }, +/* 0x87 */ { 3434, 10, 20, 13, 2, -17 }, +/* 0x88 */ { 3459, 0, 0, 8, 0, 0 }, +/* 0x89 */ { 3459, 23, 18, 24, 0, -18 }, +/* 0x8A */ { 3511, 14, 21, 16, 1, -21 }, +/* 0x8B */ { 3548, 3, 8, 6, 1, -11 }, +/* 0x8C */ { 3551, 14, 22, 16, 1, -22 }, +/* 0x8D */ { 3590, 12, 21, 15, 1, -21 }, +/* 0x8E */ { 3622, 13, 21, 15, 1, -21 }, +/* 0x8F */ { 3657, 13, 22, 15, 1, -22 }, +/* 0x90 */ { 3693, 0, 0, 8, 0, 0 }, +/* 0x91 */ { 3693, 2, 6, 6, 2, -18 }, +/* 0x92 */ { 3695, 2, 6, 6, 2, -18 }, +/* 0x93 */ { 3697, 6, 6, 10, 2, -18 }, +/* 0x94 */ { 3702, 6, 6, 10, 2, -18 }, +/* 0x95 */ { 3707, 6, 6, 10, 2, -11 }, +/* 0x96 */ { 3712, 10, 2, 12, 1, -8 }, +/* 0x97 */ { 3715, 22, 2, 24, 1, -8 }, +/* 0x98 */ { 3721, 0, 0, 8, 0, 0 }, +/* 0x99 */ { 3721, 22, 13, 24, 2, -18 }, +/* 0x9A */ { 3757, 10, 18, 12, 1, -18 }, +/* 0x9B */ { 3780, 3, 8, 6, 2, -10 }, +/* 0x9C */ { 3783, 10, 18, 12, 1, -18 }, +/* 0x9D */ { 3806, 8, 18, 11, 1, -18 }, +/* 0x9E */ { 3824, 10, 18, 12, 1, -18 }, +/* 0x9F */ { 3847, 10, 18, 12, 1, -18 }, +/* 0xA0 */ { 3870, 0, 0, 7, 0, 0 }, +/* 0xA1 */ { 3870, 7, 4, 8, 0, -18 }, +/* 0xA2 */ { 3874, 7, 4, 8, 0, -18 }, +/* 0xA3 */ { 3878, 13, 18, 15, 1, -18 }, +/* 0xA4 */ { 3908, 9, 9, 13, 2, -13 }, +/* 0xA5 */ { 3919, 16, 23, 16, 1, -18 }, +/* 0xA6 */ { 3965, 2, 23, 6, 2, -18 }, +/* 0xA7 */ { 3971, 11, 23, 13, 1, -18 }, +/* 0xA8 */ { 4003, 6, 2, 8, 1, -17 }, +/* 0xA9 */ { 4005, 18, 17, 19, 1, -17 }, +/* 0xAA */ { 4044, 14, 23, 16, 1, -18 }, +/* 0xAB */ { 4085, 8, 8, 12, 2, -11 }, +/* 0xAC */ { 4093, 12, 6, 14, 1, -9 }, +/* 0xAD */ { 4102, 6, 2, 8, 1, -8 }, +/* 0xAE */ { 4104, 18, 17, 19, 1, -17 }, +/* 0xAF */ { 4143, 13, 21, 15, 1, -21 }, +/* 0xB0 */ { 4178, 7, 8, 15, 4, -17 }, +/* 0xB1 */ { 4185, 12, 15, 14, 1, -15 }, +/* 0xB2 */ { 4208, 5, 5, 8, 1, 0 }, +/* 0xB3 */ { 4212, 4, 18, 6, 1, -18 }, +/* 0xB4 */ { 4221, 5, 4, 8, 2, -18 }, +/* 0xB5 */ { 4224, 12, 17, 13, 2, -13 }, +/* 0xB6 */ { 4250, 11, 21, 13, 2, -18 }, +/* 0xB7 */ { 4279, 2, 2, 6, 2, -8 }, +/* 0xB8 */ { 4280, 6, 5, 8, 1, 0 }, +/* 0xB9 */ { 4284, 13, 18, 13, 1, -13 }, +/* 0xBA */ { 4314, 10, 18, 12, 1, -13 }, +/* 0xBB */ { 4337, 8, 8, 12, 2, -10 }, +/* 0xBC */ { 4345, 10, 18, 14, 2, -18 }, +/* 0xBD */ { 4368, 8, 4, 8, 0, -18 }, +/* 0xBE */ { 4372, 7, 18, 9, 1, -18 }, +/* 0xBF */ { 4388, 10, 17, 12, 1, -17 }, +/* 0xC0 */ { 4410, 14, 22, 17, 2, -22 }, +/* 0xC1 */ { 4449, 14, 22, 16, 1, -22 }, +/* 0xC2 */ { 4488, 14, 22, 16, 1, -22 }, +/* 0xC3 */ { 4527, 14, 22, 16, 1, -22 }, +/* 0xC4 */ { 4566, 14, 21, 16, 1, -21 }, +/* 0xC5 */ { 4603, 10, 22, 14, 2, -22 }, +/* 0xC6 */ { 4631, 15, 22, 17, 1, -22 }, +/* 0xC7 */ { 4673, 15, 23, 17, 1, -18 }, +/* 0xC8 */ { 4717, 15, 21, 17, 1, -21 }, +/* 0xC9 */ { 4757, 12, 22, 15, 2, -22 }, +/* 0xCA */ { 4790, 13, 23, 15, 2, -18 }, +/* 0xCB */ { 4828, 12, 21, 15, 2, -21 }, +/* 0xCC */ { 4860, 12, 21, 15, 2, -21 }, +/* 0xCD */ { 4892, 4, 22, 7, 1, -22 }, +/* 0xCE */ { 4903, 6, 22, 7, 0, -22 }, +/* 0xCF */ { 4920, 14, 21, 17, 2, -21 }, +/* 0xD0 */ { 4957, 15, 18, 17, 1, -18 }, +/* 0xD1 */ { 4991, 13, 22, 18, 2, -22 }, +/* 0xD2 */ { 5027, 13, 21, 18, 2, -21 }, +/* 0xD3 */ { 5062, 17, 22, 19, 1, -22 }, +/* 0xD4 */ { 5109, 17, 22, 19, 1, -22 }, +/* 0xD5 */ { 5156, 17, 22, 19, 1, -22 }, +/* 0xD6 */ { 5203, 17, 21, 19, 1, -21 }, +/* 0xD7 */ { 5248, 8, 9, 14, 3, -10 }, +/* 0xD8 */ { 5257, 14, 21, 17, 2, -21 }, +/* 0xD9 */ { 5294, 13, 24, 17, 2, -24 }, +/* 0xDA */ { 5333, 13, 22, 17, 2, -22 }, +/* 0xDB */ { 5369, 13, 22, 17, 2, -22 }, +/* 0xDC */ { 5405, 13, 21, 17, 2, -21 }, +/* 0xDD */ { 5440, 14, 22, 16, 1, -22 }, +/* 0xDE */ { 5479, 12, 23, 15, 1, -18 }, +/* 0xDF */ { 5514, 11, 18, 14, 2, -18 }, +/* 0xE0 */ { 5539, 6, 18, 8, 1, -18 }, +/* 0xE1 */ { 5553, 12, 18, 13, 1, -18 }, +/* 0xE2 */ { 5580, 12, 18, 13, 1, -18 }, +/* 0xE3 */ { 5607, 12, 18, 13, 1, -18 }, +/* 0xE4 */ { 5634, 12, 17, 13, 1, -17 }, +/* 0xE5 */ { 5660, 5, 22, 6, 0, -22 }, +/* 0xE6 */ { 5674, 10, 18, 12, 1, -18 }, +/* 0xE7 */ { 5697, 10, 18, 12, 1, -13 }, +/* 0xE8 */ { 5720, 10, 18, 12, 1, -18 }, +/* 0xE9 */ { 5743, 11, 18, 13, 1, -18 }, +/* 0xEA */ { 5768, 11, 18, 13, 1, -13 }, +/* 0xEB */ { 5793, 11, 17, 13, 1, -17 }, +/* 0xEC */ { 5817, 11, 18, 13, 1, -18 }, +/* 0xED */ { 5842, 5, 18, 5, 0, -18 }, +/* 0xEE */ { 5854, 6, 18, 6, 0, -18 }, +/* 0xEF */ { 5868, 16, 18, 18, 1, -18 }, +/* 0xF0 */ { 5904, 12, 18, 14, 1, -18 }, +/* 0xF1 */ { 5931, 10, 18, 13, 1, -18 }, +/* 0xF2 */ { 5954, 10, 18, 13, 1, -18 }, +/* 0xF3 */ { 5977, 11, 18, 13, 1, -18 }, +/* 0xF4 */ { 6002, 11, 18, 13, 1, -18 }, +/* 0xF5 */ { 6027, 11, 18, 13, 1, -18 }, +/* 0xF6 */ { 6052, 11, 17, 13, 1, -17 }, +/* 0xF7 */ { 6076, 12, 11, 14, 1, -11 }, +/* 0xF8 */ { 6093, 6, 18, 8, 1, -18 }, +/* 0xF9 */ { 6107, 10, 19, 13, 1, -19 }, +/* 0xFA */ { 6131, 10, 18, 13, 1, -18 }, +/* 0xFB */ { 6154, 10, 18, 13, 1, -18 }, +/* 0xFC */ { 6177, 10, 17, 13, 1, -17 }, +/* 0xFD */ { 6199, 11, 23, 11, 0, -18 }, +/* 0xFE */ { 6231, 6, 21, 7, 1, -16 }, +/* 0xFF */ { 6247, 2, 2, 8, 3, -17 }, +}; + +const GFXfont FreeSans12pt_Win1250 PROGMEM = { +(uint8_t*)FreeSans12pt_Win1250Bitmaps, +(GFXglyph*)FreeSans12pt_Win1250Glyphs, +0x01, 0xFF, 19 +}; diff --git a/src/graphics/niche/Fonts/FreeSans12pt_Win1251.h b/src/graphics/niche/Fonts/FreeSans12pt_Win1251.h new file mode 100644 index 000000000..d2972f836 --- /dev/null +++ b/src/graphics/niche/Fonts/FreeSans12pt_Win1251.h @@ -0,0 +1,527 @@ +// trunk-ignore-all(clang-format) +#pragma once +/* PROPERTIES + +FONT_NAME FreeSans12pt_Win1251 +*/ +const uint8_t FreeSans12pt_Win1251Bitmaps[] PROGMEM = { +/* 0x01 */ 0x00, 0x30, 0x00, 0x09, 0x00, 0x01, 0x20, 0x00, 0x24, 0x00, 0x04, 0x80, 0x01, 0x90, 0x00, 0x62, 0x00, 0x30, 0xFE, 0x04, 0x10, 0x5F, 0x02, 0x0B, 0x00, 0x7F, 0xE0, 0x0C, 0x1C, 0x02, 0x83, 0x81, 0x9F, 0xF0, 0x02, 0x1E, 0x00, 0x41, 0xC0, 0x0E, 0x7F, 0x81, 0x78, 0x18, 0x62, 0x00, 0xFF, 0xC0, +/* 0x02 */ 0x00, 0xFF, 0x80, 0x61, 0x13, 0xF0, 0x62, 0x60, 0x07, 0xFC, 0x00, 0x83, 0x80, 0x10, 0xF0, 0x33, 0xF6, 0x01, 0x41, 0xC0, 0x18, 0x38, 0x03, 0xFF, 0xE0, 0x47, 0x02, 0x08, 0x20, 0x61, 0xC4, 0x06, 0x17, 0x00, 0x22, 0x00, 0x02, 0x40, 0x00, 0x48, 0x00, 0x09, 0x00, 0x01, 0x20, 0x00, 0x3C, 0x00, +/* 0x03 */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x00, 0x02, 0x30, 0x00, 0x09, 0x04, 0x08, 0x48, 0x70, 0xE1, 0xC3, 0x87, 0x0E, 0x08, 0x10, 0x70, 0x00, 0x03, 0x80, 0x00, 0x14, 0x00, 0x00, 0xA1, 0x81, 0x8D, 0x87, 0xF0, 0x44, 0x00, 0x06, 0x30, 0x00, 0x60, 0xC0, 0x06, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00, +/* 0x04 */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x00, 0x02, 0x30, 0x00, 0x09, 0x10, 0x02, 0x48, 0xE0, 0x61, 0xC1, 0xCC, 0x0E, 0x78, 0x1C, 0x70, 0x00, 0x03, 0x80, 0x00, 0x14, 0xFF, 0xFC, 0xA6, 0x00, 0xCD, 0x9F, 0xFE, 0x44, 0x71, 0xE6, 0x30, 0xFC, 0x60, 0xC0, 0x06, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00, +/* 0x05 */ 0x00, 0x18, 0x00, 0x00, 0x40, 0x01, 0x90, 0x01, 0xF4, 0x08, 0x12, 0x23, 0xC1, 0x91, 0x2C, 0x1C, 0x8A, 0xC3, 0x64, 0x64, 0x13, 0x22, 0x41, 0x98, 0x26, 0x2C, 0xC4, 0x22, 0x60, 0x42, 0x13, 0x04, 0x30, 0x80, 0x61, 0xA4, 0x02, 0x18, 0x20, 0x03, 0x41, 0x00, 0x20, 0x08, 0x02, 0x00, 0x60, 0x40, 0x03, 0xF8, +/* 0x06 */ 0x00, 0x10, 0x00, 0x03, 0x00, 0x1C, 0x48, 0x00, 0xB4, 0x80, 0x09, 0xF9, 0xC0, 0xE0, 0xE4, 0x0C, 0x02, 0x8F, 0x80, 0x38, 0x88, 0x01, 0x0D, 0x00, 0x18, 0x30, 0x01, 0x60, 0x80, 0x13, 0x18, 0x03, 0xF2, 0xC0, 0x20, 0x26, 0x06, 0x07, 0xFF, 0xA0, 0x02, 0x39, 0x00, 0x14, 0x70, 0x01, 0xC3, 0x00, 0x18, 0x00, +/* 0x07 */ +/* 0x08 */ 0x00, 0x1F, 0x80, 0x00, 0x60, 0x80, 0x01, 0x00, 0x80, 0x06, 0x00, 0x80, 0x3C, 0x01, 0x01, 0x8C, 0x02, 0x02, 0x08, 0x04, 0x04, 0x08, 0x0C, 0x38, 0x00, 0x04, 0x80, 0x00, 0x06, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x2E, 0xC0, 0x01, 0x83, 0x7E, 0x0C, 0x10, 0x37, 0xE2, 0x61, 0x00, 0x0C, 0xC6, 0x10, 0x98, 0x0C, 0x63, 0x00, 0x00, 0xC6, 0x00, +/* 0x09 */ 0x00, 0x1F, 0x80, 0x00, 0x60, 0x80, 0x01, 0x00, 0x80, 0x06, 0x00, 0x80, 0x3C, 0x01, 0x01, 0x8C, 0x02, 0x02, 0x08, 0x04, 0x04, 0x08, 0x0C, 0x38, 0x00, 0x04, 0x80, 0x00, 0x06, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x2E, 0xC0, 0x01, 0x83, 0x7E, 0x0C, 0x00, 0x37, 0xE0, +/* 0x0A */ +/* 0x0B */ 0x1F, 0x07, 0xC1, 0x86, 0x41, 0x10, 0x0C, 0x04, 0x80, 0x40, 0x18, 0x00, 0x00, 0xC0, 0x00, 0x06, 0x00, 0x00, 0x30, 0x00, 0x01, 0x40, 0x00, 0x0A, 0x00, 0x00, 0x88, 0x00, 0x04, 0x40, 0x00, 0x41, 0x00, 0x02, 0x04, 0x00, 0x20, 0x20, 0x02, 0x00, 0x80, 0x20, 0x02, 0x02, 0x00, 0x08, 0x20, 0x00, 0x22, 0x00, 0x00, 0xE0, 0x00, +/* 0x0C */ 0x01, 0x00, 0x00, 0x38, 0x00, 0x04, 0xC0, 0x01, 0x08, 0x00, 0x18, 0x80, 0x1C, 0x10, 0x02, 0x07, 0x80, 0x81, 0x10, 0x1F, 0xC2, 0x02, 0x00, 0x60, 0x80, 0x1A, 0x20, 0x1C, 0x42, 0x1C, 0x08, 0xFE, 0x03, 0xA0, 0x01, 0x8C, 0x01, 0xC1, 0x43, 0xD0, 0x27, 0x81, 0xF8, +/* 0x0D */ +/* 0x0E */ 0x00, 0xE0, 0x00, 0x11, 0x00, 0x01, 0x10, 0x00, 0x0B, 0x00, 0x03, 0xF8, 0x00, 0x60, 0x60, 0x09, 0x02, 0x00, 0xA0, 0x10, 0x16, 0x01, 0x01, 0x40, 0x10, 0x10, 0x01, 0x01, 0x00, 0x08, 0x10, 0x00, 0x82, 0x1F, 0x08, 0x3F, 0x90, 0x44, 0x00, 0x06, 0xBF, 0xFF, 0xAF, 0xF0, 0xFF, 0xFF, 0x0F, 0xE3, 0xFB, 0xFC, +/* 0x0F */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x40, 0x12, 0x34, 0x00, 0x69, 0x40, 0x01, 0x49, 0xE0, 0xF1, 0xCD, 0x06, 0x8E, 0x28, 0x14, 0x71, 0x40, 0xA3, 0x8B, 0xFD, 0x14, 0x50, 0x68, 0xA2, 0x81, 0x4D, 0x97, 0xFA, 0x44, 0xBF, 0xD6, 0x31, 0x02, 0xE0, 0xC8, 0x16, 0x08, 0x61, 0x08, 0x21, 0xF0, 0x80, 0xF8, 0x78, 0x00, +/* 0x10 */ 0x00, 0xF0, 0x00, 0x3A, 0x00, 0x07, 0xC0, 0x00, 0xA8, 0x00, 0x1F, 0x00, 0x02, 0xB0, 0x00, 0x52, 0x00, 0x0A, 0x40, 0x02, 0x48, 0x00, 0x49, 0x00, 0x09, 0x30, 0x01, 0x22, 0x01, 0xC4, 0x70, 0xF0, 0x85, 0xE1, 0x10, 0x88, 0x37, 0x20, 0x03, 0x9C, 0x00, 0x37, 0x00, 0x06, 0x40, 0x01, 0x86, 0x00, +/* 0x11 */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x60, 0x02, 0x36, 0x00, 0x09, 0x04, 0x0C, 0x48, 0x60, 0xC1, 0xC3, 0x0F, 0x0E, 0x00, 0x08, 0x70, 0x00, 0x23, 0x80, 0x63, 0x84, 0x01, 0x9F, 0x20, 0x0C, 0xFD, 0x80, 0x27, 0xE4, 0x03, 0x3F, 0x30, 0x33, 0xE0, 0xC0, 0x00, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00, +/* 0x12 */ 0x00, 0xC2, 0x00, 0x1C, 0x24, 0x02, 0x18, 0x60, 0x64, 0x02, 0x02, 0x40, 0x20, 0x00, 0xF2, 0x03, 0x89, 0xE0, 0x7C, 0x80, 0x0E, 0x25, 0x80, 0xE1, 0x00, 0x1A, 0x08, 0x71, 0xB0, 0xC4, 0x39, 0x84, 0xC2, 0xCC, 0x40, 0x76, 0x7C, 0x05, 0xBB, 0x80, 0x4C, 0xE0, 0x0A, 0x78, 0x00, 0x9C, 0x00, 0x0F, 0x00, 0x00, +/* 0x13 */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x00, 0x02, 0x30, 0x00, 0x09, 0x00, 0x00, 0x48, 0x60, 0xC1, 0xC6, 0xC9, 0x0E, 0x00, 0x00, 0x70, 0x00, 0x03, 0x80, 0x00, 0x14, 0xFF, 0xF8, 0xA6, 0x00, 0xCD, 0x9F, 0xFE, 0x44, 0x71, 0xE6, 0x30, 0xFC, 0x60, 0xC0, 0x06, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00, +/* 0x14 */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x20, 0x22, 0x33, 0x01, 0x89, 0x20, 0x02, 0x48, 0x60, 0xE1, 0xC8, 0x80, 0x8E, 0x46, 0x46, 0x72, 0x32, 0x33, 0x9F, 0x9F, 0x94, 0x78, 0x78, 0xA0, 0x00, 0x0D, 0x80, 0x00, 0x44, 0x0E, 0x06, 0x30, 0x00, 0x60, 0xC0, 0x06, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00, +/* 0x15 */ 0x03, 0xFC, 0x20, 0x38, 0x1C, 0x81, 0x80, 0x1D, 0x08, 0x00, 0x32, 0x60, 0x00, 0x89, 0x00, 0x02, 0x18, 0x00, 0x08, 0x61, 0xC3, 0x22, 0x8D, 0x93, 0x72, 0x00, 0x00, 0x48, 0x00, 0x01, 0x20, 0x00, 0x04, 0x9F, 0xFF, 0x92, 0x60, 0x0E, 0x44, 0xFF, 0xF2, 0x11, 0xC3, 0x88, 0x21, 0xF8, 0x40, 0x40, 0x02, 0x00, 0xC0, 0x30, 0x00, 0xFF, 0x00, +/* 0x16 */ 0x03, 0x80, 0x03, 0xC0, 0x01, 0xE0, 0x01, 0xE0, 0x03, 0xF0, 0x03, 0xF0, 0x27, 0xF0, 0x6F, 0x70, 0x6E, 0x60, 0xFC, 0x60, 0xFC, 0x7E, 0xFC, 0x7E, 0xFC, 0x3F, 0xF4, 0x1F, 0xF4, 0x1F, 0xF0, 0x0E, 0x70, 0x0E, 0x30, 0x1C, 0x38, 0x38, 0x0F, 0xF0, +/* 0x17 */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x00, 0x02, 0x30, 0x00, 0x09, 0x00, 0x00, 0x48, 0x00, 0x21, 0xC0, 0x02, 0x8E, 0x20, 0xF4, 0x70, 0x84, 0x11, 0x82, 0x40, 0x84, 0x01, 0x03, 0x20, 0x0F, 0x85, 0x80, 0x03, 0x04, 0x00, 0x04, 0x30, 0x78, 0x10, 0xC0, 0x06, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00, +/* 0x18 */ 0x00, 0xFC, 0x00, 0x02, 0x06, 0x00, 0x08, 0x24, 0x00, 0x21, 0xA4, 0x00, 0x4C, 0x48, 0x00, 0xA0, 0x50, 0x01, 0x92, 0x60, 0x03, 0x24, 0xC0, 0x06, 0x01, 0x81, 0x28, 0x03, 0x49, 0x6C, 0xC4, 0xAD, 0xD8, 0x16, 0xA4, 0xCC, 0xC4, 0x44, 0x86, 0x13, 0x05, 0x00, 0x28, 0x0A, 0x00, 0x50, 0x14, 0x00, 0x90, 0x48, 0x01, 0x20, 0x90, 0x02, 0x41, 0x20, 0x00, 0x00, +/* 0x19 */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x00, 0x02, 0x30, 0x00, 0x09, 0x00, 0x00, 0x49, 0xC3, 0x81, 0xC0, 0x00, 0x0E, 0x78, 0xF0, 0x77, 0xEF, 0xC3, 0xA7, 0x4E, 0x15, 0x0A, 0x10, 0xA7, 0x8F, 0x0D, 0x80, 0x00, 0x44, 0x00, 0x06, 0x33, 0xF0, 0x60, 0xC0, 0x06, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00, +/* 0x1A */ 0xFF, 0xFF, 0x00, 0x06, 0x00, 0x0C, 0x3E, 0x18, 0x82, 0x32, 0x02, 0x64, 0x04, 0xC8, 0x09, 0x80, 0x23, 0x00, 0x86, 0x02, 0x0C, 0x08, 0x18, 0x10, 0x30, 0x00, 0x60, 0x00, 0xC0, 0x81, 0x80, 0x03, 0x00, 0x07, 0xFF, 0xF8, +/* 0x1B */ 0x00, 0xFE, 0x00, 0x03, 0x81, 0x80, 0x04, 0x00, 0x60, 0x08, 0x00, 0x30, 0x10, 0x00, 0x10, 0x30, 0x07, 0x88, 0x23, 0xC8, 0x08, 0x22, 0x00, 0x04, 0x60, 0x00, 0x44, 0x60, 0x00, 0x84, 0x63, 0x03, 0x04, 0x61, 0xFC, 0x04, 0x6B, 0x00, 0x9E, 0xA5, 0x01, 0x6A, 0xD5, 0x01, 0x43, 0xA8, 0x81, 0x05, 0xD0, 0x82, 0x0A, 0xA0, 0x82, 0x05, 0xC0, 0x82, 0x02, 0x61, 0xFF, 0x0C, 0x1E, 0x00, 0xF0, +/* 0x1C */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x30, 0x02, 0x32, 0x00, 0x09, 0x00, 0x00, 0x48, 0x20, 0x61, 0xC3, 0x84, 0x0E, 0x1C, 0x78, 0x70, 0x40, 0x03, 0x80, 0x00, 0x14, 0x00, 0x00, 0xA0, 0x03, 0x0D, 0x83, 0xF0, 0x44, 0x00, 0x06, 0x30, 0x00, 0x60, 0xC0, 0x06, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00, +/* 0x1D */ 0x01, 0xFE, 0x00, 0x3A, 0x1C, 0x03, 0x00, 0x30, 0x23, 0x1E, 0xC3, 0x38, 0x03, 0x10, 0xC3, 0x09, 0x00, 0x18, 0x68, 0x00, 0xC1, 0x40, 0x00, 0x0A, 0x07, 0x80, 0x50, 0x46, 0x02, 0x80, 0x00, 0x1A, 0x1E, 0x00, 0xCB, 0x10, 0x0D, 0x03, 0x00, 0x48, 0x60, 0x06, 0x40, 0x00, 0x22, 0x0C, 0x02, 0x10, 0x60, 0x60, 0x43, 0xFC, 0x01, 0xE0, 0x00, 0x00, +/* 0x1E */ 0x01, 0xF0, 0x00, 0xEA, 0xC0, 0x31, 0x5F, 0x04, 0x5F, 0x88, 0x80, 0xA0, 0x48, 0x0E, 0x02, 0x8F, 0x40, 0x3C, 0x10, 0x21, 0x66, 0x87, 0x15, 0x98, 0x71, 0x41, 0x02, 0x14, 0x00, 0x01, 0x40, 0x00, 0x14, 0x00, 0x01, 0x21, 0xFE, 0x12, 0x00, 0x02, 0x10, 0x00, 0x60, 0x80, 0x0C, 0x06, 0x01, 0x80, 0x3F, 0xE0, +/* 0x1F */ 0x0E, 0x00, 0x13, 0x00, 0x23, 0x00, 0xF3, 0x01, 0x31, 0x01, 0x11, 0x03, 0xD3, 0x06, 0xF2, 0x30, 0x34, 0xC7, 0x25, 0x33, 0x2B, 0xC2, 0x57, 0x04, 0x3A, 0x08, 0x72, 0x30, 0xA3, 0xC3, 0x40, 0x04, 0x40, 0x18, 0x40, 0x60, 0x7F, 0x80, +/* ' ' 0x20 */ +/* '!' 0x21 */ 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, +/* '"' 0x22 */ 0xCF, 0x3C, 0xF3, 0x8A, 0x20, +/* '#' 0x23 */ 0x06, 0x30, 0x31, 0x03, 0x18, 0x18, 0xC7, 0xFF, 0xBF, 0xFC, 0x31, 0x01, 0x18, 0x18, 0xC7, 0xFF, 0xBF, 0xFC, 0x31, 0x01, 0x18, 0x18, 0xC0, 0xC6, 0x06, 0x30, +/* '$' 0x24 */ 0x04, 0x03, 0xE1, 0xFF, 0x72, 0x7C, 0x47, 0x88, 0xF1, 0x07, 0xA0, 0x7E, 0x03, 0xF0, 0x17, 0x02, 0x7C, 0x47, 0x88, 0xF1, 0x1B, 0x26, 0x7F, 0xC3, 0xE0, 0x10, 0x02, 0x00, +/* '%' 0x25 */ 0x00, 0x06, 0x03, 0xC0, 0x40, 0x7E, 0x0C, 0x0E, 0x70, 0x80, 0xC3, 0x18, 0x0C, 0x31, 0x00, 0xE7, 0x30, 0x07, 0xE6, 0x00, 0x3C, 0x40, 0x00, 0x0C, 0x7C, 0x00, 0x8F, 0xE0, 0x19, 0xC7, 0x01, 0x18, 0x30, 0x31, 0x83, 0x02, 0x1C, 0x70, 0x40, 0xFE, 0x04, 0x07, 0xC0, +/* '&' 0x26 */ 0x0F, 0x00, 0x7E, 0x03, 0x9C, 0x0C, 0x30, 0x30, 0xC0, 0xE7, 0x01, 0xF8, 0x03, 0x80, 0x3E, 0x01, 0xCC, 0x6E, 0x39, 0xB0, 0x7C, 0xC0, 0xF3, 0x03, 0xCE, 0x1F, 0x9F, 0xE6, 0x3E, 0x1C, +/* ''' 0x27 */ 0xFF, 0xA0, +/* '(' 0x28 */ 0x08, 0x8C, 0x46, 0x31, 0x98, 0xC6, 0x31, 0x8C, 0x63, 0x08, 0x63, 0x08, 0x61, 0x0C, 0x20, +/* ')' 0x29 */ 0x82, 0x18, 0xC3, 0x18, 0xC3, 0x18, 0xC6, 0x31, 0x8C, 0x62, 0x31, 0x88, 0xC4, 0x62, 0x00, +/* '*' 0x2A */ 0x10, 0x23, 0x5B, 0xE3, 0x8D, 0x91, 0x00, +/* '+' 0x2B */ 0x0C, 0x03, 0x00, 0xC0, 0x30, 0xFF, 0xFF, 0xF0, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, +/* ',' 0x2C */ 0xF5, 0x60, +/* '-' 0x2D */ 0xFF, 0xF0, +/* '.' 0x2E */ 0xF0, +/* '/' 0x2F */ 0x02, 0x0C, 0x10, 0x20, 0xC1, 0x02, 0x0C, 0x10, 0x20, 0xC1, 0x02, 0x0C, 0x10, 0x20, 0xC1, 0x00, +/* '0' 0x30 */ 0x1F, 0x07, 0xF1, 0xC7, 0x30, 0x6C, 0x0F, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3E, 0x0E, 0xC1, 0x9C, 0x71, 0xFC, 0x1F, 0x00, +/* '1' 0x31 */ 0x08, 0xCF, 0xFF, 0x8C, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x18, +/* '2' 0x32 */ 0x1F, 0x0F, 0xF9, 0x87, 0x60, 0x7C, 0x06, 0x00, 0xC0, 0x18, 0x07, 0x01, 0xC0, 0xF0, 0x78, 0x1C, 0x06, 0x00, 0xC0, 0x30, 0x07, 0xFF, 0xFF, 0xE0, +/* '3' 0x33 */ 0x3F, 0x0F, 0xF3, 0x87, 0x60, 0x6C, 0x0C, 0x01, 0x80, 0x60, 0x78, 0x0F, 0x80, 0x18, 0x01, 0x80, 0x3C, 0x07, 0x80, 0xD8, 0x73, 0xFC, 0x3F, 0x00, +/* '4' 0x34 */ 0x01, 0x80, 0x70, 0x0E, 0x03, 0xC0, 0xD8, 0x1B, 0x06, 0x61, 0x8C, 0x21, 0x8C, 0x33, 0x06, 0x7F, 0xFF, 0xFE, 0x03, 0x00, 0x60, 0x0C, 0x01, 0x80, +/* '5' 0x35 */ 0x3F, 0xCF, 0xF9, 0x80, 0x30, 0x06, 0x00, 0xDE, 0x1F, 0xE7, 0x0E, 0x00, 0xE0, 0x0C, 0x01, 0x80, 0x30, 0x07, 0x81, 0xB8, 0x73, 0xFC, 0x1F, 0x00, +/* '6' 0x36 */ 0x0F, 0x07, 0xF9, 0xC3, 0x30, 0x74, 0x01, 0x80, 0x33, 0xC7, 0xFE, 0xF1, 0xDC, 0x1F, 0x01, 0xE0, 0x3C, 0x06, 0xC1, 0xDC, 0x71, 0xFC, 0x1F, 0x00, +/* '7' 0x37 */ 0xFF, 0xFF, 0xFC, 0x01, 0x00, 0x60, 0x18, 0x02, 0x00, 0xC0, 0x30, 0x06, 0x01, 0x80, 0x30, 0x04, 0x01, 0x80, 0x30, 0x06, 0x01, 0x80, 0x30, 0x00, +/* '8' 0x38 */ 0x1F, 0x07, 0xF1, 0xC7, 0x30, 0x66, 0x0C, 0xC1, 0x8C, 0x61, 0xF8, 0x3F, 0x8E, 0x3B, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xD8, 0x31, 0xFC, 0x1F, 0x00, +/* '9' 0x39 */ 0x1F, 0x07, 0xF1, 0xC7, 0x70, 0x6C, 0x07, 0x80, 0xF0, 0x1E, 0x07, 0x61, 0xEF, 0xFC, 0x79, 0x80, 0x30, 0x05, 0xC1, 0x98, 0x73, 0xFC, 0x1E, 0x00, +/* ':' 0x3A */ 0xF0, 0x00, 0x03, 0xC0, +/* ';' 0x3B */ 0xF0, 0x00, 0x0F, 0x56, +/* '<' 0x3C */ 0x00, 0x70, 0x1E, 0x0F, 0x83, 0xC0, 0xF0, 0x0E, 0x00, 0x7C, 0x00, 0xF0, 0x03, 0xC0, 0x0F, 0x00, 0x10, +/* '=' 0x3D */ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, +/* '>' 0x3E */ 0xE0, 0x07, 0x80, 0x1F, 0x00, 0x7C, 0x00, 0xF0, 0x07, 0x01, 0xE0, 0xF0, 0x3C, 0x0F, 0x00, 0x80, 0x00, +/* '?' 0x3F */ 0x3F, 0x1F, 0xEE, 0x1F, 0x03, 0xC0, 0xC0, 0x30, 0x0C, 0x06, 0x03, 0x81, 0xC0, 0xE0, 0x30, 0x0C, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x03, 0x00, +/* '@' 0x40 */ 0x00, 0xFE, 0x00, 0x0F, 0xFE, 0x00, 0xF0, 0x3E, 0x07, 0x00, 0x3C, 0x38, 0x00, 0x38, 0xC1, 0xE0, 0x66, 0x0F, 0xD9, 0xD8, 0x61, 0xC3, 0xC3, 0x07, 0x0F, 0x1C, 0x1C, 0x3C, 0x60, 0x60, 0xF1, 0x81, 0x83, 0xC6, 0x06, 0x1B, 0x18, 0x38, 0xEE, 0x71, 0xE7, 0x18, 0xFD, 0xF8, 0x71, 0xE7, 0xC0, 0xE0, 0x00, 0x01, 0xE0, 0x00, 0x01, 0xFF, 0xC0, 0x01, 0xFC, 0x00, +/* 'A' 0x41 */ 0x07, 0x80, 0x1E, 0x00, 0x78, 0x03, 0xF0, 0x0C, 0xC0, 0x33, 0x01, 0xCE, 0x06, 0x18, 0x18, 0x60, 0xE1, 0xC3, 0x03, 0x0F, 0xFC, 0x7F, 0xF9, 0x80, 0x66, 0x01, 0xB8, 0x07, 0xC0, 0x0F, 0x00, 0x30, +/* 'B' 0x42 */ 0xFF, 0xC7, 0xFF, 0x30, 0x1D, 0x80, 0x6C, 0x03, 0x60, 0x1B, 0x00, 0xD8, 0x0C, 0xFF, 0xC7, 0xFF, 0x30, 0x0D, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x06, 0xFF, 0xF7, 0xFE, 0x00, +/* 'C' 0x43 */ 0x07, 0xE0, 0x3F, 0xF0, 0xE0, 0x73, 0x80, 0x76, 0x00, 0x6C, 0x00, 0x30, 0x00, 0x60, 0x00, 0xC0, 0x01, 0x80, 0x03, 0x00, 0x06, 0x00, 0x0E, 0x00, 0x6C, 0x00, 0xDC, 0x03, 0x1E, 0x0E, 0x1F, 0xF8, 0x0F, 0xC0, +/* 'D' 0x44 */ 0xFF, 0xC3, 0xFF, 0x8C, 0x07, 0x30, 0x0E, 0xC0, 0x1B, 0x00, 0x7C, 0x00, 0xF0, 0x03, 0xC0, 0x0F, 0x00, 0x3C, 0x00, 0xF0, 0x03, 0xC0, 0x1F, 0x00, 0x6C, 0x03, 0xB0, 0x1C, 0xFF, 0xE3, 0xFE, 0x00, +/* 'E' 0x45 */ 0xFF, 0xFF, 0xFF, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xFF, 0xEF, 0xFE, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xFF, 0xFF, 0xFF, +/* 'F' 0x46 */ 0xFF, 0xFF, 0xFF, 0x00, 0x60, 0x0C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xFF, 0xDF, 0xFB, 0x00, 0x60, 0x0C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xC0, 0x18, 0x00, +/* 'G' 0x47 */ 0x07, 0xF0, 0x1F, 0xFC, 0x3C, 0x1E, 0x70, 0x07, 0x60, 0x03, 0xE0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x7F, 0xC0, 0x7F, 0xC0, 0x03, 0xC0, 0x03, 0x60, 0x03, 0x60, 0x07, 0x30, 0x0F, 0x3C, 0x1F, 0x1F, 0xFB, 0x07, 0xE1, +/* 'H' 0x48 */ 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xFF, 0xFF, 0xFF, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xC0, +/* 'I' 0x49 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, +/* 'J' 0x4A */ 0x01, 0x80, 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x80, 0xC0, 0x60, 0x3C, 0x1E, 0x0F, 0x07, 0xC7, 0x7F, 0x1F, 0x00, +/* 'K' 0x4B */ 0xC0, 0x3E, 0x03, 0xB0, 0x39, 0x83, 0x8C, 0x38, 0x63, 0x83, 0x38, 0x19, 0xC0, 0xDE, 0x07, 0xB8, 0x38, 0xE1, 0x83, 0x0C, 0x1C, 0x60, 0x73, 0x01, 0x98, 0x0E, 0xC0, 0x3E, 0x00, 0xC0, +/* 'L' 0x4C */ 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xFF, 0xFF, 0xF0, +/* 'M' 0x4D */ 0xE0, 0x07, 0xE0, 0x07, 0xF0, 0x0F, 0xF0, 0x0F, 0xD0, 0x0F, 0xD8, 0x1B, 0xD8, 0x1B, 0xD8, 0x1B, 0xCC, 0x33, 0xCC, 0x33, 0xCC, 0x33, 0xC6, 0x63, 0xC6, 0x63, 0xC6, 0x63, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC1, 0x83, +/* 'N' 0x4E */ 0xE0, 0x1F, 0x00, 0xFC, 0x07, 0xE0, 0x3D, 0x81, 0xEE, 0x0F, 0x30, 0x79, 0xC3, 0xC6, 0x1E, 0x18, 0xF0, 0xE7, 0x83, 0x3C, 0x1D, 0xE0, 0x6F, 0x01, 0xF8, 0x0F, 0xC0, 0x3E, 0x01, 0xC0, +/* 'O' 0x4F */ 0x07, 0xF0, 0x0F, 0xFE, 0x0F, 0x07, 0x86, 0x00, 0xC6, 0x00, 0x33, 0x00, 0x1B, 0x00, 0x07, 0x80, 0x03, 0xC0, 0x01, 0xE0, 0x00, 0xF0, 0x00, 0x78, 0x00, 0x36, 0x00, 0x33, 0x00, 0x18, 0xC0, 0x18, 0x78, 0x3C, 0x1F, 0xFC, 0x03, 0xF8, 0x00, +/* 'P' 0x50 */ 0xFF, 0x8F, 0xFE, 0xC0, 0x6C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x06, 0xFF, 0xEF, 0xFC, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, +/* 'Q' 0x51 */ 0x07, 0xF0, 0x0F, 0xFE, 0x0F, 0x07, 0x86, 0x00, 0xC6, 0x00, 0x33, 0x00, 0x1B, 0x00, 0x07, 0x80, 0x03, 0xC0, 0x01, 0xE0, 0x00, 0xF0, 0x00, 0x78, 0x00, 0x36, 0x00, 0x33, 0x01, 0x98, 0xC0, 0xFC, 0x78, 0x3C, 0x1F, 0xFF, 0x03, 0xF9, 0x80, 0x00, 0x40, +/* 'R' 0x52 */ 0xFF, 0xE3, 0xFF, 0xCC, 0x03, 0xB0, 0x06, 0xC0, 0x1B, 0x00, 0x6C, 0x01, 0xB0, 0x0C, 0xFF, 0xE3, 0xFF, 0xCC, 0x03, 0xB0, 0x06, 0xC0, 0x1B, 0x00, 0x6C, 0x01, 0xB0, 0x06, 0xC0, 0x1B, 0x00, 0x70, +/* 'S' 0x53 */ 0x0F, 0xE0, 0x7F, 0xC3, 0x83, 0x98, 0x07, 0x60, 0x0D, 0x80, 0x07, 0x00, 0x1E, 0x00, 0x3F, 0x80, 0x3F, 0xC0, 0x0F, 0x80, 0x07, 0xC0, 0x0F, 0x00, 0x3E, 0x00, 0xDE, 0x0E, 0x3F, 0xF0, 0x3F, 0x80, +/* 'T' 0x54 */ 0xFF, 0xFF, 0xFF, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, +/* 'U' 0x55 */ 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x80, 0xEE, 0x0E, 0x3F, 0xE0, 0xFC, 0x00, +/* 'V' 0x56 */ 0xC0, 0x0F, 0x00, 0x7E, 0x01, 0x98, 0x06, 0x60, 0x39, 0xC0, 0xC3, 0x03, 0x0C, 0x1C, 0x38, 0x60, 0x61, 0x81, 0x8E, 0x07, 0x30, 0x0C, 0xC0, 0x37, 0x00, 0xF8, 0x01, 0xE0, 0x07, 0x80, 0x1C, 0x00, +/* 'W' 0x57 */ 0xE0, 0x30, 0x1D, 0x80, 0xE0, 0x76, 0x07, 0x81, 0xDC, 0x1E, 0x06, 0x70, 0x7C, 0x18, 0xC1, 0xB0, 0xE3, 0x0C, 0xC3, 0x8C, 0x33, 0x0C, 0x38, 0xC6, 0x30, 0x67, 0x18, 0xC1, 0x98, 0x67, 0x06, 0x61, 0xD8, 0x1D, 0x83, 0x60, 0x3C, 0x0D, 0x80, 0xF0, 0x3E, 0x03, 0xC0, 0x70, 0x0F, 0x01, 0xC0, 0x18, 0x07, 0x00, +/* 'X' 0x58 */ 0xE0, 0x1D, 0x80, 0xE7, 0x03, 0x0E, 0x1C, 0x18, 0x60, 0x73, 0x00, 0xFC, 0x01, 0xE0, 0x07, 0x00, 0x1E, 0x00, 0xF8, 0x03, 0x30, 0x1C, 0xE0, 0xE1, 0x83, 0x07, 0x1C, 0x0E, 0xE0, 0x1B, 0x00, 0x70, +/* 'Y' 0x59 */ 0xC0, 0x0F, 0x80, 0x76, 0x01, 0x9C, 0x0C, 0x38, 0x70, 0x61, 0x81, 0xCE, 0x03, 0x30, 0x0F, 0x80, 0x1E, 0x00, 0x30, 0x00, 0xC0, 0x03, 0x00, 0x0C, 0x00, 0x30, 0x00, 0xC0, 0x03, 0x00, 0x0C, 0x00, +/* 'Z' 0x5A */ 0xFF, 0xFF, 0xFF, 0xC0, 0x0E, 0x00, 0xE0, 0x0E, 0x00, 0x60, 0x07, 0x00, 0x70, 0x07, 0x00, 0x30, 0x03, 0x80, 0x38, 0x03, 0x80, 0x18, 0x01, 0xC0, 0x1C, 0x00, 0xFF, 0xFF, 0xFF, 0xC0, +/* '[' 0x5B */ 0xFF, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCF, 0xF0, +/* '\' 0x5C */ 0x81, 0x81, 0x02, 0x06, 0x04, 0x08, 0x18, 0x10, 0x20, 0x60, 0x40, 0x81, 0x81, 0x02, 0x06, 0x04, +/* ']' 0x5D */ 0xFF, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0xF0, +/* '^' 0x5E */ 0x0C, 0x0E, 0x05, 0x86, 0xC3, 0x21, 0x19, 0x8C, 0x83, 0xC1, 0x80, +/* '_' 0x5F */ 0xFF, 0xFE, +/* '`' 0x60 */ 0xE3, 0x8C, 0x30, +/* 'a' 0x61 */ 0x3F, 0x07, 0xF8, 0xE1, 0xCC, 0x0C, 0x00, 0xC0, 0x1C, 0x3F, 0xCF, 0x8C, 0xC0, 0xCC, 0x0C, 0xE3, 0xC7, 0xEF, 0x3C, 0x70, +/* 'b' 0x62 */ 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0xF8, 0xDF, 0xCF, 0x0E, 0xE0, 0x7C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xE0, 0x6F, 0x0E, 0xDF, 0xCC, 0xF8, +/* 'c' 0x63 */ 0x1F, 0x0F, 0xE6, 0x1F, 0x83, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x38, 0x37, 0x1C, 0xFE, 0x1F, 0x00, +/* 'd' 0x64 */ 0x00, 0x60, 0x0C, 0x01, 0x80, 0x30, 0x06, 0x3C, 0xCF, 0xFB, 0x8F, 0xE0, 0xF8, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF8, 0x3B, 0x8F, 0x3F, 0x63, 0xCC, +/* 'e' 0x65 */ 0x1F, 0x07, 0xF1, 0xC7, 0x70, 0x3C, 0x07, 0xFF, 0xFF, 0xFE, 0x00, 0xC0, 0x1C, 0x0D, 0xC3, 0x1F, 0xC1, 0xF0, +/* 'f' 0x66 */ 0x3B, 0xD8, 0xC6, 0x7F, 0xEC, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x00, +/* 'g' 0x67 */ 0x1E, 0x67, 0xFD, 0xC7, 0xF0, 0x7C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x7C, 0x1D, 0xC7, 0x9F, 0xB1, 0xE6, 0x00, 0xC0, 0x3E, 0x0E, 0x7F, 0xC7, 0xE0, +/* 'h' 0x68 */ 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x33, 0xCD, 0xFB, 0xC7, 0xE0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x30, +/* 'i' 0x69 */ 0xF0, 0x3F, 0xFF, 0xFF, 0xF0, +/* 'j' 0x6A */ 0x33, 0x00, 0x03, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0xE0, +/* 'k' 0x6B */ 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x6C, 0x33, 0x18, 0xCC, 0x37, 0x0F, 0xC3, 0xB8, 0xC6, 0x31, 0xCC, 0x3B, 0x06, 0xC1, 0xF0, 0x30, +/* 'l' 0x6C */ 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, +/* 'm' 0x6D */ 0xCF, 0x1F, 0x6F, 0xDF, 0xFC, 0x78, 0xFC, 0x18, 0x3C, 0x0C, 0x1E, 0x06, 0x0F, 0x03, 0x07, 0x81, 0x83, 0xC0, 0xC1, 0xE0, 0x60, 0xF0, 0x30, 0x78, 0x18, 0x3C, 0x0C, 0x18, +/* 'n' 0x6E */ 0xCF, 0x37, 0xEF, 0x1F, 0x83, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xC0, +/* 'o' 0x6F */ 0x1F, 0x07, 0xF1, 0xC7, 0x70, 0x7C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x7C, 0x1D, 0xC7, 0x1F, 0xC1, 0xF0, +/* 'p' 0x70 */ 0xCF, 0x8D, 0xFC, 0xF0, 0xEE, 0x06, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3E, 0x06, 0xF0, 0xEF, 0xFC, 0xCF, 0x8C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x00, +/* 'q' 0x71 */ 0x1E, 0x67, 0xFD, 0xC7, 0xF0, 0x7C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x7C, 0x1D, 0xC7, 0x9F, 0xF1, 0xE6, 0x00, 0xC0, 0x18, 0x03, 0x00, 0x60, +/* 'r' 0x72 */ 0xCF, 0x7F, 0x38, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC0, +/* 's' 0x73 */ 0x3E, 0x1F, 0xEE, 0x1B, 0x00, 0xC0, 0x3C, 0x07, 0xF0, 0x3F, 0x01, 0xF0, 0x3E, 0x1D, 0xFE, 0x3F, 0x00, +/* 't' 0x74 */ 0x63, 0x19, 0xFF, 0xB1, 0x8C, 0x63, 0x18, 0xC6, 0x31, 0xE7, +/* 'u' 0x75 */ 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x7E, 0x3D, 0xFB, 0x3C, 0xC0, +/* 'v' 0x76 */ 0xE0, 0x6C, 0x0D, 0x81, 0xB8, 0x63, 0x0C, 0x61, 0x8E, 0x60, 0xCC, 0x19, 0x83, 0xE0, 0x3C, 0x07, 0x00, 0xE0, +/* 'w' 0x77 */ 0xC1, 0xC1, 0xB0, 0xE1, 0xD8, 0x70, 0xCC, 0x2C, 0x66, 0x36, 0x31, 0x9B, 0x18, 0xCD, 0x98, 0x64, 0x6C, 0x16, 0x36, 0x0F, 0x1A, 0x07, 0x8F, 0x03, 0x83, 0x80, 0xC1, 0xC0, +/* 'x' 0x78 */ 0xC1, 0xF8, 0x66, 0x30, 0xCC, 0x3E, 0x07, 0x00, 0xC0, 0x78, 0x36, 0x0C, 0xC6, 0x3B, 0x06, 0xC0, 0xC0, +/* 'y' 0x79 */ 0xE0, 0x6C, 0x0D, 0x83, 0x38, 0x63, 0x0C, 0x63, 0x0C, 0x60, 0xCC, 0x1B, 0x03, 0x60, 0x3C, 0x07, 0x00, 0xE0, 0x18, 0x03, 0x00, 0xE0, 0x78, 0x0E, 0x00, +/* 'z' 0x7A */ 0xFF, 0xFF, 0xF0, 0x18, 0x0C, 0x07, 0x03, 0x81, 0xC0, 0x60, 0x30, 0x18, 0x0E, 0x03, 0xFF, 0xFF, 0xC0, +/* '{' 0x7B */ 0x19, 0xCC, 0x63, 0x18, 0xC6, 0x31, 0x99, 0x86, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x1C, 0x60, +/* '|' 0x7C */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, +/* '}' 0x7D */ 0xC7, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x0C, 0x33, 0x31, 0x8C, 0x63, 0x18, 0xC6, 0x73, 0x00, +/* '~' 0x7E */ 0x70, 0x3E, 0x09, 0xE4, 0x1F, 0x03, 0x80, +/* 0x7F */ +/* 0x80 */ 0xFF, 0xE0, 0xFF, 0xE0, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x07, 0xFC, 0x07, 0xFE, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x1E, 0x00, 0x1C, +/* 0x81 */ 0x07, 0x01, 0xC0, 0x20, 0x00, 0x0F, 0xFF, 0xFF, 0xF0, 0x06, 0x00, 0xC0, 0x18, 0x03, 0x00, 0x60, 0x0C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xC0, 0x18, 0x03, 0x00, 0x60, 0x0C, 0x01, 0x80, 0x00, +/* 0x82 */ 0xF5, 0x80, +/* 0x83 */ 0x0C, 0x38, 0x61, 0x80, 0x1F, 0xFF, 0xE0, 0xC1, 0x83, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x80, +/* 0x84 */ 0xCF, 0x34, 0x51, 0x88, +/* 0x85 */ 0xC6, 0x3C, 0x63, +/* 0x86 */ 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x3F, 0xFF, 0xFC, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x00, +/* 0x87 */ 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x3F, 0xFF, 0xFC, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x0F, 0xFF, 0xFF, 0x0C, 0x03, 0x00, 0xC0, 0x30, +/* 0x88 */ 0x01, 0xF0, 0x1F, 0xF0, 0xE0, 0xC7, 0x00, 0x18, 0x00, 0xC0, 0x07, 0xFF, 0x3F, 0xFC, 0x30, 0x01, 0xFF, 0x8F, 0xFC, 0x0C, 0x00, 0x18, 0x00, 0x70, 0x00, 0xE0, 0x81, 0xFE, 0x03, 0xF0, +/* 0x89 */ 0x38, 0x18, 0x00, 0xF8, 0x30, 0x03, 0x18, 0xC0, 0x04, 0x11, 0x80, 0x0C, 0x66, 0x00, 0x0F, 0x8C, 0x00, 0x0E, 0x30, 0x00, 0x00, 0x40, 0x00, 0x01, 0x80, 0x00, 0x06, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x31, 0xC0, 0xE0, 0x67, 0xC3, 0xC1, 0x98, 0xCC, 0xC3, 0x20, 0x90, 0x8C, 0x63, 0x33, 0x10, 0x7C, 0x3C, 0x60, 0x70, 0x38, +/* 0x8A */ 0x1F, 0xF8, 0x00, 0x3F, 0xF0, 0x00, 0x60, 0x60, 0x00, 0xC0, 0xC0, 0x01, 0x81, 0x80, 0x03, 0x03, 0x00, 0x06, 0x06, 0x00, 0x0C, 0x0C, 0x00, 0x18, 0x1F, 0xF0, 0x30, 0x3F, 0xF0, 0x60, 0x60, 0x30, 0xC0, 0xC0, 0x31, 0x81, 0x80, 0x66, 0x03, 0x00, 0xCC, 0x06, 0x01, 0xB8, 0x0C, 0x06, 0xE0, 0x1F, 0xFD, 0x80, 0x3F, 0xE0, +/* 0x8B */ 0x2F, 0x49, 0x99, +/* 0x8C */ 0xC0, 0x60, 0x06, 0x03, 0x00, 0x30, 0x18, 0x01, 0x80, 0xC0, 0x0C, 0x06, 0x00, 0x60, 0x30, 0x03, 0x01, 0x80, 0x18, 0x0C, 0x00, 0xFF, 0xFF, 0xC7, 0xFF, 0xFF, 0x30, 0x18, 0x1D, 0x80, 0xC0, 0x3C, 0x06, 0x01, 0xE0, 0x30, 0x0F, 0x01, 0x80, 0x78, 0x0C, 0x06, 0xC0, 0x7F, 0xF6, 0x03, 0xFE, 0x00, +/* 0x8D */ 0x03, 0x00, 0x60, 0x0C, 0x00, 0x00, 0xC0, 0x7C, 0x0E, 0xC1, 0xCC, 0x38, 0xC7, 0x0C, 0xE0, 0xDC, 0x0F, 0x80, 0xF0, 0x0F, 0x80, 0xDC, 0x0C, 0xE0, 0xC7, 0x0C, 0x30, 0xC3, 0x8C, 0x1C, 0xC0, 0xEC, 0x07, +/* 0x8E */ 0xFF, 0xE0, 0xFF, 0xE0, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x07, 0xFC, 0x07, 0xFE, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, +/* 0x8F */ 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0x06, 0x00, 0x30, 0x00, +/* 0x90 */ 0x30, 0x0F, 0xF0, 0xFF, 0x03, 0x00, 0x30, 0x03, 0x3C, 0x37, 0xE3, 0xC7, 0x38, 0x33, 0x03, 0x30, 0x33, 0x03, 0x30, 0x33, 0x03, 0x30, 0x33, 0x03, 0x30, 0x33, 0x03, 0x00, 0x60, 0x06, 0x01, 0x80, 0x30, +/* 0x91 */ 0x6A, 0xF0, +/* 0x92 */ 0xF5, 0x60, +/* 0x93 */ 0x4E, 0x28, 0xA2, 0xCF, 0x30, +/* 0x94 */ 0xCF, 0x34, 0x51, 0x4E, 0x20, +/* 0x95 */ 0x7B, 0xFF, 0xFF, 0xFD, 0xE0, +/* 0x96 */ 0xFF, 0xFF, 0xF0, +/* 0x97 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, +/* 0x98 */ +/* 0x99 */ 0xFF, 0x70, 0x1F, 0xFD, 0xC0, 0x71, 0x87, 0x83, 0xC6, 0x1E, 0x0F, 0x18, 0x68, 0x3C, 0x61, 0xB1, 0xB1, 0x86, 0xC6, 0xC6, 0x19, 0x1B, 0x18, 0x66, 0xCC, 0x61, 0x9B, 0x31, 0x86, 0x3C, 0xC6, 0x18, 0xE3, 0x18, 0x63, 0x8C, +/* 0x9A */ 0x7F, 0x80, 0x3F, 0xC0, 0x18, 0x60, 0x0C, 0x30, 0x06, 0x18, 0x03, 0x0F, 0xF1, 0x87, 0xFC, 0xC3, 0x07, 0x61, 0x81, 0xB0, 0xC0, 0xD0, 0x60, 0xF8, 0x3F, 0xEC, 0x1F, 0xE0, +/* 0x9B */ 0x99, 0x92, 0xF4, +/* 0x9C */ 0xC0, 0xC0, 0x30, 0x30, 0x0C, 0x0C, 0x03, 0x03, 0x00, 0xC0, 0xC0, 0x3F, 0xFF, 0xCF, 0xFF, 0xFB, 0x03, 0x07, 0xC0, 0xC0, 0xF0, 0x30, 0x3C, 0x0C, 0x1F, 0x03, 0xFE, 0xC0, 0xFF, 0x00, +/* 0x9D */ 0x07, 0x07, 0x03, 0x03, 0x00, 0x06, 0x0F, 0x0D, 0x8C, 0xCC, 0x6C, 0x3C, 0x1E, 0x0F, 0x86, 0xE3, 0x39, 0x8E, 0xC3, 0xE0, 0xC0, +/* 0x9E */ 0x30, 0x1F, 0xE3, 0xFC, 0x18, 0x03, 0x00, 0x67, 0x0D, 0xF9, 0xC7, 0x38, 0x66, 0x0C, 0xC1, 0x98, 0x33, 0x06, 0x60, 0xCC, 0x19, 0x83, 0x30, 0x66, 0x0C, +/* 0x9F */ 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0xFF, 0xFF, 0xC1, 0x80, 0x60, +/* 0xA0 */ +/* 0xA1 */ 0x10, 0x40, 0xC4, 0x07, 0xE0, 0x1E, 0x0C, 0x01, 0xF0, 0x1D, 0x80, 0xCE, 0x0E, 0x30, 0x61, 0xC7, 0x06, 0x30, 0x3B, 0x81, 0xD8, 0x07, 0xC0, 0x3C, 0x00, 0xE0, 0x06, 0x00, 0x70, 0x03, 0x80, 0x38, 0x01, 0xC0, 0x1C, 0x00, +/* 0xA2 */ 0x21, 0x86, 0x20, 0xFC, 0x07, 0x0E, 0x06, 0xC0, 0xD8, 0x33, 0x86, 0x30, 0xC6, 0x30, 0xC6, 0x0C, 0xC1, 0xB0, 0x36, 0x03, 0xC0, 0x70, 0x0E, 0x01, 0x80, 0x30, 0x0E, 0x07, 0x80, 0xE0, 0x00, +/* 0xA3 */ 0x01, 0x80, 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x80, 0xC0, 0x60, 0x3C, 0x1E, 0x0F, 0x07, 0xC7, 0x7F, 0x1F, 0x00, +/* 0xA4 */ 0xDD, 0xFF, 0xD8, 0xD8, 0x3C, 0x1E, 0x0F, 0x8D, 0xFF, 0xDD, 0x80, +/* 0xA5 */ 0x00, 0x60, 0x0F, 0xFF, 0xFF, 0xFC, 0x01, 0x80, 0x30, 0x06, 0x00, 0xC0, 0x18, 0x03, 0x00, 0x60, 0x0C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xC0, 0x18, 0x03, 0x00, 0x60, 0x00, +/* 0xA6 */ 0xFF, 0xFF, 0xF0, 0x3F, 0xFF, 0xFC, +/* 0xA7 */ 0x0F, 0x03, 0xF0, 0xE7, 0x18, 0x63, 0x0C, 0x70, 0x07, 0x03, 0xF8, 0xC3, 0x98, 0x3B, 0x03, 0xF0, 0x37, 0x06, 0x78, 0xC7, 0xB0, 0x7C, 0x03, 0x80, 0x39, 0x83, 0x30, 0x67, 0x1C, 0x7F, 0x07, 0xC0, +/* 0xA8 */ 0x19, 0x81, 0x98, 0x00, 0x0F, 0xFF, 0xFF, 0xFC, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0F, 0xFE, 0xFF, 0xEC, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0F, 0xFF, 0xFF, 0xF0, +/* 0xA9 */ 0x03, 0xF0, 0x03, 0xFF, 0x01, 0xE0, 0xE0, 0xE3, 0x1C, 0x73, 0xF3, 0x99, 0x86, 0x6C, 0xC1, 0x8F, 0x30, 0x03, 0xCC, 0x00, 0xF3, 0x00, 0x3C, 0xC1, 0x8D, 0x98, 0x66, 0x77, 0xF3, 0x8E, 0x79, 0xC1, 0xC0, 0xE0, 0x3F, 0xF0, 0x03, 0xF0, 0x00, +/* 0xAA */ 0x07, 0xE0, 0x3F, 0xF0, 0xF0, 0x71, 0x80, 0x76, 0x00, 0x6C, 0x00, 0x30, 0x00, 0x60, 0x00, 0xFF, 0xE1, 0xFF, 0xC3, 0x00, 0x06, 0x00, 0x0E, 0x00, 0x6C, 0x00, 0xDC, 0x03, 0x1C, 0x0E, 0x1F, 0xF8, 0x0F, 0xC0, +/* 0xAB */ 0x21, 0x63, 0xE7, 0x84, 0x84, 0xE7, 0x63, 0x21, +/* 0xAC */ 0xFF, 0xFF, 0xFF, 0x00, 0x30, 0x03, 0x00, 0x30, 0x03, +/* 0xAD */ 0xFF, 0xF0, +/* 0xAE */ 0x03, 0xF0, 0x03, 0xFF, 0x01, 0xE0, 0xE0, 0xFF, 0x1C, 0x7F, 0xF3, 0x9B, 0x04, 0x6C, 0xC1, 0x8F, 0x30, 0x43, 0xCF, 0xF0, 0xF3, 0xFC, 0x3C, 0xC1, 0x0D, 0xB0, 0x66, 0x7C, 0x1B, 0x8F, 0x07, 0xC1, 0xC0, 0xE0, 0x3F, 0xF0, 0x03, 0xF0, 0x00, +/* 0xAF */ 0xC7, 0x8C, 0x01, 0x83, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x83, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x83, 0x00, +/* 0xB0 */ 0x38, 0xFB, 0x1C, 0x18, 0x38, 0xDF, 0x1C, +/* 0xB1 */ 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x7F, 0xE7, 0xFE, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xF0, +/* 0xB2 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, +/* 0xB3 */ 0xF0, 0x3F, 0xFF, 0xFF, 0xF0, +/* 0xB4 */ 0x03, 0x03, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, +/* 0xB5 */ 0xC0, 0xCC, 0x0C, 0xC0, 0xCC, 0x0C, 0xC0, 0xCC, 0x0C, 0xC0, 0xCC, 0x0C, 0xC0, 0xCC, 0x1C, 0xE3, 0xCF, 0xEF, 0xFC, 0x7C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x00, +/* 0xB6 */ 0x1F, 0xE7, 0xFD, 0xF3, 0x7E, 0x6F, 0xCD, 0xF9, 0xBF, 0x37, 0xE6, 0x7C, 0xCF, 0x98, 0xF3, 0x06, 0x60, 0xCC, 0x19, 0x83, 0x30, 0x66, 0x0C, 0xC1, 0x98, 0x33, 0x06, 0x60, 0xCC, +/* 0xB7 */ 0xF0, +/* 0xB8 */ 0x19, 0x83, 0x30, 0x00, 0x00, 0x01, 0xF0, 0x7F, 0x1C, 0x77, 0x03, 0xC0, 0x7F, 0xFF, 0xFF, 0xE0, 0x0C, 0x01, 0xC0, 0xDC, 0x31, 0xFC, 0x1F, 0x00, +/* 0xB9 */ 0xC0, 0xC0, 0x18, 0x18, 0x03, 0x83, 0x00, 0x70, 0x60, 0x0B, 0x0C, 0x01, 0x61, 0x8F, 0xA6, 0x33, 0x1C, 0xC6, 0x41, 0x88, 0xC8, 0x31, 0x99, 0x06, 0x13, 0x20, 0xC3, 0x66, 0x38, 0x6C, 0xEF, 0x07, 0x8F, 0xA0, 0xF0, 0x04, 0x0E, 0x00, 0x81, 0xC7, 0xF0, 0x18, 0xFC, +/* 0xBA */ 0x1F, 0x87, 0xF9, 0xC3, 0x30, 0x3E, 0x01, 0xFE, 0x3F, 0xC6, 0x00, 0xE0, 0x0C, 0x0D, 0xC3, 0x9F, 0xE1, 0xF8, +/* 0xBB */ 0x88, 0xC6, 0xE7, 0x21, 0x21, 0xE7, 0xC6, 0x88, +/* 0xBC */ 0x33, 0x00, 0x03, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0xE0, +/* 0xBD */ 0x0F, 0xE0, 0x7F, 0xC3, 0x83, 0x98, 0x07, 0x60, 0x0D, 0x80, 0x07, 0x00, 0x1E, 0x00, 0x3F, 0x80, 0x3F, 0xC0, 0x0F, 0x80, 0x07, 0xC0, 0x0F, 0x00, 0x3E, 0x00, 0xDE, 0x0E, 0x3F, 0xF0, 0x3F, 0x80, +/* 0xBE */ 0x3E, 0x1F, 0xEE, 0x1B, 0x00, 0xC0, 0x3C, 0x07, 0xF0, 0x3F, 0x00, 0xF0, 0x3E, 0x1D, 0xFE, 0x3E, 0x00, +/* 0xBF */ 0xCF, 0x30, 0x00, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, +/* 0xC0 */ 0x07, 0x80, 0x1E, 0x00, 0x78, 0x03, 0xF0, 0x0C, 0xC0, 0x33, 0x01, 0xCE, 0x06, 0x18, 0x18, 0x60, 0xE1, 0xC3, 0x03, 0x0F, 0xFC, 0x7F, 0xF9, 0x80, 0x66, 0x01, 0xB8, 0x07, 0xC0, 0x0F, 0x00, 0x30, +/* 0xC1 */ 0xFF, 0xE7, 0xFF, 0x30, 0x01, 0x80, 0x0C, 0x00, 0x60, 0x03, 0x00, 0x1F, 0xF8, 0xFF, 0xF6, 0x01, 0xB0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x06, 0xFF, 0xF7, 0xFE, 0x00, +/* 0xC2 */ 0xFF, 0xC7, 0xFF, 0x30, 0x1D, 0x80, 0x6C, 0x03, 0x60, 0x1B, 0x00, 0xD8, 0x0C, 0xFF, 0xC7, 0xFF, 0x30, 0x0D, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x06, 0xFF, 0xF7, 0xFE, 0x00, +/* 0xC3 */ 0xFF, 0xFF, 0xFF, 0x00, 0x60, 0x0C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xC0, 0x18, 0x03, 0x00, 0x60, 0x0C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xC0, 0x18, 0x00, +/* 0xC4 */ 0x07, 0xFE, 0x01, 0xFF, 0x80, 0x60, 0x60, 0x18, 0x18, 0x06, 0x06, 0x01, 0x81, 0x80, 0x60, 0x60, 0x18, 0x18, 0x06, 0x06, 0x01, 0x81, 0x80, 0x60, 0x60, 0x18, 0x18, 0x0E, 0x06, 0x03, 0x01, 0x80, 0xC0, 0x60, 0x70, 0x18, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x0F, 0x00, 0x03, 0xC0, 0x00, 0xC0, +/* 0xC5 */ 0xFF, 0xFF, 0xFF, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xFF, 0xEF, 0xFE, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xFF, 0xFF, 0xFF, +/* 0xC6 */ 0x70, 0x60, 0xE3, 0x06, 0x0C, 0x38, 0x61, 0xC1, 0xC6, 0x38, 0x0E, 0x67, 0x00, 0x66, 0x60, 0x03, 0x6C, 0x00, 0x3F, 0xC0, 0x01, 0xF8, 0x00, 0x1F, 0x80, 0x03, 0xFC, 0x00, 0x76, 0xE0, 0x0E, 0x67, 0x01, 0xC6, 0x38, 0x38, 0x61, 0xC3, 0x06, 0x0C, 0x60, 0x60, 0xEE, 0x06, 0x07, +/* 0xC7 */ 0x0F, 0x81, 0xFF, 0x0C, 0x18, 0xC0, 0x66, 0x03, 0x00, 0x18, 0x01, 0xC0, 0x1C, 0x07, 0xC0, 0x3F, 0x00, 0x1C, 0x00, 0x7C, 0x01, 0xE0, 0x0F, 0x80, 0x6E, 0x0E, 0x3F, 0xE0, 0x7E, 0x00, +/* 0xC8 */ 0xC0, 0x3E, 0x01, 0xF0, 0x1F, 0x80, 0xFC, 0x0D, 0xE0, 0xEF, 0x06, 0x78, 0x73, 0xC3, 0x1E, 0x30, 0xF1, 0x87, 0x98, 0x3D, 0xC1, 0xEC, 0x0F, 0xC0, 0x7E, 0x03, 0xE0, 0x1F, 0x00, 0xC0, +/* 0xC9 */ 0x10, 0x40, 0xC4, 0x07, 0xE0, 0x1E, 0x0C, 0x03, 0xE0, 0x1F, 0x01, 0xF8, 0x0F, 0xC0, 0xDE, 0x0E, 0xF0, 0x67, 0x87, 0x3C, 0x31, 0xE3, 0x0F, 0x18, 0x79, 0x83, 0xDC, 0x1E, 0xC0, 0xFC, 0x07, 0xE0, 0x3E, 0x01, 0xF0, 0x0C, +/* 0xCA */ 0xC0, 0x7C, 0x0E, 0xC1, 0xCC, 0x38, 0xC7, 0x0C, 0xE0, 0xDC, 0x0F, 0x80, 0xF0, 0x0F, 0x80, 0xDC, 0x0C, 0xE0, 0xC7, 0x0C, 0x30, 0xC3, 0x8C, 0x1C, 0xC0, 0xEC, 0x07, +/* 0xCB */ 0x1F, 0xFC, 0x7F, 0xF1, 0x80, 0xC6, 0x03, 0x18, 0x0C, 0x60, 0x31, 0x80, 0xC6, 0x03, 0x18, 0x0C, 0x60, 0x31, 0x80, 0xC6, 0x03, 0x18, 0x0C, 0xC0, 0x33, 0x00, 0xDC, 0x03, 0xE0, 0x0F, 0x00, 0x30, +/* 0xCC */ 0xE0, 0x07, 0xE0, 0x07, 0xF0, 0x0F, 0xF0, 0x0F, 0xD0, 0x0F, 0xD8, 0x1B, 0xD8, 0x1B, 0xD8, 0x1B, 0xCC, 0x33, 0xCC, 0x33, 0xCC, 0x33, 0xC6, 0x63, 0xC6, 0x63, 0xC6, 0x63, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC1, 0x83, +/* 0xCD */ 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xFF, 0xFF, 0xFF, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xC0, +/* 0xCE */ 0x07, 0xF0, 0x0F, 0xFE, 0x0F, 0x07, 0x86, 0x00, 0xC6, 0x00, 0x33, 0x00, 0x1B, 0x00, 0x07, 0x80, 0x03, 0xC0, 0x01, 0xE0, 0x00, 0xF0, 0x00, 0x78, 0x00, 0x36, 0x00, 0x33, 0x00, 0x18, 0xC0, 0x18, 0x78, 0x3C, 0x1F, 0xFC, 0x03, 0xF8, 0x00, +/* 0xCF */ 0xFF, 0xFF, 0xFF, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xC0, +/* 0xD0 */ 0xFF, 0x8F, 0xFE, 0xC0, 0x6C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x06, 0xFF, 0xEF, 0xFC, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, +/* 0xD1 */ 0x07, 0xE0, 0x3F, 0xF0, 0xE0, 0x73, 0x80, 0x76, 0x00, 0x6C, 0x00, 0x30, 0x00, 0x60, 0x00, 0xC0, 0x01, 0x80, 0x03, 0x00, 0x06, 0x00, 0x0E, 0x00, 0x6C, 0x00, 0xDC, 0x03, 0x1E, 0x0E, 0x1F, 0xF8, 0x0F, 0xC0, +/* 0xD2 */ 0xFF, 0xFF, 0xFF, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, +/* 0xD3 */ 0xC0, 0x1F, 0x01, 0xD8, 0x0C, 0xE0, 0xE3, 0x06, 0x1C, 0x70, 0x63, 0x03, 0xB8, 0x1D, 0x80, 0x7C, 0x03, 0xC0, 0x0E, 0x00, 0x60, 0x07, 0x00, 0x38, 0x03, 0x80, 0x1C, 0x01, 0xC0, 0x00, +/* 0xD4 */ 0x00, 0xC0, 0x00, 0x30, 0x00, 0xFF, 0xC0, 0xFF, 0xFC, 0x78, 0xC7, 0x98, 0x30, 0x6E, 0x0C, 0x1F, 0x03, 0x03, 0xC0, 0xC0, 0xF0, 0x30, 0x3C, 0x0C, 0x0F, 0x83, 0x07, 0x60, 0xC1, 0x9E, 0x31, 0xE3, 0xFF, 0xF0, 0x3F, 0xF0, 0x00, 0xC0, 0x00, 0x30, 0x00, +/* 0xD5 */ 0xE0, 0x1D, 0x80, 0xE7, 0x03, 0x0E, 0x1C, 0x18, 0x60, 0x73, 0x00, 0xFC, 0x01, 0xE0, 0x07, 0x00, 0x1E, 0x00, 0xF8, 0x03, 0x30, 0x1C, 0xE0, 0xE1, 0x83, 0x07, 0x1C, 0x0E, 0xE0, 0x1B, 0x00, 0x70, +/* 0xD6 */ 0xC0, 0x19, 0x80, 0x33, 0x00, 0x66, 0x00, 0xCC, 0x01, 0x98, 0x03, 0x30, 0x06, 0x60, 0x0C, 0xC0, 0x19, 0x80, 0x33, 0x00, 0x66, 0x00, 0xCC, 0x01, 0x98, 0x03, 0x30, 0x06, 0x60, 0x0C, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x18, 0x00, 0x30, 0x00, 0x60, +/* 0xD7 */ 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x37, 0xFF, 0x3F, 0xF0, 0x03, 0x00, 0x30, 0x03, 0x00, 0x30, 0x03, 0x00, 0x30, 0x03, +/* 0xD8 */ 0xC1, 0x83, 0xC1, 0x83, 0xC1, 0x83, 0xC1, 0x83, 0xC1, 0x83, 0xC1, 0x83, 0xC1, 0x83, 0xC1, 0x83, 0xC1, 0x83, 0xC1, 0x83, 0xC1, 0x83, 0xC1, 0x83, 0xC1, 0x83, 0xC1, 0x83, 0xC1, 0x83, 0xC1, 0x83, 0xFF, 0xFF, 0xFF, 0xFF, +/* 0xD9 */ 0xC1, 0x83, 0x30, 0x60, 0xCC, 0x18, 0x33, 0x06, 0x0C, 0xC1, 0x83, 0x30, 0x60, 0xCC, 0x18, 0x33, 0x06, 0x0C, 0xC1, 0x83, 0x30, 0x60, 0xCC, 0x18, 0x33, 0x06, 0x0C, 0xC1, 0x83, 0x30, 0x60, 0xCC, 0x18, 0x33, 0x06, 0x0C, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x0C, 0x00, 0x03, 0x00, 0x00, 0xC0, +/* 0xDA */ 0xFE, 0x00, 0x3F, 0x80, 0x00, 0x60, 0x00, 0x18, 0x00, 0x06, 0x00, 0x01, 0x80, 0x00, 0x60, 0x00, 0x1F, 0xF8, 0x07, 0xFF, 0x01, 0x80, 0xE0, 0x60, 0x1C, 0x18, 0x03, 0x06, 0x00, 0xC1, 0x80, 0x30, 0x60, 0x1C, 0x18, 0x0E, 0x07, 0xFF, 0x01, 0xFF, 0x80, +/* 0xDB */ 0xC0, 0x01, 0xE0, 0x00, 0xF0, 0x00, 0x78, 0x00, 0x3C, 0x00, 0x1E, 0x00, 0x0F, 0x00, 0x07, 0xFF, 0x83, 0xFF, 0xE1, 0xE0, 0x38, 0xF0, 0x0E, 0x78, 0x03, 0x3C, 0x01, 0x9E, 0x00, 0xCF, 0x00, 0xE7, 0x80, 0xE3, 0xFF, 0xE1, 0xFF, 0xE0, 0xC0, +/* 0xDC */ 0xC0, 0x06, 0x00, 0x30, 0x01, 0x80, 0x0C, 0x00, 0x60, 0x03, 0x00, 0x1F, 0xF8, 0xFF, 0xE6, 0x03, 0xB0, 0x0F, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0xF8, 0x0E, 0xFF, 0xE7, 0xFE, 0x00, +/* 0xDD */ 0x0F, 0xC0, 0x7F, 0xE1, 0xC1, 0xE7, 0x01, 0xCC, 0x01, 0xC0, 0x01, 0x80, 0x03, 0x00, 0x07, 0x1F, 0xFE, 0x3F, 0xFC, 0x00, 0x38, 0x00, 0x7C, 0x00, 0xD8, 0x03, 0x98, 0x0E, 0x38, 0x3C, 0x3F, 0xF0, 0x1F, 0x80, +/* 0xDE */ 0xC0, 0x3F, 0x06, 0x07, 0xFE, 0x30, 0x70, 0x39, 0x87, 0x00, 0xEC, 0x30, 0x03, 0x61, 0x80, 0x1B, 0x18, 0x00, 0x78, 0xC0, 0x03, 0xFE, 0x00, 0x1F, 0xF0, 0x00, 0xF1, 0x80, 0x07, 0x8C, 0x00, 0x3C, 0x70, 0x03, 0xE1, 0x80, 0x1B, 0x0E, 0x01, 0xD8, 0x38, 0x1C, 0xC0, 0xFF, 0xC6, 0x01, 0xF8, 0x00, +/* 0xDF */ 0x0F, 0xFC, 0xFF, 0xF3, 0x00, 0xD8, 0x03, 0x60, 0x0D, 0x80, 0x36, 0x00, 0xCC, 0x03, 0x3F, 0xFC, 0x3F, 0xF0, 0x38, 0xC1, 0xC3, 0x0E, 0x0C, 0x70, 0x31, 0x80, 0xCE, 0x03, 0x70, 0x0F, 0x80, 0x30, +/* 0xE0 */ 0x3F, 0x07, 0xF8, 0xE1, 0xCC, 0x0C, 0x00, 0xC0, 0x1C, 0x3F, 0xCF, 0x8C, 0xC0, 0xCC, 0x0C, 0xE3, 0xC7, 0xEF, 0x3C, 0x70, +/* 0xE1 */ 0x00, 0xC0, 0x38, 0x3F, 0x1F, 0x87, 0x00, 0xC0, 0x17, 0xC7, 0xFC, 0xF1, 0xDC, 0x1F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1F, 0x07, 0x71, 0xC7, 0xF0, 0x7C, 0x00, +/* 0xE2 */ 0xFE, 0x3F, 0xEC, 0x3B, 0x06, 0xC1, 0xB0, 0xEF, 0xF3, 0x0E, 0xC0, 0xF0, 0x3C, 0x1F, 0xFE, 0xFF, 0x00, +/* 0xE3 */ 0xFF, 0xFF, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x83, 0x06, 0x0C, 0x00, +/* 0xE4 */ 0x0F, 0xF0, 0x3F, 0xC0, 0xC3, 0x03, 0x0C, 0x0C, 0x30, 0x30, 0xC0, 0xC3, 0x03, 0x0C, 0x1C, 0x30, 0x60, 0xC1, 0x83, 0x3F, 0xFF, 0xFF, 0xFF, 0x00, 0x3C, 0x00, 0xC0, +/* 0xE5 */ 0x1F, 0x07, 0xF1, 0xC7, 0x70, 0x3C, 0x07, 0xFF, 0xFF, 0xFE, 0x00, 0xC0, 0x1C, 0x0D, 0xC3, 0x1F, 0xC1, 0xF0, +/* 0xE6 */ 0xE1, 0x87, 0x71, 0x8E, 0x39, 0x9C, 0x1D, 0xB8, 0x0F, 0xF0, 0x07, 0xE0, 0x07, 0xE0, 0x0F, 0xF0, 0x1D, 0xB8, 0x39, 0x9C, 0x71, 0x8E, 0xE1, 0x87, 0xC1, 0x83, +/* 0xE7 */ 0x3E, 0x7F, 0xB0, 0xE0, 0x30, 0x18, 0x78, 0x3C, 0x07, 0x01, 0xE0, 0xF8, 0xEF, 0xE3, 0xE0, +/* 0xE8 */ 0xC0, 0xF8, 0x3F, 0x07, 0xE1, 0xFC, 0x37, 0x8C, 0xF3, 0x9E, 0x63, 0xD8, 0x7F, 0x0F, 0xC1, 0xF8, 0x3E, 0x06, +/* 0xE9 */ 0x21, 0x86, 0x20, 0xFC, 0x0F, 0x0C, 0x0F, 0x83, 0xF0, 0x7E, 0x1F, 0xC3, 0x78, 0xCF, 0x39, 0xE6, 0x3D, 0x87, 0xF0, 0xFC, 0x1F, 0x83, 0xE0, 0x60, +/* 0xEA */ 0xC1, 0xE1, 0xB1, 0x99, 0x8D, 0x87, 0x83, 0xC1, 0xF0, 0xDC, 0x67, 0x31, 0xD8, 0x7C, 0x18, +/* 0xEB */ 0x3F, 0xCF, 0xF3, 0x0C, 0xC3, 0x30, 0xCC, 0x33, 0x0C, 0xC3, 0x30, 0xDC, 0x36, 0x0F, 0x83, 0xC0, 0xC0, +/* 0xEC */ 0xE0, 0x7E, 0x07, 0xF0, 0xFF, 0x0F, 0xF0, 0xFD, 0x9B, 0xD9, 0xBD, 0xFB, 0xCF, 0x3C, 0xF3, 0xC6, 0x3C, 0x63, 0xC0, 0x30, +/* 0xED */ 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xFF, 0xFF, 0xFF, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xC0, +/* 0xEE */ 0x1F, 0x07, 0xF1, 0xC7, 0x70, 0x7C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x7C, 0x1D, 0xC7, 0x1F, 0xC1, 0xF0, +/* 0xEF */ 0xFF, 0xFF, 0xFC, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xC0, +/* 0xF0 */ 0xCF, 0x8D, 0xFC, 0xF0, 0xEE, 0x06, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3E, 0x06, 0xF0, 0xEF, 0xFC, 0xCF, 0x8C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x00, +/* 0xF1 */ 0x1F, 0x0F, 0xE6, 0x1F, 0x83, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x38, 0x37, 0x1C, 0xFE, 0x1F, 0x00, +/* 0xF2 */ 0xFF, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +/* 0xF3 */ 0xE0, 0x6C, 0x0D, 0x83, 0x38, 0x63, 0x0C, 0x63, 0x0C, 0x60, 0xCC, 0x1B, 0x03, 0x60, 0x3C, 0x07, 0x00, 0xE0, 0x18, 0x03, 0x00, 0xE0, 0x78, 0x0E, 0x00, +/* 0xF4 */ 0x00, 0xC0, 0x00, 0x18, 0x00, 0x03, 0x00, 0x0F, 0x67, 0x87, 0xFD, 0xF8, 0xC3, 0xE3, 0xB8, 0x78, 0x3E, 0x06, 0x03, 0xC0, 0xC0, 0x78, 0x18, 0x0F, 0x03, 0x01, 0xE0, 0x60, 0x3E, 0x1E, 0x0E, 0xC3, 0xE3, 0x9F, 0xFF, 0xE1, 0xF6, 0x78, 0x00, 0xC0, 0x00, 0x18, 0x00, 0x03, 0x00, 0x00, 0x60, 0x00, +/* 0xF5 */ 0xC1, 0xF8, 0x66, 0x30, 0xCC, 0x3E, 0x07, 0x00, 0xC0, 0x78, 0x36, 0x0C, 0xC6, 0x3B, 0x06, 0xC0, 0xC0, +/* 0xF6 */ 0xC0, 0xCC, 0x0C, 0xC0, 0xCC, 0x0C, 0xC0, 0xCC, 0x0C, 0xC0, 0xCC, 0x0C, 0xC0, 0xCC, 0x0C, 0xC0, 0xCF, 0xFF, 0xFF, 0xF0, 0x03, 0x00, 0x30, +/* 0xF7 */ 0xC1, 0xE0, 0xF0, 0x78, 0x3C, 0x1E, 0x0F, 0xFE, 0xFF, 0x01, 0x80, 0xC0, 0x60, 0x30, 0x18, +/* 0xF8 */ 0xC3, 0x0F, 0x0C, 0x3C, 0x30, 0xF0, 0xC3, 0xC3, 0x0F, 0x0C, 0x3C, 0x30, 0xF0, 0xC3, 0xC3, 0x0F, 0x0C, 0x3C, 0x30, 0xFF, 0xFF, 0xFF, 0xFC, +/* 0xF9 */ 0xC3, 0x0C, 0xC3, 0x0C, 0xC3, 0x0C, 0xC3, 0x0C, 0xC3, 0x0C, 0xC3, 0x0C, 0xC3, 0x0C, 0xC3, 0x0C, 0xC3, 0x0C, 0xC3, 0x0C, 0xC3, 0x0C, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x03, 0x00, 0x03, +/* 0xFA */ 0xFC, 0x03, 0xF0, 0x00, 0xC0, 0x03, 0x00, 0x0F, 0xF0, 0x3F, 0xE0, 0xC1, 0xC3, 0x03, 0x0C, 0x0C, 0x30, 0x30, 0xC1, 0xC3, 0xFE, 0x0F, 0xF0, +/* 0xFB */ 0xC0, 0x0F, 0x00, 0x3C, 0x00, 0xF0, 0x03, 0xFF, 0x0F, 0xFE, 0x3C, 0x1C, 0xF0, 0x33, 0xC0, 0xCF, 0x03, 0x3C, 0x1C, 0xFF, 0xE3, 0xFF, 0x0C, +/* 0xFC */ 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xFF, 0x3F, 0xEC, 0x1F, 0x03, 0xC0, 0xF0, 0x3C, 0x1F, 0xFE, 0xFF, 0x00, +/* 0xFD */ 0x3F, 0x0F, 0xF1, 0x87, 0x60, 0x60, 0x0E, 0x3F, 0xC7, 0xF8, 0x03, 0x00, 0xD8, 0x1B, 0x87, 0x3F, 0xC3, 0xF0, +/* 0xFE */ 0xC0, 0xF8, 0xC1, 0xFC, 0xC3, 0x8E, 0xC7, 0x07, 0xC6, 0x03, 0xFE, 0x03, 0xFE, 0x03, 0xC6, 0x03, 0xC6, 0x03, 0xC7, 0x06, 0xC3, 0x8E, 0xC1, 0xFC, 0xC0, 0xF8, +/* 0xFF */ 0x1F, 0xCF, 0xF7, 0x0D, 0x83, 0x60, 0xD8, 0x33, 0xFC, 0x7F, 0x0C, 0xC6, 0x33, 0x0D, 0x83, 0xC0, 0xC0, +}; + +const GFXglyph FreeSans12pt_Win1251Glyphs[] PROGMEM = { +/* 0x01 */ { 0, 19, 20, 21, 1, -17 }, +/* 0x02 */ { 48, 19, 20, 21, 1, -17 }, +/* 0x03 */ { 96, 21, 20, 23, 1, -17 }, +/* 0x04 */ { 149, 21, 20, 23, 1, -17 }, +/* 0x05 */ { 202, 20, 20, 22, 1, -17 }, +/* 0x06 */ { 252, 20, 20, 22, 1, -17 }, +/* 0x07 */ { 302, 0, 0, 8, 0, 0 }, +/* 0x08 */ { 302, 23, 20, 25, 1, -17 }, +/* 0x09 */ { 360, 23, 16, 25, 1, -16 }, +/* 0x0A */ { 406, 0, 0, 8, 0, 0 }, +/* 0x0B */ { 406, 21, 20, 23, 1, -17 }, +/* 0x0C */ { 459, 19, 18, 21, 1, -15 }, +/* 0x0D */ { 502, 0, 0, 8, 0, 0 }, +/* 0x0E */ { 502, 20, 20, 22, 1, -17 }, +/* 0x0F */ { 552, 21, 21, 23, 1, -18 }, +/* 0x10 */ { 608, 19, 20, 21, 1, -17 }, +/* 0x11 */ { 656, 21, 20, 23, 1, -17 }, +/* 0x12 */ { 709, 20, 20, 22, 1, -17 }, +/* 0x13 */ { 759, 21, 20, 23, 1, -17 }, +/* 0x14 */ { 812, 21, 20, 23, 1, -17 }, +/* 0x15 */ { 865, 22, 20, 24, 1, -17 }, +/* 0x16 */ { 920, 16, 20, 18, 1, -17 }, +/* 0x17 */ { 960, 21, 20, 23, 1, -17 }, +/* 0x18 */ { 1013, 23, 20, 25, 1, -17 }, +/* 0x19 */ { 1071, 21, 20, 23, 1, -17 }, +/* 0x1A */ { 1124, 15, 19, 17, 1, -16 }, +/* 0x1B */ { 1160, 24, 21, 26, 1, -18 }, +/* 0x1C */ { 1223, 21, 20, 23, 1, -17 }, +/* 0x1D */ { 1276, 21, 21, 23, 1, -18 }, +/* 0x1E */ { 1332, 20, 20, 22, 1, -17 }, +/* 0x1F */ { 1382, 15, 20, 17, 1, -17 }, +/* ' ' 0x20 */ { 1420, 0, 0, 6, 0, 0 }, +/* '!' 0x21 */ { 1420, 2, 18, 8, 3, -16 }, +/* '"' 0x22 */ { 1425, 6, 6, 8, 1, -15 }, +/* '#' 0x23 */ { 1430, 13, 16, 13, 0, -14 }, +/* '$' 0x24 */ { 1456, 11, 20, 13, 1, -16 }, +/* '%' 0x25 */ { 1484, 20, 17, 21, 1, -15 }, +/* '&' 0x26 */ { 1527, 14, 17, 16, 1, -15 }, +/* ''' 0x27 */ { 1557, 2, 6, 5, 1, -15 }, +/* '(' 0x28 */ { 1559, 5, 23, 8, 2, -16 }, +/* ')' 0x29 */ { 1574, 5, 23, 8, 1, -16 }, +/* '*' 0x2A */ { 1589, 7, 7, 9, 1, -16 }, +/* '+' 0x2B */ { 1596, 10, 11, 14, 2, -9 }, +/* ',' 0x2C */ { 1610, 2, 6, 7, 2, 0 }, +/* '-' 0x2D */ { 1612, 6, 2, 8, 1, -6 }, +/* '.' 0x2E */ { 1614, 2, 2, 6, 2, 0 }, +/* '/' 0x2F */ { 1615, 7, 18, 7, 0, -16 }, +/* '0' 0x30 */ { 1631, 11, 17, 13, 1, -15 }, +/* '1' 0x31 */ { 1655, 5, 17, 13, 3, -15 }, +/* '2' 0x32 */ { 1666, 11, 17, 13, 1, -15 }, +/* '3' 0x33 */ { 1690, 11, 17, 13, 1, -15 }, +/* '4' 0x34 */ { 1714, 11, 17, 13, 1, -15 }, +/* '5' 0x35 */ { 1738, 11, 17, 13, 1, -15 }, +/* '6' 0x36 */ { 1762, 11, 17, 13, 1, -15 }, +/* '7' 0x37 */ { 1786, 11, 17, 13, 1, -15 }, +/* '8' 0x38 */ { 1810, 11, 17, 13, 1, -15 }, +/* '9' 0x39 */ { 1834, 11, 17, 13, 1, -15 }, +/* ':' 0x3A */ { 1858, 2, 13, 6, 2, -11 }, +/* ';' 0x3B */ { 1862, 2, 16, 6, 2, -10 }, +/* '<' 0x3C */ { 1866, 12, 11, 14, 1, -9 }, +/* '=' 0x3D */ { 1883, 12, 6, 14, 1, -7 }, +/* '>' 0x3E */ { 1892, 12, 11, 14, 1, -9 }, +/* '?' 0x3F */ { 1909, 10, 18, 13, 2, -16 }, +/* '@' 0x40 */ { 1932, 22, 21, 24, 1, -16 }, +/* 'A' 0x41 */ { 1990, 14, 18, 16, 1, -16 }, +/* 'B' 0x42 */ { 2022, 13, 18, 16, 2, -16 }, +/* 'C' 0x43 */ { 2052, 15, 18, 17, 1, -16 }, +/* 'D' 0x44 */ { 2086, 14, 18, 17, 2, -16 }, +/* 'E' 0x45 */ { 2118, 12, 18, 15, 2, -16 }, +/* 'F' 0x46 */ { 2145, 11, 18, 14, 2, -16 }, +/* 'G' 0x47 */ { 2170, 16, 18, 18, 1, -16 }, +/* 'H' 0x48 */ { 2206, 13, 18, 17, 2, -16 }, +/* 'I' 0x49 */ { 2236, 2, 18, 7, 2, -16 }, +/* 'J' 0x4A */ { 2241, 9, 18, 13, 1, -16 }, +/* 'K' 0x4B */ { 2262, 13, 18, 16, 2, -16 }, +/* 'L' 0x4C */ { 2292, 10, 18, 14, 2, -16 }, +/* 'M' 0x4D */ { 2315, 16, 18, 20, 2, -16 }, +/* 'N' 0x4E */ { 2351, 13, 18, 18, 2, -16 }, +/* 'O' 0x4F */ { 2381, 17, 18, 19, 1, -16 }, +/* 'P' 0x50 */ { 2420, 12, 18, 16, 2, -16 }, +/* 'Q' 0x51 */ { 2447, 17, 19, 19, 1, -16 }, +/* 'R' 0x52 */ { 2488, 14, 18, 17, 2, -16 }, +/* 'S' 0x53 */ { 2520, 14, 18, 16, 1, -16 }, +/* 'T' 0x54 */ { 2552, 12, 18, 15, 1, -16 }, +/* 'U' 0x55 */ { 2579, 13, 18, 17, 2, -16 }, +/* 'V' 0x56 */ { 2609, 14, 18, 15, 1, -16 }, +/* 'W' 0x57 */ { 2641, 22, 18, 22, 0, -16 }, +/* 'X' 0x58 */ { 2691, 14, 18, 16, 1, -16 }, +/* 'Y' 0x59 */ { 2723, 14, 18, 16, 1, -16 }, +/* 'Z' 0x5A */ { 2755, 13, 18, 15, 1, -16 }, +/* '[' 0x5B */ { 2785, 4, 23, 7, 2, -16 }, +/* '\' 0x5C */ { 2797, 7, 18, 7, 0, -16 }, +/* ']' 0x5D */ { 2813, 4, 23, 7, 1, -16 }, +/* '^' 0x5E */ { 2825, 9, 9, 11, 1, -15 }, +/* '_' 0x5F */ { 2836, 15, 1, 13, -1, 5 }, +/* '`' 0x60 */ { 2838, 5, 4, 6, 1, -16 }, +/* 'a' 0x61 */ { 2841, 12, 13, 13, 1, -11 }, +/* 'b' 0x62 */ { 2861, 12, 18, 13, 1, -16 }, +/* 'c' 0x63 */ { 2888, 10, 13, 12, 1, -11 }, +/* 'd' 0x64 */ { 2905, 11, 18, 13, 1, -16 }, +/* 'e' 0x65 */ { 2930, 11, 13, 13, 1, -11 }, +/* 'f' 0x66 */ { 2948, 5, 18, 7, 1, -16 }, +/* 'g' 0x67 */ { 2960, 11, 18, 13, 1, -11 }, +/* 'h' 0x68 */ { 2985, 10, 18, 13, 1, -16 }, +/* 'i' 0x69 */ { 3008, 2, 18, 5, 2, -16 }, +/* 'j' 0x6A */ { 3013, 4, 23, 6, 0, -16 }, +/* 'k' 0x6B */ { 3025, 10, 18, 12, 1, -16 }, +/* 'l' 0x6C */ { 3048, 2, 18, 5, 1, -16 }, +/* 'm' 0x6D */ { 3053, 17, 13, 19, 1, -11 }, +/* 'n' 0x6E */ { 3081, 10, 13, 13, 1, -11 }, +/* 'o' 0x6F */ { 3098, 11, 13, 13, 1, -11 }, +/* 'p' 0x70 */ { 3116, 12, 17, 13, 1, -11 }, +/* 'q' 0x71 */ { 3142, 11, 17, 13, 1, -11 }, +/* 'r' 0x72 */ { 3166, 6, 13, 8, 1, -11 }, +/* 's' 0x73 */ { 3176, 10, 13, 12, 1, -11 }, +/* 't' 0x74 */ { 3193, 5, 16, 7, 1, -14 }, +/* 'u' 0x75 */ { 3203, 10, 13, 13, 1, -11 }, +/* 'v' 0x76 */ { 3220, 11, 13, 12, 0, -11 }, +/* 'w' 0x77 */ { 3238, 17, 13, 17, 0, -11 }, +/* 'x' 0x78 */ { 3266, 10, 13, 11, 1, -11 }, +/* 'y' 0x79 */ { 3283, 11, 18, 11, 0, -11 }, +/* 'z' 0x7A */ { 3308, 10, 13, 12, 1, -11 }, +/* '{' 0x7B */ { 3325, 5, 23, 8, 1, -16 }, +/* '|' 0x7C */ { 3340, 2, 23, 6, 2, -16 }, +/* '}' 0x7D */ { 3346, 5, 23, 8, 2, -16 }, +/* '~' 0x7E */ { 3361, 10, 5, 12, 1, -9 }, +/* 0x7F */ { 3368, 0, 0, 0, 0, 0 }, +/* 0x80 */ { 3368, 16, 22, 18, 1, -18 }, +/* 0x81 */ { 3412, 11, 22, 14, 2, -22 }, +/* 0x82 */ { 3443, 2, 5, 6, 2, -2 }, +/* 0x83 */ { 3445, 7, 18, 9, 1, -18 }, +/* 0x84 */ { 3461, 6, 5, 10, 2, -2 }, +/* 0x85 */ { 3465, 12, 2, 16, 2, -2 }, +/* 0x86 */ { 3468, 10, 21, 13, 2, -17 }, +/* 0x87 */ { 3495, 10, 20, 13, 2, -17 }, +/* 0x88 */ { 3520, 14, 17, 16, 1, -17 }, +/* 0x89 */ { 3550, 23, 18, 24, 0, -18 }, +/* 0x8A */ { 3602, 23, 18, 24, 0, -18 }, +/* 0x8B */ { 3654, 3, 8, 6, 1, -11 }, +/* 0x8C */ { 3657, 21, 18, 24, 2, -18 }, +/* 0x8D */ { 3705, 12, 22, 15, 2, -22 }, +/* 0x8E */ { 3738, 16, 18, 18, 1, -18 }, +/* 0x8F */ { 3774, 13, 21, 17, 2, -18 }, +/* 0x90 */ { 3809, 12, 22, 14, 0, -18 }, +/* 0x91 */ { 3842, 2, 6, 6, 2, -18 }, +/* 0x92 */ { 3844, 2, 6, 6, 2, -18 }, +/* 0x93 */ { 3846, 6, 6, 10, 2, -18 }, +/* 0x94 */ { 3851, 6, 6, 10, 2, -18 }, +/* 0x95 */ { 3856, 6, 6, 10, 2, -11 }, +/* 0x96 */ { 3861, 10, 2, 12, 1, -8 }, +/* 0x97 */ { 3864, 22, 2, 24, 1, -8 }, +/* 0x98 */ { 3870, 0, 0, 8, 0, 0 }, +/* 0x99 */ { 3870, 22, 13, 24, 2, -18 }, +/* 0x9A */ { 3906, 17, 13, 19, 1, -13 }, +/* 0x9B */ { 3934, 3, 8, 6, 2, -10 }, +/* 0x9C */ { 3937, 18, 13, 20, 1, -13 }, +/* 0x9D */ { 3967, 9, 18, 12, 1, -18 }, +/* 0x9E */ { 3988, 11, 18, 14, 1, -18 }, +/* 0x9F */ { 4013, 10, 15, 13, 1, -13 }, +/* 0xA0 */ { 4032, 0, 0, 7, 0, 0 }, +/* 0xA1 */ { 4032, 13, 22, 15, 1, -22 }, +/* 0xA2 */ { 4068, 11, 22, 11, 0, -17 }, +/* 0xA3 */ { 4099, 9, 18, 13, 1, -18 }, +/* 0xA4 */ { 4120, 9, 9, 13, 2, -13 }, +/* 0xA5 */ { 4131, 11, 20, 14, 2, -20 }, +/* 0xA6 */ { 4159, 2, 23, 6, 2, -18 }, +/* 0xA7 */ { 4165, 11, 23, 13, 1, -18 }, +/* 0xA8 */ { 4197, 12, 21, 15, 2, -21 }, +/* 0xA9 */ { 4229, 18, 17, 19, 1, -17 }, +/* 0xAA */ { 4268, 15, 18, 17, 1, -18 }, +/* 0xAB */ { 4302, 8, 8, 12, 2, -11 }, +/* 0xAC */ { 4310, 12, 6, 14, 1, -9 }, +/* 0xAD */ { 4319, 6, 2, 8, 1, -8 }, +/* 0xAE */ { 4321, 18, 17, 19, 1, -17 }, +/* 0xAF */ { 4360, 7, 21, 7, 0, -21 }, +/* 0xB0 */ { 4379, 7, 8, 15, 4, -17 }, +/* 0xB1 */ { 4386, 12, 15, 14, 1, -15 }, +/* 0xB2 */ { 4409, 2, 18, 7, 2, -18 }, +/* 0xB3 */ { 4414, 2, 18, 5, 2, -18 }, +/* 0xB4 */ { 4419, 8, 15, 9, 1, -15 }, +/* 0xB5 */ { 4434, 12, 17, 13, 2, -13 }, +/* 0xB6 */ { 4460, 11, 21, 13, 2, -18 }, +/* 0xB7 */ { 4489, 2, 2, 6, 2, -8 }, +/* 0xB8 */ { 4490, 11, 17, 13, 1, -17 }, +/* 0xB9 */ { 4514, 19, 18, 22, 2, -18 }, +/* 0xBA */ { 4557, 11, 13, 12, 0, -13 }, +/* 0xBB */ { 4575, 8, 8, 12, 2, -10 }, +/* 0xBC */ { 4583, 4, 23, 6, 0, -18 }, +/* 0xBD */ { 4595, 14, 18, 16, 1, -18 }, +/* 0xBE */ { 4627, 10, 13, 12, 1, -13 }, +/* 0xBF */ { 4644, 6, 17, 6, 0, -17 }, +/* 0xC0 */ { 4657, 14, 18, 16, 1, -18 }, +/* 0xC1 */ { 4689, 13, 18, 16, 2, -18 }, +/* 0xC2 */ { 4719, 13, 18, 16, 2, -18 }, +/* 0xC3 */ { 4749, 11, 18, 14, 2, -18 }, +/* 0xC4 */ { 4774, 18, 21, 19, 1, -18 }, +/* 0xC5 */ { 4822, 12, 18, 15, 2, -18 }, +/* 0xC6 */ { 4849, 20, 18, 22, 1, -18 }, +/* 0xC7 */ { 4894, 13, 18, 16, 1, -18 }, +/* 0xC8 */ { 4924, 13, 18, 18, 2, -18 }, +/* 0xC9 */ { 4954, 13, 22, 18, 2, -22 }, +/* 0xCA */ { 4990, 12, 18, 15, 2, -18 }, +/* 0xCB */ { 5017, 14, 18, 16, 0, -18 }, +/* 0xCC */ { 5049, 16, 18, 20, 2, -18 }, +/* 0xCD */ { 5085, 13, 18, 17, 2, -18 }, +/* 0xCE */ { 5115, 17, 18, 19, 1, -18 }, +/* 0xCF */ { 5154, 13, 18, 17, 2, -18 }, +/* 0xD0 */ { 5184, 12, 18, 16, 2, -18 }, +/* 0xD1 */ { 5211, 15, 18, 17, 1, -18 }, +/* 0xD2 */ { 5245, 12, 18, 15, 1, -18 }, +/* 0xD3 */ { 5272, 13, 18, 15, 1, -18 }, +/* 0xD4 */ { 5302, 18, 18, 20, 1, -18 }, +/* 0xD5 */ { 5343, 14, 18, 16, 1, -18 }, +/* 0xD6 */ { 5375, 15, 21, 18, 2, -18 }, +/* 0xD7 */ { 5415, 12, 18, 15, 1, -18 }, +/* 0xD8 */ { 5442, 16, 18, 20, 2, -18 }, +/* 0xD9 */ { 5478, 18, 21, 20, 2, -18 }, +/* 0xDA */ { 5526, 18, 18, 20, 1, -18 }, +/* 0xDB */ { 5567, 17, 18, 21, 2, -18 }, +/* 0xDC */ { 5606, 13, 18, 16, 2, -18 }, +/* 0xDD */ { 5636, 15, 18, 17, 1, -18 }, +/* 0xDE */ { 5670, 21, 18, 24, 2, -18 }, +/* 0xDF */ { 5718, 14, 18, 16, 0, -18 }, +/* 0xE0 */ { 5750, 12, 13, 13, 1, -13 }, +/* 0xE1 */ { 5770, 11, 19, 13, 1, -19 }, +/* 0xE2 */ { 5797, 10, 13, 12, 1, -13 }, +/* 0xE3 */ { 5814, 7, 13, 9, 1, -13 }, +/* 0xE4 */ { 5826, 14, 15, 14, 0, -13 }, +/* 0xE5 */ { 5853, 11, 13, 13, 1, -13 }, +/* 0xE6 */ { 5871, 16, 13, 18, 1, -13 }, +/* 0xE7 */ { 5897, 9, 13, 12, 1, -13 }, +/* 0xE8 */ { 5912, 11, 13, 13, 1, -13 }, +/* 0xE9 */ { 5930, 11, 17, 13, 1, -17 }, +/* 0xEA */ { 5954, 9, 13, 12, 1, -13 }, +/* 0xEB */ { 5969, 10, 13, 12, 0, -13 }, +/* 0xEC */ { 5986, 12, 13, 14, 1, -13 }, +/* 0xED */ { 6006, 10, 13, 13, 1, -13 }, +/* 0xEE */ { 6023, 11, 13, 13, 1, -13 }, +/* 0xEF */ { 6041, 10, 13, 13, 1, -13 }, +/* 0xF0 */ { 6058, 12, 17, 13, 1, -13 }, +/* 0xF1 */ { 6084, 10, 13, 12, 1, -13 }, +/* 0xF2 */ { 6101, 8, 13, 10, 1, -13 }, +/* 0xF3 */ { 6114, 11, 18, 11, 0, -13 }, +/* 0xF4 */ { 6139, 19, 20, 20, 1, -16 }, +/* 0xF5 */ { 6187, 10, 13, 11, 1, -13 }, +/* 0xF6 */ { 6204, 12, 15, 13, 1, -13 }, +/* 0xF7 */ { 6227, 9, 13, 12, 1, -13 }, +/* 0xF8 */ { 6242, 14, 13, 16, 1, -13 }, +/* 0xF9 */ { 6265, 16, 15, 17, 1, -13 }, +/* 0xFA */ { 6295, 14, 13, 15, 1, -13 }, +/* 0xFB */ { 6318, 14, 13, 16, 1, -13 }, +/* 0xFC */ { 6341, 10, 13, 12, 1, -13 }, +/* 0xFD */ { 6358, 11, 13, 12, 1, -13 }, +/* 0xFE */ { 6376, 16, 13, 18, 1, -13 }, +/* 0xFF */ { 6402, 10, 13, 13, 1, -13 }, +}; + +const GFXfont FreeSans12pt_Win1251 PROGMEM = { +(uint8_t*)FreeSans12pt_Win1251Bitmaps, +(GFXglyph*)FreeSans12pt_Win1251Glyphs, +0x01, 0xFF, 19 +}; diff --git a/src/graphics/niche/Fonts/FreeSans12pt_Win1252.h b/src/graphics/niche/Fonts/FreeSans12pt_Win1252.h new file mode 100644 index 000000000..752925d6d --- /dev/null +++ b/src/graphics/niche/Fonts/FreeSans12pt_Win1252.h @@ -0,0 +1,527 @@ +// trunk-ignore-all(clang-format) +#pragma once +/* PROPERTIES + +FONT_NAME FreeSans12pt_Win1252 +*/ +const uint8_t FreeSans12pt_Win1252Bitmaps[] PROGMEM = { +/* 0x01 */ 0x00, 0x30, 0x00, 0x09, 0x00, 0x01, 0x20, 0x00, 0x24, 0x00, 0x04, 0x80, 0x01, 0x90, 0x00, 0x62, 0x00, 0x30, 0xFE, 0x04, 0x10, 0x5F, 0x02, 0x0B, 0x00, 0x7F, 0xE0, 0x0C, 0x1C, 0x02, 0x83, 0x81, 0x9F, 0xF0, 0x02, 0x1E, 0x00, 0x41, 0xC0, 0x0E, 0x7F, 0x81, 0x78, 0x18, 0x62, 0x00, 0xFF, 0xC0, +/* 0x02 */ 0x00, 0xFF, 0x80, 0x61, 0x13, 0xF0, 0x62, 0x60, 0x07, 0xFC, 0x00, 0x83, 0x80, 0x10, 0xF0, 0x33, 0xF6, 0x01, 0x41, 0xC0, 0x18, 0x38, 0x03, 0xFF, 0xE0, 0x47, 0x02, 0x08, 0x20, 0x61, 0xC4, 0x06, 0x17, 0x00, 0x22, 0x00, 0x02, 0x40, 0x00, 0x48, 0x00, 0x09, 0x00, 0x01, 0x20, 0x00, 0x3C, 0x00, +/* 0x03 */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x00, 0x02, 0x30, 0x00, 0x09, 0x04, 0x08, 0x48, 0x70, 0xE1, 0xC3, 0x87, 0x0E, 0x08, 0x10, 0x70, 0x00, 0x03, 0x80, 0x00, 0x14, 0x00, 0x00, 0xA1, 0x81, 0x8D, 0x87, 0xF0, 0x44, 0x00, 0x06, 0x30, 0x00, 0x60, 0xC0, 0x06, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00, +/* 0x04 */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x00, 0x02, 0x30, 0x00, 0x09, 0x10, 0x02, 0x48, 0xE0, 0x61, 0xC1, 0xCC, 0x0E, 0x78, 0x1C, 0x70, 0x00, 0x03, 0x80, 0x00, 0x14, 0xFF, 0xFC, 0xA6, 0x00, 0xCD, 0x9F, 0xFE, 0x44, 0x71, 0xE6, 0x30, 0xFC, 0x60, 0xC0, 0x06, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00, +/* 0x05 */ 0x00, 0x18, 0x00, 0x00, 0x40, 0x01, 0x90, 0x01, 0xF4, 0x08, 0x12, 0x23, 0xC1, 0x91, 0x2C, 0x1C, 0x8A, 0xC3, 0x64, 0x64, 0x13, 0x22, 0x41, 0x98, 0x26, 0x2C, 0xC4, 0x22, 0x60, 0x42, 0x13, 0x04, 0x30, 0x80, 0x61, 0xA4, 0x02, 0x18, 0x20, 0x03, 0x41, 0x00, 0x20, 0x08, 0x02, 0x00, 0x60, 0x40, 0x03, 0xF8, +/* 0x06 */ 0x00, 0x10, 0x00, 0x03, 0x00, 0x1C, 0x48, 0x00, 0xB4, 0x80, 0x09, 0xF9, 0xC0, 0xE0, 0xE4, 0x0C, 0x02, 0x8F, 0x80, 0x38, 0x88, 0x01, 0x0D, 0x00, 0x18, 0x30, 0x01, 0x60, 0x80, 0x13, 0x18, 0x03, 0xF2, 0xC0, 0x20, 0x26, 0x06, 0x07, 0xFF, 0xA0, 0x02, 0x39, 0x00, 0x14, 0x70, 0x01, 0xC3, 0x00, 0x18, 0x00, +/* 0x07 */ +/* 0x08 */ 0x00, 0x1F, 0x80, 0x00, 0x60, 0x80, 0x01, 0x00, 0x80, 0x06, 0x00, 0x80, 0x3C, 0x01, 0x01, 0x8C, 0x02, 0x02, 0x08, 0x04, 0x04, 0x08, 0x0C, 0x38, 0x00, 0x04, 0x80, 0x00, 0x06, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x2E, 0xC0, 0x01, 0x83, 0x7E, 0x0C, 0x10, 0x37, 0xE2, 0x61, 0x00, 0x0C, 0xC6, 0x10, 0x98, 0x0C, 0x63, 0x00, 0x00, 0xC6, 0x00, +/* 0x09 */ 0x00, 0x1F, 0x80, 0x00, 0x60, 0x80, 0x01, 0x00, 0x80, 0x06, 0x00, 0x80, 0x3C, 0x01, 0x01, 0x8C, 0x02, 0x02, 0x08, 0x04, 0x04, 0x08, 0x0C, 0x38, 0x00, 0x04, 0x80, 0x00, 0x06, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x2E, 0xC0, 0x01, 0x83, 0x7E, 0x0C, 0x00, 0x37, 0xE0, +/* 0x0A */ +/* 0x0B */ 0x1F, 0x07, 0xC1, 0x86, 0x41, 0x10, 0x0C, 0x04, 0x80, 0x40, 0x18, 0x00, 0x00, 0xC0, 0x00, 0x06, 0x00, 0x00, 0x30, 0x00, 0x01, 0x40, 0x00, 0x0A, 0x00, 0x00, 0x88, 0x00, 0x04, 0x40, 0x00, 0x41, 0x00, 0x02, 0x04, 0x00, 0x20, 0x20, 0x02, 0x00, 0x80, 0x20, 0x02, 0x02, 0x00, 0x08, 0x20, 0x00, 0x22, 0x00, 0x00, 0xE0, 0x00, +/* 0x0C */ 0x01, 0x00, 0x00, 0x38, 0x00, 0x04, 0xC0, 0x01, 0x08, 0x00, 0x18, 0x80, 0x1C, 0x10, 0x02, 0x07, 0x80, 0x81, 0x10, 0x1F, 0xC2, 0x02, 0x00, 0x60, 0x80, 0x1A, 0x20, 0x1C, 0x42, 0x1C, 0x08, 0xFE, 0x03, 0xA0, 0x01, 0x8C, 0x01, 0xC1, 0x43, 0xD0, 0x27, 0x81, 0xF8, +/* 0x0D */ +/* 0x0E */ 0x00, 0xE0, 0x00, 0x11, 0x00, 0x01, 0x10, 0x00, 0x0B, 0x00, 0x03, 0xF8, 0x00, 0x60, 0x60, 0x09, 0x02, 0x00, 0xA0, 0x10, 0x16, 0x01, 0x01, 0x40, 0x10, 0x10, 0x01, 0x01, 0x00, 0x08, 0x10, 0x00, 0x82, 0x1F, 0x08, 0x3F, 0x90, 0x44, 0x00, 0x06, 0xBF, 0xFF, 0xAF, 0xF0, 0xFF, 0xFF, 0x0F, 0xE3, 0xFB, 0xFC, +/* 0x0F */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x40, 0x12, 0x34, 0x00, 0x69, 0x40, 0x01, 0x49, 0xE0, 0xF1, 0xCD, 0x06, 0x8E, 0x28, 0x14, 0x71, 0x40, 0xA3, 0x8B, 0xFD, 0x14, 0x50, 0x68, 0xA2, 0x81, 0x4D, 0x97, 0xFA, 0x44, 0xBF, 0xD6, 0x31, 0x02, 0xE0, 0xC8, 0x16, 0x08, 0x61, 0x08, 0x21, 0xF0, 0x80, 0xF8, 0x78, 0x00, +/* 0x10 */ 0x00, 0xF0, 0x00, 0x3A, 0x00, 0x07, 0xC0, 0x00, 0xA8, 0x00, 0x1F, 0x00, 0x02, 0xB0, 0x00, 0x52, 0x00, 0x0A, 0x40, 0x02, 0x48, 0x00, 0x49, 0x00, 0x09, 0x30, 0x01, 0x22, 0x01, 0xC4, 0x70, 0xF0, 0x85, 0xE1, 0x10, 0x88, 0x37, 0x20, 0x03, 0x9C, 0x00, 0x37, 0x00, 0x06, 0x40, 0x01, 0x86, 0x00, +/* 0x11 */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x60, 0x02, 0x36, 0x00, 0x09, 0x04, 0x0C, 0x48, 0x60, 0xC1, 0xC3, 0x0F, 0x0E, 0x00, 0x08, 0x70, 0x00, 0x23, 0x80, 0x63, 0x84, 0x01, 0x9F, 0x20, 0x0C, 0xFD, 0x80, 0x27, 0xE4, 0x03, 0x3F, 0x30, 0x33, 0xE0, 0xC0, 0x00, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00, +/* 0x12 */ 0x00, 0xC2, 0x00, 0x1C, 0x24, 0x02, 0x18, 0x60, 0x64, 0x02, 0x02, 0x40, 0x20, 0x00, 0xF2, 0x03, 0x89, 0xE0, 0x7C, 0x80, 0x0E, 0x25, 0x80, 0xE1, 0x00, 0x1A, 0x08, 0x71, 0xB0, 0xC4, 0x39, 0x84, 0xC2, 0xCC, 0x40, 0x76, 0x7C, 0x05, 0xBB, 0x80, 0x4C, 0xE0, 0x0A, 0x78, 0x00, 0x9C, 0x00, 0x0F, 0x00, 0x00, +/* 0x13 */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x00, 0x02, 0x30, 0x00, 0x09, 0x00, 0x00, 0x48, 0x60, 0xC1, 0xC6, 0xC9, 0x0E, 0x00, 0x00, 0x70, 0x00, 0x03, 0x80, 0x00, 0x14, 0xFF, 0xF8, 0xA6, 0x00, 0xCD, 0x9F, 0xFE, 0x44, 0x71, 0xE6, 0x30, 0xFC, 0x60, 0xC0, 0x06, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00, +/* 0x14 */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x20, 0x22, 0x33, 0x01, 0x89, 0x20, 0x02, 0x48, 0x60, 0xE1, 0xC8, 0x80, 0x8E, 0x46, 0x46, 0x72, 0x32, 0x33, 0x9F, 0x9F, 0x94, 0x78, 0x78, 0xA0, 0x00, 0x0D, 0x80, 0x00, 0x44, 0x0E, 0x06, 0x30, 0x00, 0x60, 0xC0, 0x06, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00, +/* 0x15 */ 0x03, 0xFC, 0x20, 0x38, 0x1C, 0x81, 0x80, 0x1D, 0x08, 0x00, 0x32, 0x60, 0x00, 0x89, 0x00, 0x02, 0x18, 0x00, 0x08, 0x61, 0xC3, 0x22, 0x8D, 0x93, 0x72, 0x00, 0x00, 0x48, 0x00, 0x01, 0x20, 0x00, 0x04, 0x9F, 0xFF, 0x92, 0x60, 0x0E, 0x44, 0xFF, 0xF2, 0x11, 0xC3, 0x88, 0x21, 0xF8, 0x40, 0x40, 0x02, 0x00, 0xC0, 0x30, 0x00, 0xFF, 0x00, +/* 0x16 */ 0x03, 0x80, 0x03, 0xC0, 0x01, 0xE0, 0x01, 0xE0, 0x03, 0xF0, 0x03, 0xF0, 0x27, 0xF0, 0x6F, 0x70, 0x6E, 0x60, 0xFC, 0x60, 0xFC, 0x7E, 0xFC, 0x7E, 0xFC, 0x3F, 0xF4, 0x1F, 0xF4, 0x1F, 0xF0, 0x0E, 0x70, 0x0E, 0x30, 0x1C, 0x38, 0x38, 0x0F, 0xF0, +/* 0x17 */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x00, 0x02, 0x30, 0x00, 0x09, 0x00, 0x00, 0x48, 0x00, 0x21, 0xC0, 0x02, 0x8E, 0x20, 0xF4, 0x70, 0x84, 0x11, 0x82, 0x40, 0x84, 0x01, 0x03, 0x20, 0x0F, 0x85, 0x80, 0x03, 0x04, 0x00, 0x04, 0x30, 0x78, 0x10, 0xC0, 0x06, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00, +/* 0x18 */ 0x00, 0xFC, 0x00, 0x02, 0x06, 0x00, 0x08, 0x24, 0x00, 0x21, 0xA4, 0x00, 0x4C, 0x48, 0x00, 0xA0, 0x50, 0x01, 0x92, 0x60, 0x03, 0x24, 0xC0, 0x06, 0x01, 0x81, 0x28, 0x03, 0x49, 0x6C, 0xC4, 0xAD, 0xD8, 0x16, 0xA4, 0xCC, 0xC4, 0x44, 0x86, 0x13, 0x05, 0x00, 0x28, 0x0A, 0x00, 0x50, 0x14, 0x00, 0x90, 0x48, 0x01, 0x20, 0x90, 0x02, 0x41, 0x20, 0x00, 0x00, +/* 0x19 */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x00, 0x02, 0x30, 0x00, 0x09, 0x00, 0x00, 0x49, 0xC3, 0x81, 0xC0, 0x00, 0x0E, 0x78, 0xF0, 0x77, 0xEF, 0xC3, 0xA7, 0x4E, 0x15, 0x0A, 0x10, 0xA7, 0x8F, 0x0D, 0x80, 0x00, 0x44, 0x00, 0x06, 0x33, 0xF0, 0x60, 0xC0, 0x06, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00, +/* 0x1A */ 0xFF, 0xFF, 0x00, 0x06, 0x00, 0x0C, 0x3E, 0x18, 0x82, 0x32, 0x02, 0x64, 0x04, 0xC8, 0x09, 0x80, 0x23, 0x00, 0x86, 0x02, 0x0C, 0x08, 0x18, 0x10, 0x30, 0x00, 0x60, 0x00, 0xC0, 0x81, 0x80, 0x03, 0x00, 0x07, 0xFF, 0xF8, +/* 0x1B */ 0x00, 0xFE, 0x00, 0x03, 0x81, 0x80, 0x04, 0x00, 0x60, 0x08, 0x00, 0x30, 0x10, 0x00, 0x10, 0x30, 0x07, 0x88, 0x23, 0xC8, 0x08, 0x22, 0x00, 0x04, 0x60, 0x00, 0x44, 0x60, 0x00, 0x84, 0x63, 0x03, 0x04, 0x61, 0xFC, 0x04, 0x6B, 0x00, 0x9E, 0xA5, 0x01, 0x6A, 0xD5, 0x01, 0x43, 0xA8, 0x81, 0x05, 0xD0, 0x82, 0x0A, 0xA0, 0x82, 0x05, 0xC0, 0x82, 0x02, 0x61, 0xFF, 0x0C, 0x1E, 0x00, 0xF0, +/* 0x1C */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x30, 0x02, 0x32, 0x00, 0x09, 0x00, 0x00, 0x48, 0x20, 0x61, 0xC3, 0x84, 0x0E, 0x1C, 0x78, 0x70, 0x40, 0x03, 0x80, 0x00, 0x14, 0x00, 0x00, 0xA0, 0x03, 0x0D, 0x83, 0xF0, 0x44, 0x00, 0x06, 0x30, 0x00, 0x60, 0xC0, 0x06, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00, +/* 0x1D */ 0x01, 0xFE, 0x00, 0x3A, 0x1C, 0x03, 0x00, 0x30, 0x23, 0x1E, 0xC3, 0x38, 0x03, 0x10, 0xC3, 0x09, 0x00, 0x18, 0x68, 0x00, 0xC1, 0x40, 0x00, 0x0A, 0x07, 0x80, 0x50, 0x46, 0x02, 0x80, 0x00, 0x1A, 0x1E, 0x00, 0xCB, 0x10, 0x0D, 0x03, 0x00, 0x48, 0x60, 0x06, 0x40, 0x00, 0x22, 0x0C, 0x02, 0x10, 0x60, 0x60, 0x43, 0xFC, 0x01, 0xE0, 0x00, 0x00, +/* 0x1E */ 0x01, 0xF0, 0x00, 0xEA, 0xC0, 0x31, 0x5F, 0x04, 0x5F, 0x88, 0x80, 0xA0, 0x48, 0x0E, 0x02, 0x8F, 0x40, 0x3C, 0x10, 0x21, 0x66, 0x87, 0x15, 0x98, 0x71, 0x41, 0x02, 0x14, 0x00, 0x01, 0x40, 0x00, 0x14, 0x00, 0x01, 0x21, 0xFE, 0x12, 0x00, 0x02, 0x10, 0x00, 0x60, 0x80, 0x0C, 0x06, 0x01, 0x80, 0x3F, 0xE0, +/* 0x1F */ 0x0E, 0x00, 0x13, 0x00, 0x23, 0x00, 0xF3, 0x01, 0x31, 0x01, 0x11, 0x03, 0xD3, 0x06, 0xF2, 0x30, 0x34, 0xC7, 0x25, 0x33, 0x2B, 0xC2, 0x57, 0x04, 0x3A, 0x08, 0x72, 0x30, 0xA3, 0xC3, 0x40, 0x04, 0x40, 0x18, 0x40, 0x60, 0x7F, 0x80, +/* ' ' 0x20 */ +/* '!' 0x21 */ 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, +/* '"' 0x22 */ 0xCF, 0x3C, 0xF3, 0x8A, 0x20, +/* '#' 0x23 */ 0x06, 0x30, 0x31, 0x03, 0x18, 0x18, 0xC7, 0xFF, 0xBF, 0xFC, 0x31, 0x01, 0x18, 0x18, 0xC7, 0xFF, 0xBF, 0xFC, 0x31, 0x01, 0x18, 0x18, 0xC0, 0xC6, 0x06, 0x30, +/* '$' 0x24 */ 0x04, 0x03, 0xE1, 0xFF, 0x72, 0x7C, 0x47, 0x88, 0xF1, 0x07, 0xA0, 0x7E, 0x03, 0xF0, 0x17, 0x02, 0x7C, 0x47, 0x88, 0xF1, 0x1B, 0x26, 0x7F, 0xC3, 0xE0, 0x10, 0x02, 0x00, +/* '%' 0x25 */ 0x00, 0x06, 0x03, 0xC0, 0x40, 0x7E, 0x0C, 0x0E, 0x70, 0x80, 0xC3, 0x18, 0x0C, 0x31, 0x00, 0xE7, 0x30, 0x07, 0xE6, 0x00, 0x3C, 0x40, 0x00, 0x0C, 0x7C, 0x00, 0x8F, 0xE0, 0x19, 0xC7, 0x01, 0x18, 0x30, 0x31, 0x83, 0x02, 0x1C, 0x70, 0x40, 0xFE, 0x04, 0x07, 0xC0, +/* '&' 0x26 */ 0x0F, 0x00, 0x7E, 0x03, 0x9C, 0x0C, 0x30, 0x30, 0xC0, 0xE7, 0x01, 0xF8, 0x03, 0x80, 0x3E, 0x01, 0xCC, 0x6E, 0x39, 0xB0, 0x7C, 0xC0, 0xF3, 0x03, 0xCE, 0x1F, 0x9F, 0xE6, 0x3E, 0x1C, +/* ''' 0x27 */ 0xFF, 0xA0, +/* '(' 0x28 */ 0x08, 0x8C, 0x46, 0x31, 0x98, 0xC6, 0x31, 0x8C, 0x63, 0x08, 0x63, 0x08, 0x61, 0x0C, 0x20, +/* ')' 0x29 */ 0x82, 0x18, 0xC3, 0x18, 0xC3, 0x18, 0xC6, 0x31, 0x8C, 0x62, 0x31, 0x88, 0xC4, 0x62, 0x00, +/* '*' 0x2A */ 0x10, 0x23, 0x5B, 0xE3, 0x8D, 0x91, 0x00, +/* '+' 0x2B */ 0x0C, 0x03, 0x00, 0xC0, 0x30, 0xFF, 0xFF, 0xF0, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, +/* ',' 0x2C */ 0xF5, 0x60, +/* '-' 0x2D */ 0xFF, 0xF0, +/* '.' 0x2E */ 0xF0, +/* '/' 0x2F */ 0x02, 0x0C, 0x10, 0x20, 0xC1, 0x02, 0x0C, 0x10, 0x20, 0xC1, 0x02, 0x0C, 0x10, 0x20, 0xC1, 0x00, +/* '0' 0x30 */ 0x1F, 0x07, 0xF1, 0xC7, 0x30, 0x6C, 0x0F, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3E, 0x0E, 0xC1, 0x9C, 0x71, 0xFC, 0x1F, 0x00, +/* '1' 0x31 */ 0x08, 0xCF, 0xFF, 0x8C, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x18, +/* '2' 0x32 */ 0x1F, 0x0F, 0xF9, 0x87, 0x60, 0x7C, 0x06, 0x00, 0xC0, 0x18, 0x07, 0x01, 0xC0, 0xF0, 0x78, 0x1C, 0x06, 0x00, 0xC0, 0x30, 0x07, 0xFF, 0xFF, 0xE0, +/* '3' 0x33 */ 0x3F, 0x0F, 0xF3, 0x87, 0x60, 0x6C, 0x0C, 0x01, 0x80, 0x60, 0x78, 0x0F, 0x80, 0x18, 0x01, 0x80, 0x3C, 0x07, 0x80, 0xD8, 0x73, 0xFC, 0x3F, 0x00, +/* '4' 0x34 */ 0x01, 0x80, 0x70, 0x0E, 0x03, 0xC0, 0xD8, 0x1B, 0x06, 0x61, 0x8C, 0x21, 0x8C, 0x33, 0x06, 0x7F, 0xFF, 0xFE, 0x03, 0x00, 0x60, 0x0C, 0x01, 0x80, +/* '5' 0x35 */ 0x3F, 0xCF, 0xF9, 0x80, 0x30, 0x06, 0x00, 0xDE, 0x1F, 0xE7, 0x0E, 0x00, 0xE0, 0x0C, 0x01, 0x80, 0x30, 0x07, 0x81, 0xB8, 0x73, 0xFC, 0x1F, 0x00, +/* '6' 0x36 */ 0x0F, 0x07, 0xF9, 0xC3, 0x30, 0x74, 0x01, 0x80, 0x33, 0xC7, 0xFE, 0xF1, 0xDC, 0x1F, 0x01, 0xE0, 0x3C, 0x06, 0xC1, 0xDC, 0x71, 0xFC, 0x1F, 0x00, +/* '7' 0x37 */ 0xFF, 0xFF, 0xFC, 0x01, 0x00, 0x60, 0x18, 0x02, 0x00, 0xC0, 0x30, 0x06, 0x01, 0x80, 0x30, 0x04, 0x01, 0x80, 0x30, 0x06, 0x01, 0x80, 0x30, 0x00, +/* '8' 0x38 */ 0x1F, 0x07, 0xF1, 0xC7, 0x30, 0x66, 0x0C, 0xC1, 0x8C, 0x61, 0xF8, 0x3F, 0x8E, 0x3B, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xD8, 0x31, 0xFC, 0x1F, 0x00, +/* '9' 0x39 */ 0x1F, 0x07, 0xF1, 0xC7, 0x70, 0x6C, 0x07, 0x80, 0xF0, 0x1E, 0x07, 0x61, 0xEF, 0xFC, 0x79, 0x80, 0x30, 0x05, 0xC1, 0x98, 0x73, 0xFC, 0x1E, 0x00, +/* ':' 0x3A */ 0xF0, 0x00, 0x03, 0xC0, +/* ';' 0x3B */ 0xF0, 0x00, 0x0F, 0x56, +/* '<' 0x3C */ 0x00, 0x70, 0x1E, 0x0F, 0x83, 0xC0, 0xF0, 0x0E, 0x00, 0x7C, 0x00, 0xF0, 0x03, 0xC0, 0x0F, 0x00, 0x10, +/* '=' 0x3D */ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, +/* '>' 0x3E */ 0xE0, 0x07, 0x80, 0x1F, 0x00, 0x7C, 0x00, 0xF0, 0x07, 0x01, 0xE0, 0xF0, 0x3C, 0x0F, 0x00, 0x80, 0x00, +/* '?' 0x3F */ 0x3F, 0x1F, 0xEE, 0x1F, 0x03, 0xC0, 0xC0, 0x30, 0x0C, 0x06, 0x03, 0x81, 0xC0, 0xE0, 0x30, 0x0C, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x03, 0x00, +/* '@' 0x40 */ 0x00, 0xFE, 0x00, 0x0F, 0xFE, 0x00, 0xF0, 0x3E, 0x07, 0x00, 0x3C, 0x38, 0x00, 0x38, 0xC1, 0xE0, 0x66, 0x0F, 0xD9, 0xD8, 0x61, 0xC3, 0xC3, 0x07, 0x0F, 0x1C, 0x1C, 0x3C, 0x60, 0x60, 0xF1, 0x81, 0x83, 0xC6, 0x06, 0x1B, 0x18, 0x38, 0xEE, 0x71, 0xE7, 0x18, 0xFD, 0xF8, 0x71, 0xE7, 0xC0, 0xE0, 0x00, 0x01, 0xE0, 0x00, 0x01, 0xFF, 0xC0, 0x01, 0xFC, 0x00, +/* 'A' 0x41 */ 0x07, 0x80, 0x1E, 0x00, 0x78, 0x03, 0xF0, 0x0C, 0xC0, 0x33, 0x01, 0xCE, 0x06, 0x18, 0x18, 0x60, 0xE1, 0xC3, 0x03, 0x0F, 0xFC, 0x7F, 0xF9, 0x80, 0x66, 0x01, 0xB8, 0x07, 0xC0, 0x0F, 0x00, 0x30, +/* 'B' 0x42 */ 0xFF, 0xC7, 0xFF, 0x30, 0x1D, 0x80, 0x6C, 0x03, 0x60, 0x1B, 0x00, 0xD8, 0x0C, 0xFF, 0xC7, 0xFF, 0x30, 0x0D, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x06, 0xFF, 0xF7, 0xFE, 0x00, +/* 'C' 0x43 */ 0x07, 0xE0, 0x3F, 0xF0, 0xE0, 0x73, 0x80, 0x76, 0x00, 0x6C, 0x00, 0x30, 0x00, 0x60, 0x00, 0xC0, 0x01, 0x80, 0x03, 0x00, 0x06, 0x00, 0x0E, 0x00, 0x6C, 0x00, 0xDC, 0x03, 0x1E, 0x0E, 0x1F, 0xF8, 0x0F, 0xC0, +/* 'D' 0x44 */ 0xFF, 0xC3, 0xFF, 0x8C, 0x07, 0x30, 0x0E, 0xC0, 0x1B, 0x00, 0x7C, 0x00, 0xF0, 0x03, 0xC0, 0x0F, 0x00, 0x3C, 0x00, 0xF0, 0x03, 0xC0, 0x1F, 0x00, 0x6C, 0x03, 0xB0, 0x1C, 0xFF, 0xE3, 0xFE, 0x00, +/* 'E' 0x45 */ 0xFF, 0xFF, 0xFF, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xFF, 0xEF, 0xFE, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xFF, 0xFF, 0xFF, +/* 'F' 0x46 */ 0xFF, 0xFF, 0xFF, 0x00, 0x60, 0x0C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xFF, 0xDF, 0xFB, 0x00, 0x60, 0x0C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xC0, 0x18, 0x00, +/* 'G' 0x47 */ 0x07, 0xF0, 0x1F, 0xFC, 0x3C, 0x1E, 0x70, 0x07, 0x60, 0x03, 0xE0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x7F, 0xC0, 0x7F, 0xC0, 0x03, 0xC0, 0x03, 0x60, 0x03, 0x60, 0x07, 0x30, 0x0F, 0x3C, 0x1F, 0x1F, 0xFB, 0x07, 0xE1, +/* 'H' 0x48 */ 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xFF, 0xFF, 0xFF, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xC0, +/* 'I' 0x49 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, +/* 'J' 0x4A */ 0x01, 0x80, 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x80, 0xC0, 0x60, 0x3C, 0x1E, 0x0F, 0x07, 0xC7, 0x7F, 0x1F, 0x00, +/* 'K' 0x4B */ 0xC0, 0x3E, 0x03, 0xB0, 0x39, 0x83, 0x8C, 0x38, 0x63, 0x83, 0x38, 0x19, 0xC0, 0xDE, 0x07, 0xB8, 0x38, 0xE1, 0x83, 0x0C, 0x1C, 0x60, 0x73, 0x01, 0x98, 0x0E, 0xC0, 0x3E, 0x00, 0xC0, +/* 'L' 0x4C */ 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xFF, 0xFF, 0xF0, +/* 'M' 0x4D */ 0xE0, 0x07, 0xE0, 0x07, 0xF0, 0x0F, 0xF0, 0x0F, 0xD0, 0x0F, 0xD8, 0x1B, 0xD8, 0x1B, 0xD8, 0x1B, 0xCC, 0x33, 0xCC, 0x33, 0xCC, 0x33, 0xC6, 0x63, 0xC6, 0x63, 0xC6, 0x63, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC1, 0x83, +/* 'N' 0x4E */ 0xE0, 0x1F, 0x00, 0xFC, 0x07, 0xE0, 0x3D, 0x81, 0xEE, 0x0F, 0x30, 0x79, 0xC3, 0xC6, 0x1E, 0x18, 0xF0, 0xE7, 0x83, 0x3C, 0x1D, 0xE0, 0x6F, 0x01, 0xF8, 0x0F, 0xC0, 0x3E, 0x01, 0xC0, +/* 'O' 0x4F */ 0x07, 0xF0, 0x0F, 0xFE, 0x0F, 0x07, 0x86, 0x00, 0xC6, 0x00, 0x33, 0x00, 0x1B, 0x00, 0x07, 0x80, 0x03, 0xC0, 0x01, 0xE0, 0x00, 0xF0, 0x00, 0x78, 0x00, 0x36, 0x00, 0x33, 0x00, 0x18, 0xC0, 0x18, 0x78, 0x3C, 0x1F, 0xFC, 0x03, 0xF8, 0x00, +/* 'P' 0x50 */ 0xFF, 0x8F, 0xFE, 0xC0, 0x6C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x06, 0xFF, 0xEF, 0xFC, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, +/* 'Q' 0x51 */ 0x07, 0xF0, 0x0F, 0xFE, 0x0F, 0x07, 0x86, 0x00, 0xC6, 0x00, 0x33, 0x00, 0x1B, 0x00, 0x07, 0x80, 0x03, 0xC0, 0x01, 0xE0, 0x00, 0xF0, 0x00, 0x78, 0x00, 0x36, 0x00, 0x33, 0x01, 0x98, 0xC0, 0xFC, 0x78, 0x3C, 0x1F, 0xFF, 0x03, 0xF9, 0x80, 0x00, 0x40, +/* 'R' 0x52 */ 0xFF, 0xE3, 0xFF, 0xCC, 0x03, 0xB0, 0x06, 0xC0, 0x1B, 0x00, 0x6C, 0x01, 0xB0, 0x0C, 0xFF, 0xE3, 0xFF, 0xCC, 0x03, 0xB0, 0x06, 0xC0, 0x1B, 0x00, 0x6C, 0x01, 0xB0, 0x06, 0xC0, 0x1B, 0x00, 0x70, +/* 'S' 0x53 */ 0x0F, 0xE0, 0x7F, 0xC3, 0x83, 0x98, 0x07, 0x60, 0x0D, 0x80, 0x07, 0x00, 0x1E, 0x00, 0x3F, 0x80, 0x3F, 0xC0, 0x0F, 0x80, 0x07, 0xC0, 0x0F, 0x00, 0x3E, 0x00, 0xDE, 0x0E, 0x3F, 0xF0, 0x3F, 0x80, +/* 'T' 0x54 */ 0xFF, 0xFF, 0xFF, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, +/* 'U' 0x55 */ 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x80, 0xEE, 0x0E, 0x3F, 0xE0, 0xFC, 0x00, +/* 'V' 0x56 */ 0xC0, 0x0F, 0x00, 0x7E, 0x01, 0x98, 0x06, 0x60, 0x39, 0xC0, 0xC3, 0x03, 0x0C, 0x1C, 0x38, 0x60, 0x61, 0x81, 0x8E, 0x07, 0x30, 0x0C, 0xC0, 0x37, 0x00, 0xF8, 0x01, 0xE0, 0x07, 0x80, 0x1C, 0x00, +/* 'W' 0x57 */ 0xE0, 0x30, 0x1D, 0x80, 0xE0, 0x76, 0x07, 0x81, 0xDC, 0x1E, 0x06, 0x70, 0x7C, 0x18, 0xC1, 0xB0, 0xE3, 0x0C, 0xC3, 0x8C, 0x33, 0x0C, 0x38, 0xC6, 0x30, 0x67, 0x18, 0xC1, 0x98, 0x67, 0x06, 0x61, 0xD8, 0x1D, 0x83, 0x60, 0x3C, 0x0D, 0x80, 0xF0, 0x3E, 0x03, 0xC0, 0x70, 0x0F, 0x01, 0xC0, 0x18, 0x07, 0x00, +/* 'X' 0x58 */ 0xE0, 0x1D, 0x80, 0xE7, 0x03, 0x0E, 0x1C, 0x18, 0x60, 0x73, 0x00, 0xFC, 0x01, 0xE0, 0x07, 0x00, 0x1E, 0x00, 0xF8, 0x03, 0x30, 0x1C, 0xE0, 0xE1, 0x83, 0x07, 0x1C, 0x0E, 0xE0, 0x1B, 0x00, 0x70, +/* 'Y' 0x59 */ 0xC0, 0x0F, 0x80, 0x76, 0x01, 0x9C, 0x0C, 0x38, 0x70, 0x61, 0x81, 0xCE, 0x03, 0x30, 0x0F, 0x80, 0x1E, 0x00, 0x30, 0x00, 0xC0, 0x03, 0x00, 0x0C, 0x00, 0x30, 0x00, 0xC0, 0x03, 0x00, 0x0C, 0x00, +/* 'Z' 0x5A */ 0xFF, 0xFF, 0xFF, 0xC0, 0x0E, 0x00, 0xE0, 0x0E, 0x00, 0x60, 0x07, 0x00, 0x70, 0x07, 0x00, 0x30, 0x03, 0x80, 0x38, 0x03, 0x80, 0x18, 0x01, 0xC0, 0x1C, 0x00, 0xFF, 0xFF, 0xFF, 0xC0, +/* '[' 0x5B */ 0xFF, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCF, 0xF0, +/* '\' 0x5C */ 0x81, 0x81, 0x02, 0x06, 0x04, 0x08, 0x18, 0x10, 0x20, 0x60, 0x40, 0x81, 0x81, 0x02, 0x06, 0x04, +/* ']' 0x5D */ 0xFF, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0xF0, +/* '^' 0x5E */ 0x0C, 0x0E, 0x05, 0x86, 0xC3, 0x21, 0x19, 0x8C, 0x83, 0xC1, 0x80, +/* '_' 0x5F */ 0xFF, 0xFE, +/* '`' 0x60 */ 0xE3, 0x8C, 0x30, +/* 'a' 0x61 */ 0x3F, 0x07, 0xF8, 0xE1, 0xCC, 0x0C, 0x00, 0xC0, 0x1C, 0x3F, 0xCF, 0x8C, 0xC0, 0xCC, 0x0C, 0xE3, 0xC7, 0xEF, 0x3C, 0x70, +/* 'b' 0x62 */ 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0xF8, 0xDF, 0xCF, 0x0E, 0xE0, 0x7C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xE0, 0x6F, 0x0E, 0xDF, 0xCC, 0xF8, +/* 'c' 0x63 */ 0x1F, 0x0F, 0xE6, 0x1F, 0x83, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x38, 0x37, 0x1C, 0xFE, 0x1F, 0x00, +/* 'd' 0x64 */ 0x00, 0x60, 0x0C, 0x01, 0x80, 0x30, 0x06, 0x3C, 0xCF, 0xFB, 0x8F, 0xE0, 0xF8, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF8, 0x3B, 0x8F, 0x3F, 0x63, 0xCC, +/* 'e' 0x65 */ 0x1F, 0x07, 0xF1, 0xC7, 0x70, 0x3C, 0x07, 0xFF, 0xFF, 0xFE, 0x00, 0xC0, 0x1C, 0x0D, 0xC3, 0x1F, 0xC1, 0xF0, +/* 'f' 0x66 */ 0x3B, 0xD8, 0xC6, 0x7F, 0xEC, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x00, +/* 'g' 0x67 */ 0x1E, 0x67, 0xFD, 0xC7, 0xF0, 0x7C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x7C, 0x1D, 0xC7, 0x9F, 0xB1, 0xE6, 0x00, 0xC0, 0x3E, 0x0E, 0x7F, 0xC7, 0xE0, +/* 'h' 0x68 */ 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x33, 0xCD, 0xFB, 0xC7, 0xE0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x30, +/* 'i' 0x69 */ 0xF0, 0x3F, 0xFF, 0xFF, 0xF0, +/* 'j' 0x6A */ 0x33, 0x00, 0x03, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0xE0, +/* 'k' 0x6B */ 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x6C, 0x33, 0x18, 0xCC, 0x37, 0x0F, 0xC3, 0xB8, 0xC6, 0x31, 0xCC, 0x3B, 0x06, 0xC1, 0xF0, 0x30, +/* 'l' 0x6C */ 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, +/* 'm' 0x6D */ 0xCF, 0x1F, 0x6F, 0xDF, 0xFC, 0x78, 0xFC, 0x18, 0x3C, 0x0C, 0x1E, 0x06, 0x0F, 0x03, 0x07, 0x81, 0x83, 0xC0, 0xC1, 0xE0, 0x60, 0xF0, 0x30, 0x78, 0x18, 0x3C, 0x0C, 0x18, +/* 'n' 0x6E */ 0xCF, 0x37, 0xEF, 0x1F, 0x83, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xC0, +/* 'o' 0x6F */ 0x1F, 0x07, 0xF1, 0xC7, 0x70, 0x7C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x7C, 0x1D, 0xC7, 0x1F, 0xC1, 0xF0, +/* 'p' 0x70 */ 0xCF, 0x8D, 0xFC, 0xF0, 0xEE, 0x06, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3E, 0x06, 0xF0, 0xEF, 0xFC, 0xCF, 0x8C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x00, +/* 'q' 0x71 */ 0x1E, 0x67, 0xFD, 0xC7, 0xF0, 0x7C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x7C, 0x1D, 0xC7, 0x9F, 0xF1, 0xE6, 0x00, 0xC0, 0x18, 0x03, 0x00, 0x60, +/* 'r' 0x72 */ 0xCF, 0x7F, 0x38, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC0, +/* 's' 0x73 */ 0x3E, 0x1F, 0xEE, 0x1B, 0x00, 0xC0, 0x3C, 0x07, 0xF0, 0x3F, 0x01, 0xF0, 0x3E, 0x1D, 0xFE, 0x3F, 0x00, +/* 't' 0x74 */ 0x63, 0x19, 0xFF, 0xB1, 0x8C, 0x63, 0x18, 0xC6, 0x31, 0xE7, +/* 'u' 0x75 */ 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x7E, 0x3D, 0xFB, 0x3C, 0xC0, +/* 'v' 0x76 */ 0xE0, 0x6C, 0x0D, 0x81, 0xB8, 0x63, 0x0C, 0x61, 0x8E, 0x60, 0xCC, 0x19, 0x83, 0xE0, 0x3C, 0x07, 0x00, 0xE0, +/* 'w' 0x77 */ 0xC1, 0xC1, 0xB0, 0xE1, 0xD8, 0x70, 0xCC, 0x2C, 0x66, 0x36, 0x31, 0x9B, 0x18, 0xCD, 0x98, 0x64, 0x6C, 0x16, 0x36, 0x0F, 0x1A, 0x07, 0x8F, 0x03, 0x83, 0x80, 0xC1, 0xC0, +/* 'x' 0x78 */ 0xC1, 0xF8, 0x66, 0x30, 0xCC, 0x3E, 0x07, 0x00, 0xC0, 0x78, 0x36, 0x0C, 0xC6, 0x3B, 0x06, 0xC0, 0xC0, +/* 'y' 0x79 */ 0xE0, 0x6C, 0x0D, 0x83, 0x38, 0x63, 0x0C, 0x63, 0x0C, 0x60, 0xCC, 0x1B, 0x03, 0x60, 0x3C, 0x07, 0x00, 0xE0, 0x18, 0x03, 0x00, 0xE0, 0x78, 0x0E, 0x00, +/* 'z' 0x7A */ 0xFF, 0xFF, 0xF0, 0x18, 0x0C, 0x07, 0x03, 0x81, 0xC0, 0x60, 0x30, 0x18, 0x0E, 0x03, 0xFF, 0xFF, 0xC0, +/* '{' 0x7B */ 0x19, 0xCC, 0x63, 0x18, 0xC6, 0x31, 0x99, 0x86, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x1C, 0x60, +/* '|' 0x7C */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, +/* '}' 0x7D */ 0xC7, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x0C, 0x33, 0x31, 0x8C, 0x63, 0x18, 0xC6, 0x73, 0x00, +/* '~' 0x7E */ 0x70, 0x3E, 0x09, 0xE4, 0x1F, 0x03, 0x80, +/* 0x7F */ +/* 0x80 */ 0x01, 0xF0, 0x1F, 0xF0, 0xE0, 0xC7, 0x00, 0x18, 0x00, 0xC0, 0x07, 0xFF, 0x3F, 0xFC, 0x30, 0x01, 0xFF, 0x8F, 0xFC, 0x0C, 0x00, 0x18, 0x00, 0x70, 0x00, 0xE0, 0x81, 0xFE, 0x03, 0xF0, +/* 0x81 */ +/* 0x82 */ 0xF5, 0x80, +/* 0x83 */ 0x1C, 0xF3, 0x0C, 0x31, 0xF7, 0xCC, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x33, 0xCE, 0x00, +/* 0x84 */ 0xCF, 0x34, 0x51, 0x88, +/* 0x85 */ 0xC6, 0x3C, 0x63, +/* 0x86 */ 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x3F, 0xFF, 0xFC, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x00, +/* 0x87 */ 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x3F, 0xFF, 0xFC, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x0F, 0xFF, 0xFF, 0x0C, 0x03, 0x00, 0xC0, 0x30, +/* 0x88 */ 0x38, 0xD9, 0xB6, 0x30, +/* 0x89 */ 0x38, 0x18, 0x00, 0xF8, 0x30, 0x03, 0x18, 0xC0, 0x04, 0x11, 0x80, 0x0C, 0x66, 0x00, 0x0F, 0x8C, 0x00, 0x0E, 0x30, 0x00, 0x00, 0x40, 0x00, 0x01, 0x80, 0x00, 0x06, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x31, 0xC0, 0xE0, 0x67, 0xC3, 0xC1, 0x98, 0xCC, 0xC3, 0x20, 0x90, 0x8C, 0x63, 0x33, 0x10, 0x7C, 0x3C, 0x60, 0x70, 0x38, +/* 0x8A */ 0x0C, 0x40, 0x1F, 0x00, 0x38, 0x03, 0xF8, 0x1F, 0xF0, 0xE0, 0xE6, 0x01, 0xD8, 0x03, 0x60, 0x01, 0xC0, 0x07, 0x80, 0x0F, 0xE0, 0x0F, 0xF0, 0x03, 0xE0, 0x01, 0xF0, 0x03, 0xC0, 0x0F, 0x80, 0x37, 0x83, 0x8F, 0xFC, 0x0F, 0xE0, +/* 0x8B */ 0x2F, 0x49, 0x99, +/* 0x8C */ 0x07, 0xCF, 0xFC, 0x7F, 0xFF, 0xF3, 0x83, 0xC0, 0x18, 0x07, 0x00, 0x60, 0x0C, 0x03, 0x00, 0x30, 0x0C, 0x00, 0xC0, 0x30, 0x03, 0x00, 0xC0, 0x0F, 0xFF, 0x00, 0x3F, 0xFC, 0x00, 0xC0, 0x30, 0x03, 0x00, 0xC0, 0x0C, 0x01, 0x80, 0x30, 0x07, 0x01, 0xC0, 0x0E, 0x0F, 0x00, 0x1F, 0xEF, 0xFC, 0x1F, 0x3F, 0xF0, +/* 0x8D */ +/* 0x8E */ 0x0C, 0xC0, 0x3C, 0x00, 0xE1, 0xFF, 0xFF, 0xFF, 0x80, 0x1C, 0x01, 0xC0, 0x1C, 0x00, 0xC0, 0x0E, 0x00, 0xE0, 0x0E, 0x00, 0x60, 0x07, 0x00, 0x70, 0x07, 0x00, 0x30, 0x03, 0x80, 0x38, 0x01, 0xFF, 0xFF, 0xFF, 0x80, +/* 0x8F */ +/* 0x90 */ +/* 0x91 */ 0x6A, 0xF0, +/* 0x92 */ 0xF5, 0x60, +/* 0x93 */ 0x4E, 0x28, 0xA2, 0xCF, 0x30, +/* 0x94 */ 0xCF, 0x34, 0x51, 0x4E, 0x20, +/* 0x95 */ 0x7B, 0xFF, 0xFF, 0xFD, 0xE0, +/* 0x96 */ 0xFF, 0xFF, 0xF0, +/* 0x97 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, +/* 0x98 */ 0x63, 0xFE, 0x70, +/* 0x99 */ 0xFF, 0x70, 0x1F, 0xFD, 0xC0, 0x71, 0x87, 0x83, 0xC6, 0x1E, 0x0F, 0x18, 0x68, 0x3C, 0x61, 0xB1, 0xB1, 0x86, 0xC6, 0xC6, 0x19, 0x1B, 0x18, 0x66, 0xCC, 0x61, 0x9B, 0x31, 0x86, 0x3C, 0xC6, 0x18, 0xE3, 0x18, 0x63, 0x8C, +/* 0x9A */ 0x63, 0x0D, 0x83, 0x60, 0x70, 0x00, 0x0F, 0x87, 0xFB, 0x86, 0xC0, 0x30, 0x0F, 0x01, 0xFC, 0x0F, 0xC0, 0x7C, 0x0F, 0x87, 0x7F, 0x8F, 0xC0, +/* 0x9B */ 0x99, 0x92, 0xF4, +/* 0x9C */ 0x1F, 0x0F, 0x83, 0xF9, 0xFC, 0x71, 0xF8, 0x6E, 0x0F, 0x03, 0xC0, 0x60, 0x3C, 0x07, 0xFF, 0xC0, 0x7F, 0xFC, 0x06, 0x00, 0xC0, 0x60, 0x0E, 0x0F, 0x03, 0x71, 0xF8, 0x63, 0xF9, 0xFC, 0x1F, 0x0F, 0x80, +/* 0x9D */ +/* 0x9E */ 0x63, 0x0C, 0x83, 0x60, 0x70, 0x00, 0x3F, 0xFF, 0xFC, 0x06, 0x03, 0x01, 0xC0, 0xE0, 0x70, 0x18, 0x0C, 0x06, 0x03, 0x80, 0xFF, 0xFF, 0xF0, +/* 0x9F */ 0x0C, 0xC0, 0x33, 0x00, 0x00, 0x30, 0x03, 0xE0, 0x1D, 0x80, 0x67, 0x03, 0x0E, 0x1C, 0x18, 0x60, 0x73, 0x80, 0xCC, 0x03, 0xE0, 0x07, 0x80, 0x0C, 0x00, 0x30, 0x00, 0xC0, 0x03, 0x00, 0x0C, 0x00, 0x30, 0x00, 0xC0, 0x03, 0x00, +/* 0xA0 */ +/* 0xA1 */ 0xF0, 0xBF, 0xFF, 0xFF, 0xF0, +/* 0xA2 */ 0x04, 0x00, 0x80, 0x7C, 0x1F, 0xE7, 0x4C, 0xC8, 0xF1, 0x1E, 0x20, 0xC4, 0x18, 0x83, 0x10, 0x72, 0x37, 0x4E, 0x7F, 0x87, 0xC0, 0x20, 0x04, 0x00, +/* 0xA3 */ 0x0F, 0xC1, 0xFE, 0x38, 0x76, 0x03, 0x60, 0x36, 0x00, 0x70, 0x03, 0x80, 0xFF, 0x0F, 0xF0, 0x1C, 0x00, 0xC0, 0x0C, 0x01, 0x80, 0x10, 0x02, 0xF1, 0x7F, 0xF6, 0x1F, +/* 0xA4 */ 0xDD, 0xFF, 0xD8, 0xD8, 0x3C, 0x1E, 0x0F, 0x8D, 0xFF, 0xDD, 0x80, +/* 0xA5 */ 0xC0, 0x3E, 0x06, 0x60, 0x63, 0x0C, 0x30, 0xC1, 0x98, 0x19, 0x80, 0xF0, 0x0F, 0x07, 0xFE, 0x06, 0x00, 0x60, 0x7F, 0xE0, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, +/* 0xA6 */ 0xFF, 0xFF, 0xF0, 0x3F, 0xFF, 0xFC, +/* 0xA7 */ 0x0F, 0x03, 0xF0, 0xE7, 0x18, 0x63, 0x0C, 0x70, 0x07, 0x03, 0xF8, 0xC3, 0x98, 0x3B, 0x03, 0xF0, 0x37, 0x06, 0x78, 0xC7, 0xB0, 0x7C, 0x03, 0x80, 0x39, 0x83, 0x30, 0x67, 0x1C, 0x7F, 0x07, 0xC0, +/* 0xA8 */ 0xCF, 0x30, +/* 0xA9 */ 0x03, 0xF0, 0x03, 0xFF, 0x01, 0xE0, 0xE0, 0xE3, 0x1C, 0x73, 0xF3, 0x99, 0x86, 0x6C, 0xC1, 0x8F, 0x30, 0x03, 0xCC, 0x00, 0xF3, 0x00, 0x3C, 0xC1, 0x8D, 0x98, 0x66, 0x77, 0xF3, 0x8E, 0x79, 0xC1, 0xC0, 0xE0, 0x3F, 0xF0, 0x03, 0xF0, 0x00, +/* 0xAA */ 0x79, 0x08, 0x11, 0xEE, 0x50, 0xA3, 0x3B, 0x00, 0x03, 0xF8, +/* 0xAB */ 0x21, 0x63, 0xE7, 0x84, 0x84, 0xE7, 0x63, 0x21, +/* 0xAC */ 0xFF, 0xFF, 0xFF, 0x00, 0x30, 0x03, 0x00, 0x30, 0x03, +/* 0xAD */ 0xFF, 0xF0, +/* 0xAE */ 0x03, 0xF0, 0x03, 0xFF, 0x01, 0xE0, 0xE0, 0xFF, 0x1C, 0x7F, 0xF3, 0x9B, 0x04, 0x6C, 0xC1, 0x8F, 0x30, 0x43, 0xCF, 0xF0, 0xF3, 0xFC, 0x3C, 0xC1, 0x0D, 0xB0, 0x66, 0x7C, 0x1B, 0x8F, 0x07, 0xC1, 0xC0, 0xE0, 0x3F, 0xF0, 0x03, 0xF0, 0x00, +/* 0xAF */ 0xFF, 0xF0, +/* 0xB0 */ 0x38, 0xFB, 0x1C, 0x18, 0x38, 0xDF, 0x1C, +/* 0xB1 */ 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x7F, 0xE7, 0xFE, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xF0, +/* 0xB2 */ 0x7D, 0x8F, 0x18, 0x30, 0xC6, 0x18, 0x60, 0xFF, 0xFC, +/* 0xB3 */ 0x7D, 0x8F, 0x18, 0x31, 0x80, 0xC1, 0xE3, 0xC6, 0xF8, +/* 0xB4 */ 0x3B, 0x99, 0x80, +/* 0xB5 */ 0xC0, 0xCC, 0x0C, 0xC0, 0xCC, 0x0C, 0xC0, 0xCC, 0x0C, 0xC0, 0xCC, 0x0C, 0xC0, 0xCC, 0x1C, 0xE3, 0xCF, 0xEF, 0xFC, 0x7C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x00, +/* 0xB6 */ 0x1F, 0xE7, 0xFD, 0xF3, 0x7E, 0x6F, 0xCD, 0xF9, 0xBF, 0x37, 0xE6, 0x7C, 0xCF, 0x98, 0xF3, 0x06, 0x60, 0xCC, 0x19, 0x83, 0x30, 0x66, 0x0C, 0xC1, 0x98, 0x33, 0x06, 0x60, 0xCC, +/* 0xB7 */ 0xF0, +/* 0xB8 */ 0x10, 0xF0, 0xE3, 0x78, +/* 0xB9 */ 0x2F, 0xB6, 0xDB, 0x6C, +/* 0xBA */ 0x79, 0x38, 0x61, 0x86, 0x1C, 0xDE, 0x00, 0x0F, 0xC0, +/* 0xBB */ 0x88, 0xC6, 0xE7, 0x21, 0x21, 0xE7, 0xC6, 0x88, +/* 0xBC */ 0x20, 0x08, 0x30, 0x0C, 0x38, 0x04, 0x0C, 0x06, 0x06, 0x02, 0x03, 0x02, 0x01, 0x81, 0x00, 0xC1, 0x06, 0x61, 0x87, 0x30, 0x83, 0x80, 0xC2, 0xC0, 0x42, 0x60, 0x43, 0x30, 0x21, 0xFC, 0x20, 0x0C, 0x30, 0x06, 0x10, 0x03, 0x00, +/* 0xBD */ 0x20, 0x00, 0x08, 0x02, 0x06, 0x01, 0x83, 0x80, 0x40, 0x60, 0x20, 0x18, 0x18, 0x06, 0x04, 0x01, 0x83, 0x00, 0x61, 0x9F, 0x98, 0x4E, 0x76, 0x33, 0x0C, 0x08, 0x03, 0x04, 0x03, 0x83, 0x01, 0x80, 0x81, 0x80, 0x60, 0xC0, 0x30, 0x3F, 0xC8, 0x0F, 0xF0, +/* 0xBE */ 0x7C, 0x00, 0x18, 0xC0, 0x43, 0x18, 0x18, 0x03, 0x02, 0x00, 0x60, 0xC0, 0x30, 0x10, 0x01, 0x84, 0x00, 0x31, 0x80, 0xC6, 0x20, 0xD8, 0xC8, 0x39, 0xF1, 0x07, 0x00, 0x41, 0x60, 0x18, 0x4C, 0x02, 0x11, 0x80, 0x83, 0xF8, 0x10, 0x06, 0x04, 0x00, 0xC1, 0x00, 0x18, +/* 0xBF */ 0x0C, 0x06, 0x00, 0x00, 0x00, 0xC0, 0x60, 0x60, 0x30, 0x30, 0x38, 0x38, 0x18, 0x0C, 0x06, 0x0F, 0x07, 0xC7, 0x7F, 0x1F, 0x00, +/* 0xC0 */ 0x0C, 0x00, 0x18, 0x00, 0x30, 0x00, 0x00, 0x07, 0x80, 0x1E, 0x00, 0x78, 0x03, 0xF0, 0x0C, 0xC0, 0x33, 0x01, 0xCE, 0x06, 0x18, 0x18, 0x60, 0xE1, 0xC3, 0x03, 0x0F, 0xFC, 0x7F, 0xF9, 0x80, 0x66, 0x01, 0xB8, 0x07, 0xC0, 0x0F, 0x00, 0x30, +/* 0xC1 */ 0x01, 0xC0, 0x0C, 0x00, 0x20, 0x00, 0x00, 0x07, 0x80, 0x1E, 0x00, 0x78, 0x03, 0xF0, 0x0C, 0xC0, 0x33, 0x01, 0xCE, 0x06, 0x18, 0x18, 0x60, 0xE1, 0xC3, 0x03, 0x0F, 0xFC, 0x7F, 0xF9, 0x80, 0x66, 0x01, 0xB8, 0x07, 0xC0, 0x0F, 0x00, 0x30, +/* 0xC2 */ 0x07, 0x00, 0x3E, 0x01, 0x8C, 0x00, 0x00, 0x07, 0x80, 0x1E, 0x00, 0x78, 0x03, 0xF0, 0x0C, 0xC0, 0x33, 0x01, 0xCE, 0x06, 0x18, 0x18, 0x60, 0xE1, 0xC3, 0x03, 0x0F, 0xFC, 0x7F, 0xF9, 0x80, 0x66, 0x01, 0xB8, 0x07, 0xC0, 0x0F, 0x00, 0x30, +/* 0xC3 */ 0x0E, 0x40, 0x7F, 0x01, 0x98, 0x00, 0x00, 0x07, 0x80, 0x1E, 0x00, 0x78, 0x03, 0xF0, 0x0C, 0xC0, 0x33, 0x01, 0xCE, 0x06, 0x18, 0x18, 0x60, 0xE1, 0xC3, 0x03, 0x0F, 0xFC, 0x7F, 0xF9, 0x80, 0x66, 0x01, 0xB8, 0x07, 0xC0, 0x0F, 0x00, 0x30, +/* 0xC4 */ 0x0C, 0xC0, 0x33, 0x00, 0x00, 0x01, 0xE0, 0x07, 0x80, 0x1E, 0x00, 0xFC, 0x03, 0x30, 0x0C, 0xC0, 0x73, 0x81, 0x86, 0x06, 0x18, 0x38, 0x70, 0xC0, 0xC3, 0xFF, 0x1F, 0xFE, 0x60, 0x19, 0x80, 0x6E, 0x01, 0xF0, 0x03, 0xC0, 0x0C, +/* 0xC5 */ 0x03, 0x00, 0x1E, 0x00, 0xEC, 0x03, 0x30, 0x0F, 0xC0, 0x1E, 0x00, 0x78, 0x01, 0xE0, 0x07, 0x80, 0x3F, 0x00, 0xCC, 0x03, 0x30, 0x1C, 0xE0, 0x61, 0x81, 0x86, 0x0E, 0x1C, 0x30, 0x30, 0xFF, 0xC7, 0xFF, 0x98, 0x06, 0x60, 0x1B, 0x80, 0x7C, 0x00, 0xF0, 0x03, +/* 0xC6 */ 0x01, 0xFF, 0xFC, 0x07, 0xFF, 0xF0, 0x31, 0x80, 0x00, 0xC6, 0x00, 0x07, 0x18, 0x00, 0x18, 0x60, 0x00, 0x61, 0x80, 0x03, 0x86, 0x00, 0x0C, 0x1F, 0xF8, 0x70, 0x7F, 0xE1, 0x81, 0x80, 0x07, 0xFE, 0x00, 0x3F, 0xF8, 0x00, 0xC0, 0x60, 0x07, 0x01, 0x80, 0x1C, 0x06, 0x00, 0x60, 0x1F, 0xFF, 0x80, 0x7F, 0xF0, +/* 0xC7 */ 0x07, 0xE0, 0x3F, 0xF0, 0xE0, 0x73, 0x80, 0x66, 0x00, 0x7C, 0x00, 0x30, 0x00, 0x60, 0x00, 0xC0, 0x01, 0x80, 0x03, 0x00, 0x06, 0x00, 0x0E, 0x00, 0x6C, 0x01, 0xDC, 0x03, 0x1C, 0x1E, 0x1F, 0xF8, 0x0F, 0xC0, 0x08, 0x00, 0x1E, 0x00, 0x0C, 0x01, 0x18, 0x01, 0xE0, 0x00, +/* 0xC8 */ 0x1C, 0x00, 0xC0, 0x02, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xFF, 0xEF, 0xFE, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xFF, 0xFF, 0xFF, +/* 0xC9 */ 0x07, 0x00, 0x60, 0x0C, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xFF, 0xEF, 0xFE, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xFF, 0xFF, 0xFF, +/* 0xCA */ 0x0E, 0x01, 0xF0, 0x31, 0x80, 0x00, 0xFF, 0xFF, 0xFF, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xFF, 0xEF, 0xFE, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xFF, 0xFF, 0xFF, +/* 0xCB */ 0x19, 0x81, 0x98, 0x00, 0x0F, 0xFF, 0xFF, 0xFC, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0F, 0xFE, 0xFF, 0xEC, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0F, 0xFF, 0xFF, 0xF0, +/* 0xCC */ 0xE7, 0x10, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, +/* 0xCD */ 0x36, 0xC0, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, +/* 0xCE */ 0x39, 0xFC, 0x40, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC0, +/* 0xCF */ 0xC7, 0x8C, 0x01, 0x83, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x83, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x83, 0x00, +/* 0xD0 */ 0x7F, 0xE0, 0xFF, 0xE1, 0x80, 0xE3, 0x00, 0xE6, 0x00, 0xCC, 0x01, 0xD8, 0x01, 0xB0, 0x03, 0xFE, 0x07, 0xFC, 0x0D, 0x80, 0x1B, 0x00, 0x36, 0x00, 0x6C, 0x01, 0x98, 0x07, 0x30, 0x1C, 0x7F, 0xF0, 0xFF, 0xC0, +/* 0xD1 */ 0x08, 0xC0, 0xFE, 0x05, 0xE0, 0x00, 0x0E, 0x01, 0xF0, 0x0F, 0xC0, 0x7E, 0x03, 0xD8, 0x1E, 0xE0, 0xF3, 0x07, 0x9C, 0x3C, 0x61, 0xE1, 0x8F, 0x0E, 0x78, 0x33, 0xC1, 0xDE, 0x06, 0xF0, 0x1F, 0x80, 0xFC, 0x03, 0xE0, 0x1C, +/* 0xD2 */ 0x07, 0x00, 0x01, 0x80, 0x00, 0x60, 0x00, 0x00, 0x00, 0x7F, 0x00, 0xFF, 0xE0, 0xF0, 0x78, 0x60, 0x0C, 0x60, 0x03, 0x30, 0x01, 0xB0, 0x00, 0x78, 0x00, 0x3C, 0x00, 0x1E, 0x00, 0x0F, 0x00, 0x07, 0x80, 0x03, 0x60, 0x03, 0x30, 0x01, 0x8C, 0x01, 0x87, 0x83, 0xC1, 0xFF, 0xC0, 0x3F, 0x80, +/* 0xD3 */ 0x00, 0xE0, 0x00, 0x60, 0x00, 0x40, 0x00, 0x00, 0x00, 0x7F, 0x00, 0xFF, 0xE0, 0xF0, 0x78, 0x60, 0x0C, 0x60, 0x03, 0x30, 0x01, 0xB0, 0x00, 0x78, 0x00, 0x3C, 0x00, 0x1E, 0x00, 0x0F, 0x00, 0x07, 0x80, 0x03, 0x60, 0x03, 0x30, 0x01, 0x8C, 0x01, 0x87, 0x83, 0xC1, 0xFF, 0xC0, 0x3F, 0x80, +/* 0xD4 */ 0x03, 0xC0, 0x01, 0xE0, 0x01, 0x98, 0x00, 0x00, 0x00, 0x7F, 0x00, 0xFF, 0xE0, 0xF0, 0x78, 0x60, 0x0C, 0x60, 0x03, 0x30, 0x01, 0xB0, 0x00, 0x78, 0x00, 0x3C, 0x00, 0x1E, 0x00, 0x0F, 0x00, 0x07, 0x80, 0x03, 0x60, 0x03, 0x30, 0x01, 0x8C, 0x01, 0x87, 0x83, 0xC1, 0xFF, 0xC0, 0x3F, 0x80, +/* 0xD5 */ 0x07, 0x20, 0x03, 0xF0, 0x01, 0x38, 0x00, 0x00, 0x00, 0x7F, 0x00, 0xFF, 0xE0, 0xF0, 0x78, 0x60, 0x0C, 0x60, 0x03, 0x30, 0x01, 0xB0, 0x00, 0x78, 0x00, 0x3C, 0x00, 0x1E, 0x00, 0x0F, 0x00, 0x07, 0x80, 0x03, 0x60, 0x03, 0x30, 0x01, 0x8C, 0x01, 0x87, 0x83, 0xC1, 0xFF, 0xC0, 0x3F, 0x80, +/* 0xD6 */ 0x06, 0x30, 0x03, 0x18, 0x00, 0x00, 0x00, 0xFE, 0x01, 0xFF, 0xC1, 0xE0, 0xF0, 0xC0, 0x18, 0xC0, 0x06, 0x60, 0x03, 0x60, 0x00, 0xF0, 0x00, 0x78, 0x00, 0x3C, 0x00, 0x1E, 0x00, 0x0F, 0x00, 0x06, 0xC0, 0x06, 0x60, 0x03, 0x18, 0x03, 0x0F, 0x07, 0x83, 0xFF, 0x80, 0x7F, 0x00, +/* 0xD7 */ 0x81, 0xC3, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0xC3, 0x81, +/* 0xD8 */ 0x07, 0xF0, 0x8F, 0xFE, 0x8F, 0x07, 0xC6, 0x00, 0xE6, 0x00, 0xF3, 0x00, 0xDF, 0x00, 0xC7, 0x80, 0xC3, 0xC0, 0xC1, 0xE0, 0xC0, 0xF0, 0xC0, 0x78, 0xC0, 0x3E, 0xC0, 0x33, 0xC0, 0x19, 0xC0, 0x1C, 0xF8, 0x3C, 0xDF, 0xF8, 0x43, 0xF8, 0x00, +/* 0xD9 */ 0x0C, 0x00, 0x30, 0x00, 0xC0, 0x00, 0x0C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF8, 0x0E, 0xE0, 0xE3, 0xFE, 0x0F, 0xC0, +/* 0xDA */ 0x03, 0x80, 0x18, 0x01, 0x80, 0x00, 0x0C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF8, 0x0E, 0xE0, 0xE3, 0xFE, 0x0F, 0xC0, +/* 0xDB */ 0x07, 0x00, 0x7C, 0x06, 0x20, 0x00, 0x0C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF8, 0x0E, 0xE0, 0xE3, 0xFE, 0x0F, 0xC0, +/* 0xDC */ 0x0C, 0xC0, 0x66, 0x00, 0x01, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1F, 0x01, 0xDC, 0x1C, 0x7F, 0xC1, 0xF8, 0x00, +/* 0xDD */ 0x01, 0x80, 0x0C, 0x00, 0x60, 0x00, 0x00, 0xC0, 0x0F, 0x80, 0x76, 0x01, 0x9C, 0x0C, 0x38, 0x70, 0x61, 0x81, 0xCE, 0x03, 0x30, 0x0F, 0x80, 0x1E, 0x00, 0x30, 0x00, 0xC0, 0x03, 0x00, 0x0C, 0x00, 0x30, 0x00, 0xC0, 0x03, 0x00, 0x0C, 0x00, +/* 0xDE */ 0xC0, 0x0C, 0x00, 0xC0, 0x0F, 0xF8, 0xFF, 0xEC, 0x06, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x6F, 0xFE, 0xFF, 0x8C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, +/* 0xDF */ 0x1F, 0x0F, 0xF3, 0x87, 0x60, 0x6C, 0x0D, 0x81, 0xB0, 0x66, 0x38, 0xC7, 0xD8, 0x1B, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x3E, 0x0E, 0xCF, 0x99, 0xE0, +/* 0xE0 */ 0x1C, 0x00, 0xC0, 0x06, 0x00, 0x20, 0x00, 0x03, 0xF0, 0x7F, 0x8E, 0x1C, 0xC0, 0xC0, 0x0C, 0x01, 0xC3, 0xFC, 0xF8, 0xCC, 0x0C, 0xC0, 0xCE, 0x3C, 0x7E, 0xF3, 0xC7, +/* 0xE1 */ 0x07, 0x00, 0x60, 0x0C, 0x01, 0x80, 0x00, 0x03, 0xF0, 0x7F, 0x8E, 0x1C, 0xC0, 0xC0, 0x0C, 0x01, 0xC3, 0xFC, 0xF8, 0xCC, 0x0C, 0xC0, 0xCE, 0x3C, 0x7E, 0xF3, 0xC7, +/* 0xE2 */ 0x0C, 0x01, 0xE0, 0x1B, 0x03, 0x30, 0x00, 0x03, 0xF0, 0x7F, 0x8E, 0x1C, 0xC0, 0xC0, 0x0C, 0x01, 0xC3, 0xFC, 0xF8, 0xCC, 0x0C, 0xC0, 0xCE, 0x3C, 0x7E, 0xF3, 0xC7, +/* 0xE3 */ 0x19, 0x83, 0xF0, 0x27, 0x00, 0x00, 0x00, 0x03, 0xF0, 0x7F, 0x8E, 0x1C, 0xC0, 0xC0, 0x0C, 0x01, 0xC3, 0xFC, 0xF8, 0xCC, 0x0C, 0xC0, 0xCE, 0x3C, 0x7E, 0xF3, 0xC7, +/* 0xE4 */ 0x19, 0x81, 0x98, 0x00, 0x00, 0x00, 0x3F, 0x07, 0xF8, 0xE1, 0xCC, 0x0C, 0x00, 0xC0, 0x1C, 0x3F, 0xCF, 0x8C, 0xC0, 0xCC, 0x0C, 0xE3, 0xC7, 0xEF, 0x3C, 0x70, +/* 0xE5 */ 0x0E, 0x01, 0xF0, 0x1B, 0x81, 0xB8, 0x1F, 0x00, 0xE0, 0x3F, 0x07, 0xF8, 0xE1, 0xCC, 0x0C, 0x00, 0xC0, 0x1C, 0x3F, 0xCF, 0x8C, 0xC0, 0xCC, 0x0C, 0xE3, 0xC7, 0xEF, 0x3C, 0x70, +/* 0xE6 */ 0x3F, 0x1F, 0x0F, 0xF7, 0xF3, 0x87, 0xC3, 0x60, 0x70, 0x30, 0x0C, 0x06, 0x3F, 0xFF, 0xDF, 0xFF, 0xFF, 0x06, 0x00, 0xC0, 0xC0, 0x18, 0x3C, 0x0F, 0x8F, 0xC7, 0x3F, 0x9F, 0xE3, 0xC1, 0xF0, +/* 0xE7 */ 0x1F, 0x0F, 0xE7, 0x1D, 0x83, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x38, 0x37, 0x1C, 0xFE, 0x1F, 0x02, 0x00, 0xE0, 0x0C, 0x23, 0x07, 0x80, +/* 0xE8 */ 0x1C, 0x01, 0x80, 0x18, 0x01, 0x00, 0x00, 0x3E, 0x0F, 0xE3, 0x8E, 0xE0, 0x78, 0x0F, 0xFF, 0xFF, 0xFC, 0x01, 0x80, 0x38, 0x1B, 0x86, 0x3F, 0x83, 0xE0, +/* 0xE9 */ 0x03, 0x00, 0xC0, 0x30, 0x04, 0x00, 0x00, 0x3E, 0x0F, 0xE3, 0x8E, 0xE0, 0x78, 0x0F, 0xFF, 0xFF, 0xFC, 0x01, 0x80, 0x38, 0x1B, 0x86, 0x3F, 0x83, 0xE0, +/* 0xEA */ 0x0C, 0x03, 0xC0, 0x6C, 0x18, 0x80, 0x00, 0x3E, 0x0F, 0xE3, 0x8E, 0xE0, 0x78, 0x0F, 0xFF, 0xFF, 0xFC, 0x01, 0x80, 0x38, 0x1B, 0x86, 0x3F, 0x83, 0xE0, +/* 0xEB */ 0x31, 0x86, 0x30, 0x00, 0x00, 0x01, 0xF0, 0x7F, 0x1C, 0x77, 0x03, 0xC0, 0x7F, 0xFF, 0xFF, 0xE0, 0x0C, 0x01, 0xC0, 0xDC, 0x31, 0xFC, 0x1F, 0x00, +/* 0xEC */ 0xC6, 0x31, 0x06, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, +/* 0xED */ 0x39, 0x99, 0x80, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x18, 0xC6, 0x31, 0x80, +/* 0xEE */ 0x71, 0xED, 0xA3, 0x00, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC0, +/* 0xEF */ 0xCF, 0x30, 0x00, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, +/* 0xF0 */ 0x20, 0x07, 0xE0, 0x70, 0x3B, 0x00, 0x30, 0x3F, 0x0F, 0xF3, 0x8E, 0xE0, 0xF8, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF8, 0x3B, 0x8E, 0x3F, 0x83, 0xE0, +/* 0xF1 */ 0x19, 0x8F, 0xE2, 0x70, 0x00, 0x00, 0x33, 0xCD, 0xFB, 0xC7, 0xE0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x30, +/* 0xF2 */ 0x1C, 0x01, 0x80, 0x18, 0x01, 0x00, 0x00, 0x3E, 0x0F, 0xE3, 0x8E, 0xE0, 0xF8, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF8, 0x3B, 0x8E, 0x3F, 0x83, 0xE0, +/* 0xF3 */ 0x07, 0x00, 0xC0, 0x30, 0x04, 0x00, 0x00, 0x3E, 0x0F, 0xE3, 0x8E, 0xE0, 0xF8, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF8, 0x3B, 0x8E, 0x3F, 0x83, 0xE0, +/* 0xF4 */ 0x0C, 0x03, 0xC0, 0xD8, 0x19, 0x80, 0x00, 0x3E, 0x0F, 0xE3, 0x8E, 0xE0, 0xF8, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF8, 0x3B, 0x8E, 0x3F, 0x83, 0xE0, +/* 0xF5 */ 0x19, 0x87, 0xE0, 0x9C, 0x00, 0x00, 0x00, 0x3E, 0x0F, 0xE3, 0x8E, 0xE0, 0xF8, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF8, 0x3B, 0x8E, 0x3F, 0x83, 0xE0, +/* 0xF6 */ 0x31, 0x86, 0x30, 0x00, 0x00, 0x01, 0xF0, 0x7F, 0x1C, 0x77, 0x07, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0xC1, 0xDC, 0x71, 0xFC, 0x1F, 0x00, +/* 0xF7 */ 0x06, 0x00, 0x60, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x06, 0x00, +/* 0xF8 */ 0x1F, 0x27, 0xF5, 0xC7, 0x70, 0x7C, 0x17, 0x84, 0xF1, 0x1E, 0x43, 0xD0, 0x7C, 0x1D, 0xC7, 0x3F, 0xC9, 0xF0, +/* 0xF9 */ 0x18, 0x03, 0x00, 0x60, 0x08, 0x00, 0x30, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x1F, 0x8F, 0x7E, 0xCF, 0x30, +/* 0xFA */ 0x03, 0x01, 0x80, 0x60, 0x30, 0x00, 0x30, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x1F, 0x8F, 0x7E, 0xCF, 0x30, +/* 0xFB */ 0x0C, 0x07, 0x81, 0x20, 0xCC, 0x00, 0x30, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x1F, 0x8F, 0x7E, 0xCF, 0x30, +/* 0xFC */ 0x31, 0x8C, 0x60, 0x00, 0x00, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x7E, 0x3D, 0xFB, 0x3C, 0xC0, +/* 0xFD */ 0x03, 0x80, 0x60, 0x18, 0x06, 0x00, 0x01, 0xC0, 0xD8, 0x1B, 0x06, 0x70, 0xC6, 0x18, 0xC6, 0x18, 0xC1, 0x98, 0x36, 0x06, 0xC0, 0x78, 0x0E, 0x01, 0xC0, 0x30, 0x06, 0x01, 0xC0, 0xF0, 0x1C, 0x00, +/* 0xFE */ 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xCF, 0x8F, 0xFC, 0xF0, 0xEE, 0x06, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3E, 0x06, 0xF0, 0xEF, 0xFC, 0xCF, 0x8C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x00, +/* 0xFF */ 0x19, 0x83, 0x30, 0x00, 0x00, 0x0E, 0x06, 0xC0, 0xD8, 0x33, 0x86, 0x30, 0xC6, 0x30, 0xC6, 0x0C, 0xC1, 0xB0, 0x36, 0x03, 0xC0, 0x70, 0x0E, 0x01, 0x80, 0x30, 0x0E, 0x07, 0x80, 0xE0, 0x00, +}; + +const GFXglyph FreeSans12pt_Win1252Glyphs[] PROGMEM = { +/* 0x01 */ { 0, 19, 20, 21, 1, -17 }, +/* 0x02 */ { 48, 19, 20, 21, 1, -17 }, +/* 0x03 */ { 96, 21, 20, 23, 1, -17 }, +/* 0x04 */ { 149, 21, 20, 23, 1, -17 }, +/* 0x05 */ { 202, 20, 20, 22, 1, -17 }, +/* 0x06 */ { 252, 20, 20, 22, 1, -17 }, +/* 0x07 */ { 302, 0, 0, 8, 0, 0 }, +/* 0x08 */ { 302, 23, 20, 25, 1, -17 }, +/* 0x09 */ { 360, 23, 16, 25, 1, -16 }, +/* 0x0A */ { 406, 0, 0, 8, 0, 0 }, +/* 0x0B */ { 406, 21, 20, 23, 1, -17 }, +/* 0x0C */ { 459, 19, 18, 21, 1, -15 }, +/* 0x0D */ { 502, 0, 0, 8, 0, 0 }, +/* 0x0E */ { 502, 20, 20, 22, 1, -17 }, +/* 0x0F */ { 552, 21, 21, 23, 1, -18 }, +/* 0x10 */ { 608, 19, 20, 21, 1, -17 }, +/* 0x11 */ { 656, 21, 20, 23, 1, -17 }, +/* 0x12 */ { 709, 20, 20, 22, 1, -17 }, +/* 0x13 */ { 759, 21, 20, 23, 1, -17 }, +/* 0x14 */ { 812, 21, 20, 23, 1, -17 }, +/* 0x15 */ { 865, 22, 20, 24, 1, -17 }, +/* 0x16 */ { 920, 16, 20, 18, 1, -17 }, +/* 0x17 */ { 960, 21, 20, 23, 1, -17 }, +/* 0x18 */ { 1013, 23, 20, 25, 1, -17 }, +/* 0x19 */ { 1071, 21, 20, 23, 1, -17 }, +/* 0x1A */ { 1124, 15, 19, 17, 1, -16 }, +/* 0x1B */ { 1160, 24, 21, 26, 1, -18 }, +/* 0x1C */ { 1223, 21, 20, 23, 1, -17 }, +/* 0x1D */ { 1276, 21, 21, 23, 1, -18 }, +/* 0x1E */ { 1332, 20, 20, 22, 1, -17 }, +/* 0x1F */ { 1382, 15, 20, 17, 1, -17 }, +/* ' ' 0x20 */ { 1420, 0, 0, 6, 0, 0 }, +/* '!' 0x21 */ { 1420, 2, 18, 8, 3, -16 }, +/* '"' 0x22 */ { 1425, 6, 6, 8, 1, -15 }, +/* '#' 0x23 */ { 1430, 13, 16, 13, 0, -14 }, +/* '$' 0x24 */ { 1456, 11, 20, 13, 1, -16 }, +/* '%' 0x25 */ { 1484, 20, 17, 21, 1, -15 }, +/* '&' 0x26 */ { 1527, 14, 17, 16, 1, -15 }, +/* ''' 0x27 */ { 1557, 2, 6, 5, 1, -15 }, +/* '(' 0x28 */ { 1559, 5, 23, 8, 2, -16 }, +/* ')' 0x29 */ { 1574, 5, 23, 8, 1, -16 }, +/* '*' 0x2A */ { 1589, 7, 7, 9, 1, -16 }, +/* '+' 0x2B */ { 1596, 10, 11, 14, 2, -9 }, +/* ',' 0x2C */ { 1610, 2, 6, 7, 2, 0 }, +/* '-' 0x2D */ { 1612, 6, 2, 8, 1, -6 }, +/* '.' 0x2E */ { 1614, 2, 2, 6, 2, 0 }, +/* '/' 0x2F */ { 1615, 7, 18, 7, 0, -16 }, +/* '0' 0x30 */ { 1631, 11, 17, 13, 1, -15 }, +/* '1' 0x31 */ { 1655, 5, 17, 13, 3, -15 }, +/* '2' 0x32 */ { 1666, 11, 17, 13, 1, -15 }, +/* '3' 0x33 */ { 1690, 11, 17, 13, 1, -15 }, +/* '4' 0x34 */ { 1714, 11, 17, 13, 1, -15 }, +/* '5' 0x35 */ { 1738, 11, 17, 13, 1, -15 }, +/* '6' 0x36 */ { 1762, 11, 17, 13, 1, -15 }, +/* '7' 0x37 */ { 1786, 11, 17, 13, 1, -15 }, +/* '8' 0x38 */ { 1810, 11, 17, 13, 1, -15 }, +/* '9' 0x39 */ { 1834, 11, 17, 13, 1, -15 }, +/* ':' 0x3A */ { 1858, 2, 13, 6, 2, -11 }, +/* ';' 0x3B */ { 1862, 2, 16, 6, 2, -10 }, +/* '<' 0x3C */ { 1866, 12, 11, 14, 1, -9 }, +/* '=' 0x3D */ { 1883, 12, 6, 14, 1, -7 }, +/* '>' 0x3E */ { 1892, 12, 11, 14, 1, -9 }, +/* '?' 0x3F */ { 1909, 10, 18, 13, 2, -16 }, +/* '@' 0x40 */ { 1932, 22, 21, 24, 1, -16 }, +/* 'A' 0x41 */ { 1990, 14, 18, 16, 1, -16 }, +/* 'B' 0x42 */ { 2022, 13, 18, 16, 2, -16 }, +/* 'C' 0x43 */ { 2052, 15, 18, 17, 1, -16 }, +/* 'D' 0x44 */ { 2086, 14, 18, 17, 2, -16 }, +/* 'E' 0x45 */ { 2118, 12, 18, 15, 2, -16 }, +/* 'F' 0x46 */ { 2145, 11, 18, 14, 2, -16 }, +/* 'G' 0x47 */ { 2170, 16, 18, 18, 1, -16 }, +/* 'H' 0x48 */ { 2206, 13, 18, 17, 2, -16 }, +/* 'I' 0x49 */ { 2236, 2, 18, 7, 2, -16 }, +/* 'J' 0x4A */ { 2241, 9, 18, 13, 1, -16 }, +/* 'K' 0x4B */ { 2262, 13, 18, 16, 2, -16 }, +/* 'L' 0x4C */ { 2292, 10, 18, 14, 2, -16 }, +/* 'M' 0x4D */ { 2315, 16, 18, 20, 2, -16 }, +/* 'N' 0x4E */ { 2351, 13, 18, 18, 2, -16 }, +/* 'O' 0x4F */ { 2381, 17, 18, 19, 1, -16 }, +/* 'P' 0x50 */ { 2420, 12, 18, 16, 2, -16 }, +/* 'Q' 0x51 */ { 2447, 17, 19, 19, 1, -16 }, +/* 'R' 0x52 */ { 2488, 14, 18, 17, 2, -16 }, +/* 'S' 0x53 */ { 2520, 14, 18, 16, 1, -16 }, +/* 'T' 0x54 */ { 2552, 12, 18, 15, 1, -16 }, +/* 'U' 0x55 */ { 2579, 13, 18, 17, 2, -16 }, +/* 'V' 0x56 */ { 2609, 14, 18, 15, 1, -16 }, +/* 'W' 0x57 */ { 2641, 22, 18, 22, 0, -16 }, +/* 'X' 0x58 */ { 2691, 14, 18, 16, 1, -16 }, +/* 'Y' 0x59 */ { 2723, 14, 18, 16, 1, -16 }, +/* 'Z' 0x5A */ { 2755, 13, 18, 15, 1, -16 }, +/* '[' 0x5B */ { 2785, 4, 23, 7, 2, -16 }, +/* '\' 0x5C */ { 2797, 7, 18, 7, 0, -16 }, +/* ']' 0x5D */ { 2813, 4, 23, 7, 1, -16 }, +/* '^' 0x5E */ { 2825, 9, 9, 11, 1, -15 }, +/* '_' 0x5F */ { 2836, 15, 1, 13, -1, 5 }, +/* '`' 0x60 */ { 2838, 5, 4, 6, 1, -16 }, +/* 'a' 0x61 */ { 2841, 12, 13, 13, 1, -11 }, +/* 'b' 0x62 */ { 2861, 12, 18, 13, 1, -16 }, +/* 'c' 0x63 */ { 2888, 10, 13, 12, 1, -11 }, +/* 'd' 0x64 */ { 2905, 11, 18, 13, 1, -16 }, +/* 'e' 0x65 */ { 2930, 11, 13, 13, 1, -11 }, +/* 'f' 0x66 */ { 2948, 5, 18, 7, 1, -16 }, +/* 'g' 0x67 */ { 2960, 11, 18, 13, 1, -11 }, +/* 'h' 0x68 */ { 2985, 10, 18, 13, 1, -16 }, +/* 'i' 0x69 */ { 3008, 2, 18, 5, 2, -16 }, +/* 'j' 0x6A */ { 3013, 4, 23, 6, 0, -16 }, +/* 'k' 0x6B */ { 3025, 10, 18, 12, 1, -16 }, +/* 'l' 0x6C */ { 3048, 2, 18, 5, 1, -16 }, +/* 'm' 0x6D */ { 3053, 17, 13, 19, 1, -11 }, +/* 'n' 0x6E */ { 3081, 10, 13, 13, 1, -11 }, +/* 'o' 0x6F */ { 3098, 11, 13, 13, 1, -11 }, +/* 'p' 0x70 */ { 3116, 12, 17, 13, 1, -11 }, +/* 'q' 0x71 */ { 3142, 11, 17, 13, 1, -11 }, +/* 'r' 0x72 */ { 3166, 6, 13, 8, 1, -11 }, +/* 's' 0x73 */ { 3176, 10, 13, 12, 1, -11 }, +/* 't' 0x74 */ { 3193, 5, 16, 7, 1, -14 }, +/* 'u' 0x75 */ { 3203, 10, 13, 13, 1, -11 }, +/* 'v' 0x76 */ { 3220, 11, 13, 12, 0, -11 }, +/* 'w' 0x77 */ { 3238, 17, 13, 17, 0, -11 }, +/* 'x' 0x78 */ { 3266, 10, 13, 11, 1, -11 }, +/* 'y' 0x79 */ { 3283, 11, 18, 11, 0, -11 }, +/* 'z' 0x7A */ { 3308, 10, 13, 12, 1, -11 }, +/* '{' 0x7B */ { 3325, 5, 23, 8, 1, -16 }, +/* '|' 0x7C */ { 3340, 2, 23, 6, 2, -16 }, +/* '}' 0x7D */ { 3346, 5, 23, 8, 2, -16 }, +/* '~' 0x7E */ { 3361, 10, 5, 12, 1, -9 }, +/* 0x7F */ { 3368, 0, 0, 0, 0, 0 }, +/* 0x80 */ { 3368, 14, 17, 16, 1, -15 }, +/* 0x81 */ { 3398, 0, 0, 8, 0, 0 }, +/* 0x82 */ { 3398, 2, 5, 6, 2, 0 }, +/* 0x83 */ { 3400, 6, 23, 7, 0, -16 }, +/* 0x84 */ { 3418, 6, 5, 10, 2, 0 }, +/* 0x85 */ { 3422, 12, 2, 16, 2, 0 }, +/* 0x86 */ { 3425, 10, 21, 13, 2, -15 }, +/* 0x87 */ { 3452, 10, 20, 13, 2, -15 }, +/* 0x88 */ { 3477, 7, 4, 8, 0, -16 }, +/* 0x89 */ { 3481, 23, 18, 24, 0, -16 }, +/* 0x8A */ { 3533, 14, 21, 16, 1, -19 }, +/* 0x8B */ { 3570, 3, 8, 6, 1, -9 }, +/* 0x8C */ { 3573, 22, 18, 24, 1, -16 }, +/* 0x8D */ { 3623, 0, 0, 8, 0, 0 }, +/* 0x8E */ { 3623, 13, 21, 15, 1, -19 }, +/* 0x8F */ { 3658, 0, 0, 8, 0, 0 }, +/* 0x90 */ { 3658, 0, 0, 8, 0, 0 }, +/* 0x91 */ { 3658, 2, 6, 6, 2, -16 }, +/* 0x92 */ { 3660, 2, 6, 6, 2, -16 }, +/* 0x93 */ { 3662, 6, 6, 10, 2, -16 }, +/* 0x94 */ { 3667, 6, 6, 10, 2, -16 }, +/* 0x95 */ { 3672, 6, 6, 10, 2, -9 }, +/* 0x96 */ { 3677, 10, 2, 12, 1, -6 }, +/* 0x97 */ { 3680, 22, 2, 24, 1, -6 }, +/* 0x98 */ { 3686, 7, 3, 8, 0, -16 }, +/* 0x99 */ { 3689, 22, 13, 24, 2, -16 }, +/* 0x9A */ { 3725, 10, 18, 12, 1, -16 }, +/* 0x9B */ { 3748, 3, 8, 6, 2, -8 }, +/* 0x9C */ { 3751, 20, 13, 22, 1, -11 }, +/* 0x9D */ { 3784, 0, 0, 8, 0, 0 }, +/* 0x9E */ { 3784, 10, 18, 12, 1, -16 }, +/* 0x9F */ { 3807, 14, 21, 16, 1, -19 }, +/* 0xA0 */ { 3844, 0, 0, 7, 0, 0 }, +/* 0xA1 */ { 3844, 2, 18, 8, 3, -11 }, +/* 0xA2 */ { 3849, 11, 17, 13, 1, -13 }, +/* 0xA3 */ { 3873, 12, 18, 13, 0, -16 }, +/* 0xA4 */ { 3900, 9, 9, 13, 2, -11 }, +/* 0xA5 */ { 3911, 12, 17, 13, 1, -15 }, +/* 0xA6 */ { 3937, 2, 23, 6, 2, -16 }, +/* 0xA7 */ { 3943, 11, 23, 13, 1, -16 }, +/* 0xA8 */ { 3975, 6, 2, 8, 1, -15 }, +/* 0xA9 */ { 3977, 18, 17, 19, 1, -15 }, +/* 0xAA */ { 4016, 7, 11, 9, 1, -16 }, +/* 0xAB */ { 4026, 8, 8, 12, 2, -9 }, +/* 0xAC */ { 4034, 12, 6, 14, 1, -7 }, +/* 0xAD */ { 4043, 6, 2, 8, 1, -6 }, +/* 0xAE */ { 4045, 18, 17, 19, 1, -15 }, +/* 0xAF */ { 4084, 6, 2, 8, 1, -15 }, +/* 0xB0 */ { 4086, 7, 8, 15, 4, -15 }, +/* 0xB1 */ { 4093, 12, 15, 14, 1, -13 }, +/* 0xB2 */ { 4116, 7, 10, 8, 1, -17 }, +/* 0xB3 */ { 4125, 7, 10, 8, 1, -17 }, +/* 0xB4 */ { 4134, 5, 4, 8, 2, -16 }, +/* 0xB5 */ { 4137, 12, 17, 13, 2, -11 }, +/* 0xB6 */ { 4163, 11, 21, 13, 2, -16 }, +/* 0xB7 */ { 4192, 2, 2, 6, 2, -6 }, +/* 0xB8 */ { 4193, 6, 5, 8, 1, 2 }, +/* 0xB9 */ { 4197, 3, 10, 8, 3, -18 }, +/* 0xBA */ { 4201, 6, 11, 9, 1, -16 }, +/* 0xBB */ { 4210, 8, 8, 12, 2, -8 }, +/* 0xBC */ { 4218, 17, 17, 21, 3, -15 }, +/* 0xBD */ { 4255, 18, 18, 21, 3, -16 }, +/* 0xBE */ { 4296, 19, 18, 21, 1, -16 }, +/* 0xBF */ { 4339, 9, 18, 13, 3, -11 }, +/* 0xC0 */ { 4360, 14, 22, 16, 1, -20 }, +/* 0xC1 */ { 4399, 14, 22, 16, 1, -20 }, +/* 0xC2 */ { 4438, 14, 22, 16, 1, -20 }, +/* 0xC3 */ { 4477, 14, 22, 16, 1, -20 }, +/* 0xC4 */ { 4516, 14, 21, 16, 1, -19 }, +/* 0xC5 */ { 4553, 14, 24, 16, 1, -22 }, +/* 0xC6 */ { 4595, 22, 18, 24, 0, -16 }, +/* 0xC7 */ { 4645, 15, 23, 17, 1, -16 }, +/* 0xC8 */ { 4689, 12, 22, 15, 2, -20 }, +/* 0xC9 */ { 4722, 12, 22, 15, 2, -20 }, +/* 0xCA */ { 4755, 12, 22, 15, 2, -20 }, +/* 0xCB */ { 4788, 12, 21, 15, 2, -19 }, +/* 0xCC */ { 4820, 4, 22, 7, 0, -20 }, +/* 0xCD */ { 4831, 4, 22, 7, 1, -20 }, +/* 0xCE */ { 4842, 6, 22, 7, 0, -20 }, +/* 0xCF */ { 4859, 7, 21, 7, 0, -19 }, +/* 0xD0 */ { 4878, 15, 18, 17, 1, -16 }, +/* 0xD1 */ { 4912, 13, 22, 18, 2, -20 }, +/* 0xD2 */ { 4948, 17, 22, 19, 1, -20 }, +/* 0xD3 */ { 4995, 17, 22, 19, 1, -20 }, +/* 0xD4 */ { 5042, 17, 22, 19, 1, -20 }, +/* 0xD5 */ { 5089, 17, 22, 19, 1, -20 }, +/* 0xD6 */ { 5136, 17, 21, 19, 1, -19 }, +/* 0xD7 */ { 5181, 8, 9, 14, 3, -8 }, +/* 0xD8 */ { 5190, 17, 18, 19, 1, -16 }, +/* 0xD9 */ { 5229, 13, 22, 17, 2, -20 }, +/* 0xDA */ { 5265, 13, 22, 17, 2, -20 }, +/* 0xDB */ { 5301, 13, 22, 17, 2, -20 }, +/* 0xDC */ { 5337, 13, 21, 17, 2, -19 }, +/* 0xDD */ { 5372, 14, 22, 16, 1, -20 }, +/* 0xDE */ { 5411, 12, 18, 15, 2, -16 }, +/* 0xDF */ { 5438, 11, 18, 14, 2, -16 }, +/* 0xE0 */ { 5463, 12, 18, 13, 1, -16 }, +/* 0xE1 */ { 5490, 12, 18, 13, 1, -16 }, +/* 0xE2 */ { 5517, 12, 18, 13, 1, -16 }, +/* 0xE3 */ { 5544, 12, 18, 13, 1, -16 }, +/* 0xE4 */ { 5571, 12, 17, 13, 1, -15 }, +/* 0xE5 */ { 5597, 12, 19, 13, 1, -17 }, +/* 0xE6 */ { 5626, 19, 13, 21, 1, -11 }, +/* 0xE7 */ { 5657, 10, 18, 12, 1, -11 }, +/* 0xE8 */ { 5680, 11, 18, 13, 1, -16 }, +/* 0xE9 */ { 5705, 11, 18, 13, 1, -16 }, +/* 0xEA */ { 5730, 11, 18, 13, 1, -16 }, +/* 0xEB */ { 5755, 11, 17, 13, 1, -15 }, +/* 0xEC */ { 5779, 4, 18, 5, 1, -16 }, +/* 0xED */ { 5788, 5, 18, 5, 0, -16 }, +/* 0xEE */ { 5800, 6, 18, 6, 0, -16 }, +/* 0xEF */ { 5814, 6, 17, 6, 0, -15 }, +/* 0xF0 */ { 5827, 11, 18, 13, 1, -16 }, +/* 0xF1 */ { 5852, 10, 18, 13, 1, -16 }, +/* 0xF2 */ { 5875, 11, 18, 13, 1, -16 }, +/* 0xF3 */ { 5900, 11, 18, 13, 1, -16 }, +/* 0xF4 */ { 5925, 11, 18, 13, 1, -16 }, +/* 0xF5 */ { 5950, 11, 18, 13, 1, -16 }, +/* 0xF6 */ { 5975, 11, 17, 13, 1, -15 }, +/* 0xF7 */ { 5999, 12, 11, 14, 1, -9 }, +/* 0xF8 */ { 6016, 11, 13, 13, 1, -11 }, +/* 0xF9 */ { 6034, 10, 18, 13, 1, -16 }, +/* 0xFA */ { 6057, 10, 18, 13, 1, -16 }, +/* 0xFB */ { 6080, 10, 18, 13, 1, -16 }, +/* 0xFC */ { 6103, 10, 17, 13, 1, -15 }, +/* 0xFD */ { 6125, 11, 23, 11, 0, -16 }, +/* 0xFE */ { 6157, 12, 21, 13, 1, -15 }, +/* 0xFF */ { 6189, 11, 22, 11, 0, -15 }, +}; + +const GFXfont FreeSans12pt_Win1252 PROGMEM = { +(uint8_t*)FreeSans12pt_Win1252Bitmaps, +(GFXglyph*)FreeSans12pt_Win1252Glyphs, +0x01, 0xFF, 19 +}; diff --git a/src/graphics/niche/Fonts/FreeSans6pt_Win1250.h b/src/graphics/niche/Fonts/FreeSans6pt_Win1250.h index aee777783..4042bd835 100644 --- a/src/graphics/niche/Fonts/FreeSans6pt_Win1250.h +++ b/src/graphics/niche/Fonts/FreeSans6pt_Win1250.h @@ -1,457 +1,527 @@ +// trunk-ignore-all(clang-format) #pragma once +/* PROPERTIES + +FONT_NAME FreeSans6pt_Win1250 +*/ const uint8_t FreeSans6pt_Win1250Bitmaps[] PROGMEM = { - /* ' ' 0x20 */ - 0xFC, 0x80, /* '!' 0x21 */ - 0xB6, 0x80, /* '"' 0x22 */ - 0x24, 0x51, 0xF9, 0x42, 0x9F, 0x92, 0x28, /* '#' 0x23 */ - 0x10, 0xE5, 0x55, 0x50, 0xE1, 0x65, 0x55, 0xE1, 0x00, /* '$' 0x24 */ - 0x71, 0x24, 0x89, 0x22, 0x50, 0x74, 0x02, 0x70, 0xA4, 0x49, 0x11, 0xC0, /* '%' 0x25 */ - 0x71, 0x24, 0x9C, 0x62, 0x58, 0xA7, 0xF4, /* '&' 0x26 */ - 0xE0, /* ''' 0x27 */ - 0x5A, 0xAA, 0x94, /* '(' 0x28 */ - 0x89, 0x12, 0x49, 0x29, 0x00, /* ')' 0x29 */ - 0x5E, 0x80, /* '*' 0x2A */ - 0x21, 0x3E, 0x42, 0x00, /* '+' 0x2B */ - 0xE0, /* ',' 0x2C */ - 0xC0, /* '-' 0x2D */ - 0x80, /* '.' 0x2E */ - 0x24, 0xA4, 0xA4, 0x80, /* '/' 0x2F */ - 0x76, 0xE3, 0x18, 0xC6, 0x3B, 0x70, /* '0' 0x30 */ - 0x27, 0x92, 0x49, 0x20, /* '1' 0x31 */ - 0x79, 0x10, 0x41, 0x08, 0xC6, 0x10, 0xFC, /* '2' 0x32 */ - 0x79, 0x30, 0x43, 0x18, 0x10, 0x71, 0x78, /* '3' 0x33 */ - 0x08, 0x61, 0x8A, 0x49, 0x2F, 0xC2, 0x08, /* '4' 0x34 */ - 0xFC, 0x21, 0xE8, 0x84, 0x31, 0xF0, /* '5' 0x35 */ - 0x74, 0x61, 0xE8, 0xC6, 0x31, 0x70, /* '6' 0x36 */ - 0xF8, 0x44, 0x22, 0x11, 0x08, 0x40, /* '7' 0x37 */ - 0x39, 0x34, 0x53, 0x39, 0x1C, 0x51, 0x38, /* '8' 0x38 */ - 0x39, 0x3C, 0x71, 0x4C, 0xF0, 0x53, 0x78, /* '9' 0x39 */ - 0x82, /* ':' 0x3A */ - 0x87, /* ';' 0x3B */ - 0x3E, 0x30, 0x60, 0x80, /* '<' 0x3C */ - 0xF8, 0x3E, /* '=' 0x3D */ - 0xE0, 0xC6, 0xC8, 0x00, /* '>' 0x3E */ - 0x74, 0x42, 0x11, 0x10, 0x80, 0x20, /* '?' 0x3F */ - 0x0F, 0x86, 0x19, 0x9A, 0xA4, 0xD9, 0x13, 0x22, 0x56, 0xDA, 0x6E, 0x60, 0x06, 0x00, 0x3C, 0x00, /* '@' 0x40 */ - 0x18, 0x18, 0x24, 0x24, 0x24, 0x7E, 0x42, 0x42, 0xC3, /* 'A' 0x41 */ - 0xFA, 0x18, 0x61, 0xFA, 0x18, 0x61, 0xFC, /* 'B' 0x42 */ - 0x3E, 0x63, 0x40, 0x40, 0xC0, 0x40, 0x41, 0x63, 0x3E, /* 'C' 0x43 */ - 0xF9, 0x0A, 0x1C, 0x18, 0x30, 0x61, 0xC2, 0xF8, /* 'D' 0x44 */ - 0xFE, 0x08, 0x20, 0xFE, 0x08, 0x20, 0xFC, /* 'E' 0x45 */ - 0xFE, 0x08, 0x20, 0xFA, 0x08, 0x20, 0x80, /* 'F' 0x46 */ - 0x1E, 0x61, 0x40, 0x40, 0xC7, 0x41, 0x41, 0x63, 0x1D, /* 'G' 0x47 */ - 0x83, 0x06, 0x0C, 0x1F, 0xF0, 0x60, 0xC1, 0x82, /* 'H' 0x48 */ - 0xFF, 0x80, /* 'I' 0x49 */ - 0x08, 0x42, 0x10, 0x87, 0x29, 0x70, /* 'J' 0x4A */ - 0x85, 0x12, 0x45, 0x0D, 0x13, 0x22, 0x42, 0x86, /* 'K' 0x4B */ - 0x84, 0x21, 0x08, 0x42, 0x10, 0xF8, /* 'L' 0x4C */ - 0xC3, 0xC3, 0xC3, 0xA5, 0xA5, 0xA5, 0x99, 0x99, 0x99, /* 'M' 0x4D */ - 0x83, 0x86, 0x8D, 0x19, 0x33, 0x62, 0xC3, 0x86, /* 'N' 0x4E */ - 0x1E, 0x31, 0x90, 0x68, 0x1C, 0x0A, 0x05, 0x06, 0xC6, 0x1E, 0x00, /* 'O' 0x4F */ - 0xFA, 0x18, 0x61, 0xFA, 0x08, 0x20, 0x80, /* 'P' 0x50 */ - 0x1E, 0x31, 0x90, 0x68, 0x1C, 0x0A, 0x05, 0x16, 0xC6, 0x1F, 0x00, 0x40, /* 'Q' 0x51 */ - 0xFD, 0x0E, 0x1C, 0x2F, 0x90, 0xA1, 0x42, 0x86, /* 'R' 0x52 */ - 0x7A, 0x18, 0x30, 0x78, 0x38, 0x61, 0x78, /* 'S' 0x53 */ - 0xFE, 0x20, 0x40, 0x81, 0x02, 0x04, 0x08, 0x10, /* 'T' 0x54 */ - 0x83, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xE2, 0x78, /* 'U' 0x55 */ - 0xC2, 0x85, 0x0B, 0x22, 0x44, 0x8E, 0x0C, 0x18, /* 'V' 0x56 */ - 0xC4, 0x28, 0xCD, 0x29, 0x25, 0x24, 0xA4, 0x52, 0x8C, 0x61, 0x8C, 0x31, 0x80, /* 'W' 0x57 */ - 0x87, 0x34, 0x8C, 0x30, 0xC4, 0xA3, 0x84, /* 'X' 0x58 */ - 0xC3, 0x42, 0x24, 0x34, 0x18, 0x08, 0x08, 0x08, 0x08, /* 'Y' 0x59 */ - 0x7E, 0x0C, 0x30, 0x41, 0x06, 0x18, 0x20, 0xFE, /* 'Z' 0x5A */ - 0xEA, 0xAA, 0xAB, /* '[' 0x5B */ - 0x92, 0x24, 0x89, 0x20, /* '\' 0x5C */ - 0xD5, 0x55, 0x57, /* ']' 0x5D */ - 0x46, 0xA9, /* '^' 0x5E */ - 0xFE, /* '_' 0x5F */ - 0x80, /* '`' 0x60 */ - 0x79, 0x20, 0x4F, 0xC6, 0x37, 0x40, /* 'a' 0x61 */ - 0x84, 0x3D, 0x18, 0xC6, 0x31, 0xF0, /* 'b' 0x62 */ - 0x39, 0x3C, 0x20, 0xC1, 0x33, 0x80, /* 'c' 0x63 */ - 0x04, 0x13, 0xD3, 0xC6, 0x1C, 0x53, 0x3C, /* 'd' 0x64 */ - 0x39, 0x38, 0x7F, 0x81, 0x13, 0x80, /* 'e' 0x65 */ - 0x6B, 0xA4, 0x92, 0x40, /* 'f' 0x66 */ - 0x35, 0x3C, 0x61, 0xC5, 0x33, 0x41, 0x4D, 0xE0, /* 'g' 0x67 */ - 0x84, 0x3D, 0x38, 0xC6, 0x31, 0x88, /* 'h' 0x68 */ - 0xBF, 0x80, /* 'i' 0x69 */ - 0x45, 0x55, 0x57, /* 'j' 0x6A */ - 0x84, 0x25, 0x4E, 0x52, 0xD2, 0x88, /* 'k' 0x6B */ - 0xFF, 0x80, /* 'l' 0x6C */ - 0xF7, 0x99, 0x91, 0x91, 0x91, 0x91, 0x91, /* 'm' 0x6D */ - 0xF4, 0x63, 0x18, 0xC6, 0x20, /* 'n' 0x6E */ - 0x39, 0x3C, 0x61, 0xC5, 0x33, 0x80, /* 'o' 0x6F */ - 0xF4, 0x63, 0x18, 0xC7, 0xD0, 0x80, /* 'p' 0x70 */ - 0x3D, 0x3C, 0x61, 0xC5, 0x37, 0x41, 0x04, /* 'q' 0x71 */ - 0xF2, 0x49, 0x20, /* 'r' 0x72 */ - 0x7A, 0x50, 0xE0, 0xE5, 0xE0, /* 's' 0x73 */ - 0x5D, 0x24, 0x93, /* 't' 0x74 */ - 0x8C, 0x63, 0x18, 0xCF, 0xA0, /* 'u' 0x75 */ - 0x85, 0x24, 0x92, 0x30, 0xC3, 0x00, /* 'v' 0x76 */ - 0x89, 0x59, 0x59, 0x55, 0x56, 0x26, 0x26, /* 'w' 0x77 */ - 0x4A, 0x4C, 0x43, 0x27, 0x20, /* 'x' 0x78 */ - 0x8A, 0x52, 0xA5, 0x18, 0x84, 0x22, 0x00, /* 'y' 0x79 */ - 0x78, 0x44, 0x46, 0x23, 0xE0, /* 'z' 0x7A */ - 0x6A, 0xAA, 0xA9, /* '{' 0x7B */ - 0xFF, 0xE0, /* '|' 0x7C */ - 0x95, 0x55, 0x56, /* '}' 0x7D */ - 0x66, 0x60, /* '~' 0x7E */ - 0xFF, 0xC0, 0x67, 0x34, 0x58, 0x4C, 0x46, 0x03, 0x11, 0x80, 0xFF, 0xC0, /* 0x7F */ - 0x1C, 0x45, 0x07, 0xE4, 0x1F, 0x10, 0x10, 0x1E, /* 0x80 */ - /* 0x81 */ - 0xE0, /* 0x82 */ - /* 0x83 */ - 0xB6, 0x80, /* 0x84 */ - 0xA8, /* 0x85 */ - 0x21, 0x09, 0xF2, 0x10, 0x84, 0x21, 0x08, /* 0x86 */ - 0x21, 0x09, 0xF2, 0x10, 0x84, 0xF9, 0x08, /* 0x87 */ - /* 0x88 */ - 0x62, 0x09, 0x40, 0x98, 0x06, 0x80, 0x10, 0x01, 0x66, 0x29, 0x92, 0x99, 0x06, 0x60, /* 0x89 */ - 0x28, 0x47, 0xA1, 0x83, 0x07, 0x83, 0x87, 0x17, 0x80, /* 0x8A */ - 0x64, /* 0x8B */ - 0x10, 0x87, 0xA1, 0x83, 0x07, 0x83, 0x87, 0x17, 0x80, /* 0x8C */ - 0x28, 0x4F, 0xC4, 0x10, 0x41, 0x04, 0x10, 0x40, /* 0x8D */ - 0x14, 0x11, 0xF8, 0x30, 0xC1, 0x04, 0x18, 0x61, 0xFC, /* 0x8E */ - 0x08, 0x21, 0xF8, 0x30, 0xC1, 0x04, 0x18, 0x61, 0xFC, /* 0x8F */ - /* 0x90 */ - 0xE0, /* 0x91 */ - 0xE0, /* 0x92 */ - 0xB6, 0x80, /* 0x93 */ - 0xB6, 0x80, /* 0x94 */ - 0xFF, 0x80, /* 0x95 */ - 0xFC, /* 0x96 */ - 0xFF, 0xF0, /* 0x97 */ - /* 0x98 */ - 0xE6, 0x28, 0xCD, 0x19, 0xA3, 0x34, 0x6A, 0x8B, 0x51, 0x68, /* 0x99 */ - 0x52, 0x69, 0x8E, 0x19, 0x60, /* 0x9A */ - 0x98, /* 0x9B */ - 0x24, 0x06, 0x98, 0xE1, 0x96, /* 0x9C */ - 0x15, 0xE4, 0x44, 0x44, 0x60, /* 0x9D */ - 0x51, 0x00, 0xF0, 0x88, 0x8C, 0x47, 0xC0, /* 0x9E */ - 0x11, 0x00, 0xF0, 0x88, 0x8C, 0x47, 0xC0, /* 0x9F */ - /* 0xA0 */ - 0xA8, /* 0xA1 */ - 0x96, /* 0xA2 */ - 0x41, 0x05, 0x18, 0x43, 0x04, 0x10, 0x7C, /* 0xA3 */ - 0xFC, 0x63, 0xF0, /* 0xA4 */ - 0x30, 0x38, 0x28, 0x48, 0x4C, 0x7C, 0x84, 0x86, 0x82, 0x04, 0x07, /* 0xA5 */ - 0xF9, 0xF0, /* 0xA6 */ - 0x32, 0x91, 0xC9, 0x47, 0x26, 0x14, 0xA4, 0xC0, /* 0xA7 */ - 0xA0, /* 0xA8 */ - 0x3E, 0x3F, 0xB8, 0xF4, 0x1A, 0x0D, 0x17, 0x76, 0xC6, 0x3E, 0x00, /* 0xA9 */ - 0x7A, 0x18, 0x30, 0x78, 0x38, 0x61, 0x78, 0xC1, 0x0C, /* 0xAA */ - 0x5A, 0xA5, /* 0xAB */ - 0xFC, 0x10, 0x40, /* 0xAC */ - /* 0xAD */ - 0x3E, 0x31, 0xB7, 0x72, 0x99, 0xCC, 0xC7, 0x56, 0xC6, 0x3E, 0x00, /* 0xAE */ - 0x18, 0x31, 0xF8, 0x30, 0xC1, 0x04, 0x18, 0x61, 0xFC, /* 0xAF */ - 0x69, 0x96, /* 0xB0 */ - 0x21, 0x3E, 0x42, 0x03, 0xE0, /* 0xB1 */ - 0x9C, /* 0xB2 */ - 0x49, 0x35, 0x92, 0x40, /* 0xB3 */ - 0x80, /* 0xB4 */ - 0x8A, 0x28, 0xA2, 0x8A, 0x6E, 0xE0, 0x80, /* 0xB5 */ - 0x7F, 0xAE, 0xBA, 0x68, 0xA2, 0x8A, 0x28, 0xA0, /* 0xB6 */ - 0x80, /* 0xB7 */ - 0x67, 0x80, /* 0xB8 */ - 0x78, 0x84, 0x04, 0x3C, 0xC4, 0x8C, 0x76, 0x04, 0x07, /* 0xB9 */ - 0x69, 0x8E, 0x19, 0x66, 0x26, /* 0xBA */ - 0xA5, 0x5A, /* 0xBB */ - 0xA5, 0x21, 0x08, 0x42, 0x10, 0xF8, /* 0xBC */ - 0xA0, /* 0xBD */ - 0xBA, 0x49, 0x24, 0x90, /* 0xBE */ - 0x31, 0x9E, 0x11, 0x11, 0x88, 0xF8, /* 0xBF */ - 0x10, 0x43, 0xE4, 0x28, 0x50, 0xBE, 0x42, 0x85, 0x0C, /* 0xC0 */ - 0x08, 0x10, 0x00, 0x18, 0x3C, 0x24, 0x24, 0x7E, 0x42, 0xC3, /* 0xC1 */ - 0x18, 0x24, 0x00, 0x18, 0x3C, 0x24, 0x24, 0x7E, 0x42, 0xC3, /* 0xC2 */ - 0x24, 0x18, 0x00, 0x18, 0x3C, 0x24, 0x24, 0x7E, 0x42, 0xC3, /* 0xC3 */ - 0x24, 0x00, 0x18, 0x3C, 0x24, 0x24, 0x7E, 0x42, 0x42, 0xC3, /* 0xC4 */ - 0x11, 0x21, 0x08, 0x42, 0x10, 0x87, 0xC0, /* 0xC5 */ - 0x08, 0x20, 0x01, 0xE4, 0x30, 0x20, 0x40, 0x82, 0x8C, 0xF0, /* 0xC6 */ - 0x3E, 0x61, 0xC0, 0x80, 0x80, 0x80, 0xC1, 0x63, 0x3E, 0x0C, 0x04, 0x1C, /* 0xC7 */ - 0x28, 0x20, 0x01, 0xE4, 0x30, 0x20, 0x40, 0x82, 0x8C, 0xF0, /* 0xC8 */ - 0x08, 0x40, 0x3F, 0x82, 0x0F, 0xA0, 0x83, 0xF0, /* 0xC9 */ - 0xFD, 0x02, 0x04, 0x0F, 0xD0, 0x20, 0x40, 0xFC, 0x10, 0x38, /* 0xCA */ - 0x28, 0x0F, 0xE0, 0x83, 0xE8, 0x20, 0x83, 0xF0, /* 0xCB */ - 0x28, 0x40, 0x3F, 0x82, 0x0F, 0xA0, 0x82, 0x0F, 0xC0, /* 0xCC */ - 0x62, 0xAA, 0xA0, /* 0xCD */ - 0x54, 0x24, 0x92, 0x48, /* 0xCE */ - 0x50, 0x43, 0xE4, 0x28, 0x30, 0x60, 0xC1, 0x85, 0xF0, /* 0xCF */ - 0x7C, 0x42, 0x41, 0x41, 0xF1, 0x41, 0x41, 0x42, 0x7C, /* 0xD0 */ - 0x08, 0x23, 0x0F, 0x1B, 0x32, 0x66, 0xC7, 0x87, 0x04, /* 0xD1 */ - 0x28, 0x23, 0x0F, 0x1B, 0x32, 0x66, 0xC7, 0x87, 0x04, /* 0xD2 */ - 0x04, 0x04, 0x0F, 0x8C, 0x6C, 0x1C, 0x06, 0x03, 0x83, 0x63, 0x1F, 0x00, /* 0xD3 */ - 0x08, 0x0A, 0x00, 0x07, 0xC6, 0x36, 0x0E, 0x03, 0x01, 0xC1, 0xB1, 0x8F, 0x80, /* 0xD4 */ - 0x0A, 0x0A, 0x00, 0x07, 0xC6, 0x36, 0x0E, 0x03, 0x01, 0xC1, 0xB1, 0x8F, 0x80, /* 0xD5 */ - 0x14, 0x00, 0x00, 0x07, 0xC6, 0x36, 0x0E, 0x03, 0x01, 0xC1, 0xB1, 0x8F, 0x80, /* 0xD6 */ - 0x8A, 0x88, 0xA8, 0x80, /* 0xD7 */ - 0x50, 0x43, 0xE4, 0x28, 0x50, 0xBE, 0x42, 0x85, 0x0C, /* 0xD8 */ - 0x10, 0x52, 0x4C, 0x18, 0x30, 0x60, 0xC1, 0xC6, 0xF8, /* 0xD9 */ - 0x08, 0x22, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0xC6, 0xF8, /* 0xDA */ - 0x14, 0x52, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0xC6, 0xF8, /* 0xDB */ - 0x29, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0xC6, 0xF8, /* 0xDC */ - 0x09, 0x25, 0x12, 0x22, 0x87, 0x04, 0x08, 0x10, 0x20, /* 0xDD */ - 0xFC, 0x41, 0x04, 0x10, 0x41, 0x04, 0x10, 0x60, 0x8E, /* 0xDE */ - 0x7A, 0x18, 0x61, 0x8A, 0x18, 0x61, 0xB8, /* 0xDF */ - 0x42, 0xE9, 0x24, 0x80, /* 0xE0 */ - 0x10, 0x40, 0x03, 0xC8, 0x40, 0x8F, 0x62, 0x8C, 0xEC, /* 0xE1 */ - 0x10, 0x50, 0x03, 0xC8, 0x40, 0x8F, 0x62, 0x8C, 0xEC, /* 0xE2 */ - 0x48, 0x60, 0x03, 0xC8, 0x40, 0x8F, 0x62, 0x8C, 0xEC, /* 0xE3 */ - 0x28, 0x01, 0xE4, 0x20, 0x47, 0xB1, 0x46, 0x76, /* 0xE4 */ - 0x62, 0xAA, 0xA0, /* 0xE5 */ - 0x10, 0x80, 0x1E, 0xC6, 0x08, 0x20, 0xC5, 0xE0, /* 0xE6 */ - 0x7B, 0x18, 0x20, 0x83, 0x17, 0x8C, 0x11, 0xC0, /* 0xE7 */ - 0x28, 0x40, 0x1E, 0xC6, 0x08, 0x20, 0xC5, 0xE0, /* 0xE8 */ - 0x10, 0x80, 0x1E, 0xCE, 0x1F, 0xE0, 0xC5, 0xE0, /* 0xE9 */ - 0x7B, 0x38, 0x7F, 0x83, 0x37, 0x84, 0x1C, /* 0xEA */ - 0x28, 0x07, 0xB3, 0x87, 0xF8, 0x31, 0x78, /* 0xEB */ - 0x28, 0x40, 0x1E, 0xCE, 0x1F, 0xE0, 0xC5, 0xE0, /* 0xEC */ - 0x62, 0xAA, 0xA0, /* 0xED */ - 0x54, 0x24, 0x92, 0x48, /* 0xEE */ - 0x02, 0x0C, 0x13, 0xEC, 0xD0, 0xA1, 0x42, 0xCC, 0xE8, /* 0xEF */ - 0x04, 0x1D, 0xD6, 0x68, 0x50, 0xA1, 0x66, 0x74, /* 0xF0 */ - 0x11, 0x01, 0x6C, 0xC6, 0x31, 0x8C, 0x40, /* 0xF1 */ - 0x20, 0x81, 0x6C, 0xC6, 0x31, 0x8C, 0x40, /* 0xF2 */ - 0x10, 0x80, 0x1E, 0xCE, 0x18, 0x61, 0xCD, 0xE0, /* 0xF3 */ - 0x10, 0xA0, 0x1E, 0xCE, 0x18, 0x61, 0xCD, 0xE0, /* 0xF4 */ - 0x29, 0x40, 0x1E, 0xCE, 0x18, 0x61, 0xCD, 0xE0, /* 0xF5 */ - 0x28, 0x07, 0xB3, 0x86, 0x18, 0x73, 0x78, /* 0xF6 */ - 0x20, 0x3E, 0x02, 0x00, /* 0xF7 */ - 0xA8, 0x5D, 0x24, 0x90, /* 0xF8 */ - 0x22, 0x89, 0x18, 0xC6, 0x31, 0x9B, 0x40, /* 0xF9 */ - 0x11, 0x23, 0x18, 0xC6, 0x33, 0x68, /* 0xFA */ - 0x2A, 0x81, 0x18, 0xC6, 0x31, 0x9B, 0x40, /* 0xFB */ - 0x50, 0x23, 0x18, 0xC6, 0x33, 0x68, /* 0xFC */ - 0x10, 0x88, 0x52, 0x49, 0x23, 0x0C, 0x30, 0x82, 0x18, /* 0xFD */ - 0x4E, 0x44, 0x44, 0x46, 0x31, 0x70, /* 0xFE */ - 0x80, /* 0xFF */ +/* 0x01 */ 0x1C, 0x0A, 0x05, 0x04, 0xFE, 0x08, 0x1C, 0x02, 0x07, 0xE0, 0x9F, 0xC0, +/* 0x02 */ 0x3F, 0xF0, 0x40, 0xE0, 0x10, 0x3F, 0x04, 0x9E, 0x28, 0x14, 0x0E, 0x00, +/* 0x03 */ 0x3F, 0x10, 0x28, 0x06, 0x49, 0x80, 0x60, 0x19, 0x26, 0x31, 0x40, 0x8F, 0xC0, +/* 0x04 */ 0x3F, 0x10, 0x2A, 0x16, 0x49, 0xA1, 0x60, 0x19, 0xE6, 0x31, 0x40, 0x8F, 0xC0, +/* 0x05 */ 0x28, 0x15, 0x2A, 0xB5, 0x55, 0xA8, 0x54, 0x12, 0x04, 0x41, 0x08, 0x81, 0xC0, +/* 0x06 */ 0x04, 0x08, 0x88, 0x82, 0x07, 0x01, 0x11, 0xA2, 0xC4, 0x40, 0x70, 0x20, 0x88, 0x88, 0x10, 0x00, +/* 0x07 */ +/* 0x08 */ 0x03, 0x83, 0x44, 0x48, 0x28, 0x01, 0x80, 0x17, 0xFE, 0x08, 0x45, 0x28, 0x84, 0x00, +/* 0x09 */ 0x01, 0xC0, 0x68, 0x82, 0x41, 0x10, 0x02, 0x80, 0x06, 0x00, 0x14, 0x00, 0x8F, 0xFC, +/* 0x0A */ +/* 0x0B */ 0x22, 0x2A, 0xA2, 0x30, 0x18, 0x0A, 0x09, 0x04, 0x44, 0x14, 0x04, 0x00, +/* 0x0C */ 0x46, 0x00, 0x19, 0x03, 0x21, 0x20, 0x93, 0x04, 0x20, 0x11, 0x80, 0x50, 0x02, 0x7F, 0xE0, +/* 0x0D */ +/* 0x0E */ 0x08, 0x0E, 0x08, 0x88, 0x24, 0x12, 0x09, 0x05, 0x01, 0xFF, 0x8A, 0x02, 0x00, +/* 0x0F */ 0x3F, 0x14, 0xAA, 0x16, 0x01, 0x92, 0x60, 0x18, 0xC6, 0x49, 0x40, 0x8F, 0xC0, +/* 0x10 */ 0x1B, 0x02, 0xA0, 0x54, 0x12, 0x42, 0x48, 0x49, 0x31, 0x1E, 0x23, 0xEA, 0xFE, 0x3C, +/* 0x11 */ 0x3F, 0x02, 0x00, 0x20, 0x6D, 0x27, 0xF8, 0x3F, 0xC1, 0xFE, 0x37, 0xD0, 0xBE, 0x40, 0xE1, 0xE2, 0x00, +/* 0x12 */ 0x12, 0x42, 0x20, 0x24, 0xC0, 0x29, 0x99, 0x05, 0x23, 0x30, 0xB0, 0x30, 0x00, +/* 0x13 */ 0x3F, 0x88, 0x0A, 0x44, 0xD5, 0x58, 0x03, 0x00, 0x67, 0xCC, 0x71, 0x40, 0x47, 0xF0, +/* 0x14 */ 0x3F, 0x18, 0x69, 0x26, 0x85, 0xA1, 0x6C, 0xD8, 0x06, 0x31, 0x40, 0x8F, 0xC0, +/* 0x15 */ 0x3F, 0x11, 0x00, 0xE8, 0x03, 0xA0, 0x1F, 0xB3, 0x7E, 0x00, 0xE9, 0xE0, 0x23, 0x00, 0x40, 0x40, 0xFE, 0x00, +/* 0x16 */ 0x30, 0x38, 0x3A, 0x3E, 0x6E, 0xEB, 0xC3, 0xC3, 0x66, 0x3C, +/* 0x17 */ 0x3F, 0x04, 0x00, 0x82, 0x88, 0x5C, 0xA4, 0x49, 0x22, 0x81, 0x98, 0xC4, 0x40, 0xA3, 0xF0, +/* 0x18 */ 0x07, 0x80, 0x42, 0x04, 0x08, 0x21, 0x41, 0x42, 0x60, 0x0E, 0x8C, 0xB2, 0x89, 0x50, 0x52, 0x82, 0x80, +/* 0x19 */ 0x3F, 0xC4, 0x02, 0x80, 0x18, 0x01, 0xB3, 0x1B, 0xB9, 0x80, 0x19, 0xE1, 0x40, 0x23, 0xFC, +/* 0x1A */ 0xFF, 0xC0, 0x67, 0x34, 0x58, 0x4C, 0x46, 0x03, 0x11, 0x80, 0xFF, 0xC0, +/* 0x1B */ 0x0F, 0xC0, 0x40, 0x82, 0x49, 0x08, 0x04, 0x00, 0x00, 0x12, 0x02, 0x31, 0x34, 0x0B, 0x88, 0x45, 0x00, 0x20, +/* 0x1C */ 0x3F, 0x88, 0x0A, 0x44, 0xC9, 0x19, 0x3B, 0x00, 0x60, 0x4C, 0x71, 0x40, 0x47, 0xF0, +/* 0x1D */ 0x3F, 0x8B, 0x0A, 0x00, 0xC8, 0x18, 0x13, 0x00, 0x48, 0xCA, 0xC1, 0x44, 0x53, 0x30, +/* 0x1E */ 0x19, 0xC2, 0x02, 0x50, 0x1E, 0x49, 0x80, 0x12, 0x01, 0x27, 0x92, 0x01, 0x10, 0x20, 0xFC, +/* 0x1F */ 0x30, 0x1C, 0x0C, 0x3E, 0x7E, 0xCF, 0x07, 0xC7, 0x7F, 0x3F, +/* ' ' 0x20 */ +/* '!' 0x21 */ 0xFC, 0x80, +/* '"' 0x22 */ 0xB6, 0x80, +/* '#' 0x23 */ 0x24, 0x51, 0xF9, 0x42, 0x9F, 0x92, 0x28, +/* '$' 0x24 */ 0x10, 0xE5, 0x55, 0x50, 0xE1, 0x65, 0x55, 0xE1, 0x00, +/* '%' 0x25 */ 0x71, 0x24, 0x89, 0x22, 0x50, 0x74, 0x02, 0x70, 0xA4, 0x49, 0x11, 0xC0, +/* '&' 0x26 */ 0x71, 0x24, 0x9C, 0x62, 0x58, 0xA7, 0xF4, +/* ''' 0x27 */ 0xE0, +/* '(' 0x28 */ 0x5A, 0xAA, 0x94, +/* ')' 0x29 */ 0x89, 0x12, 0x49, 0x29, 0x00, +/* '*' 0x2A */ 0x5E, 0x80, +/* '+' 0x2B */ 0x21, 0x3E, 0x42, 0x00, +/* ',' 0x2C */ 0xE0, +/* '-' 0x2D */ 0xC0, +/* '.' 0x2E */ 0x80, +/* '/' 0x2F */ 0x24, 0xA4, 0xA4, 0x80, +/* '0' 0x30 */ 0x76, 0xE3, 0x18, 0xC6, 0x3B, 0x70, +/* '1' 0x31 */ 0x27, 0x92, 0x49, 0x20, +/* '2' 0x32 */ 0x79, 0x10, 0x41, 0x08, 0xC6, 0x10, 0xFC, +/* '3' 0x33 */ 0x79, 0x30, 0x43, 0x18, 0x10, 0x71, 0x78, +/* '4' 0x34 */ 0x08, 0x61, 0x8A, 0x49, 0x2F, 0xC2, 0x08, +/* '5' 0x35 */ 0xFC, 0x21, 0xE8, 0x84, 0x31, 0xF0, +/* '6' 0x36 */ 0x74, 0x61, 0xE8, 0xC6, 0x31, 0x70, +/* '7' 0x37 */ 0xF8, 0x44, 0x22, 0x11, 0x08, 0x40, +/* '8' 0x38 */ 0x39, 0x34, 0x53, 0x39, 0x1C, 0x51, 0x38, +/* '9' 0x39 */ 0x39, 0x3C, 0x71, 0x4C, 0xF0, 0x53, 0x78, +/* ':' 0x3A */ 0x82, +/* ';' 0x3B */ 0x87, +/* '<' 0x3C */ 0x3E, 0x30, 0x60, 0x80, +/* '=' 0x3D */ 0xF8, 0x3E, +/* '>' 0x3E */ 0xE0, 0xC6, 0xC8, 0x00, +/* '?' 0x3F */ 0x74, 0x42, 0x11, 0x10, 0x80, 0x20, +/* '@' 0x40 */ 0x0F, 0x86, 0x19, 0x9A, 0xA4, 0xD9, 0x13, 0x22, 0x56, 0xDA, 0x6E, 0x60, 0x06, 0x00, 0x3C, 0x00, +/* 'A' 0x41 */ 0x18, 0x18, 0x24, 0x24, 0x24, 0x7E, 0x42, 0x42, 0xC3, +/* 'B' 0x42 */ 0xFA, 0x18, 0x61, 0xFA, 0x18, 0x61, 0xFC, +/* 'C' 0x43 */ 0x3E, 0x63, 0x40, 0x40, 0xC0, 0x40, 0x41, 0x63, 0x3E, +/* 'D' 0x44 */ 0xF9, 0x0A, 0x1C, 0x18, 0x30, 0x61, 0xC2, 0xF8, +/* 'E' 0x45 */ 0xFE, 0x08, 0x20, 0xFE, 0x08, 0x20, 0xFC, +/* 'F' 0x46 */ 0xFE, 0x08, 0x20, 0xFA, 0x08, 0x20, 0x80, +/* 'G' 0x47 */ 0x1E, 0x61, 0x40, 0x40, 0xC7, 0x41, 0x41, 0x63, 0x1D, +/* 'H' 0x48 */ 0x83, 0x06, 0x0C, 0x1F, 0xF0, 0x60, 0xC1, 0x82, +/* 'I' 0x49 */ 0xFF, 0x80, +/* 'J' 0x4A */ 0x08, 0x42, 0x10, 0x87, 0x29, 0x70, +/* 'K' 0x4B */ 0x85, 0x12, 0x45, 0x0D, 0x13, 0x22, 0x42, 0x86, +/* 'L' 0x4C */ 0x84, 0x21, 0x08, 0x42, 0x10, 0xF8, +/* 'M' 0x4D */ 0xC3, 0xC3, 0xC3, 0xA5, 0xA5, 0xA5, 0x99, 0x99, 0x99, +/* 'N' 0x4E */ 0x83, 0x86, 0x8D, 0x19, 0x33, 0x62, 0xC3, 0x86, +/* 'O' 0x4F */ 0x1E, 0x31, 0x90, 0x68, 0x1C, 0x0A, 0x05, 0x06, 0xC6, 0x1E, 0x00, +/* 'P' 0x50 */ 0xFA, 0x18, 0x61, 0xFA, 0x08, 0x20, 0x80, +/* 'Q' 0x51 */ 0x1E, 0x31, 0x90, 0x68, 0x1C, 0x0A, 0x05, 0x16, 0xC6, 0x1F, 0x00, 0x40, +/* 'R' 0x52 */ 0xFD, 0x0E, 0x1C, 0x2F, 0x90, 0xA1, 0x42, 0x86, +/* 'S' 0x53 */ 0x7A, 0x18, 0x30, 0x78, 0x38, 0x61, 0x78, +/* 'T' 0x54 */ 0xFE, 0x20, 0x40, 0x81, 0x02, 0x04, 0x08, 0x10, +/* 'U' 0x55 */ 0x83, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xE2, 0x78, +/* 'V' 0x56 */ 0xC2, 0x85, 0x0B, 0x22, 0x44, 0x8E, 0x0C, 0x18, +/* 'W' 0x57 */ 0xC4, 0x28, 0xCD, 0x29, 0x25, 0x24, 0xA4, 0x52, 0x8C, 0x61, 0x8C, 0x31, 0x80, +/* 'X' 0x58 */ 0x87, 0x34, 0x8C, 0x30, 0xC4, 0xA3, 0x84, +/* 'Y' 0x59 */ 0xC3, 0x42, 0x24, 0x34, 0x18, 0x08, 0x08, 0x08, 0x08, +/* 'Z' 0x5A */ 0x7E, 0x0C, 0x30, 0x41, 0x06, 0x18, 0x20, 0xFE, +/* '[' 0x5B */ 0xEA, 0xAA, 0xAB, +/* '\' 0x5C */ 0x92, 0x24, 0x89, 0x20, +/* ']' 0x5D */ 0xD5, 0x55, 0x57, +/* '^' 0x5E */ 0x46, 0xA9, +/* '_' 0x5F */ 0xFE, +/* '`' 0x60 */ 0x80, +/* 'a' 0x61 */ 0x79, 0x20, 0x4F, 0xC6, 0x37, 0x40, +/* 'b' 0x62 */ 0x84, 0x3D, 0x18, 0xC6, 0x31, 0xF0, +/* 'c' 0x63 */ 0x39, 0x3C, 0x20, 0xC1, 0x33, 0x80, +/* 'd' 0x64 */ 0x04, 0x13, 0xD3, 0xC6, 0x1C, 0x53, 0x3C, +/* 'e' 0x65 */ 0x39, 0x38, 0x7F, 0x81, 0x13, 0x80, +/* 'f' 0x66 */ 0x6B, 0xA4, 0x92, 0x40, +/* 'g' 0x67 */ 0x35, 0x3C, 0x61, 0xC5, 0x33, 0x41, 0x4D, 0xE0, +/* 'h' 0x68 */ 0x84, 0x3D, 0x38, 0xC6, 0x31, 0x88, +/* 'i' 0x69 */ 0xBF, 0x80, +/* 'j' 0x6A */ 0x45, 0x55, 0x57, +/* 'k' 0x6B */ 0x84, 0x25, 0x4E, 0x52, 0xD2, 0x88, +/* 'l' 0x6C */ 0xFF, 0x80, +/* 'm' 0x6D */ 0xF7, 0x99, 0x91, 0x91, 0x91, 0x91, 0x91, +/* 'n' 0x6E */ 0xF4, 0x63, 0x18, 0xC6, 0x20, +/* 'o' 0x6F */ 0x39, 0x3C, 0x61, 0xC5, 0x33, 0x80, +/* 'p' 0x70 */ 0xF4, 0x63, 0x18, 0xC7, 0xD0, 0x80, +/* 'q' 0x71 */ 0x3D, 0x3C, 0x61, 0xC5, 0x37, 0x41, 0x04, +/* 'r' 0x72 */ 0xF2, 0x49, 0x20, +/* 's' 0x73 */ 0x7A, 0x50, 0xE0, 0xE5, 0xE0, +/* 't' 0x74 */ 0x5D, 0x24, 0x93, +/* 'u' 0x75 */ 0x8C, 0x63, 0x18, 0xCF, 0xA0, +/* 'v' 0x76 */ 0x85, 0x24, 0x92, 0x30, 0xC3, 0x00, +/* 'w' 0x77 */ 0x89, 0x59, 0x59, 0x55, 0x56, 0x26, 0x26, +/* 'x' 0x78 */ 0x4A, 0x4C, 0x43, 0x27, 0x20, +/* 'y' 0x79 */ 0x8A, 0x52, 0xA5, 0x18, 0x84, 0x22, 0x00, +/* 'z' 0x7A */ 0x78, 0x44, 0x46, 0x23, 0xE0, +/* '{' 0x7B */ 0x6A, 0xAA, 0xA9, +/* '|' 0x7C */ 0xFF, 0xE0, +/* '}' 0x7D */ 0x95, 0x55, 0x56, +/* '~' 0x7E */ 0x66, 0x60, +/* 0x7F */ 0xFF, 0xC0, 0x67, 0x34, 0x58, 0x4C, 0x46, 0x03, 0x11, 0x80, 0xFF, 0xC0, +/* 0x80 */ 0x1C, 0x45, 0x07, 0xE4, 0x1F, 0x10, 0x10, 0x1E, +/* 0x81 */ +/* 0x82 */ 0xE0, +/* 0x83 */ +/* 0x84 */ 0xB6, 0x80, +/* 0x85 */ 0xA8, +/* 0x86 */ 0x21, 0x09, 0xF2, 0x10, 0x84, 0x21, 0x08, +/* 0x87 */ 0x21, 0x09, 0xF2, 0x10, 0x84, 0xF9, 0x08, +/* 0x88 */ +/* 0x89 */ 0x62, 0x09, 0x40, 0x98, 0x06, 0x80, 0x10, 0x01, 0x66, 0x29, 0x92, 0x99, 0x06, 0x60, +/* 0x8A */ 0x28, 0x47, 0xA1, 0x83, 0x07, 0x83, 0x87, 0x17, 0x80, +/* 0x8B */ 0x64, +/* 0x8C */ 0x10, 0x87, 0xA1, 0x83, 0x07, 0x83, 0x87, 0x17, 0x80, +/* 0x8D */ 0x28, 0x4F, 0xC4, 0x10, 0x41, 0x04, 0x10, 0x40, +/* 0x8E */ 0x14, 0x11, 0xF8, 0x30, 0xC1, 0x04, 0x18, 0x61, 0xFC, +/* 0x8F */ 0x08, 0x21, 0xF8, 0x30, 0xC1, 0x04, 0x18, 0x61, 0xFC, +/* 0x90 */ +/* 0x91 */ 0xE0, +/* 0x92 */ 0xE0, +/* 0x93 */ 0xB6, 0x80, +/* 0x94 */ 0xB6, 0x80, +/* 0x95 */ 0xFF, 0x80, +/* 0x96 */ 0xFC, +/* 0x97 */ 0xFF, 0xF0, +/* 0x98 */ +/* 0x99 */ 0xE6, 0x28, 0xCD, 0x19, 0xA3, 0x34, 0x6A, 0x8B, 0x51, 0x68, +/* 0x9A */ 0x52, 0x69, 0x8E, 0x19, 0x60, +/* 0x9B */ 0x98, +/* 0x9C */ 0x24, 0x06, 0x98, 0xE1, 0x96, +/* 0x9D */ 0x15, 0xE4, 0x44, 0x44, 0x60, +/* 0x9E */ 0x51, 0x00, 0xF0, 0x88, 0x8C, 0x47, 0xC0, +/* 0x9F */ 0x11, 0x00, 0xF0, 0x88, 0x8C, 0x47, 0xC0, +/* 0xA0 */ +/* 0xA1 */ 0xA8, +/* 0xA2 */ 0x96, +/* 0xA3 */ 0x41, 0x05, 0x18, 0x43, 0x04, 0x10, 0x7C, +/* 0xA4 */ 0xFC, 0x63, 0xF0, +/* 0xA5 */ 0x30, 0x38, 0x28, 0x48, 0x4C, 0x7C, 0x84, 0x86, 0x82, 0x04, 0x07, +/* 0xA6 */ 0xF9, 0xF0, +/* 0xA7 */ 0x32, 0x91, 0xC9, 0x47, 0x26, 0x14, 0xA4, 0xC0, +/* 0xA8 */ 0xA0, +/* 0xA9 */ 0x3E, 0x3F, 0xB8, 0xF4, 0x1A, 0x0D, 0x17, 0x76, 0xC6, 0x3E, 0x00, +/* 0xAA */ 0x7A, 0x18, 0x30, 0x78, 0x38, 0x61, 0x78, 0xC1, 0x0C, +/* 0xAB */ 0x5A, 0xA5, +/* 0xAC */ 0xFC, 0x10, 0x40, +/* 0xAD */ +/* 0xAE */ 0x3E, 0x31, 0xB7, 0x72, 0x99, 0xCC, 0xC7, 0x56, 0xC6, 0x3E, 0x00, +/* 0xAF */ 0x18, 0x31, 0xF8, 0x30, 0xC1, 0x04, 0x18, 0x61, 0xFC, +/* 0xB0 */ 0x69, 0x96, +/* 0xB1 */ 0x21, 0x3E, 0x42, 0x03, 0xE0, +/* 0xB2 */ 0x9C, +/* 0xB3 */ 0x49, 0x35, 0x92, 0x40, +/* 0xB4 */ 0x80, +/* 0xB5 */ 0x8A, 0x28, 0xA2, 0x8A, 0x6E, 0xE0, 0x80, +/* 0xB6 */ 0x7F, 0xAE, 0xBA, 0x68, 0xA2, 0x8A, 0x28, 0xA0, +/* 0xB7 */ 0x80, +/* 0xB8 */ 0x67, 0x80, +/* 0xB9 */ 0x78, 0x84, 0x04, 0x3C, 0xC4, 0x8C, 0x76, 0x04, 0x07, +/* 0xBA */ 0x69, 0x8E, 0x19, 0x66, 0x26, +/* 0xBB */ 0xA5, 0x5A, +/* 0xBC */ 0xA5, 0x21, 0x08, 0x42, 0x10, 0xF8, +/* 0xBD */ 0xA0, +/* 0xBE */ 0xBA, 0x49, 0x24, 0x90, +/* 0xBF */ 0x31, 0x9E, 0x11, 0x11, 0x88, 0xF8, +/* 0xC0 */ 0x10, 0x43, 0xE4, 0x28, 0x50, 0xBE, 0x42, 0x85, 0x0C, +/* 0xC1 */ 0x08, 0x10, 0x00, 0x18, 0x3C, 0x24, 0x24, 0x7E, 0x42, 0xC3, +/* 0xC2 */ 0x18, 0x24, 0x00, 0x18, 0x3C, 0x24, 0x24, 0x7E, 0x42, 0xC3, +/* 0xC3 */ 0x24, 0x18, 0x00, 0x18, 0x3C, 0x24, 0x24, 0x7E, 0x42, 0xC3, +/* 0xC4 */ 0x24, 0x00, 0x18, 0x3C, 0x24, 0x24, 0x7E, 0x42, 0x42, 0xC3, +/* 0xC5 */ 0x11, 0x21, 0x08, 0x42, 0x10, 0x87, 0xC0, +/* 0xC6 */ 0x08, 0x20, 0x01, 0xE4, 0x30, 0x20, 0x40, 0x82, 0x8C, 0xF0, +/* 0xC7 */ 0x3E, 0x61, 0xC0, 0x80, 0x80, 0x80, 0xC1, 0x63, 0x3E, 0x0C, 0x04, 0x1C, +/* 0xC8 */ 0x28, 0x20, 0x01, 0xE4, 0x30, 0x20, 0x40, 0x82, 0x8C, 0xF0, +/* 0xC9 */ 0x08, 0x40, 0x3F, 0x82, 0x0F, 0xA0, 0x83, 0xF0, +/* 0xCA */ 0xFD, 0x02, 0x04, 0x0F, 0xD0, 0x20, 0x40, 0xFC, 0x10, 0x38, +/* 0xCB */ 0x28, 0x0F, 0xE0, 0x83, 0xE8, 0x20, 0x83, 0xF0, +/* 0xCC */ 0x28, 0x40, 0x3F, 0x82, 0x0F, 0xA0, 0x82, 0x0F, 0xC0, +/* 0xCD */ 0x62, 0xAA, 0xA0, +/* 0xCE */ 0x54, 0x24, 0x92, 0x48, +/* 0xCF */ 0x50, 0x43, 0xE4, 0x28, 0x30, 0x60, 0xC1, 0x85, 0xF0, +/* 0xD0 */ 0x7C, 0x42, 0x41, 0x41, 0xF1, 0x41, 0x41, 0x42, 0x7C, +/* 0xD1 */ 0x08, 0x23, 0x0F, 0x1B, 0x32, 0x66, 0xC7, 0x87, 0x04, +/* 0xD2 */ 0x28, 0x23, 0x0F, 0x1B, 0x32, 0x66, 0xC7, 0x87, 0x04, +/* 0xD3 */ 0x04, 0x04, 0x0F, 0x8C, 0x6C, 0x1C, 0x06, 0x03, 0x83, 0x63, 0x1F, 0x00, +/* 0xD4 */ 0x08, 0x0A, 0x00, 0x07, 0xC6, 0x36, 0x0E, 0x03, 0x01, 0xC1, 0xB1, 0x8F, 0x80, +/* 0xD5 */ 0x0A, 0x0A, 0x00, 0x07, 0xC6, 0x36, 0x0E, 0x03, 0x01, 0xC1, 0xB1, 0x8F, 0x80, +/* 0xD6 */ 0x14, 0x00, 0x00, 0x07, 0xC6, 0x36, 0x0E, 0x03, 0x01, 0xC1, 0xB1, 0x8F, 0x80, +/* 0xD7 */ 0x8A, 0x88, 0xA8, 0x80, +/* 0xD8 */ 0x50, 0x43, 0xE4, 0x28, 0x50, 0xBE, 0x42, 0x85, 0x0C, +/* 0xD9 */ 0x10, 0x52, 0x4C, 0x18, 0x30, 0x60, 0xC1, 0xC6, 0xF8, +/* 0xDA */ 0x08, 0x22, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0xC6, 0xF8, +/* 0xDB */ 0x14, 0x52, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0xC6, 0xF8, +/* 0xDC */ 0x29, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0xC6, 0xF8, +/* 0xDD */ 0x09, 0x25, 0x12, 0x22, 0x87, 0x04, 0x08, 0x10, 0x20, +/* 0xDE */ 0xFC, 0x41, 0x04, 0x10, 0x41, 0x04, 0x10, 0x60, 0x8E, +/* 0xDF */ 0x7A, 0x18, 0x61, 0x8A, 0x18, 0x61, 0xB8, +/* 0xE0 */ 0x42, 0xE9, 0x24, 0x80, +/* 0xE1 */ 0x10, 0x40, 0x03, 0xC8, 0x40, 0x8F, 0x62, 0x8C, 0xEC, +/* 0xE2 */ 0x10, 0x50, 0x03, 0xC8, 0x40, 0x8F, 0x62, 0x8C, 0xEC, +/* 0xE3 */ 0x48, 0x60, 0x03, 0xC8, 0x40, 0x8F, 0x62, 0x8C, 0xEC, +/* 0xE4 */ 0x28, 0x01, 0xE4, 0x20, 0x47, 0xB1, 0x46, 0x76, +/* 0xE5 */ 0x62, 0xAA, 0xA0, +/* 0xE6 */ 0x10, 0x80, 0x1E, 0xC6, 0x08, 0x20, 0xC5, 0xE0, +/* 0xE7 */ 0x7B, 0x18, 0x20, 0x83, 0x17, 0x8C, 0x11, 0xC0, +/* 0xE8 */ 0x28, 0x40, 0x1E, 0xC6, 0x08, 0x20, 0xC5, 0xE0, +/* 0xE9 */ 0x10, 0x80, 0x1E, 0xCE, 0x1F, 0xE0, 0xC5, 0xE0, +/* 0xEA */ 0x7B, 0x38, 0x7F, 0x83, 0x37, 0x84, 0x1C, +/* 0xEB */ 0x28, 0x07, 0xB3, 0x87, 0xF8, 0x31, 0x78, +/* 0xEC */ 0x28, 0x40, 0x1E, 0xCE, 0x1F, 0xE0, 0xC5, 0xE0, +/* 0xED */ 0x62, 0xAA, 0xA0, +/* 0xEE */ 0x54, 0x24, 0x92, 0x48, +/* 0xEF */ 0x02, 0x0C, 0x13, 0xEC, 0xD0, 0xA1, 0x42, 0xCC, 0xE8, +/* 0xF0 */ 0x04, 0x1D, 0xD6, 0x68, 0x50, 0xA1, 0x66, 0x74, +/* 0xF1 */ 0x11, 0x01, 0x6C, 0xC6, 0x31, 0x8C, 0x40, +/* 0xF2 */ 0x20, 0x81, 0x6C, 0xC6, 0x31, 0x8C, 0x40, +/* 0xF3 */ 0x10, 0x80, 0x1E, 0xCE, 0x18, 0x61, 0xCD, 0xE0, +/* 0xF4 */ 0x10, 0xA0, 0x1E, 0xCE, 0x18, 0x61, 0xCD, 0xE0, +/* 0xF5 */ 0x29, 0x40, 0x1E, 0xCE, 0x18, 0x61, 0xCD, 0xE0, +/* 0xF6 */ 0x28, 0x07, 0xB3, 0x86, 0x18, 0x73, 0x78, +/* 0xF7 */ 0x20, 0x3E, 0x02, 0x00, +/* 0xF8 */ 0xA8, 0x5D, 0x24, 0x90, +/* 0xF9 */ 0x22, 0x89, 0x18, 0xC6, 0x31, 0x9B, 0x40, +/* 0xFA */ 0x11, 0x23, 0x18, 0xC6, 0x33, 0x68, +/* 0xFB */ 0x2A, 0x81, 0x18, 0xC6, 0x31, 0x9B, 0x40, +/* 0xFC */ 0x50, 0x23, 0x18, 0xC6, 0x33, 0x68, +/* 0xFD */ 0x10, 0x88, 0x52, 0x49, 0x23, 0x0C, 0x30, 0x82, 0x18, +/* 0xFE */ 0x4E, 0x44, 0x44, 0x46, 0x31, 0x70, +/* 0xFF */ 0x80, }; const GFXglyph FreeSans6pt_Win1250Glyphs[] PROGMEM = { - /* ' ' 0x20 */ {0, 0, 0, 3, 0, 0}, - /* '!' 0x21 */ {0, 1, 9, 4, 2, -8}, - /* '"' 0x22 */ {2, 3, 3, 4, 0, -8}, - /* '#' 0x23 */ {4, 7, 8, 7, 0, -7}, - /* '$' 0x24 */ {11, 6, 11, 7, 0, -9}, - /* '%' 0x25 */ {20, 10, 9, 11, 0, -8}, - /* '&' 0x26 */ {32, 6, 9, 8, 1, -8}, - /* ''' 0x27 */ {39, 1, 3, 2, 1, -8}, - /* '(' 0x28 */ {40, 2, 11, 4, 1, -8}, - /* ')' 0x29 */ {43, 3, 11, 4, 0, -8}, - /* '*' 0x2A */ {48, 3, 3, 5, 1, -8}, - /* '+' 0x2B */ {50, 5, 5, 7, 1, -4}, - /* ',' 0x2C */ {54, 1, 3, 3, 1, 0}, - /* '-' 0x2D */ {55, 2, 1, 4, 1, -3}, - /* '.' 0x2E */ {56, 1, 1, 3, 1, 0}, - /* '/' 0x2F */ {57, 3, 9, 3, 0, -8}, - /* '0' 0x30 */ {61, 5, 9, 7, 1, -8}, - /* '1' 0x31 */ {67, 3, 9, 7, 1, -8}, - /* '2' 0x32 */ {71, 6, 9, 7, 0, -8}, - /* '3' 0x33 */ {78, 6, 9, 7, 0, -8}, - /* '4' 0x34 */ {85, 6, 9, 7, 0, -8}, - /* '5' 0x35 */ {92, 5, 9, 7, 1, -8}, - /* '6' 0x36 */ {98, 5, 9, 7, 1, -8}, - /* '7' 0x37 */ {104, 5, 9, 7, 1, -8}, - /* '8' 0x38 */ {110, 6, 9, 7, 0, -8}, - /* '9' 0x39 */ {117, 6, 9, 7, 0, -8}, - /* ':' 0x3A */ {124, 1, 7, 3, 1, -6}, - /* ';' 0x3B */ {125, 1, 8, 3, 1, -5}, - /* '<' 0x3C */ {126, 5, 5, 7, 1, -4}, - /* '=' 0x3D */ {130, 5, 3, 7, 1, -3}, - /* '>' 0x3E */ {132, 5, 5, 7, 1, -4}, - /* '?' 0x3F */ {136, 5, 9, 7, 1, -8}, - /* '@' 0x40 */ {142, 11, 11, 12, 0, -8}, - /* 'A' 0x41 */ {158, 8, 9, 8, 0, -8}, - /* 'B' 0x42 */ {167, 6, 9, 8, 1, -8}, - /* 'C' 0x43 */ {174, 8, 9, 9, 0, -8}, - /* 'D' 0x44 */ {183, 7, 9, 8, 1, -8}, - /* 'E' 0x45 */ {191, 6, 9, 8, 1, -8}, - /* 'F' 0x46 */ {198, 6, 9, 7, 1, -8}, - /* 'G' 0x47 */ {205, 8, 9, 9, 0, -8}, - /* 'H' 0x48 */ {214, 7, 9, 9, 1, -8}, - /* 'I' 0x49 */ {222, 1, 9, 3, 1, -8}, - /* 'J' 0x4A */ {224, 5, 9, 6, 0, -8}, - /* 'K' 0x4B */ {230, 7, 9, 8, 1, -8}, - /* 'L' 0x4C */ {238, 5, 9, 7, 1, -8}, - /* 'M' 0x4D */ {244, 8, 9, 10, 1, -8}, - /* 'N' 0x4E */ {253, 7, 9, 9, 1, -8}, - /* 'O' 0x4F */ {261, 9, 9, 9, 0, -8}, - /* 'P' 0x50 */ {272, 6, 9, 8, 1, -8}, - /* 'Q' 0x51 */ {279, 9, 10, 9, 0, -8}, - /* 'R' 0x52 */ {291, 7, 9, 9, 1, -8}, - /* 'S' 0x53 */ {299, 6, 9, 8, 1, -8}, - /* 'T' 0x54 */ {306, 7, 9, 8, 0, -8}, - /* 'U' 0x55 */ {314, 7, 9, 9, 1, -8}, - /* 'V' 0x56 */ {322, 7, 9, 8, 0, -8}, - /* 'W' 0x57 */ {330, 11, 9, 11, 0, -8}, - /* 'X' 0x58 */ {343, 6, 9, 8, 1, -8}, - /* 'Y' 0x59 */ {350, 8, 9, 8, 0, -8}, - /* 'Z' 0x5A */ {359, 7, 9, 7, 0, -8}, - /* '[' 0x5B */ {367, 2, 12, 3, 1, -8}, - /* '\' 0x5C */ {370, 3, 9, 3, 0, -8}, - /* ']' 0x5D */ {374, 2, 12, 3, 0, -8}, - /* '^' 0x5E */ {377, 4, 4, 6, 1, -8}, - /* '_' 0x5F */ {379, 7, 1, 7, 0, 2}, - /* '`' 0x60 */ {380, 1, 1, 3, 1, -8}, - /* 'a' 0x61 */ {381, 6, 7, 7, 0, -6}, - /* 'b' 0x62 */ {387, 5, 9, 7, 1, -8}, - /* 'c' 0x63 */ {393, 6, 7, 6, 0, -6}, - /* 'd' 0x64 */ {399, 6, 9, 7, 0, -8}, - /* 'e' 0x65 */ {406, 6, 7, 6, 0, -6}, - /* 'f' 0x66 */ {412, 3, 9, 3, 0, -8}, - /* 'g' 0x67 */ {416, 6, 10, 7, 0, -6}, - /* 'h' 0x68 */ {424, 5, 9, 6, 1, -8}, - /* 'i' 0x69 */ {430, 1, 9, 3, 1, -8}, - /* 'j' 0x6A */ {432, 2, 12, 3, 0, -8}, - /* 'k' 0x6B */ {435, 5, 9, 6, 1, -8}, - /* 'l' 0x6C */ {441, 1, 9, 3, 1, -8}, - /* 'm' 0x6D */ {443, 8, 7, 10, 1, -6}, - /* 'n' 0x6E */ {450, 5, 7, 6, 1, -6}, - /* 'o' 0x6F */ {455, 6, 7, 6, 0, -6}, - /* 'p' 0x70 */ {461, 5, 9, 7, 1, -6}, - /* 'q' 0x71 */ {467, 6, 9, 7, 0, -6}, - /* 'r' 0x72 */ {474, 3, 7, 4, 1, -6}, - /* 's' 0x73 */ {477, 5, 7, 6, 0, -6}, - /* 't' 0x74 */ {482, 3, 8, 3, 0, -7}, - /* 'u' 0x75 */ {485, 5, 7, 6, 1, -6}, - /* 'v' 0x76 */ {490, 6, 7, 6, 0, -6}, - /* 'w' 0x77 */ {496, 8, 7, 9, 0, -6}, - /* 'x' 0x78 */ {503, 5, 7, 6, 0, -6}, - /* 'y' 0x79 */ {508, 5, 10, 6, 0, -6}, - /* 'z' 0x7A */ {515, 5, 7, 6, 0, -6}, - /* '{' 0x7B */ {520, 2, 12, 4, 1, -8}, - /* '|' 0x7C */ {523, 1, 11, 3, 1, -8}, - /* '}' 0x7D */ {525, 2, 12, 4, 1, -8}, - /* '~' 0x7E */ {528, 6, 2, 6, 0, -4}, - /* 0x7F */ {530, 9, 10, 11, 1, -8}, - /* 0x80 */ {542, 7, 9, 8, 0, -8}, - /* 0x81 */ {550, 0, 0, 8, 0, 0}, - /* 0x82 */ {550, 1, 3, 3, 1, 0}, - /* 0x83 */ {551, 0, 0, 8, 0, 0}, - /* 0x84 */ {551, 3, 3, 5, 1, 0}, - /* 0x85 */ {553, 5, 1, 7, 1, 0}, - /* 0x86 */ {554, 5, 11, 7, 1, -8}, - /* 0x87 */ {561, 5, 11, 7, 1, -8}, - /* 0x88 */ {568, 0, 0, 8, 0, 0}, - /* 0x89 */ {568, 12, 9, 12, 0, -8}, - /* 0x8A */ {582, 6, 11, 8, 1, -9}, - /* 0x8B */ {591, 2, 3, 4, 1, -4}, - /* 0x8C */ {592, 6, 11, 8, 1, -10}, - /* 0x8D */ {601, 6, 10, 8, 0, -9}, - /* 0x8E */ {609, 7, 10, 7, 0, -9}, - /* 0x8F */ {618, 7, 10, 7, 0, -9}, - /* 0x90 */ {627, 0, 0, 8, 0, 0}, - /* 0x91 */ {627, 1, 3, 3, 1, -8}, - /* 0x92 */ {628, 1, 3, 2, 1, -8}, - /* 0x93 */ {629, 3, 3, 5, 1, -8}, - /* 0x94 */ {631, 3, 3, 5, 1, -8}, - /* 0x95 */ {633, 3, 3, 5, 1, -5}, - /* 0x96 */ {635, 6, 1, 6, 0, -3}, - /* 0x97 */ {636, 12, 1, 12, 0, -3}, - /* 0x98 */ {638, 0, 0, 8, 0, 0}, - /* 0x99 */ {638, 11, 7, 12, 1, -8}, - /* 0x9A */ {648, 4, 9, 6, 1, -8}, - /* 0x9B */ {653, 2, 3, 3, 1, -4}, - /* 0x9C */ {654, 4, 10, 6, 1, -9}, - /* 0x9D */ {659, 4, 9, 5, 0, -8}, - /* 0x9E */ {664, 5, 10, 6, 0, -9}, - /* 0x9F */ {671, 5, 10, 6, 0, -9}, - /* 0xA0 */ {678, 0, 0, 3, 0, 0}, - /* 0xA1 */ {678, 3, 2, 4, 0, -8}, - /* 0xA2 */ {679, 4, 2, 4, 0, -8}, - /* 0xA3 */ {680, 6, 9, 7, 0, -8}, - /* 0xA4 */ {687, 5, 4, 7, 1, -5}, - /* 0xA5 */ {690, 8, 11, 8, 1, -8}, - /* 0xA6 */ {701, 1, 12, 3, 1, -8}, - /* 0xA7 */ {703, 5, 12, 7, 1, -8}, - /* 0xA8 */ {711, 3, 1, 4, 0, -7}, - /* 0xA9 */ {712, 9, 9, 10, 0, -8}, - /* 0xAA */ {723, 6, 12, 8, 1, -8}, - /* 0xAB */ {732, 4, 4, 6, 1, -4}, - /* 0xAC */ {734, 6, 3, 7, 1, -4}, - /* 0xAD */ {737, 0, 0, 0, 0, 0}, - /* 0xAE */ {737, 9, 9, 10, 0, -8}, - /* 0xAF */ {748, 7, 10, 7, 0, -9}, - /* 0xB0 */ {757, 4, 4, 7, 2, -8}, - /* 0xB1 */ {759, 5, 7, 7, 1, -6}, - /* 0xB2 */ {764, 3, 2, 4, 1, 1}, - /* 0xB3 */ {765, 3, 9, 3, 0, -8}, - /* 0xB4 */ {769, 1, 1, 4, 1, -8}, - /* 0xB5 */ {770, 6, 9, 7, 1, -6}, - /* 0xB6 */ {777, 6, 10, 6, 1, -8}, - /* 0xB7 */ {785, 1, 1, 3, 1, -2}, - /* 0xB8 */ {786, 3, 3, 4, 1, 1}, - /* 0xB9 */ {788, 8, 9, 7, 0, -6}, - /* 0xBA */ {797, 4, 10, 6, 1, -6}, - /* 0xBB */ {802, 4, 4, 6, 1, -5}, - /* 0xBC */ {804, 5, 9, 7, 1, -8}, - /* 0xBD */ {810, 3, 1, 4, 0, -8}, - /* 0xBE */ {811, 3, 10, 3, 1, -9}, - /* 0xBF */ {815, 5, 9, 6, 0, -8}, - /* 0xC0 */ {821, 7, 10, 9, 1, -9}, - /* 0xC1 */ {830, 8, 10, 8, 0, -9}, - /* 0xC2 */ {840, 8, 10, 8, 0, -9}, - /* 0xC3 */ {850, 8, 10, 8, 0, -9}, - /* 0xC4 */ {860, 8, 10, 8, 0, -9}, - /* 0xC5 */ {870, 5, 10, 7, 1, -9}, - /* 0xC6 */ {877, 7, 11, 9, 0, -10}, - /* 0xC7 */ {887, 8, 12, 9, 0, -8}, - /* 0xC8 */ {899, 7, 11, 9, 0, -10}, - /* 0xC9 */ {909, 6, 10, 8, 1, -9}, - /* 0xCA */ {917, 7, 11, 8, 1, -8}, - /* 0xCB */ {927, 6, 10, 8, 1, -9}, - /* 0xCC */ {935, 6, 11, 8, 1, -10}, - /* 0xCD */ {944, 2, 10, 3, 1, -9}, - /* 0xCE */ {947, 3, 10, 4, 0, -9}, - /* 0xCF */ {951, 7, 10, 8, 1, -9}, - /* 0xD0 */ {960, 8, 9, 8, 0, -8}, - /* 0xD1 */ {969, 7, 10, 9, 1, -9}, - /* 0xD2 */ {978, 7, 10, 9, 1, -9}, - /* 0xD3 */ {987, 9, 10, 9, 0, -9}, - /* 0xD4 */ {999, 9, 11, 9, 0, -10}, - /* 0xD5 */ {1012, 9, 11, 9, 0, -10}, - /* 0xD6 */ {1025, 9, 11, 9, 0, -10}, - /* 0xD7 */ {1038, 5, 5, 7, 1, -5}, - /* 0xD8 */ {1042, 7, 10, 9, 1, -9}, - /* 0xD9 */ {1051, 7, 10, 9, 1, -9}, - /* 0xDA */ {1060, 7, 10, 9, 1, -9}, - /* 0xDB */ {1069, 7, 10, 9, 1, -9}, - /* 0xDC */ {1078, 7, 10, 9, 1, -9}, - /* 0xDD */ {1087, 7, 10, 8, 1, -9}, - /* 0xDE */ {1096, 6, 12, 7, 0, -8}, - /* 0xDF */ {1105, 6, 9, 7, 1, -8}, - /* 0xE0 */ {1112, 3, 9, 4, 1, -8}, - /* 0xE1 */ {1116, 7, 10, 7, 0, -9}, - /* 0xE2 */ {1125, 7, 10, 7, 0, -9}, - /* 0xE3 */ {1134, 7, 10, 7, 0, -9}, - /* 0xE4 */ {1143, 7, 9, 7, 0, -8}, - /* 0xE5 */ {1151, 2, 10, 3, 1, -9}, - /* 0xE6 */ {1154, 6, 10, 6, 0, -9}, - /* 0xE7 */ {1162, 6, 10, 6, 0, -6}, - /* 0xE8 */ {1170, 6, 10, 6, 0, -9}, - /* 0xE9 */ {1178, 6, 10, 6, 0, -9}, - /* 0xEA */ {1186, 6, 9, 6, 0, -6}, - /* 0xEB */ {1193, 6, 9, 6, 0, -8}, - /* 0xEC */ {1200, 6, 10, 6, 0, -9}, - /* 0xED */ {1208, 2, 10, 3, 1, -9}, - /* 0xEE */ {1211, 3, 10, 3, 0, -9}, - /* 0xEF */ {1215, 7, 10, 7, 0, -9}, - /* 0xF0 */ {1224, 7, 9, 7, 0, -8}, - /* 0xF1 */ {1232, 5, 10, 6, 1, -9}, - /* 0xF2 */ {1239, 5, 10, 6, 1, -9}, - /* 0xF3 */ {1246, 6, 10, 6, 0, -9}, - /* 0xF4 */ {1254, 6, 10, 6, 0, -9}, - /* 0xF5 */ {1262, 6, 10, 6, 0, -9}, - /* 0xF6 */ {1270, 6, 9, 6, 0, -8}, - /* 0xF7 */ {1277, 5, 5, 7, 1, -5}, - /* 0xF8 */ {1281, 3, 10, 4, 1, -9}, - /* 0xF9 */ {1285, 5, 10, 6, 1, -9}, - /* 0xFA */ {1292, 5, 9, 6, 1, -8}, - /* 0xFB */ {1298, 5, 10, 6, 1, -9}, - /* 0xFC */ {1305, 5, 9, 6, 1, -8}, - /* 0xFD */ {1311, 6, 12, 6, 0, -8}, - /* 0xFE */ {1320, 4, 11, 3, 0, -7}, - /* 0xFF */ {1326, 1, 1, 4, 1, -7}, +/* 0x01 */ { 0, 9, 10, 11, 1, -9 }, +/* 0x02 */ { 12, 9, 10, 11, 1, -8 }, +/* 0x03 */ { 24, 10, 10, 12, 1, -8 }, +/* 0x04 */ { 37, 10, 10, 12, 1, -8 }, +/* 0x05 */ { 50, 10, 10, 12, 1, -9 }, +/* 0x06 */ { 63, 11, 11, 13, 1, -9 }, +/* 0x07 */ { 79, 0, 0, 8, 0, 0 }, +/* 0x08 */ { 79, 12, 9, 14, 1, -8 }, +/* 0x09 */ { 93, 14, 8, 16, 1, -7 }, +/* 0x0A */ { 107, 0, 0, 8, 0, 0 }, +/* 0x0B */ { 107, 9, 10, 11, 1, -9 }, +/* 0x0C */ { 119, 13, 9, 15, 1, -8 }, +/* 0x0D */ { 134, 0, 0, 8, 0, 0 }, +/* 0x0E */ { 134, 9, 11, 11, 1, -9 }, +/* 0x0F */ { 147, 10, 10, 12, 1, -9 }, +/* 0x10 */ { 160, 11, 10, 13, 1, -9 }, +/* 0x11 */ { 174, 13, 10, 15, 1, -9 }, +/* 0x12 */ { 191, 10, 10, 12, 1, -9 }, +/* 0x13 */ { 204, 11, 10, 13, 1, -9 }, +/* 0x14 */ { 218, 10, 10, 12, 1, -9 }, +/* 0x15 */ { 231, 14, 10, 16, 1, -9 }, +/* 0x16 */ { 249, 8, 10, 10, 1, -9 }, +/* 0x17 */ { 259, 12, 10, 14, 1, -9 }, +/* 0x18 */ { 274, 13, 10, 15, 1, -9 }, +/* 0x19 */ { 291, 12, 10, 14, 1, -9 }, +/* 0x1A */ { 306, 9, 10, 11, 1, -8 }, +/* 0x1B */ { 318, 14, 10, 16, 1, -9 }, +/* 0x1C */ { 336, 11, 10, 13, 1, -9 }, +/* 0x1D */ { 350, 11, 10, 13, 1, -9 }, +/* 0x1E */ { 364, 12, 10, 14, 1, -9 }, +/* 0x1F */ { 379, 8, 10, 11, 2, -9 }, +/* ' ' 0x20 */ { 389, 0, 0, 3, 0, 0 }, +/* '!' 0x21 */ { 389, 1, 9, 4, 2, -8 }, +/* '"' 0x22 */ { 391, 3, 3, 4, 0, -8 }, +/* '#' 0x23 */ { 393, 7, 8, 7, 0, -7 }, +/* '$' 0x24 */ { 400, 6, 11, 7, 0, -9 }, +/* '%' 0x25 */ { 409, 10, 9, 11, 0, -8 }, +/* '&' 0x26 */ { 421, 6, 9, 8, 1, -8 }, +/* ''' 0x27 */ { 428, 1, 3, 2, 1, -8 }, +/* '(' 0x28 */ { 429, 2, 11, 4, 1, -8 }, +/* ')' 0x29 */ { 432, 3, 11, 4, 0, -8 }, +/* '*' 0x2A */ { 437, 3, 3, 5, 1, -8 }, +/* '+' 0x2B */ { 439, 5, 5, 7, 1, -4 }, +/* ',' 0x2C */ { 443, 1, 3, 3, 1, 0 }, +/* '-' 0x2D */ { 444, 2, 1, 4, 1, -3 }, +/* '.' 0x2E */ { 445, 1, 1, 3, 1, 0 }, +/* '/' 0x2F */ { 446, 3, 9, 3, 0, -8 }, +/* '0' 0x30 */ { 450, 5, 9, 7, 1, -8 }, +/* '1' 0x31 */ { 456, 3, 9, 7, 1, -8 }, +/* '2' 0x32 */ { 460, 6, 9, 7, 0, -8 }, +/* '3' 0x33 */ { 467, 6, 9, 7, 0, -8 }, +/* '4' 0x34 */ { 474, 6, 9, 7, 0, -8 }, +/* '5' 0x35 */ { 481, 5, 9, 7, 1, -8 }, +/* '6' 0x36 */ { 487, 5, 9, 7, 1, -8 }, +/* '7' 0x37 */ { 493, 5, 9, 7, 1, -8 }, +/* '8' 0x38 */ { 499, 6, 9, 7, 0, -8 }, +/* '9' 0x39 */ { 506, 6, 9, 7, 0, -8 }, +/* ':' 0x3A */ { 513, 1, 7, 3, 1, -6 }, +/* ';' 0x3B */ { 514, 1, 8, 3, 1, -5 }, +/* '<' 0x3C */ { 515, 5, 5, 7, 1, -4 }, +/* '=' 0x3D */ { 519, 5, 3, 7, 1, -3 }, +/* '>' 0x3E */ { 521, 5, 5, 7, 1, -4 }, +/* '?' 0x3F */ { 525, 5, 9, 7, 1, -8 }, +/* '@' 0x40 */ { 531, 11, 11, 12, 0, -8 }, +/* 'A' 0x41 */ { 547, 8, 9, 8, 0, -8 }, +/* 'B' 0x42 */ { 556, 6, 9, 8, 1, -8 }, +/* 'C' 0x43 */ { 563, 8, 9, 9, 0, -8 }, +/* 'D' 0x44 */ { 572, 7, 9, 8, 1, -8 }, +/* 'E' 0x45 */ { 580, 6, 9, 8, 1, -8 }, +/* 'F' 0x46 */ { 587, 6, 9, 7, 1, -8 }, +/* 'G' 0x47 */ { 594, 8, 9, 9, 0, -8 }, +/* 'H' 0x48 */ { 603, 7, 9, 9, 1, -8 }, +/* 'I' 0x49 */ { 611, 1, 9, 3, 1, -8 }, +/* 'J' 0x4A */ { 613, 5, 9, 6, 0, -8 }, +/* 'K' 0x4B */ { 619, 7, 9, 8, 1, -8 }, +/* 'L' 0x4C */ { 627, 5, 9, 7, 1, -8 }, +/* 'M' 0x4D */ { 633, 8, 9, 10, 1, -8 }, +/* 'N' 0x4E */ { 642, 7, 9, 9, 1, -8 }, +/* 'O' 0x4F */ { 650, 9, 9, 9, 0, -8 }, +/* 'P' 0x50 */ { 661, 6, 9, 8, 1, -8 }, +/* 'Q' 0x51 */ { 668, 9, 10, 9, 0, -8 }, +/* 'R' 0x52 */ { 680, 7, 9, 9, 1, -8 }, +/* 'S' 0x53 */ { 688, 6, 9, 8, 1, -8 }, +/* 'T' 0x54 */ { 695, 7, 9, 8, 0, -8 }, +/* 'U' 0x55 */ { 703, 7, 9, 9, 1, -8 }, +/* 'V' 0x56 */ { 711, 7, 9, 8, 0, -8 }, +/* 'W' 0x57 */ { 719, 11, 9, 11, 0, -8 }, +/* 'X' 0x58 */ { 732, 6, 9, 8, 1, -8 }, +/* 'Y' 0x59 */ { 739, 8, 9, 8, 0, -8 }, +/* 'Z' 0x5A */ { 748, 7, 9, 7, 0, -8 }, +/* '[' 0x5B */ { 756, 2, 12, 3, 1, -8 }, +/* '\' 0x5C */ { 759, 3, 9, 3, 0, -8 }, +/* ']' 0x5D */ { 763, 2, 12, 3, 0, -8 }, +/* '^' 0x5E */ { 766, 4, 4, 6, 1, -8 }, +/* '_' 0x5F */ { 768, 7, 1, 7, 0, 2 }, +/* '`' 0x60 */ { 769, 1, 1, 3, 1, -8 }, +/* 'a' 0x61 */ { 770, 6, 7, 7, 0, -6 }, +/* 'b' 0x62 */ { 776, 5, 9, 7, 1, -8 }, +/* 'c' 0x63 */ { 782, 6, 7, 6, 0, -6 }, +/* 'd' 0x64 */ { 788, 6, 9, 7, 0, -8 }, +/* 'e' 0x65 */ { 795, 6, 7, 6, 0, -6 }, +/* 'f' 0x66 */ { 801, 3, 9, 3, 0, -8 }, +/* 'g' 0x67 */ { 805, 6, 10, 7, 0, -6 }, +/* 'h' 0x68 */ { 813, 5, 9, 6, 1, -8 }, +/* 'i' 0x69 */ { 819, 1, 9, 3, 1, -8 }, +/* 'j' 0x6A */ { 821, 2, 12, 3, 0, -8 }, +/* 'k' 0x6B */ { 824, 5, 9, 6, 1, -8 }, +/* 'l' 0x6C */ { 830, 1, 9, 3, 1, -8 }, +/* 'm' 0x6D */ { 832, 8, 7, 10, 1, -6 }, +/* 'n' 0x6E */ { 839, 5, 7, 6, 1, -6 }, +/* 'o' 0x6F */ { 844, 6, 7, 6, 0, -6 }, +/* 'p' 0x70 */ { 850, 5, 9, 7, 1, -6 }, +/* 'q' 0x71 */ { 856, 6, 9, 7, 0, -6 }, +/* 'r' 0x72 */ { 863, 3, 7, 4, 1, -6 }, +/* 's' 0x73 */ { 866, 5, 7, 6, 0, -6 }, +/* 't' 0x74 */ { 871, 3, 8, 3, 0, -7 }, +/* 'u' 0x75 */ { 874, 5, 7, 6, 1, -6 }, +/* 'v' 0x76 */ { 879, 6, 7, 6, 0, -6 }, +/* 'w' 0x77 */ { 885, 8, 7, 9, 0, -6 }, +/* 'x' 0x78 */ { 892, 5, 7, 6, 0, -6 }, +/* 'y' 0x79 */ { 897, 5, 10, 6, 0, -6 }, +/* 'z' 0x7A */ { 904, 5, 7, 6, 0, -6 }, +/* '{' 0x7B */ { 909, 2, 12, 4, 1, -8 }, +/* '|' 0x7C */ { 912, 1, 11, 3, 1, -8 }, +/* '}' 0x7D */ { 914, 2, 12, 4, 1, -8 }, +/* '~' 0x7E */ { 917, 6, 2, 6, 0, -4 }, +/* 0x7F */ { 919, 9, 10, 0, 1, -8 }, +/* 0x80 */ { 931, 7, 9, 8, 0, -8 }, +/* 0x81 */ { 939, 0, 0, 8, 0, 0 }, +/* 0x82 */ { 939, 1, 3, 3, 1, 0 }, +/* 0x83 */ { 940, 0, 0, 8, 0, 0 }, +/* 0x84 */ { 940, 3, 3, 5, 1, 0 }, +/* 0x85 */ { 942, 5, 1, 7, 1, 0 }, +/* 0x86 */ { 943, 5, 11, 7, 1, -8 }, +/* 0x87 */ { 950, 5, 11, 7, 1, -8 }, +/* 0x88 */ { 957, 0, 0, 8, 0, 0 }, +/* 0x89 */ { 957, 12, 9, 12, 0, -8 }, +/* 0x8A */ { 971, 6, 11, 8, 1, -9 }, +/* 0x8B */ { 980, 2, 3, 4, 1, -4 }, +/* 0x8C */ { 981, 6, 11, 8, 1, -10 }, +/* 0x8D */ { 990, 6, 10, 8, 0, -9 }, +/* 0x8E */ { 998, 7, 10, 7, 0, -9 }, +/* 0x8F */ { 1007, 7, 10, 7, 0, -9 }, +/* 0x90 */ { 1016, 0, 0, 8, 0, 0 }, +/* 0x91 */ { 1016, 1, 3, 3, 1, -8 }, +/* 0x92 */ { 1017, 1, 3, 2, 1, -8 }, +/* 0x93 */ { 1018, 3, 3, 5, 1, -8 }, +/* 0x94 */ { 1020, 3, 3, 5, 1, -8 }, +/* 0x95 */ { 1022, 3, 3, 5, 1, -5 }, +/* 0x96 */ { 1024, 6, 1, 6, 0, -3 }, +/* 0x97 */ { 1025, 12, 1, 12, 0, -3 }, +/* 0x98 */ { 1027, 0, 0, 8, 0, 0 }, +/* 0x99 */ { 1027, 11, 7, 12, 1, -8 }, +/* 0x9A */ { 1037, 4, 9, 6, 1, -8 }, +/* 0x9B */ { 1042, 2, 3, 3, 1, -4 }, +/* 0x9C */ { 1043, 4, 10, 6, 1, -9 }, +/* 0x9D */ { 1048, 4, 9, 5, 0, -8 }, +/* 0x9E */ { 1053, 5, 10, 6, 0, -9 }, +/* 0x9F */ { 1060, 5, 10, 6, 0, -9 }, +/* 0xA0 */ { 1067, 0, 0, 3, 0, 0 }, +/* 0xA1 */ { 1067, 3, 2, 4, 0, -8 }, +/* 0xA2 */ { 1068, 4, 2, 4, 0, -8 }, +/* 0xA3 */ { 1069, 6, 9, 7, 0, -8 }, +/* 0xA4 */ { 1076, 5, 4, 7, 1, -5 }, +/* 0xA5 */ { 1079, 8, 11, 8, 1, -8 }, +/* 0xA6 */ { 1090, 1, 12, 3, 1, -8 }, +/* 0xA7 */ { 1092, 5, 12, 7, 1, -8 }, +/* 0xA8 */ { 1100, 3, 1, 4, 0, -7 }, +/* 0xA9 */ { 1101, 9, 9, 10, 0, -8 }, +/* 0xAA */ { 1112, 6, 12, 8, 1, -8 }, +/* 0xAB */ { 1121, 4, 4, 6, 1, -4 }, +/* 0xAC */ { 1123, 6, 3, 7, 1, -4 }, +/* 0xAD */ { 1126, 0, 0, 0, 0, 0 }, +/* 0xAE */ { 1126, 9, 9, 10, 0, -8 }, +/* 0xAF */ { 1137, 7, 10, 7, 0, -9 }, +/* 0xB0 */ { 1146, 4, 4, 7, 2, -8 }, +/* 0xB1 */ { 1148, 5, 7, 7, 1, -6 }, +/* 0xB2 */ { 1153, 3, 2, 4, 1, 1 }, +/* 0xB3 */ { 1154, 3, 9, 3, 0, -8 }, +/* 0xB4 */ { 1158, 1, 1, 4, 1, -8 }, +/* 0xB5 */ { 1159, 6, 9, 7, 1, -6 }, +/* 0xB6 */ { 1166, 6, 10, 6, 1, -8 }, +/* 0xB7 */ { 1174, 1, 1, 3, 1, -2 }, +/* 0xB8 */ { 1175, 3, 3, 4, 1, 1 }, +/* 0xB9 */ { 1177, 8, 9, 7, 0, -6 }, +/* 0xBA */ { 1186, 4, 10, 6, 1, -6 }, +/* 0xBB */ { 1191, 4, 4, 6, 1, -5 }, +/* 0xBC */ { 1193, 5, 9, 7, 1, -8 }, +/* 0xBD */ { 1199, 3, 1, 4, 0, -8 }, +/* 0xBE */ { 1200, 3, 10, 3, 1, -9 }, +/* 0xBF */ { 1204, 5, 9, 6, 0, -8 }, +/* 0xC0 */ { 1210, 7, 10, 9, 1, -9 }, +/* 0xC1 */ { 1219, 8, 10, 8, 0, -9 }, +/* 0xC2 */ { 1229, 8, 10, 8, 0, -9 }, +/* 0xC3 */ { 1239, 8, 10, 8, 0, -9 }, +/* 0xC4 */ { 1249, 8, 10, 8, 0, -9 }, +/* 0xC5 */ { 1259, 5, 10, 7, 1, -9 }, +/* 0xC6 */ { 1266, 7, 11, 9, 0, -10 }, +/* 0xC7 */ { 1276, 8, 12, 9, 0, -8 }, +/* 0xC8 */ { 1288, 7, 11, 9, 0, -10 }, +/* 0xC9 */ { 1298, 6, 10, 8, 1, -9 }, +/* 0xCA */ { 1306, 7, 11, 8, 1, -8 }, +/* 0xCB */ { 1316, 6, 10, 8, 1, -9 }, +/* 0xCC */ { 1324, 6, 11, 8, 1, -10 }, +/* 0xCD */ { 1333, 2, 10, 3, 1, -9 }, +/* 0xCE */ { 1336, 3, 10, 4, 0, -9 }, +/* 0xCF */ { 1340, 7, 10, 8, 1, -9 }, +/* 0xD0 */ { 1349, 8, 9, 8, 0, -8 }, +/* 0xD1 */ { 1358, 7, 10, 9, 1, -9 }, +/* 0xD2 */ { 1367, 7, 10, 9, 1, -9 }, +/* 0xD3 */ { 1376, 9, 10, 9, 0, -9 }, +/* 0xD4 */ { 1388, 9, 11, 9, 0, -10 }, +/* 0xD5 */ { 1401, 9, 11, 9, 0, -10 }, +/* 0xD6 */ { 1414, 9, 11, 9, 0, -10 }, +/* 0xD7 */ { 1427, 5, 5, 7, 1, -5 }, +/* 0xD8 */ { 1431, 7, 10, 9, 1, -9 }, +/* 0xD9 */ { 1440, 7, 10, 9, 1, -9 }, +/* 0xDA */ { 1449, 7, 10, 9, 1, -9 }, +/* 0xDB */ { 1458, 7, 10, 9, 1, -9 }, +/* 0xDC */ { 1467, 7, 10, 9, 1, -9 }, +/* 0xDD */ { 1476, 7, 10, 8, 1, -9 }, +/* 0xDE */ { 1485, 6, 12, 7, 0, -8 }, +/* 0xDF */ { 1494, 6, 9, 7, 1, -8 }, +/* 0xE0 */ { 1501, 3, 9, 4, 1, -8 }, +/* 0xE1 */ { 1505, 7, 10, 7, 0, -9 }, +/* 0xE2 */ { 1514, 7, 10, 7, 0, -9 }, +/* 0xE3 */ { 1523, 7, 10, 7, 0, -9 }, +/* 0xE4 */ { 1532, 7, 9, 7, 0, -8 }, +/* 0xE5 */ { 1540, 2, 10, 3, 1, -9 }, +/* 0xE6 */ { 1543, 6, 10, 6, 0, -9 }, +/* 0xE7 */ { 1551, 6, 10, 6, 0, -6 }, +/* 0xE8 */ { 1559, 6, 10, 6, 0, -9 }, +/* 0xE9 */ { 1567, 6, 10, 6, 0, -9 }, +/* 0xEA */ { 1575, 6, 9, 6, 0, -6 }, +/* 0xEB */ { 1582, 6, 9, 6, 0, -8 }, +/* 0xEC */ { 1589, 6, 10, 6, 0, -9 }, +/* 0xED */ { 1597, 2, 10, 3, 1, -9 }, +/* 0xEE */ { 1600, 3, 10, 3, 0, -9 }, +/* 0xEF */ { 1604, 7, 10, 7, 0, -9 }, +/* 0xF0 */ { 1613, 7, 9, 7, 0, -8 }, +/* 0xF1 */ { 1621, 5, 10, 6, 1, -9 }, +/* 0xF2 */ { 1628, 5, 10, 6, 1, -9 }, +/* 0xF3 */ { 1635, 6, 10, 6, 0, -9 }, +/* 0xF4 */ { 1643, 6, 10, 6, 0, -9 }, +/* 0xF5 */ { 1651, 6, 10, 6, 0, -9 }, +/* 0xF6 */ { 1659, 6, 9, 6, 0, -8 }, +/* 0xF7 */ { 1666, 5, 5, 7, 1, -5 }, +/* 0xF8 */ { 1670, 3, 10, 4, 1, -9 }, +/* 0xF9 */ { 1674, 5, 10, 6, 1, -9 }, +/* 0xFA */ { 1681, 5, 9, 6, 1, -8 }, +/* 0xFB */ { 1687, 5, 10, 6, 1, -9 }, +/* 0xFC */ { 1694, 5, 9, 6, 1, -8 }, +/* 0xFD */ { 1700, 6, 12, 6, 0, -8 }, +/* 0xFE */ { 1709, 4, 11, 3, 0, -7 }, +/* 0xFF */ { 1715, 1, 1, 4, 1, -7 }, }; -const GFXfont FreeSans6pt_Win1250 PROGMEM = {(uint8_t *)FreeSans6pt_Win1250Bitmaps, (GFXglyph *)FreeSans6pt_Win1250Glyphs, 0x20, - 0xFF, 14}; +const GFXfont FreeSans6pt_Win1250 PROGMEM = { +(uint8_t*)FreeSans6pt_Win1250Bitmaps, +(GFXglyph*)FreeSans6pt_Win1250Glyphs, +0x01, 0xFF, 14 +}; diff --git a/src/graphics/niche/Fonts/FreeSans6pt_Win1251.h b/src/graphics/niche/Fonts/FreeSans6pt_Win1251.h index 4d3ad1705..8fe505fbd 100644 --- a/src/graphics/niche/Fonts/FreeSans6pt_Win1251.h +++ b/src/graphics/niche/Fonts/FreeSans6pt_Win1251.h @@ -1,457 +1,527 @@ +// trunk-ignore-all(clang-format) #pragma once +/* PROPERTIES + +FONT_NAME FreeSans6pt_Win1251 +*/ const uint8_t FreeSans6pt_Win1251Bitmaps[] PROGMEM = { - /* ' ' 0x20 */ - 0xFC, 0x80, /* '!' 0x21 */ - 0xB6, 0x80, /* '"' 0x22 */ - 0x24, 0x51, 0xF9, 0x42, 0x9F, 0x92, 0x28, /* '#' 0x23 */ - 0x10, 0xE5, 0x55, 0x50, 0xE1, 0x65, 0x55, 0xE1, 0x00, /* '$' 0x24 */ - 0x71, 0x24, 0x89, 0x22, 0x50, 0x74, 0x02, 0x70, 0xA4, 0x49, 0x11, 0xC0, /* '%' 0x25 */ - 0x71, 0x24, 0x9C, 0x62, 0x58, 0xA7, 0xF4, /* '&' 0x26 */ - 0xE0, /* ''' 0x27 */ - 0x5A, 0xAA, 0x94, /* '(' 0x28 */ - 0x89, 0x12, 0x49, 0x29, 0x00, /* ')' 0x29 */ - 0x5E, 0x80, /* '*' 0x2A */ - 0x21, 0x3E, 0x42, 0x00, /* '+' 0x2B */ - 0xE0, /* ',' 0x2C */ - 0xC0, /* '-' 0x2D */ - 0x80, /* '.' 0x2E */ - 0x24, 0xA4, 0xA4, 0x80, /* '/' 0x2F */ - 0x76, 0xE3, 0x18, 0xC6, 0x3B, 0x70, /* '0' 0x30 */ - 0x27, 0x92, 0x49, 0x20, /* '1' 0x31 */ - 0x79, 0x10, 0x41, 0x08, 0xC6, 0x10, 0xFC, /* '2' 0x32 */ - 0x79, 0x30, 0x43, 0x18, 0x10, 0x71, 0x78, /* '3' 0x33 */ - 0x08, 0x61, 0x8A, 0x49, 0x2F, 0xC2, 0x08, /* '4' 0x34 */ - 0xFC, 0x21, 0xE8, 0x84, 0x31, 0xF0, /* '5' 0x35 */ - 0x74, 0x61, 0xE8, 0xC6, 0x31, 0x70, /* '6' 0x36 */ - 0xF8, 0x44, 0x22, 0x11, 0x08, 0x40, /* '7' 0x37 */ - 0x39, 0x34, 0x53, 0x39, 0x1C, 0x51, 0x38, /* '8' 0x38 */ - 0x39, 0x3C, 0x71, 0x4C, 0xF0, 0x53, 0x78, /* '9' 0x39 */ - 0x82, /* ':' 0x3A */ - 0x87, /* ';' 0x3B */ - 0x3E, 0x30, 0x60, 0x80, /* '<' 0x3C */ - 0xF8, 0x3E, /* '=' 0x3D */ - 0xE0, 0xC6, 0xC8, 0x00, /* '>' 0x3E */ - 0x74, 0x42, 0x11, 0x10, 0x80, 0x20, /* '?' 0x3F */ - 0x0F, 0x86, 0x19, 0x9A, 0xA4, 0xD9, 0x13, 0x22, 0x56, 0xDA, 0x6E, 0x60, 0x06, 0x00, 0x3C, 0x00, /* '@' 0x40 */ - 0x18, 0x18, 0x24, 0x24, 0x24, 0x7E, 0x42, 0x42, 0xC3, /* 'A' 0x41 */ - 0xFA, 0x18, 0x61, 0xFA, 0x18, 0x61, 0xFC, /* 'B' 0x42 */ - 0x3E, 0x63, 0x40, 0x40, 0xC0, 0x40, 0x41, 0x63, 0x3E, /* 'C' 0x43 */ - 0xF9, 0x0A, 0x1C, 0x18, 0x30, 0x61, 0xC2, 0xF8, /* 'D' 0x44 */ - 0xFE, 0x08, 0x20, 0xFE, 0x08, 0x20, 0xFC, /* 'E' 0x45 */ - 0xFE, 0x08, 0x20, 0xFA, 0x08, 0x20, 0x80, /* 'F' 0x46 */ - 0x1E, 0x61, 0x40, 0x40, 0xC7, 0x41, 0x41, 0x63, 0x1D, /* 'G' 0x47 */ - 0x83, 0x06, 0x0C, 0x1F, 0xF0, 0x60, 0xC1, 0x82, /* 'H' 0x48 */ - 0xFF, 0x80, /* 'I' 0x49 */ - 0x08, 0x42, 0x10, 0x87, 0x29, 0x70, /* 'J' 0x4A */ - 0x85, 0x12, 0x45, 0x0D, 0x13, 0x22, 0x42, 0x86, /* 'K' 0x4B */ - 0x84, 0x21, 0x08, 0x42, 0x10, 0xF8, /* 'L' 0x4C */ - 0xC3, 0xC3, 0xC3, 0xA5, 0xA5, 0xA5, 0x99, 0x99, 0x99, /* 'M' 0x4D */ - 0x83, 0x86, 0x8D, 0x19, 0x33, 0x62, 0xC3, 0x86, /* 'N' 0x4E */ - 0x1E, 0x31, 0x90, 0x68, 0x1C, 0x0A, 0x05, 0x06, 0xC6, 0x1E, 0x00, /* 'O' 0x4F */ - 0xFA, 0x18, 0x61, 0xFA, 0x08, 0x20, 0x80, /* 'P' 0x50 */ - 0x1E, 0x31, 0x90, 0x68, 0x1C, 0x0A, 0x05, 0x16, 0xC6, 0x1F, 0x00, 0x40, /* 'Q' 0x51 */ - 0xFD, 0x0E, 0x1C, 0x2F, 0x90, 0xA1, 0x42, 0x86, /* 'R' 0x52 */ - 0x7A, 0x18, 0x30, 0x78, 0x38, 0x61, 0x78, /* 'S' 0x53 */ - 0xFE, 0x20, 0x40, 0x81, 0x02, 0x04, 0x08, 0x10, /* 'T' 0x54 */ - 0x83, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xE2, 0x78, /* 'U' 0x55 */ - 0xC2, 0x85, 0x0B, 0x22, 0x44, 0x8E, 0x0C, 0x18, /* 'V' 0x56 */ - 0xC4, 0x28, 0xCD, 0x29, 0x25, 0x24, 0xA4, 0x52, 0x8C, 0x61, 0x8C, 0x31, 0x80, /* 'W' 0x57 */ - 0x87, 0x34, 0x8C, 0x30, 0xC4, 0xA3, 0x84, /* 'X' 0x58 */ - 0xC3, 0x42, 0x24, 0x34, 0x18, 0x08, 0x08, 0x08, 0x08, /* 'Y' 0x59 */ - 0x7E, 0x0C, 0x30, 0x41, 0x06, 0x18, 0x20, 0xFE, /* 'Z' 0x5A */ - 0xEA, 0xAA, 0xAB, /* '[' 0x5B */ - 0x92, 0x24, 0x89, 0x20, /* '\' 0x5C */ - 0xD5, 0x55, 0x57, /* ']' 0x5D */ - 0x46, 0xA9, /* '^' 0x5E */ - 0xFE, /* '_' 0x5F */ - 0x80, /* '`' 0x60 */ - 0x79, 0x20, 0x4F, 0xC6, 0x37, 0x40, /* 'a' 0x61 */ - 0x84, 0x3D, 0x18, 0xC6, 0x31, 0xF0, /* 'b' 0x62 */ - 0x39, 0x3C, 0x20, 0xC1, 0x33, 0x80, /* 'c' 0x63 */ - 0x04, 0x13, 0xD3, 0xC6, 0x1C, 0x53, 0x3C, /* 'd' 0x64 */ - 0x39, 0x38, 0x7F, 0x81, 0x13, 0x80, /* 'e' 0x65 */ - 0x6B, 0xA4, 0x92, 0x40, /* 'f' 0x66 */ - 0x35, 0x3C, 0x61, 0xC5, 0x33, 0x41, 0x4D, 0xE0, /* 'g' 0x67 */ - 0x84, 0x3D, 0x38, 0xC6, 0x31, 0x88, /* 'h' 0x68 */ - 0xBF, 0x80, /* 'i' 0x69 */ - 0x45, 0x55, 0x57, /* 'j' 0x6A */ - 0x84, 0x25, 0x4E, 0x52, 0xD2, 0x88, /* 'k' 0x6B */ - 0xFF, 0x80, /* 'l' 0x6C */ - 0xF7, 0x99, 0x91, 0x91, 0x91, 0x91, 0x91, /* 'm' 0x6D */ - 0xF4, 0x63, 0x18, 0xC6, 0x20, /* 'n' 0x6E */ - 0x39, 0x3C, 0x61, 0xC5, 0x33, 0x80, /* 'o' 0x6F */ - 0xF4, 0x63, 0x18, 0xC7, 0xD0, 0x80, /* 'p' 0x70 */ - 0x3D, 0x3C, 0x61, 0xC5, 0x37, 0x41, 0x04, /* 'q' 0x71 */ - 0xF2, 0x49, 0x20, /* 'r' 0x72 */ - 0x7A, 0x50, 0xE0, 0xE5, 0xE0, /* 's' 0x73 */ - 0x5D, 0x24, 0x93, /* 't' 0x74 */ - 0x8C, 0x63, 0x18, 0xCF, 0xA0, /* 'u' 0x75 */ - 0x85, 0x24, 0x92, 0x30, 0xC3, 0x00, /* 'v' 0x76 */ - 0x89, 0x59, 0x59, 0x55, 0x56, 0x26, 0x26, /* 'w' 0x77 */ - 0x4A, 0x4C, 0x43, 0x27, 0x20, /* 'x' 0x78 */ - 0x8A, 0x52, 0xA5, 0x18, 0x84, 0x22, 0x00, /* 'y' 0x79 */ - 0x78, 0x44, 0x46, 0x23, 0xE0, /* 'z' 0x7A */ - 0x6A, 0xAA, 0xA9, /* '{' 0x7B */ - 0xFF, 0xE0, /* '|' 0x7C */ - 0x95, 0x55, 0x56, /* '}' 0x7D */ - 0x66, 0x60, /* '~' 0x7E */ - 0xFF, 0xC0, 0x67, 0x34, 0x58, 0x4C, 0x46, 0x03, 0x11, 0x80, 0xFF, 0xC0, /* 0x7F */ - 0xFC, 0x08, 0x04, 0x02, 0x01, 0xF0, 0x8C, 0x46, 0x23, 0x11, 0x80, 0xC0, 0xC0, /* 0x80 */ - 0x10, 0x8F, 0xE0, 0x82, 0x08, 0x20, 0x82, 0x00, /* 0x81 */ - 0xE0, /* 0x82 */ - 0x24, 0x0F, 0x88, 0x88, 0x80, /* 0x83 */ - 0xB6, 0x80, /* 0x84 */ - 0xA8, /* 0x85 */ - 0x21, 0x09, 0xF2, 0x10, 0x84, 0x21, 0x08, /* 0x86 */ - 0x21, 0x09, 0xF2, 0x10, 0x84, 0xF9, 0x08, /* 0x87 */ - 0x1C, 0x45, 0x07, 0xE4, 0x1F, 0x10, 0x10, 0x1E, /* 0x88 */ - 0x62, 0x09, 0x40, 0x98, 0x06, 0x80, 0x10, 0x01, 0x66, 0x29, 0x92, 0x99, 0x06, 0x60, /* 0x89 */ - 0x7C, 0x08, 0x81, 0x10, 0x22, 0x04, 0x7C, 0x88, 0x51, 0x0A, 0x21, 0x87, 0xC0, /* 0x8A */ - 0x64, /* 0x8B */ - 0x84, 0x10, 0x82, 0x10, 0x42, 0x0F, 0xFD, 0x08, 0xA1, 0x0C, 0x23, 0x87, 0xC0, /* 0x8C */ - 0x10, 0x88, 0xE6, 0xB3, 0x8C, 0x28, 0x92, 0x28, 0xC0, /* 0x8D */ - 0xFC, 0x08, 0x04, 0x02, 0x01, 0xF0, 0x8C, 0x46, 0x23, 0x11, 0x80, /* 0x8E */ - 0x83, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0xFE, 0x20, 0x40, /* 0x8F */ - 0x43, 0xC4, 0x1F, 0x45, 0x14, 0x51, 0x44, 0x11, 0x80, /* 0x90 */ - 0xE0, /* 0x91 */ - 0xE0, /* 0x92 */ - 0xB6, 0x80, /* 0x93 */ - 0xB6, 0x80, /* 0x94 */ - 0xFF, 0x80, /* 0x95 */ - 0xFC, /* 0x96 */ - 0xFF, 0xF0, /* 0x97 */ - /* 0x98 */ - 0xE6, 0x28, 0xCD, 0x19, 0xA3, 0x34, 0x6A, 0x8B, 0x51, 0x68, /* 0x99 */ - 0x78, 0x24, 0x13, 0xC9, 0x14, 0x8E, 0x7C, /* 0x9A */ - 0x98, /* 0x9B */ - 0x88, 0x44, 0x3F, 0xD1, 0x38, 0x8C, 0x78, /* 0x9C */ - 0x24, 0x09, 0xAC, 0xCA, 0x90, /* 0x9D */ - 0x43, 0xC4, 0x1F, 0x45, 0x14, 0x51, 0x44, /* 0x9E */ - 0x8C, 0x63, 0x18, 0xFC, 0x80, /* 0x9F */ - /* 0xA0 */ - 0x24, 0x33, 0x0A, 0x36, 0x45, 0x8E, 0x0C, 0x10, 0x60, 0x80, /* 0xA1 */ - 0x51, 0x22, 0x95, 0xA8, 0xC4, 0x23, 0x10, /* 0xA2 */ - 0x08, 0x42, 0x10, 0x86, 0x31, 0x78, /* 0xA3 */ - 0xFC, 0x63, 0xF0, /* 0xA4 */ - 0x07, 0xF8, 0x20, 0x82, 0x08, 0x20, 0x82, 0x00, /* 0xA5 */ - 0xF9, 0xF0, /* 0xA6 */ - 0x32, 0x91, 0xC9, 0x47, 0x26, 0x14, 0xA4, 0xC0, /* 0xA7 */ - 0x28, 0x0F, 0xE0, 0x82, 0x0F, 0xE0, 0x82, 0x0F, 0xC0, /* 0xA8 */ - 0x3E, 0x3F, 0xB8, 0xF4, 0x1A, 0x0D, 0x17, 0x76, 0xC6, 0x3E, 0x00, /* 0xA9 */ - 0x38, 0x8A, 0x0C, 0x0F, 0x90, 0x20, 0xE3, 0x7C, /* 0xAA */ - 0x5A, 0xA5, /* 0xAB */ - 0x51, 0x55, 0x56, /* 0xAC */ - /* 0xAD */ - 0x3E, 0x31, 0xB7, 0x72, 0x99, 0xCC, 0xC7, 0x56, 0xC6, 0x3E, 0x00, /* 0xAE */ - 0xA1, 0x24, 0x92, 0x49, 0x00, /* 0xAF */ - 0x69, 0x96, /* 0xB0 */ - 0x21, 0x3E, 0x42, 0x03, 0xE0, /* 0xB1 */ - 0xFF, 0x80, /* 0xB2 */ - 0xDF, 0x80, /* 0xB3 */ - 0x27, 0xC9, 0x24, /* 0xB4 */ - 0x8A, 0x28, 0xA2, 0x8A, 0x6E, 0xE0, 0x80, /* 0xB5 */ - 0x7F, 0xAE, 0xBA, 0x68, 0xA2, 0x8A, 0x28, 0xA0, /* 0xB6 */ - 0x80, /* 0xB7 */ - 0x28, 0xA0, 0x1E, 0x47, 0xFC, 0x11, 0x78, /* 0xB8 */ - 0x88, 0x44, 0x32, 0x59, 0xDA, 0xCD, 0x66, 0x6B, 0x32, 0x8B, 0x80, /* 0xB9 */ - 0x79, 0x1F, 0x30, 0x45, 0xE0, /* 0xBA */ - 0xA5, 0x5A, /* 0xBB */ - 0x45, 0x55, 0x57, /* 0xBC */ - 0x7A, 0x18, 0x70, 0x78, 0x38, 0x61, 0x7C, /* 0xBD */ - 0x7A, 0x1C, 0x1C, 0xBC, /* 0xBE */ - 0xB4, 0x24, 0x92, 0x40, /* 0xBF */ - 0x18, 0x18, 0x3C, 0x24, 0x24, 0x7E, 0x42, 0x42, 0xC3, /* 0xC0 */ - 0xFE, 0x08, 0x20, 0xFA, 0x18, 0x61, 0xF8, /* 0xC1 */ - 0xFA, 0x18, 0x61, 0xFA, 0x18, 0x61, 0xFC, /* 0xC2 */ - 0xFE, 0x08, 0x20, 0x82, 0x08, 0x20, 0x80, /* 0xC3 */ - 0x1F, 0x08, 0x84, 0x42, 0x21, 0x10, 0x88, 0x44, 0x42, 0xFF, 0xC0, 0x60, 0x20, /* 0xC4 */ - 0xFE, 0x08, 0x20, 0xFE, 0x08, 0x20, 0xFC, /* 0xC5 */ - 0x88, 0xA4, 0x9A, 0x87, 0xC1, 0xC1, 0xF1, 0xAD, 0x92, 0x88, 0x80, /* 0xC6 */ - 0x7A, 0x18, 0x41, 0x38, 0x18, 0x61, 0x7C, /* 0xC7 */ - 0x87, 0x0E, 0x2C, 0x59, 0x34, 0x68, 0xE1, 0xC2, /* 0xC8 */ - 0x28, 0x22, 0x1C, 0x38, 0xB1, 0x64, 0xD1, 0xA3, 0x87, 0x08, /* 0xC9 */ - 0x8E, 0x6B, 0x38, 0xC2, 0x89, 0x22, 0x8C, /* 0xCA */ - 0x3E, 0x44, 0x89, 0x12, 0x24, 0x58, 0xA1, 0xC2, /* 0xCB */ - 0xC3, 0xC3, 0xC3, 0xA5, 0xA5, 0xA5, 0x99, 0x99, 0x99, /* 0xCC */ - 0x83, 0x06, 0x0C, 0x1F, 0xF0, 0x60, 0xC1, 0x82, /* 0xCD */ - 0x3C, 0x42, 0x81, 0x81, 0x81, 0x81, 0x81, 0xC2, 0x7C, /* 0xCE */ - 0xFF, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x82, /* 0xCF */ - 0xFA, 0x18, 0x61, 0xFE, 0x08, 0x20, 0x80, /* 0xD0 */ - 0x38, 0x8A, 0x0C, 0x08, 0x10, 0x20, 0xE3, 0x7C, /* 0xD1 */ - 0xFE, 0x20, 0x40, 0x81, 0x02, 0x04, 0x08, 0x10, /* 0xD2 */ - 0xC2, 0x8D, 0x91, 0x63, 0x83, 0x04, 0x18, 0x20, /* 0xD3 */ - 0x08, 0x1F, 0x32, 0x71, 0x18, 0x8C, 0x47, 0x26, 0xFE, 0x08, 0x00, /* 0xD4 */ - 0x87, 0x34, 0x8C, 0x30, 0xC4, 0xB3, 0x84, /* 0xD5 */ - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0xFF, 0x01, 0x01, /* 0xD6 */ - 0x8E, 0x38, 0xE3, 0x8D, 0xF0, 0xC3, 0x0C, /* 0xD7 */ - 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0xFF, /* 0xD8 */ - 0x99, 0x4C, 0xA6, 0x53, 0x29, 0x94, 0xCA, 0x65, 0x32, 0xFF, 0x80, 0x40, 0x20, /* 0xD9 */ - 0xF0, 0x04, 0x01, 0x00, 0x40, 0x1F, 0x84, 0x21, 0x0C, 0x42, 0x1F, 0x00, /* 0xDA */ - 0x81, 0xC0, 0xE0, 0x70, 0x3F, 0xDC, 0x2E, 0x17, 0x0B, 0xF9, 0x80, /* 0xDB */ - 0x82, 0x08, 0x20, 0xFE, 0x18, 0x61, 0xF8, /* 0xDC */ - 0x79, 0x8A, 0x18, 0x13, 0xE0, 0x60, 0xC2, 0x7C, /* 0xDD */ - 0x87, 0x26, 0x39, 0x06, 0x41, 0xF0, 0x64, 0x19, 0x06, 0x63, 0x8F, 0x80, /* 0xDE */ - 0x7E, 0x18, 0x61, 0x7C, 0xD6, 0x71, 0x84, /* 0xDF */ - 0x79, 0x11, 0xD9, 0xCD, 0xD0, /* 0xE0 */ - 0x0D, 0xC4, 0x1E, 0x47, 0x1C, 0x51, 0x78, /* 0xE1 */ - 0xF4, 0xBD, 0x29, 0xF8, /* 0xE2 */ - 0xF8, 0x88, 0x88, /* 0xE3 */ - 0x3C, 0x48, 0x91, 0x22, 0x5F, 0xE0, 0x80, /* 0xE4 */ - 0x79, 0x1F, 0xF0, 0x45, 0xE0, /* 0xE5 */ - 0x92, 0x54, 0x38, 0x3C, 0x56, 0x93, /* 0xE6 */ - 0x78, 0x23, 0x82, 0xCD, 0xE0, /* 0xE7 */ - 0x9C, 0xEB, 0x5C, 0xC4, /* 0xE8 */ - 0x70, 0x27, 0x3A, 0xD7, 0x31, /* 0xE9 */ - 0x9A, 0xCC, 0xA9, /* 0xEA */ - 0x7A, 0x52, 0x94, 0xE4, /* 0xEB */ - 0x8F, 0x3D, 0x6D, 0xA6, 0x90, /* 0xEC */ - 0x8C, 0x7F, 0x18, 0xC4, /* 0xED */ - 0x79, 0x1C, 0x71, 0x45, 0xE0, /* 0xEE */ - 0xFC, 0x63, 0x18, 0xC4, /* 0xEF */ - 0xFC, 0x63, 0x18, 0xFA, 0x10, 0x80, /* 0xF0 */ - 0x79, 0x1C, 0x30, 0x45, 0xE0, /* 0xF1 */ - 0xF9, 0x08, 0x42, 0x10, /* 0xF2 */ - 0x8A, 0x56, 0xA3, 0x10, 0x8C, 0x40, /* 0xF3 */ - 0x04, 0x01, 0x07, 0xF9, 0x31, 0xC4, 0x71, 0x14, 0xC5, 0xFE, 0x04, 0x01, 0x00, 0x40, /* 0xF4 */ - 0x4B, 0x8C, 0x65, 0xE4, /* 0xF5 */ - 0x8A, 0x28, 0xA2, 0x8B, 0xF0, 0x40, /* 0xF6 */ - 0x99, 0x97, 0x11, /* 0xF7 */ - 0x96, 0x59, 0x65, 0x97, 0xF0, /* 0xF8 */ - 0x95, 0x2A, 0x54, 0xA9, 0x5F, 0xC0, 0x80, /* 0xF9 */ - 0xF0, 0x20, 0x78, 0x91, 0x23, 0xC0, /* 0xFA */ - 0x86, 0x1F, 0x63, 0x8F, 0xD0, /* 0xFB */ - 0x84, 0x3D, 0x18, 0xF8, /* 0xFC */ - 0xF4, 0xDE, 0x19, 0xF8, /* 0xFD */ - 0x9E, 0xA2, 0xE1, 0xA1, 0xA2, 0x9E, /* 0xFE */ - 0xFC, 0x7E, 0xD4, 0xC4, /* 0xFF */ +/* 0x01 */ 0x1C, 0x0A, 0x05, 0x04, 0xFE, 0x08, 0x1C, 0x02, 0x07, 0xE0, 0x9F, 0xC0, +/* 0x02 */ 0x3F, 0xF0, 0x40, 0xE0, 0x10, 0x3F, 0x04, 0x9E, 0x28, 0x14, 0x0E, 0x00, +/* 0x03 */ 0x3F, 0x10, 0x28, 0x06, 0x49, 0x80, 0x60, 0x19, 0x26, 0x31, 0x40, 0x8F, 0xC0, +/* 0x04 */ 0x3F, 0x10, 0x2A, 0x16, 0x49, 0xA1, 0x60, 0x19, 0xE6, 0x31, 0x40, 0x8F, 0xC0, +/* 0x05 */ 0x28, 0x15, 0x2A, 0xB5, 0x55, 0xA8, 0x54, 0x12, 0x04, 0x41, 0x08, 0x81, 0xC0, +/* 0x06 */ 0x04, 0x08, 0x88, 0x82, 0x07, 0x01, 0x11, 0xA2, 0xC4, 0x40, 0x70, 0x20, 0x88, 0x88, 0x10, 0x00, +/* 0x07 */ +/* 0x08 */ 0x03, 0x83, 0x44, 0x48, 0x28, 0x01, 0x80, 0x17, 0xFE, 0x08, 0x45, 0x28, 0x84, 0x00, +/* 0x09 */ 0x01, 0xC0, 0x68, 0x82, 0x41, 0x10, 0x02, 0x80, 0x06, 0x00, 0x14, 0x00, 0x8F, 0xFC, +/* 0x0A */ +/* 0x0B */ 0x22, 0x2A, 0xA2, 0x30, 0x18, 0x0A, 0x09, 0x04, 0x44, 0x14, 0x04, 0x00, +/* 0x0C */ 0x46, 0x00, 0x19, 0x03, 0x21, 0x20, 0x93, 0x04, 0x20, 0x11, 0x80, 0x50, 0x02, 0x7F, 0xE0, +/* 0x0D */ +/* 0x0E */ 0x08, 0x0E, 0x08, 0x88, 0x24, 0x12, 0x09, 0x05, 0x01, 0xFF, 0x8A, 0x02, 0x00, +/* 0x0F */ 0x3F, 0x14, 0xAA, 0x16, 0x01, 0x92, 0x60, 0x18, 0xC6, 0x49, 0x40, 0x8F, 0xC0, +/* 0x10 */ 0x1B, 0x02, 0xA0, 0x54, 0x12, 0x42, 0x48, 0x49, 0x31, 0x1E, 0x23, 0xEA, 0xFE, 0x3C, +/* 0x11 */ 0x3F, 0x02, 0x00, 0x20, 0x6D, 0x27, 0xF8, 0x3F, 0xC1, 0xFE, 0x37, 0xD0, 0xBE, 0x40, 0xE1, 0xE2, 0x00, +/* 0x12 */ 0x12, 0x42, 0x20, 0x24, 0xC0, 0x29, 0x99, 0x05, 0x23, 0x30, 0xB0, 0x30, 0x00, +/* 0x13 */ 0x3F, 0x88, 0x0A, 0x44, 0xD5, 0x58, 0x03, 0x00, 0x67, 0xCC, 0x71, 0x40, 0x47, 0xF0, +/* 0x14 */ 0x3F, 0x18, 0x69, 0x26, 0x85, 0xA1, 0x6C, 0xD8, 0x06, 0x31, 0x40, 0x8F, 0xC0, +/* 0x15 */ 0x3F, 0x11, 0x00, 0xE8, 0x03, 0xA0, 0x1F, 0xB3, 0x7E, 0x00, 0xE9, 0xE0, 0x23, 0x00, 0x40, 0x40, 0xFE, 0x00, +/* 0x16 */ 0x30, 0x38, 0x3A, 0x3E, 0x6E, 0xEB, 0xC3, 0xC3, 0x66, 0x3C, +/* 0x17 */ 0x3F, 0x04, 0x00, 0x82, 0x88, 0x5C, 0xA4, 0x49, 0x22, 0x81, 0x98, 0xC4, 0x40, 0xA3, 0xF0, +/* 0x18 */ 0x07, 0x80, 0x42, 0x04, 0x08, 0x21, 0x41, 0x42, 0x60, 0x0E, 0x8C, 0xB2, 0x89, 0x50, 0x52, 0x82, 0x80, +/* 0x19 */ 0x3F, 0xC4, 0x02, 0x80, 0x18, 0x01, 0xB3, 0x1B, 0xB9, 0x80, 0x19, 0xE1, 0x40, 0x23, 0xFC, +/* 0x1A */ 0xFF, 0xC0, 0x67, 0x34, 0x58, 0x4C, 0x46, 0x03, 0x11, 0x80, 0xFF, 0xC0, +/* 0x1B */ 0x0F, 0xC0, 0x40, 0x82, 0x49, 0x08, 0x04, 0x00, 0x00, 0x12, 0x02, 0x31, 0x34, 0x0B, 0x88, 0x45, 0x00, 0x20, +/* 0x1C */ 0x3F, 0x88, 0x0A, 0x44, 0xC9, 0x19, 0x3B, 0x00, 0x60, 0x4C, 0x71, 0x40, 0x47, 0xF0, +/* 0x1D */ 0x3F, 0x8B, 0x0A, 0x00, 0xC8, 0x18, 0x13, 0x00, 0x48, 0xCA, 0xC1, 0x44, 0x53, 0x30, +/* 0x1E */ 0x19, 0xC2, 0x02, 0x50, 0x1E, 0x49, 0x80, 0x12, 0x01, 0x27, 0x92, 0x01, 0x10, 0x20, 0xFC, +/* 0x1F */ 0x30, 0x1C, 0x0C, 0x3E, 0x7E, 0xCF, 0x07, 0xC7, 0x7F, 0x3F, +/* ' ' 0x20 */ +/* '!' 0x21 */ 0xFC, 0x80, +/* '"' 0x22 */ 0xB6, 0x80, +/* '#' 0x23 */ 0x24, 0x51, 0xF9, 0x42, 0x9F, 0x92, 0x28, +/* '$' 0x24 */ 0x10, 0xE5, 0x55, 0x50, 0xE1, 0x65, 0x55, 0xE1, 0x00, +/* '%' 0x25 */ 0x71, 0x24, 0x89, 0x22, 0x50, 0x74, 0x02, 0x70, 0xA4, 0x49, 0x11, 0xC0, +/* '&' 0x26 */ 0x71, 0x24, 0x9C, 0x62, 0x58, 0xA7, 0xF4, +/* ''' 0x27 */ 0xE0, +/* '(' 0x28 */ 0x5A, 0xAA, 0x94, +/* ')' 0x29 */ 0x89, 0x12, 0x49, 0x29, 0x00, +/* '*' 0x2A */ 0x5E, 0x80, +/* '+' 0x2B */ 0x21, 0x3E, 0x42, 0x00, +/* ',' 0x2C */ 0xE0, +/* '-' 0x2D */ 0xC0, +/* '.' 0x2E */ 0x80, +/* '/' 0x2F */ 0x24, 0xA4, 0xA4, 0x80, +/* '0' 0x30 */ 0x76, 0xE3, 0x18, 0xC6, 0x3B, 0x70, +/* '1' 0x31 */ 0x27, 0x92, 0x49, 0x20, +/* '2' 0x32 */ 0x79, 0x10, 0x41, 0x08, 0xC6, 0x10, 0xFC, +/* '3' 0x33 */ 0x79, 0x30, 0x43, 0x18, 0x10, 0x71, 0x78, +/* '4' 0x34 */ 0x08, 0x61, 0x8A, 0x49, 0x2F, 0xC2, 0x08, +/* '5' 0x35 */ 0xFC, 0x21, 0xE8, 0x84, 0x31, 0xF0, +/* '6' 0x36 */ 0x74, 0x61, 0xE8, 0xC6, 0x31, 0x70, +/* '7' 0x37 */ 0xF8, 0x44, 0x22, 0x11, 0x08, 0x40, +/* '8' 0x38 */ 0x39, 0x34, 0x53, 0x39, 0x1C, 0x51, 0x38, +/* '9' 0x39 */ 0x39, 0x3C, 0x71, 0x4C, 0xF0, 0x53, 0x78, +/* ':' 0x3A */ 0x82, +/* ';' 0x3B */ 0x87, +/* '<' 0x3C */ 0x3E, 0x30, 0x60, 0x80, +/* '=' 0x3D */ 0xF8, 0x3E, +/* '>' 0x3E */ 0xE0, 0xC6, 0xC8, 0x00, +/* '?' 0x3F */ 0x74, 0x42, 0x11, 0x10, 0x80, 0x20, +/* '@' 0x40 */ 0x0F, 0x86, 0x19, 0x9A, 0xA4, 0xD9, 0x13, 0x22, 0x56, 0xDA, 0x6E, 0x60, 0x06, 0x00, 0x3C, 0x00, +/* 'A' 0x41 */ 0x18, 0x18, 0x24, 0x24, 0x24, 0x7E, 0x42, 0x42, 0xC3, +/* 'B' 0x42 */ 0xFA, 0x18, 0x61, 0xFA, 0x18, 0x61, 0xFC, +/* 'C' 0x43 */ 0x3E, 0x63, 0x40, 0x40, 0xC0, 0x40, 0x41, 0x63, 0x3E, +/* 'D' 0x44 */ 0xF9, 0x0A, 0x1C, 0x18, 0x30, 0x61, 0xC2, 0xF8, +/* 'E' 0x45 */ 0xFE, 0x08, 0x20, 0xFE, 0x08, 0x20, 0xFC, +/* 'F' 0x46 */ 0xFE, 0x08, 0x20, 0xFA, 0x08, 0x20, 0x80, +/* 'G' 0x47 */ 0x1E, 0x61, 0x40, 0x40, 0xC7, 0x41, 0x41, 0x63, 0x1D, +/* 'H' 0x48 */ 0x83, 0x06, 0x0C, 0x1F, 0xF0, 0x60, 0xC1, 0x82, +/* 'I' 0x49 */ 0xFF, 0x80, +/* 'J' 0x4A */ 0x08, 0x42, 0x10, 0x87, 0x29, 0x70, +/* 'K' 0x4B */ 0x85, 0x12, 0x45, 0x0D, 0x13, 0x22, 0x42, 0x86, +/* 'L' 0x4C */ 0x84, 0x21, 0x08, 0x42, 0x10, 0xF8, +/* 'M' 0x4D */ 0xC3, 0xC3, 0xC3, 0xA5, 0xA5, 0xA5, 0x99, 0x99, 0x99, +/* 'N' 0x4E */ 0x83, 0x86, 0x8D, 0x19, 0x33, 0x62, 0xC3, 0x86, +/* 'O' 0x4F */ 0x1E, 0x31, 0x90, 0x68, 0x1C, 0x0A, 0x05, 0x06, 0xC6, 0x1E, 0x00, +/* 'P' 0x50 */ 0xFA, 0x18, 0x61, 0xFA, 0x08, 0x20, 0x80, +/* 'Q' 0x51 */ 0x1E, 0x31, 0x90, 0x68, 0x1C, 0x0A, 0x05, 0x16, 0xC6, 0x1F, 0x00, 0x40, +/* 'R' 0x52 */ 0xFD, 0x0E, 0x1C, 0x2F, 0x90, 0xA1, 0x42, 0x86, +/* 'S' 0x53 */ 0x7A, 0x18, 0x30, 0x78, 0x38, 0x61, 0x78, +/* 'T' 0x54 */ 0xFE, 0x20, 0x40, 0x81, 0x02, 0x04, 0x08, 0x10, +/* 'U' 0x55 */ 0x83, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xE2, 0x78, +/* 'V' 0x56 */ 0xC2, 0x85, 0x0B, 0x22, 0x44, 0x8E, 0x0C, 0x18, +/* 'W' 0x57 */ 0xC4, 0x28, 0xCD, 0x29, 0x25, 0x24, 0xA4, 0x52, 0x8C, 0x61, 0x8C, 0x31, 0x80, +/* 'X' 0x58 */ 0x87, 0x34, 0x8C, 0x30, 0xC4, 0xA3, 0x84, +/* 'Y' 0x59 */ 0xC3, 0x42, 0x24, 0x34, 0x18, 0x08, 0x08, 0x08, 0x08, +/* 'Z' 0x5A */ 0x7E, 0x0C, 0x30, 0x41, 0x06, 0x18, 0x20, 0xFE, +/* '[' 0x5B */ 0xEA, 0xAA, 0xAB, +/* '\' 0x5C */ 0x92, 0x24, 0x89, 0x20, +/* ']' 0x5D */ 0xD5, 0x55, 0x57, +/* '^' 0x5E */ 0x46, 0xA9, +/* '_' 0x5F */ 0xFE, +/* '`' 0x60 */ 0x80, +/* 'a' 0x61 */ 0x79, 0x20, 0x4F, 0xC6, 0x37, 0x40, +/* 'b' 0x62 */ 0x84, 0x3D, 0x18, 0xC6, 0x31, 0xF0, +/* 'c' 0x63 */ 0x39, 0x3C, 0x20, 0xC1, 0x33, 0x80, +/* 'd' 0x64 */ 0x04, 0x13, 0xD3, 0xC6, 0x1C, 0x53, 0x3C, +/* 'e' 0x65 */ 0x39, 0x38, 0x7F, 0x81, 0x13, 0x80, +/* 'f' 0x66 */ 0x6B, 0xA4, 0x92, 0x40, +/* 'g' 0x67 */ 0x35, 0x3C, 0x61, 0xC5, 0x33, 0x41, 0x4D, 0xE0, +/* 'h' 0x68 */ 0x84, 0x3D, 0x38, 0xC6, 0x31, 0x88, +/* 'i' 0x69 */ 0xBF, 0x80, +/* 'j' 0x6A */ 0x45, 0x55, 0x57, +/* 'k' 0x6B */ 0x84, 0x25, 0x4E, 0x52, 0xD2, 0x88, +/* 'l' 0x6C */ 0xFF, 0x80, +/* 'm' 0x6D */ 0xF7, 0x99, 0x91, 0x91, 0x91, 0x91, 0x91, +/* 'n' 0x6E */ 0xF4, 0x63, 0x18, 0xC6, 0x20, +/* 'o' 0x6F */ 0x39, 0x3C, 0x61, 0xC5, 0x33, 0x80, +/* 'p' 0x70 */ 0xF4, 0x63, 0x18, 0xC7, 0xD0, 0x80, +/* 'q' 0x71 */ 0x3D, 0x3C, 0x61, 0xC5, 0x37, 0x41, 0x04, +/* 'r' 0x72 */ 0xF2, 0x49, 0x20, +/* 's' 0x73 */ 0x7A, 0x50, 0xE0, 0xE5, 0xE0, +/* 't' 0x74 */ 0x5D, 0x24, 0x93, +/* 'u' 0x75 */ 0x8C, 0x63, 0x18, 0xCF, 0xA0, +/* 'v' 0x76 */ 0x85, 0x24, 0x92, 0x30, 0xC3, 0x00, +/* 'w' 0x77 */ 0x89, 0x59, 0x59, 0x55, 0x56, 0x26, 0x26, +/* 'x' 0x78 */ 0x4A, 0x4C, 0x43, 0x27, 0x20, +/* 'y' 0x79 */ 0x8A, 0x52, 0xA5, 0x18, 0x84, 0x22, 0x00, +/* 'z' 0x7A */ 0x78, 0x44, 0x46, 0x23, 0xE0, +/* '{' 0x7B */ 0x6A, 0xAA, 0xA9, +/* '|' 0x7C */ 0xFF, 0xE0, +/* '}' 0x7D */ 0x95, 0x55, 0x56, +/* '~' 0x7E */ 0x66, 0x60, +/* 0x7F */ +/* 0x80 */ 0xFC, 0x08, 0x04, 0x02, 0x01, 0xF0, 0x8C, 0x46, 0x23, 0x11, 0x80, 0xC0, 0xC0, +/* 0x81 */ 0x10, 0x8F, 0xE0, 0x82, 0x08, 0x20, 0x82, 0x00, +/* 0x82 */ 0xE0, +/* 0x83 */ 0x24, 0x0F, 0x88, 0x88, 0x80, +/* 0x84 */ 0xB6, 0x80, +/* 0x85 */ 0xA8, +/* 0x86 */ 0x21, 0x09, 0xF2, 0x10, 0x84, 0x21, 0x08, +/* 0x87 */ 0x21, 0x09, 0xF2, 0x10, 0x84, 0xF9, 0x08, +/* 0x88 */ 0x1C, 0x45, 0x07, 0xE4, 0x1F, 0x10, 0x10, 0x1E, +/* 0x89 */ 0x62, 0x09, 0x40, 0x98, 0x06, 0x80, 0x10, 0x01, 0x66, 0x29, 0x92, 0x99, 0x06, 0x60, +/* 0x8A */ 0x7C, 0x08, 0x81, 0x10, 0x22, 0x04, 0x7C, 0x88, 0x51, 0x0A, 0x21, 0x87, 0xC0, +/* 0x8B */ 0x64, +/* 0x8C */ 0x84, 0x10, 0x82, 0x10, 0x42, 0x0F, 0xFD, 0x08, 0xA1, 0x0C, 0x23, 0x87, 0xC0, +/* 0x8D */ 0x10, 0x88, 0xE6, 0xB3, 0x8C, 0x28, 0x92, 0x28, 0xC0, +/* 0x8E */ 0xFC, 0x08, 0x04, 0x02, 0x01, 0xF0, 0x8C, 0x46, 0x23, 0x11, 0x80, +/* 0x8F */ 0x83, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0xFE, 0x20, 0x40, +/* 0x90 */ 0x43, 0xC4, 0x1F, 0x45, 0x14, 0x51, 0x44, 0x11, 0x80, +/* 0x91 */ 0xE0, +/* 0x92 */ 0xE0, +/* 0x93 */ 0xB6, 0x80, +/* 0x94 */ 0xB6, 0x80, +/* 0x95 */ 0xFF, 0x80, +/* 0x96 */ 0xFC, +/* 0x97 */ 0xFF, 0xF0, +/* 0x98 */ +/* 0x99 */ 0xE6, 0x28, 0xCD, 0x19, 0xA3, 0x34, 0x6A, 0x8B, 0x51, 0x68, +/* 0x9A */ 0x78, 0x24, 0x13, 0xC9, 0x14, 0x8E, 0x7C, +/* 0x9B */ 0x98, +/* 0x9C */ 0x88, 0x44, 0x3F, 0xD1, 0x38, 0x8C, 0x78, +/* 0x9D */ 0x24, 0x09, 0xAC, 0xCA, 0x90, +/* 0x9E */ 0x43, 0xC4, 0x1F, 0x45, 0x14, 0x51, 0x44, +/* 0x9F */ 0x8C, 0x63, 0x18, 0xFC, 0x80, +/* 0xA0 */ +/* 0xA1 */ 0x24, 0x33, 0x0A, 0x36, 0x45, 0x8E, 0x0C, 0x10, 0x60, 0x80, +/* 0xA2 */ 0x51, 0x22, 0x95, 0xA8, 0xC4, 0x23, 0x10, +/* 0xA3 */ 0x08, 0x42, 0x10, 0x86, 0x31, 0x78, +/* 0xA4 */ 0xFC, 0x63, 0xF0, +/* 0xA5 */ 0x07, 0xF8, 0x20, 0x82, 0x08, 0x20, 0x82, 0x00, +/* 0xA6 */ 0xF9, 0xF0, +/* 0xA7 */ 0x32, 0x91, 0xC9, 0x47, 0x26, 0x14, 0xA4, 0xC0, +/* 0xA8 */ 0x28, 0x0F, 0xE0, 0x82, 0x0F, 0xE0, 0x82, 0x0F, 0xC0, +/* 0xA9 */ 0x3E, 0x3F, 0xB8, 0xF4, 0x1A, 0x0D, 0x17, 0x76, 0xC6, 0x3E, 0x00, +/* 0xAA */ 0x38, 0x8A, 0x0C, 0x0F, 0x90, 0x20, 0xE3, 0x7C, +/* 0xAB */ 0x5A, 0xA5, +/* 0xAC */ 0x51, 0x55, 0x56, +/* 0xAD */ +/* 0xAE */ 0x3E, 0x31, 0xB7, 0x72, 0x99, 0xCC, 0xC7, 0x56, 0xC6, 0x3E, 0x00, +/* 0xAF */ 0xA1, 0x24, 0x92, 0x49, 0x00, +/* 0xB0 */ 0x69, 0x96, +/* 0xB1 */ 0x21, 0x3E, 0x42, 0x03, 0xE0, +/* 0xB2 */ 0xFF, 0x80, +/* 0xB3 */ 0xDF, 0x80, +/* 0xB4 */ 0x27, 0xC9, 0x24, +/* 0xB5 */ 0x8A, 0x28, 0xA2, 0x8A, 0x6E, 0xE0, 0x80, +/* 0xB6 */ 0x7F, 0xAE, 0xBA, 0x68, 0xA2, 0x8A, 0x28, 0xA0, +/* 0xB7 */ 0x80, +/* 0xB8 */ 0x28, 0xA0, 0x1E, 0x47, 0xFC, 0x11, 0x78, +/* 0xB9 */ 0x88, 0x44, 0x32, 0x59, 0xDA, 0xCD, 0x66, 0x6B, 0x32, 0x8B, 0x80, +/* 0xBA */ 0x79, 0x1F, 0x30, 0x45, 0xE0, +/* 0xBB */ 0xA5, 0x5A, +/* 0xBC */ 0x45, 0x55, 0x57, +/* 0xBD */ 0x7A, 0x18, 0x70, 0x78, 0x38, 0x61, 0x7C, +/* 0xBE */ 0x7A, 0x1C, 0x1C, 0xBC, +/* 0xBF */ 0xB4, 0x24, 0x92, 0x40, +/* 0xC0 */ 0x18, 0x18, 0x3C, 0x24, 0x24, 0x7E, 0x42, 0x42, 0xC3, +/* 0xC1 */ 0xFE, 0x08, 0x20, 0xFA, 0x18, 0x61, 0xF8, +/* 0xC2 */ 0xFA, 0x18, 0x61, 0xFA, 0x18, 0x61, 0xFC, +/* 0xC3 */ 0xFE, 0x08, 0x20, 0x82, 0x08, 0x20, 0x80, +/* 0xC4 */ 0x1F, 0x08, 0x84, 0x42, 0x21, 0x10, 0x88, 0x44, 0x42, 0xFF, 0xC0, 0x60, 0x20, +/* 0xC5 */ 0xFE, 0x08, 0x20, 0xFE, 0x08, 0x20, 0xFC, +/* 0xC6 */ 0x88, 0xA4, 0x9A, 0x87, 0xC1, 0xC1, 0xF1, 0xAD, 0x92, 0x88, 0x80, +/* 0xC7 */ 0x7A, 0x18, 0x41, 0x38, 0x18, 0x61, 0x7C, +/* 0xC8 */ 0x87, 0x0E, 0x2C, 0x59, 0x34, 0x68, 0xE1, 0xC2, +/* 0xC9 */ 0x28, 0x22, 0x1C, 0x38, 0xB1, 0x64, 0xD1, 0xA3, 0x87, 0x08, +/* 0xCA */ 0x8E, 0x6B, 0x38, 0xC2, 0x89, 0x22, 0x8C, +/* 0xCB */ 0x3E, 0x44, 0x89, 0x12, 0x24, 0x58, 0xA1, 0xC2, +/* 0xCC */ 0xC3, 0xC3, 0xC3, 0xA5, 0xA5, 0xA5, 0x99, 0x99, 0x99, +/* 0xCD */ 0x83, 0x06, 0x0C, 0x1F, 0xF0, 0x60, 0xC1, 0x82, +/* 0xCE */ 0x3C, 0x42, 0x81, 0x81, 0x81, 0x81, 0x81, 0xC2, 0x7C, +/* 0xCF */ 0xFF, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x82, +/* 0xD0 */ 0xFA, 0x18, 0x61, 0xFE, 0x08, 0x20, 0x80, +/* 0xD1 */ 0x38, 0x8A, 0x0C, 0x08, 0x10, 0x20, 0xE3, 0x7C, +/* 0xD2 */ 0xFE, 0x20, 0x40, 0x81, 0x02, 0x04, 0x08, 0x10, +/* 0xD3 */ 0xC2, 0x8D, 0x91, 0x63, 0x83, 0x04, 0x18, 0x20, +/* 0xD4 */ 0x08, 0x1F, 0x32, 0x71, 0x18, 0x8C, 0x47, 0x26, 0xFE, 0x08, 0x00, +/* 0xD5 */ 0x87, 0x34, 0x8C, 0x30, 0xC4, 0xB3, 0x84, +/* 0xD6 */ 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0xFF, 0x01, 0x01, +/* 0xD7 */ 0x8E, 0x38, 0xE3, 0x8D, 0xF0, 0xC3, 0x0C, +/* 0xD8 */ 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0xFF, +/* 0xD9 */ 0x99, 0x4C, 0xA6, 0x53, 0x29, 0x94, 0xCA, 0x65, 0x32, 0xFF, 0x80, 0x40, 0x20, +/* 0xDA */ 0xF0, 0x04, 0x01, 0x00, 0x40, 0x1F, 0x84, 0x21, 0x0C, 0x42, 0x1F, 0x00, +/* 0xDB */ 0x81, 0xC0, 0xE0, 0x70, 0x3F, 0xDC, 0x2E, 0x17, 0x0B, 0xF9, 0x80, +/* 0xDC */ 0x82, 0x08, 0x20, 0xFE, 0x18, 0x61, 0xF8, +/* 0xDD */ 0x79, 0x8A, 0x18, 0x13, 0xE0, 0x60, 0xC2, 0x7C, +/* 0xDE */ 0x87, 0x26, 0x39, 0x06, 0x41, 0xF0, 0x64, 0x19, 0x06, 0x63, 0x8F, 0x80, +/* 0xDF */ 0x7E, 0x18, 0x61, 0x7C, 0xD6, 0x71, 0x84, +/* 0xE0 */ 0x79, 0x11, 0xD9, 0xCD, 0xD0, +/* 0xE1 */ 0x0D, 0xC4, 0x1E, 0x47, 0x1C, 0x51, 0x78, +/* 0xE2 */ 0xF4, 0xBD, 0x29, 0xF8, +/* 0xE3 */ 0xF8, 0x88, 0x88, +/* 0xE4 */ 0x3C, 0x48, 0x91, 0x22, 0x5F, 0xE0, 0x80, +/* 0xE5 */ 0x79, 0x1F, 0xF0, 0x45, 0xE0, +/* 0xE6 */ 0x92, 0x54, 0x38, 0x3C, 0x56, 0x93, +/* 0xE7 */ 0x78, 0x23, 0x82, 0xCD, 0xE0, +/* 0xE8 */ 0x9C, 0xEB, 0x5C, 0xC4, +/* 0xE9 */ 0x70, 0x27, 0x3A, 0xD7, 0x31, +/* 0xEA */ 0x9A, 0xCC, 0xA9, +/* 0xEB */ 0x7A, 0x52, 0x94, 0xE4, +/* 0xEC */ 0x8F, 0x3D, 0x6D, 0xA6, 0x90, +/* 0xED */ 0x8C, 0x7F, 0x18, 0xC4, +/* 0xEE */ 0x79, 0x1C, 0x71, 0x45, 0xE0, +/* 0xEF */ 0xFC, 0x63, 0x18, 0xC4, +/* 0xF0 */ 0xFC, 0x63, 0x18, 0xFA, 0x10, 0x80, +/* 0xF1 */ 0x79, 0x1C, 0x30, 0x45, 0xE0, +/* 0xF2 */ 0xF9, 0x08, 0x42, 0x10, +/* 0xF3 */ 0x8A, 0x56, 0xA3, 0x10, 0x8C, 0x40, +/* 0xF4 */ 0x04, 0x01, 0x07, 0xF9, 0x31, 0xC4, 0x71, 0x14, 0xC5, 0xFE, 0x04, 0x01, 0x00, 0x40, +/* 0xF5 */ 0x4B, 0x8C, 0x65, 0xE4, +/* 0xF6 */ 0x8A, 0x28, 0xA2, 0x8B, 0xF0, 0x40, +/* 0xF7 */ 0x99, 0x97, 0x11, +/* 0xF8 */ 0x96, 0x59, 0x65, 0x97, 0xF0, +/* 0xF9 */ 0x95, 0x2A, 0x54, 0xA9, 0x5F, 0xC0, 0x80, +/* 0xFA */ 0xF0, 0x20, 0x78, 0x91, 0x23, 0xC0, +/* 0xFB */ 0x86, 0x1F, 0x63, 0x8F, 0xD0, +/* 0xFC */ 0x84, 0x3D, 0x18, 0xF8, +/* 0xFD */ 0xF4, 0xDE, 0x19, 0xF8, +/* 0xFE */ 0x9E, 0xA2, 0xE1, 0xA1, 0xA2, 0x9E, +/* 0xFF */ 0xFC, 0x7E, 0xD4, 0xC4, }; const GFXglyph FreeSans6pt_Win1251Glyphs[] PROGMEM = { - /* ' ' 0x20 */ {0, 0, 0, 3, 0, 0}, - /* '!' 0x21 */ {0, 1, 9, 4, 2, -8}, - /* '"' 0x22 */ {2, 3, 3, 4, 0, -8}, - /* '#' 0x23 */ {4, 7, 8, 7, 0, -7}, - /* '$' 0x24 */ {11, 6, 11, 7, 0, -9}, - /* '%' 0x25 */ {20, 10, 9, 11, 0, -8}, - /* '&' 0x26 */ {32, 6, 9, 8, 1, -8}, - /* ''' 0x27 */ {39, 1, 3, 2, 1, -8}, - /* '(' 0x28 */ {40, 2, 11, 4, 1, -8}, - /* ')' 0x29 */ {43, 3, 11, 4, 0, -8}, - /* '*' 0x2A */ {48, 3, 3, 5, 1, -8}, - /* '+' 0x2B */ {50, 5, 5, 7, 1, -4}, - /* ',' 0x2C */ {54, 1, 3, 3, 1, 0}, - /* '-' 0x2D */ {55, 2, 1, 4, 1, -3}, - /* '.' 0x2E */ {56, 1, 1, 3, 1, 0}, - /* '/' 0x2F */ {57, 3, 9, 3, 0, -8}, - /* '0' 0x30 */ {61, 5, 9, 7, 1, -8}, - /* '1' 0x31 */ {67, 3, 9, 7, 1, -8}, - /* '2' 0x32 */ {71, 6, 9, 7, 0, -8}, - /* '3' 0x33 */ {78, 6, 9, 7, 0, -8}, - /* '4' 0x34 */ {85, 6, 9, 7, 0, -8}, - /* '5' 0x35 */ {92, 5, 9, 7, 1, -8}, - /* '6' 0x36 */ {98, 5, 9, 7, 1, -8}, - /* '7' 0x37 */ {104, 5, 9, 7, 1, -8}, - /* '8' 0x38 */ {110, 6, 9, 7, 0, -8}, - /* '9' 0x39 */ {117, 6, 9, 7, 0, -8}, - /* ':' 0x3A */ {124, 1, 7, 3, 1, -6}, - /* ';' 0x3B */ {125, 1, 8, 3, 1, -5}, - /* '<' 0x3C */ {126, 5, 5, 7, 1, -4}, - /* '=' 0x3D */ {130, 5, 3, 7, 1, -3}, - /* '>' 0x3E */ {132, 5, 5, 7, 1, -4}, - /* '?' 0x3F */ {136, 5, 9, 7, 1, -8}, - /* '@' 0x40 */ {142, 11, 11, 12, 0, -8}, - /* 'A' 0x41 */ {158, 8, 9, 8, 0, -8}, - /* 'B' 0x42 */ {167, 6, 9, 8, 1, -8}, - /* 'C' 0x43 */ {174, 8, 9, 9, 0, -8}, - /* 'D' 0x44 */ {183, 7, 9, 8, 1, -8}, - /* 'E' 0x45 */ {191, 6, 9, 8, 1, -8}, - /* 'F' 0x46 */ {198, 6, 9, 7, 1, -8}, - /* 'G' 0x47 */ {205, 8, 9, 9, 0, -8}, - /* 'H' 0x48 */ {214, 7, 9, 9, 1, -8}, - /* 'I' 0x49 */ {222, 1, 9, 3, 1, -8}, - /* 'J' 0x4A */ {224, 5, 9, 6, 0, -8}, - /* 'K' 0x4B */ {230, 7, 9, 8, 1, -8}, - /* 'L' 0x4C */ {238, 5, 9, 7, 1, -8}, - /* 'M' 0x4D */ {244, 8, 9, 10, 1, -8}, - /* 'N' 0x4E */ {253, 7, 9, 9, 1, -8}, - /* 'O' 0x4F */ {261, 9, 9, 9, 0, -8}, - /* 'P' 0x50 */ {272, 6, 9, 8, 1, -8}, - /* 'Q' 0x51 */ {279, 9, 10, 9, 0, -8}, - /* 'R' 0x52 */ {291, 7, 9, 9, 1, -8}, - /* 'S' 0x53 */ {299, 6, 9, 8, 1, -8}, - /* 'T' 0x54 */ {306, 7, 9, 8, 0, -8}, - /* 'U' 0x55 */ {314, 7, 9, 9, 1, -8}, - /* 'V' 0x56 */ {322, 7, 9, 8, 0, -8}, - /* 'W' 0x57 */ {330, 11, 9, 11, 0, -8}, - /* 'X' 0x58 */ {343, 6, 9, 8, 1, -8}, - /* 'Y' 0x59 */ {350, 8, 9, 8, 0, -8}, - /* 'Z' 0x5A */ {359, 7, 9, 7, 0, -8}, - /* '[' 0x5B */ {367, 2, 12, 3, 1, -8}, - /* '\' 0x5C */ {370, 3, 9, 3, 0, -8}, - /* ']' 0x5D */ {374, 2, 12, 3, 0, -8}, - /* '^' 0x5E */ {377, 4, 4, 6, 1, -8}, - /* '_' 0x5F */ {379, 7, 1, 7, 0, 2}, - /* '`' 0x60 */ {380, 1, 1, 3, 1, -8}, - /* 'a' 0x61 */ {381, 6, 7, 7, 0, -6}, - /* 'b' 0x62 */ {387, 5, 9, 7, 1, -8}, - /* 'c' 0x63 */ {393, 6, 7, 6, 0, -6}, - /* 'd' 0x64 */ {399, 6, 9, 7, 0, -8}, - /* 'e' 0x65 */ {406, 6, 7, 6, 0, -6}, - /* 'f' 0x66 */ {412, 3, 9, 3, 0, -8}, - /* 'g' 0x67 */ {416, 6, 10, 7, 0, -6}, - /* 'h' 0x68 */ {424, 5, 9, 6, 1, -8}, - /* 'i' 0x69 */ {430, 1, 9, 3, 1, -8}, - /* 'j' 0x6A */ {432, 2, 12, 3, 0, -8}, - /* 'k' 0x6B */ {435, 5, 9, 6, 1, -8}, - /* 'l' 0x6C */ {441, 1, 9, 3, 1, -8}, - /* 'm' 0x6D */ {443, 8, 7, 10, 1, -6}, - /* 'n' 0x6E */ {450, 5, 7, 6, 1, -6}, - /* 'o' 0x6F */ {455, 6, 7, 6, 0, -6}, - /* 'p' 0x70 */ {461, 5, 9, 7, 1, -6}, - /* 'q' 0x71 */ {467, 6, 9, 7, 0, -6}, - /* 'r' 0x72 */ {474, 3, 7, 4, 1, -6}, - /* 's' 0x73 */ {477, 5, 7, 6, 0, -6}, - /* 't' 0x74 */ {482, 3, 8, 3, 0, -7}, - /* 'u' 0x75 */ {485, 5, 7, 6, 1, -6}, - /* 'v' 0x76 */ {490, 6, 7, 6, 0, -6}, - /* 'w' 0x77 */ {496, 8, 7, 9, 0, -6}, - /* 'x' 0x78 */ {503, 5, 7, 6, 0, -6}, - /* 'y' 0x79 */ {508, 5, 10, 6, 0, -6}, - /* 'z' 0x7A */ {515, 5, 7, 6, 0, -6}, - /* '{' 0x7B */ {520, 2, 12, 4, 1, -8}, - /* '|' 0x7C */ {523, 1, 11, 3, 1, -8}, - /* '}' 0x7D */ {525, 2, 12, 4, 1, -8}, - /* '~' 0x7E */ {528, 6, 2, 6, 0, -4}, - /* 0x7F */ {530, 9, 10, 11, 1, -8}, - /* 0x80 */ {542, 9, 11, 9, 0, -8}, - /* 0x81 */ {555, 6, 10, 7, 1, -9}, - /* 0x82 */ {563, 1, 3, 3, 1, 0}, - /* 0x83 */ {564, 4, 9, 5, 1, -8}, - /* 0x84 */ {569, 3, 3, 5, 1, 0}, - /* 0x85 */ {571, 5, 1, 7, 1, 0}, - /* 0x86 */ {572, 5, 11, 7, 1, -8}, - /* 0x87 */ {579, 5, 11, 7, 1, -8}, - /* 0x88 */ {586, 7, 9, 8, 0, -8}, - /* 0x89 */ {594, 12, 9, 12, 0, -8}, - /* 0x8A */ {608, 11, 9, 13, 1, -8}, - /* 0x8B */ {621, 2, 3, 4, 1, -4}, - /* 0x8C */ {622, 11, 9, 12, 1, -8}, - /* 0x8D */ {635, 6, 11, 8, 1, -10}, - /* 0x8E */ {644, 9, 9, 9, 0, -8}, - /* 0x8F */ {655, 7, 11, 9, 1, -8}, - /* 0x90 */ {665, 6, 11, 7, 0, -8}, - /* 0x91 */ {674, 1, 3, 3, 1, -8}, - /* 0x92 */ {675, 1, 3, 2, 1, -8}, - /* 0x93 */ {676, 3, 3, 5, 1, -8}, - /* 0x94 */ {678, 3, 3, 5, 1, -8}, - /* 0x95 */ {680, 3, 3, 5, 1, -5}, - /* 0x96 */ {682, 6, 1, 6, 0, -3}, - /* 0x97 */ {683, 12, 1, 12, 0, -3}, - /* 0x98 */ {685, 0, 0, 8, 0, 0}, - /* 0x99 */ {685, 11, 7, 12, 1, -8}, - /* 0x9A */ {695, 9, 6, 10, 0, -5}, - /* 0x9B */ {702, 2, 3, 3, 1, -4}, - /* 0x9C */ {703, 9, 6, 10, 1, -5}, - /* 0x9D */ {710, 4, 9, 6, 1, -8}, - /* 0x9E */ {715, 6, 9, 7, 0, -8}, - /* 0x9F */ {722, 5, 7, 7, 1, -5}, - /* 0xA0 */ {727, 0, 0, 3, 0, 0}, - /* 0xA1 */ {727, 7, 11, 7, 0, -10}, - /* 0xA2 */ {737, 5, 11, 6, 0, -7}, - /* 0xA3 */ {744, 5, 9, 6, 0, -8}, - /* 0xA4 */ {750, 5, 4, 7, 1, -5}, - /* 0xA5 */ {753, 6, 10, 7, 1, -9}, - /* 0xA6 */ {761, 1, 12, 3, 1, -8}, - /* 0xA7 */ {763, 5, 12, 7, 1, -8}, - /* 0xA8 */ {771, 6, 11, 8, 1, -10}, - /* 0xA9 */ {780, 9, 9, 10, 0, -8}, - /* 0xAA */ {791, 7, 9, 9, 1, -8}, - /* 0xAB */ {799, 4, 4, 6, 1, -4}, - /* 0xAC */ {801, 2, 12, 3, 0, -8}, - /* 0xAD */ {804, 0, 0, 0, 0, 0}, - /* 0xAE */ {804, 9, 9, 10, 0, -8}, - /* 0xAF */ {815, 3, 11, 3, 0, -10}, - /* 0xB0 */ {820, 4, 4, 7, 2, -8}, - /* 0xB1 */ {822, 5, 7, 7, 1, -6}, - /* 0xB2 */ {827, 1, 9, 3, 1, -8}, - /* 0xB3 */ {829, 1, 9, 3, 1, -8}, - /* 0xB4 */ {831, 3, 8, 5, 1, -7}, - /* 0xB5 */ {834, 6, 9, 7, 1, -6}, - /* 0xB6 */ {841, 6, 10, 6, 1, -8}, - /* 0xB7 */ {849, 1, 1, 3, 1, -2}, - /* 0xB8 */ {850, 6, 9, 7, 0, -8}, - /* 0xB9 */ {857, 9, 9, 11, 1, -8}, - /* 0xBA */ {868, 6, 6, 6, 0, -5}, - /* 0xBB */ {873, 4, 4, 6, 1, -5}, - /* 0xBC */ {875, 2, 12, 3, 0, -8}, - /* 0xBD */ {878, 6, 9, 8, 1, -8}, - /* 0xBE */ {885, 5, 6, 6, 0, -5}, - /* 0xBF */ {889, 3, 9, 3, 0, -8}, - /* 0xC0 */ {893, 8, 9, 8, 0, -8}, - /* 0xC1 */ {902, 6, 9, 8, 1, -8}, - /* 0xC2 */ {909, 6, 9, 8, 1, -8}, - /* 0xC3 */ {916, 6, 9, 7, 1, -8}, - /* 0xC4 */ {923, 9, 11, 10, 0, -8}, - /* 0xC5 */ {936, 6, 9, 8, 1, -8}, - /* 0xC6 */ {943, 9, 9, 11, 1, -8}, - /* 0xC7 */ {954, 6, 9, 8, 1, -8}, - /* 0xC8 */ {961, 7, 9, 9, 1, -8}, - /* 0xC9 */ {969, 7, 11, 9, 1, -10}, - /* 0xCA */ {979, 6, 9, 8, 1, -8}, - /* 0xCB */ {986, 7, 9, 8, 0, -8}, - /* 0xCC */ {994, 8, 9, 10, 1, -8}, - /* 0xCD */ {1003, 7, 9, 9, 1, -8}, - /* 0xCE */ {1011, 8, 9, 10, 1, -8}, - /* 0xCF */ {1020, 7, 9, 9, 1, -8}, - /* 0xD0 */ {1028, 6, 9, 8, 1, -8}, - /* 0xD1 */ {1035, 7, 9, 9, 1, -8}, - /* 0xD2 */ {1043, 7, 9, 7, 0, -8}, - /* 0xD3 */ {1051, 7, 9, 7, 0, -8}, - /* 0xD4 */ {1059, 9, 9, 10, 1, -8}, - /* 0xD5 */ {1070, 6, 9, 8, 1, -8}, - /* 0xD6 */ {1077, 8, 11, 9, 1, -8}, - /* 0xD7 */ {1088, 6, 9, 8, 1, -8}, - /* 0xD8 */ {1095, 8, 9, 10, 1, -8}, - /* 0xD9 */ {1104, 9, 11, 10, 1, -8}, - /* 0xDA */ {1117, 10, 9, 10, 0, -8}, - /* 0xDB */ {1129, 9, 9, 10, 1, -8}, - /* 0xDC */ {1140, 6, 9, 8, 1, -8}, - /* 0xDD */ {1147, 7, 9, 9, 1, -8}, - /* 0xDE */ {1155, 10, 9, 12, 1, -8}, - /* 0xDF */ {1167, 6, 9, 8, 1, -8}, - /* 0xE0 */ {1174, 6, 6, 7, 0, -5}, - /* 0xE1 */ {1179, 6, 9, 7, 0, -8}, - /* 0xE2 */ {1186, 5, 6, 6, 1, -5}, - /* 0xE3 */ {1190, 4, 6, 5, 1, -5}, - /* 0xE4 */ {1193, 7, 7, 7, 0, -5}, - /* 0xE5 */ {1200, 6, 6, 7, 0, -5}, - /* 0xE6 */ {1205, 8, 6, 9, 1, -5}, - /* 0xE7 */ {1211, 6, 6, 6, 0, -5}, - /* 0xE8 */ {1216, 5, 6, 7, 1, -5}, - /* 0xE9 */ {1220, 5, 8, 7, 1, -7}, - /* 0xEA */ {1225, 4, 6, 6, 1, -5}, - /* 0xEB */ {1228, 5, 6, 6, 0, -5}, - /* 0xEC */ {1232, 6, 6, 7, 1, -5}, - /* 0xED */ {1237, 5, 6, 7, 1, -5}, - /* 0xEE */ {1241, 6, 6, 7, 0, -5}, - /* 0xEF */ {1246, 5, 6, 7, 1, -5}, - /* 0xF0 */ {1250, 5, 9, 7, 1, -5}, - /* 0xF1 */ {1256, 6, 6, 6, 0, -5}, - /* 0xF2 */ {1261, 5, 6, 5, 0, -5}, - /* 0xF3 */ {1265, 5, 9, 6, 0, -5}, - /* 0xF4 */ {1271, 10, 11, 10, 0, -7}, - /* 0xF5 */ {1285, 5, 6, 6, 0, -5}, - /* 0xF6 */ {1289, 6, 7, 7, 1, -5}, - /* 0xF7 */ {1295, 4, 6, 6, 1, -5}, - /* 0xF8 */ {1298, 6, 6, 8, 1, -5}, - /* 0xF9 */ {1303, 7, 7, 9, 1, -5}, - /* 0xFA */ {1310, 7, 6, 8, 0, -5}, - /* 0xFB */ {1316, 6, 6, 8, 1, -5}, - /* 0xFC */ {1321, 5, 6, 6, 1, -5}, - /* 0xFD */ {1325, 5, 6, 6, 1, -5}, - /* 0xFE */ {1329, 8, 6, 9, 1, -5}, - /* 0xFF */ {1335, 5, 6, 7, 1, -5}, +/* 0x01 */ { 0, 9, 10, 11, 1, -9 }, +/* 0x02 */ { 12, 9, 10, 11, 1, -8 }, +/* 0x03 */ { 24, 10, 10, 12, 1, -8 }, +/* 0x04 */ { 37, 10, 10, 12, 1, -8 }, +/* 0x05 */ { 50, 10, 10, 12, 1, -9 }, +/* 0x06 */ { 63, 11, 11, 13, 1, -9 }, +/* 0x07 */ { 79, 0, 0, 8, 0, 0 }, +/* 0x08 */ { 79, 12, 9, 14, 1, -8 }, +/* 0x09 */ { 93, 14, 8, 16, 1, -7 }, +/* 0x0A */ { 107, 0, 0, 8, 0, 0 }, +/* 0x0B */ { 107, 9, 10, 11, 1, -9 }, +/* 0x0C */ { 119, 13, 9, 15, 1, -8 }, +/* 0x0D */ { 134, 0, 0, 8, 0, 0 }, +/* 0x0E */ { 134, 9, 11, 11, 1, -9 }, +/* 0x0F */ { 147, 10, 10, 12, 1, -9 }, +/* 0x10 */ { 160, 11, 10, 13, 1, -9 }, +/* 0x11 */ { 174, 13, 10, 15, 1, -9 }, +/* 0x12 */ { 191, 10, 10, 12, 1, -9 }, +/* 0x13 */ { 204, 11, 10, 13, 1, -9 }, +/* 0x14 */ { 218, 10, 10, 12, 1, -9 }, +/* 0x15 */ { 231, 14, 10, 16, 1, -9 }, +/* 0x16 */ { 249, 8, 10, 10, 1, -9 }, +/* 0x17 */ { 259, 12, 10, 14, 1, -9 }, +/* 0x18 */ { 274, 13, 10, 15, 1, -9 }, +/* 0x19 */ { 291, 12, 10, 14, 1, -9 }, +/* 0x1A */ { 306, 9, 10, 11, 1, -8 }, +/* 0x1B */ { 318, 14, 10, 16, 1, -9 }, +/* 0x1C */ { 336, 11, 10, 13, 1, -9 }, +/* 0x1D */ { 350, 11, 10, 13, 1, -9 }, +/* 0x1E */ { 364, 12, 10, 14, 1, -9 }, +/* 0x1F */ { 379, 8, 10, 11, 2, -9 }, +/* ' ' 0x20 */ { 389, 0, 0, 3, 0, 0 }, +/* '!' 0x21 */ { 389, 1, 9, 4, 2, -8 }, +/* '"' 0x22 */ { 391, 3, 3, 4, 0, -8 }, +/* '#' 0x23 */ { 393, 7, 8, 7, 0, -7 }, +/* '$' 0x24 */ { 400, 6, 11, 7, 0, -9 }, +/* '%' 0x25 */ { 409, 10, 9, 11, 0, -8 }, +/* '&' 0x26 */ { 421, 6, 9, 8, 1, -8 }, +/* ''' 0x27 */ { 428, 1, 3, 2, 1, -8 }, +/* '(' 0x28 */ { 429, 2, 11, 4, 1, -8 }, +/* ')' 0x29 */ { 432, 3, 11, 4, 0, -8 }, +/* '*' 0x2A */ { 437, 3, 3, 5, 1, -8 }, +/* '+' 0x2B */ { 439, 5, 5, 7, 1, -4 }, +/* ',' 0x2C */ { 443, 1, 3, 3, 1, 0 }, +/* '-' 0x2D */ { 444, 2, 1, 4, 1, -3 }, +/* '.' 0x2E */ { 445, 1, 1, 3, 1, 0 }, +/* '/' 0x2F */ { 446, 3, 9, 3, 0, -8 }, +/* '0' 0x30 */ { 450, 5, 9, 7, 1, -8 }, +/* '1' 0x31 */ { 456, 3, 9, 7, 1, -8 }, +/* '2' 0x32 */ { 460, 6, 9, 7, 0, -8 }, +/* '3' 0x33 */ { 467, 6, 9, 7, 0, -8 }, +/* '4' 0x34 */ { 474, 6, 9, 7, 0, -8 }, +/* '5' 0x35 */ { 481, 5, 9, 7, 1, -8 }, +/* '6' 0x36 */ { 487, 5, 9, 7, 1, -8 }, +/* '7' 0x37 */ { 493, 5, 9, 7, 1, -8 }, +/* '8' 0x38 */ { 499, 6, 9, 7, 0, -8 }, +/* '9' 0x39 */ { 506, 6, 9, 7, 0, -8 }, +/* ':' 0x3A */ { 513, 1, 7, 3, 1, -6 }, +/* ';' 0x3B */ { 514, 1, 8, 3, 1, -5 }, +/* '<' 0x3C */ { 515, 5, 5, 7, 1, -4 }, +/* '=' 0x3D */ { 519, 5, 3, 7, 1, -3 }, +/* '>' 0x3E */ { 521, 5, 5, 7, 1, -4 }, +/* '?' 0x3F */ { 525, 5, 9, 7, 1, -8 }, +/* '@' 0x40 */ { 531, 11, 11, 12, 0, -8 }, +/* 'A' 0x41 */ { 547, 8, 9, 8, 0, -8 }, +/* 'B' 0x42 */ { 556, 6, 9, 8, 1, -8 }, +/* 'C' 0x43 */ { 563, 8, 9, 9, 0, -8 }, +/* 'D' 0x44 */ { 572, 7, 9, 8, 1, -8 }, +/* 'E' 0x45 */ { 580, 6, 9, 8, 1, -8 }, +/* 'F' 0x46 */ { 587, 6, 9, 7, 1, -8 }, +/* 'G' 0x47 */ { 594, 8, 9, 9, 0, -8 }, +/* 'H' 0x48 */ { 603, 7, 9, 9, 1, -8 }, +/* 'I' 0x49 */ { 611, 1, 9, 3, 1, -8 }, +/* 'J' 0x4A */ { 613, 5, 9, 6, 0, -8 }, +/* 'K' 0x4B */ { 619, 7, 9, 8, 1, -8 }, +/* 'L' 0x4C */ { 627, 5, 9, 7, 1, -8 }, +/* 'M' 0x4D */ { 633, 8, 9, 10, 1, -8 }, +/* 'N' 0x4E */ { 642, 7, 9, 9, 1, -8 }, +/* 'O' 0x4F */ { 650, 9, 9, 9, 0, -8 }, +/* 'P' 0x50 */ { 661, 6, 9, 8, 1, -8 }, +/* 'Q' 0x51 */ { 668, 9, 10, 9, 0, -8 }, +/* 'R' 0x52 */ { 680, 7, 9, 9, 1, -8 }, +/* 'S' 0x53 */ { 688, 6, 9, 8, 1, -8 }, +/* 'T' 0x54 */ { 695, 7, 9, 8, 0, -8 }, +/* 'U' 0x55 */ { 703, 7, 9, 9, 1, -8 }, +/* 'V' 0x56 */ { 711, 7, 9, 8, 0, -8 }, +/* 'W' 0x57 */ { 719, 11, 9, 11, 0, -8 }, +/* 'X' 0x58 */ { 732, 6, 9, 8, 1, -8 }, +/* 'Y' 0x59 */ { 739, 8, 9, 8, 0, -8 }, +/* 'Z' 0x5A */ { 748, 7, 9, 7, 0, -8 }, +/* '[' 0x5B */ { 756, 2, 12, 3, 1, -8 }, +/* '\' 0x5C */ { 759, 3, 9, 3, 0, -8 }, +/* ']' 0x5D */ { 763, 2, 12, 3, 0, -8 }, +/* '^' 0x5E */ { 766, 4, 4, 6, 1, -8 }, +/* '_' 0x5F */ { 768, 7, 1, 7, 0, 2 }, +/* '`' 0x60 */ { 769, 1, 1, 3, 1, -8 }, +/* 'a' 0x61 */ { 770, 6, 7, 7, 0, -6 }, +/* 'b' 0x62 */ { 776, 5, 9, 7, 1, -8 }, +/* 'c' 0x63 */ { 782, 6, 7, 6, 0, -6 }, +/* 'd' 0x64 */ { 788, 6, 9, 7, 0, -8 }, +/* 'e' 0x65 */ { 795, 6, 7, 6, 0, -6 }, +/* 'f' 0x66 */ { 801, 3, 9, 3, 0, -8 }, +/* 'g' 0x67 */ { 805, 6, 10, 7, 0, -6 }, +/* 'h' 0x68 */ { 813, 5, 9, 6, 1, -8 }, +/* 'i' 0x69 */ { 819, 1, 9, 3, 1, -8 }, +/* 'j' 0x6A */ { 821, 2, 12, 3, 0, -8 }, +/* 'k' 0x6B */ { 824, 5, 9, 6, 1, -8 }, +/* 'l' 0x6C */ { 830, 1, 9, 3, 1, -8 }, +/* 'm' 0x6D */ { 832, 8, 7, 10, 1, -6 }, +/* 'n' 0x6E */ { 839, 5, 7, 6, 1, -6 }, +/* 'o' 0x6F */ { 844, 6, 7, 6, 0, -6 }, +/* 'p' 0x70 */ { 850, 5, 9, 7, 1, -6 }, +/* 'q' 0x71 */ { 856, 6, 9, 7, 0, -6 }, +/* 'r' 0x72 */ { 863, 3, 7, 4, 1, -6 }, +/* 's' 0x73 */ { 866, 5, 7, 6, 0, -6 }, +/* 't' 0x74 */ { 871, 3, 8, 3, 0, -7 }, +/* 'u' 0x75 */ { 874, 5, 7, 6, 1, -6 }, +/* 'v' 0x76 */ { 879, 6, 7, 6, 0, -6 }, +/* 'w' 0x77 */ { 885, 8, 7, 9, 0, -6 }, +/* 'x' 0x78 */ { 892, 5, 7, 6, 0, -6 }, +/* 'y' 0x79 */ { 897, 5, 10, 6, 0, -6 }, +/* 'z' 0x7A */ { 904, 5, 7, 6, 0, -6 }, +/* '{' 0x7B */ { 909, 2, 12, 4, 1, -8 }, +/* '|' 0x7C */ { 912, 1, 11, 3, 1, -8 }, +/* '}' 0x7D */ { 914, 2, 12, 4, 1, -8 }, +/* '~' 0x7E */ { 917, 6, 2, 6, 0, -4 }, +/* 0x7F */ { 919, 0, 0, 0, 0, 0 }, +/* 0x80 */ { 919, 9, 11, 9, 0, -8 }, +/* 0x81 */ { 932, 6, 10, 7, 1, -9 }, +/* 0x82 */ { 940, 1, 3, 3, 1, 0 }, +/* 0x83 */ { 941, 4, 9, 5, 1, -8 }, +/* 0x84 */ { 946, 3, 3, 5, 1, 0 }, +/* 0x85 */ { 948, 5, 1, 7, 1, 0 }, +/* 0x86 */ { 949, 5, 11, 7, 1, -8 }, +/* 0x87 */ { 956, 5, 11, 7, 1, -8 }, +/* 0x88 */ { 963, 7, 9, 8, 0, -8 }, +/* 0x89 */ { 971, 12, 9, 12, 0, -8 }, +/* 0x8A */ { 985, 11, 9, 13, 1, -8 }, +/* 0x8B */ { 998, 2, 3, 4, 1, -4 }, +/* 0x8C */ { 999, 11, 9, 12, 1, -8 }, +/* 0x8D */ { 1012, 6, 11, 8, 1, -10 }, +/* 0x8E */ { 1021, 9, 9, 9, 0, -8 }, +/* 0x8F */ { 1032, 7, 11, 9, 1, -8 }, +/* 0x90 */ { 1042, 6, 11, 7, 0, -8 }, +/* 0x91 */ { 1051, 1, 3, 3, 1, -8 }, +/* 0x92 */ { 1052, 1, 3, 2, 1, -8 }, +/* 0x93 */ { 1053, 3, 3, 5, 1, -8 }, +/* 0x94 */ { 1055, 3, 3, 5, 1, -8 }, +/* 0x95 */ { 1057, 3, 3, 5, 1, -5 }, +/* 0x96 */ { 1059, 6, 1, 6, 0, -3 }, +/* 0x97 */ { 1060, 12, 1, 12, 0, -3 }, +/* 0x98 */ { 1062, 0, 0, 8, 0, 0 }, +/* 0x99 */ { 1062, 11, 7, 12, 1, -8 }, +/* 0x9A */ { 1072, 9, 6, 10, 0, -5 }, +/* 0x9B */ { 1079, 2, 3, 3, 1, -4 }, +/* 0x9C */ { 1080, 9, 6, 10, 1, -5 }, +/* 0x9D */ { 1087, 4, 9, 6, 1, -8 }, +/* 0x9E */ { 1092, 6, 9, 7, 0, -8 }, +/* 0x9F */ { 1099, 5, 7, 7, 1, -5 }, +/* 0xA0 */ { 1104, 0, 0, 3, 0, 0 }, +/* 0xA1 */ { 1104, 7, 11, 7, 0, -10 }, +/* 0xA2 */ { 1114, 5, 11, 6, 0, -7 }, +/* 0xA3 */ { 1121, 5, 9, 6, 0, -8 }, +/* 0xA4 */ { 1127, 5, 4, 7, 1, -5 }, +/* 0xA5 */ { 1130, 6, 10, 7, 1, -9 }, +/* 0xA6 */ { 1138, 1, 12, 3, 1, -8 }, +/* 0xA7 */ { 1140, 5, 12, 7, 1, -8 }, +/* 0xA8 */ { 1148, 6, 11, 8, 1, -10 }, +/* 0xA9 */ { 1157, 9, 9, 10, 0, -8 }, +/* 0xAA */ { 1168, 7, 9, 9, 1, -8 }, +/* 0xAB */ { 1176, 4, 4, 6, 1, -4 }, +/* 0xAC */ { 1178, 2, 12, 3, 0, -8 }, +/* 0xAD */ { 1181, 0, 0, 0, 0, 0 }, +/* 0xAE */ { 1181, 9, 9, 10, 0, -8 }, +/* 0xAF */ { 1192, 3, 11, 3, 0, -10 }, +/* 0xB0 */ { 1197, 4, 4, 7, 2, -8 }, +/* 0xB1 */ { 1199, 5, 7, 7, 1, -6 }, +/* 0xB2 */ { 1204, 1, 9, 3, 1, -8 }, +/* 0xB3 */ { 1206, 1, 9, 3, 1, -8 }, +/* 0xB4 */ { 1208, 3, 8, 5, 1, -7 }, +/* 0xB5 */ { 1211, 6, 9, 7, 1, -6 }, +/* 0xB6 */ { 1218, 6, 10, 6, 1, -8 }, +/* 0xB7 */ { 1226, 1, 1, 3, 1, -2 }, +/* 0xB8 */ { 1227, 6, 9, 7, 0, -8 }, +/* 0xB9 */ { 1234, 9, 9, 11, 1, -8 }, +/* 0xBA */ { 1245, 6, 6, 6, 0, -5 }, +/* 0xBB */ { 1250, 4, 4, 6, 1, -5 }, +/* 0xBC */ { 1252, 2, 12, 3, 0, -8 }, +/* 0xBD */ { 1255, 6, 9, 8, 1, -8 }, +/* 0xBE */ { 1262, 5, 6, 6, 0, -5 }, +/* 0xBF */ { 1266, 3, 9, 3, 0, -8 }, +/* 0xC0 */ { 1270, 8, 9, 8, 0, -8 }, +/* 0xC1 */ { 1279, 6, 9, 8, 1, -8 }, +/* 0xC2 */ { 1286, 6, 9, 8, 1, -8 }, +/* 0xC3 */ { 1293, 6, 9, 7, 1, -8 }, +/* 0xC4 */ { 1300, 9, 11, 10, 0, -8 }, +/* 0xC5 */ { 1313, 6, 9, 8, 1, -8 }, +/* 0xC6 */ { 1320, 9, 9, 11, 1, -8 }, +/* 0xC7 */ { 1331, 6, 9, 8, 1, -8 }, +/* 0xC8 */ { 1338, 7, 9, 9, 1, -8 }, +/* 0xC9 */ { 1346, 7, 11, 9, 1, -10 }, +/* 0xCA */ { 1356, 6, 9, 8, 1, -8 }, +/* 0xCB */ { 1363, 7, 9, 8, 0, -8 }, +/* 0xCC */ { 1371, 8, 9, 10, 1, -8 }, +/* 0xCD */ { 1380, 7, 9, 9, 1, -8 }, +/* 0xCE */ { 1388, 8, 9, 10, 1, -8 }, +/* 0xCF */ { 1397, 7, 9, 9, 1, -8 }, +/* 0xD0 */ { 1405, 6, 9, 8, 1, -8 }, +/* 0xD1 */ { 1412, 7, 9, 9, 1, -8 }, +/* 0xD2 */ { 1420, 7, 9, 7, 0, -8 }, +/* 0xD3 */ { 1428, 7, 9, 7, 0, -8 }, +/* 0xD4 */ { 1436, 9, 9, 10, 1, -8 }, +/* 0xD5 */ { 1447, 6, 9, 8, 1, -8 }, +/* 0xD6 */ { 1454, 8, 11, 9, 1, -8 }, +/* 0xD7 */ { 1465, 6, 9, 8, 1, -8 }, +/* 0xD8 */ { 1472, 8, 9, 10, 1, -8 }, +/* 0xD9 */ { 1481, 9, 11, 10, 1, -8 }, +/* 0xDA */ { 1494, 10, 9, 10, 0, -8 }, +/* 0xDB */ { 1506, 9, 9, 10, 1, -8 }, +/* 0xDC */ { 1517, 6, 9, 8, 1, -8 }, +/* 0xDD */ { 1524, 7, 9, 9, 1, -8 }, +/* 0xDE */ { 1532, 10, 9, 12, 1, -8 }, +/* 0xDF */ { 1544, 6, 9, 8, 1, -8 }, +/* 0xE0 */ { 1551, 6, 6, 7, 0, -5 }, +/* 0xE1 */ { 1556, 6, 9, 7, 0, -8 }, +/* 0xE2 */ { 1563, 5, 6, 6, 1, -5 }, +/* 0xE3 */ { 1567, 4, 6, 5, 1, -5 }, +/* 0xE4 */ { 1570, 7, 7, 7, 0, -5 }, +/* 0xE5 */ { 1577, 6, 6, 7, 0, -5 }, +/* 0xE6 */ { 1582, 8, 6, 9, 1, -5 }, +/* 0xE7 */ { 1588, 6, 6, 6, 0, -5 }, +/* 0xE8 */ { 1593, 5, 6, 7, 1, -5 }, +/* 0xE9 */ { 1597, 5, 8, 7, 1, -7 }, +/* 0xEA */ { 1602, 4, 6, 6, 1, -5 }, +/* 0xEB */ { 1605, 5, 6, 6, 0, -5 }, +/* 0xEC */ { 1609, 6, 6, 7, 1, -5 }, +/* 0xED */ { 1614, 5, 6, 7, 1, -5 }, +/* 0xEE */ { 1618, 6, 6, 7, 0, -5 }, +/* 0xEF */ { 1623, 5, 6, 7, 1, -5 }, +/* 0xF0 */ { 1627, 5, 9, 7, 1, -5 }, +/* 0xF1 */ { 1633, 6, 6, 6, 0, -5 }, +/* 0xF2 */ { 1638, 5, 6, 5, 0, -5 }, +/* 0xF3 */ { 1642, 5, 9, 6, 0, -5 }, +/* 0xF4 */ { 1648, 10, 11, 10, 0, -7 }, +/* 0xF5 */ { 1662, 5, 6, 6, 0, -5 }, +/* 0xF6 */ { 1666, 6, 7, 7, 1, -5 }, +/* 0xF7 */ { 1672, 4, 6, 6, 1, -5 }, +/* 0xF8 */ { 1675, 6, 6, 8, 1, -5 }, +/* 0xF9 */ { 1680, 7, 7, 9, 1, -5 }, +/* 0xFA */ { 1687, 7, 6, 8, 0, -5 }, +/* 0xFB */ { 1693, 6, 6, 8, 1, -5 }, +/* 0xFC */ { 1698, 5, 6, 6, 1, -5 }, +/* 0xFD */ { 1702, 5, 6, 6, 1, -5 }, +/* 0xFE */ { 1706, 8, 6, 9, 1, -5 }, +/* 0xFF */ { 1712, 5, 6, 7, 1, -5 }, }; -const GFXfont FreeSans6pt_Win1251 PROGMEM = {(uint8_t *)FreeSans6pt_Win1251Bitmaps, (GFXglyph *)FreeSans6pt_Win1251Glyphs, 0x20, - 0xFF, 14}; +const GFXfont FreeSans6pt_Win1251 PROGMEM = { +(uint8_t*)FreeSans6pt_Win1251Bitmaps, +(GFXglyph*)FreeSans6pt_Win1251Glyphs, +0x01, 0xFF, 14 +}; diff --git a/src/graphics/niche/Fonts/FreeSans6pt_Win1252.h b/src/graphics/niche/Fonts/FreeSans6pt_Win1252.h index 32f995270..b17be8756 100644 --- a/src/graphics/niche/Fonts/FreeSans6pt_Win1252.h +++ b/src/graphics/niche/Fonts/FreeSans6pt_Win1252.h @@ -1,457 +1,527 @@ +// trunk-ignore-all(clang-format) #pragma once +/* PROPERTIES + +FONT_NAME FreeSans6pt_Win1252 +*/ const uint8_t FreeSans6pt_Win1252Bitmaps[] PROGMEM = { - /* ' ' 0x20 */ - 0xFC, 0x80, /* '!' 0x21 */ - 0xB6, 0x80, /* '"' 0x22 */ - 0x24, 0x51, 0xF9, 0x42, 0x9F, 0x92, 0x28, /* '#' 0x23 */ - 0x10, 0xE5, 0x55, 0x50, 0xE1, 0x65, 0x55, 0xE1, 0x00, /* '$' 0x24 */ - 0x71, 0x24, 0x89, 0x22, 0x50, 0x74, 0x02, 0x70, 0xA4, 0x49, 0x11, 0xC0, /* '%' 0x25 */ - 0x71, 0x24, 0x9C, 0x62, 0x58, 0xA7, 0xF4, /* '&' 0x26 */ - 0xE0, /* ''' 0x27 */ - 0x5A, 0xAA, 0x94, /* '(' 0x28 */ - 0x89, 0x12, 0x49, 0x29, 0x00, /* ')' 0x29 */ - 0x5E, 0x80, /* '*' 0x2A */ - 0x21, 0x3E, 0x42, 0x00, /* '+' 0x2B */ - 0xE0, /* ',' 0x2C */ - 0xC0, /* '-' 0x2D */ - 0x80, /* '.' 0x2E */ - 0x24, 0xA4, 0xA4, 0x80, /* '/' 0x2F */ - 0x76, 0xE3, 0x18, 0xC6, 0x3B, 0x70, /* '0' 0x30 */ - 0x27, 0x92, 0x49, 0x20, /* '1' 0x31 */ - 0x79, 0x10, 0x41, 0x08, 0xC6, 0x10, 0xFC, /* '2' 0x32 */ - 0x79, 0x30, 0x43, 0x18, 0x10, 0x71, 0x78, /* '3' 0x33 */ - 0x08, 0x61, 0x8A, 0x49, 0x2F, 0xC2, 0x08, /* '4' 0x34 */ - 0xFC, 0x21, 0xE8, 0x84, 0x31, 0xF0, /* '5' 0x35 */ - 0x74, 0x61, 0xE8, 0xC6, 0x31, 0x70, /* '6' 0x36 */ - 0xF8, 0x44, 0x22, 0x11, 0x08, 0x40, /* '7' 0x37 */ - 0x39, 0x34, 0x53, 0x39, 0x1C, 0x51, 0x38, /* '8' 0x38 */ - 0x39, 0x3C, 0x71, 0x4C, 0xF0, 0x53, 0x78, /* '9' 0x39 */ - 0x82, /* ':' 0x3A */ - 0x87, /* ';' 0x3B */ - 0x3E, 0x30, 0x60, 0x80, /* '<' 0x3C */ - 0xF8, 0x3E, /* '=' 0x3D */ - 0xE0, 0xC6, 0xC8, 0x00, /* '>' 0x3E */ - 0x74, 0x42, 0x11, 0x10, 0x80, 0x20, /* '?' 0x3F */ - 0x0F, 0x86, 0x19, 0x9A, 0xA4, 0xD9, 0x13, 0x22, 0x56, 0xDA, 0x6E, 0x60, 0x06, 0x00, 0x3C, 0x00, /* '@' 0x40 */ - 0x18, 0x18, 0x24, 0x24, 0x24, 0x7E, 0x42, 0x42, 0xC3, /* 'A' 0x41 */ - 0xFA, 0x18, 0x61, 0xFA, 0x18, 0x61, 0xFC, /* 'B' 0x42 */ - 0x3E, 0x63, 0x40, 0x40, 0xC0, 0x40, 0x41, 0x63, 0x3E, /* 'C' 0x43 */ - 0xF9, 0x0A, 0x1C, 0x18, 0x30, 0x61, 0xC2, 0xF8, /* 'D' 0x44 */ - 0xFE, 0x08, 0x20, 0xFE, 0x08, 0x20, 0xFC, /* 'E' 0x45 */ - 0xFE, 0x08, 0x20, 0xFA, 0x08, 0x20, 0x80, /* 'F' 0x46 */ - 0x1E, 0x61, 0x40, 0x40, 0xC7, 0x41, 0x41, 0x63, 0x1D, /* 'G' 0x47 */ - 0x83, 0x06, 0x0C, 0x1F, 0xF0, 0x60, 0xC1, 0x82, /* 'H' 0x48 */ - 0xFF, 0x80, /* 'I' 0x49 */ - 0x08, 0x42, 0x10, 0x87, 0x29, 0x70, /* 'J' 0x4A */ - 0x85, 0x12, 0x45, 0x0D, 0x13, 0x22, 0x42, 0x86, /* 'K' 0x4B */ - 0x84, 0x21, 0x08, 0x42, 0x10, 0xF8, /* 'L' 0x4C */ - 0xC3, 0xC3, 0xC3, 0xA5, 0xA5, 0xA5, 0x99, 0x99, 0x99, /* 'M' 0x4D */ - 0x83, 0x86, 0x8D, 0x19, 0x33, 0x62, 0xC3, 0x86, /* 'N' 0x4E */ - 0x1E, 0x31, 0x90, 0x68, 0x1C, 0x0A, 0x05, 0x06, 0xC6, 0x1E, 0x00, /* 'O' 0x4F */ - 0xFA, 0x18, 0x61, 0xFA, 0x08, 0x20, 0x80, /* 'P' 0x50 */ - 0x1E, 0x31, 0x90, 0x68, 0x1C, 0x0A, 0x05, 0x16, 0xC6, 0x1F, 0x00, 0x40, /* 'Q' 0x51 */ - 0xFD, 0x0E, 0x1C, 0x2F, 0x90, 0xA1, 0x42, 0x86, /* 'R' 0x52 */ - 0x7A, 0x18, 0x30, 0x78, 0x38, 0x61, 0x78, /* 'S' 0x53 */ - 0xFE, 0x20, 0x40, 0x81, 0x02, 0x04, 0x08, 0x10, /* 'T' 0x54 */ - 0x83, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xE2, 0x78, /* 'U' 0x55 */ - 0xC2, 0x85, 0x0B, 0x22, 0x44, 0x8E, 0x0C, 0x18, /* 'V' 0x56 */ - 0xC4, 0x28, 0xCD, 0x29, 0x25, 0x24, 0xA4, 0x52, 0x8C, 0x61, 0x8C, 0x31, 0x80, /* 'W' 0x57 */ - 0x87, 0x34, 0x8C, 0x30, 0xC4, 0xA3, 0x84, /* 'X' 0x58 */ - 0xC3, 0x42, 0x24, 0x34, 0x18, 0x08, 0x08, 0x08, 0x08, /* 'Y' 0x59 */ - 0x7E, 0x0C, 0x30, 0x41, 0x06, 0x18, 0x20, 0xFE, /* 'Z' 0x5A */ - 0xEA, 0xAA, 0xAB, /* '[' 0x5B */ - 0x92, 0x24, 0x89, 0x20, /* '\' 0x5C */ - 0xD5, 0x55, 0x57, /* ']' 0x5D */ - 0x46, 0xA9, /* '^' 0x5E */ - 0xFE, /* '_' 0x5F */ - 0x80, /* '`' 0x60 */ - 0x79, 0x20, 0x4F, 0xC6, 0x37, 0x40, /* 'a' 0x61 */ - 0x84, 0x3D, 0x18, 0xC6, 0x31, 0xF0, /* 'b' 0x62 */ - 0x39, 0x3C, 0x20, 0xC1, 0x33, 0x80, /* 'c' 0x63 */ - 0x04, 0x13, 0xD3, 0xC6, 0x1C, 0x53, 0x3C, /* 'd' 0x64 */ - 0x39, 0x38, 0x7F, 0x81, 0x13, 0x80, /* 'e' 0x65 */ - 0x6B, 0xA4, 0x92, 0x40, /* 'f' 0x66 */ - 0x35, 0x3C, 0x61, 0xC5, 0x33, 0x41, 0x4D, 0xE0, /* 'g' 0x67 */ - 0x84, 0x3D, 0x38, 0xC6, 0x31, 0x88, /* 'h' 0x68 */ - 0xBF, 0x80, /* 'i' 0x69 */ - 0x45, 0x55, 0x57, /* 'j' 0x6A */ - 0x84, 0x25, 0x4E, 0x52, 0xD2, 0x88, /* 'k' 0x6B */ - 0xFF, 0x80, /* 'l' 0x6C */ - 0xF7, 0x99, 0x91, 0x91, 0x91, 0x91, 0x91, /* 'm' 0x6D */ - 0xF4, 0x63, 0x18, 0xC6, 0x20, /* 'n' 0x6E */ - 0x39, 0x3C, 0x61, 0xC5, 0x33, 0x80, /* 'o' 0x6F */ - 0xF4, 0x63, 0x18, 0xC7, 0xD0, 0x80, /* 'p' 0x70 */ - 0x3D, 0x3C, 0x61, 0xC5, 0x37, 0x41, 0x04, /* 'q' 0x71 */ - 0xF2, 0x49, 0x20, /* 'r' 0x72 */ - 0x7A, 0x50, 0xE0, 0xE5, 0xE0, /* 's' 0x73 */ - 0x5D, 0x24, 0x93, /* 't' 0x74 */ - 0x8C, 0x63, 0x18, 0xCF, 0xA0, /* 'u' 0x75 */ - 0x85, 0x24, 0x92, 0x30, 0xC3, 0x00, /* 'v' 0x76 */ - 0x89, 0x59, 0x59, 0x55, 0x56, 0x26, 0x26, /* 'w' 0x77 */ - 0x4A, 0x4C, 0x43, 0x27, 0x20, /* 'x' 0x78 */ - 0x8A, 0x52, 0xA5, 0x18, 0x84, 0x22, 0x00, /* 'y' 0x79 */ - 0x78, 0x44, 0x46, 0x23, 0xE0, /* 'z' 0x7A */ - 0x6A, 0xAA, 0xA9, /* '{' 0x7B */ - 0xFF, 0xE0, /* '|' 0x7C */ - 0x95, 0x55, 0x56, /* '}' 0x7D */ - 0x66, 0x60, /* '~' 0x7E */ - 0xFF, 0xC0, 0x67, 0x34, 0x58, 0x4C, 0x46, 0x03, 0x11, 0x80, 0xFF, 0xC0, /* 0x7F */ - 0x1C, 0x45, 0x07, 0xE4, 0x1F, 0x10, 0x10, 0x1E, /* 0x80 */ - /* 0x81 */ - 0xE0, /* 0x82 */ - 0x6B, 0xA4, 0x92, 0x49, 0x60, /* 0x83 */ - 0xB6, 0x80, /* 0x84 */ - 0xA8, /* 0x85 */ - 0x21, 0x09, 0xF2, 0x10, 0x84, 0x21, 0x08, /* 0x86 */ - 0x21, 0x09, 0xF2, 0x10, 0x84, 0xF9, 0x08, /* 0x87 */ - 0x54, /* 0x88 */ - 0x62, 0x09, 0x40, 0x98, 0x06, 0x80, 0x10, 0x01, 0x66, 0x29, 0x92, 0x99, 0x06, 0x60, /* 0x89 */ - 0x28, 0x47, 0xA1, 0x83, 0x07, 0x83, 0x87, 0x17, 0x80, /* 0x8A */ - 0x64, /* 0x8B */ - 0x3B, 0xE8, 0xC2, 0x08, 0x41, 0x08, 0x3F, 0x04, 0x20, 0x82, 0x30, 0x3B, 0xE0, /* 0x8C */ - /* 0x8D */ - 0x14, 0x11, 0xF8, 0x30, 0xC1, 0x04, 0x18, 0x61, 0xFC, /* 0x8E */ - /* 0x8F */ - /* 0x90 */ - 0xE0, /* 0x91 */ - 0xE0, /* 0x92 */ - 0xB6, 0x80, /* 0x93 */ - 0xB6, 0x80, /* 0x94 */ - 0xFF, 0x80, /* 0x95 */ - 0xFC, /* 0x96 */ - 0xFF, 0xF0, /* 0x97 */ - 0xDB, /* 0x98 */ - 0xE6, 0x28, 0xCD, 0x19, 0xA3, 0x34, 0x6A, 0x8B, 0x51, 0x68, /* 0x99 */ - 0x52, 0x69, 0x8E, 0x19, 0x60, /* 0x9A */ - 0x98, /* 0x9B */ - 0x7B, 0xD9, 0xCE, 0x10, 0xC3, 0xF8, 0x41, 0x9C, 0x5E, 0xF0, /* 0x9C */ - /* 0x9D */ - 0x51, 0x1E, 0x11, 0x11, 0x88, 0xF8, /* 0x9E */ - 0x29, 0x05, 0x12, 0x22, 0x87, 0x04, 0x08, 0x10, 0x20, /* 0x9F */ - /* 0xA0 */ - 0xBF, 0x80, /* 0xA1 */ - 0x23, 0xAB, 0x4A, 0x52, 0xAE, 0x20, /* 0xA2 */ - 0x39, 0x14, 0x10, 0xF0, 0x82, 0x1C, 0x4C, /* 0xA3 */ - 0xFC, 0x63, 0xF0, /* 0xA4 */ - 0x8C, 0x54, 0xAF, 0x93, 0xE4, 0x20, /* 0xA5 */ - 0xF9, 0xF0, /* 0xA6 */ - 0x32, 0x91, 0xC9, 0x47, 0x26, 0x14, 0xA4, 0xC0, /* 0xA7 */ - 0xA0, /* 0xA8 */ - 0x3E, 0x3F, 0xB8, 0xF4, 0x1A, 0x0D, 0x17, 0x76, 0xC6, 0x3E, 0x00, /* 0xA9 */ - 0x61, 0x79, 0x60, /* 0xAA */ - 0x5A, 0xA5, /* 0xAB */ - 0xFC, 0x10, 0x40, /* 0xAC */ - /* 0xAD */ - 0x3E, 0x31, 0xB7, 0x72, 0x99, 0xCC, 0xC7, 0x56, 0xC6, 0x3E, 0x00, /* 0xAE */ - 0xE0, /* 0xAF */ - 0x69, 0x96, /* 0xB0 */ - 0x21, 0x3E, 0x42, 0x03, 0xE0, /* 0xB1 */ - 0x69, 0x3C, 0xF0, /* 0xB2 */ - 0x79, 0x29, 0x70, /* 0xB3 */ - 0x80, /* 0xB4 */ - 0x8A, 0x28, 0xA2, 0x8A, 0x6E, 0xE0, 0x80, /* 0xB5 */ - 0x7F, 0xAE, 0xBA, 0x68, 0xA2, 0x8A, 0x28, 0xA0, /* 0xB6 */ - 0x80, /* 0xB7 */ - 0x67, 0x80, /* 0xB8 */ - 0x75, 0x50, /* 0xB9 */ - 0x69, 0x96, 0xF0, /* 0xBA */ - 0xA5, 0x5A, /* 0xBB */ - 0x42, 0x30, 0x84, 0x41, 0x10, 0x48, 0x82, 0x61, 0x28, 0x8F, 0x20, 0x80, /* 0xBC */ - 0x40, 0x63, 0x11, 0x09, 0x74, 0xA8, 0x84, 0x44, 0x44, 0x43, 0x80, /* 0xBD */ - 0x71, 0x24, 0x82, 0x20, 0x50, 0x98, 0x9A, 0x61, 0x28, 0x4F, 0x20, 0x80, /* 0xBE */ - 0x20, 0x08, 0x44, 0x42, 0x11, 0x70, /* 0xBF */ - 0x10, 0x08, 0x00, 0x18, 0x3C, 0x24, 0x24, 0x7E, 0x42, 0xC3, /* 0xC0 */ - 0x08, 0x10, 0x00, 0x18, 0x3C, 0x24, 0x24, 0x7E, 0x42, 0xC3, /* 0xC1 */ - 0x18, 0x24, 0x00, 0x18, 0x3C, 0x24, 0x24, 0x7E, 0x42, 0xC3, /* 0xC2 */ - 0x34, 0x2C, 0x00, 0x18, 0x3C, 0x24, 0x24, 0x7E, 0x42, 0xC3, /* 0xC3 */ - 0x24, 0x00, 0x18, 0x3C, 0x24, 0x24, 0x7E, 0x42, 0x42, 0xC3, /* 0xC4 */ - 0x18, 0x24, 0x18, 0x18, 0x3C, 0x24, 0x24, 0x7E, 0x42, 0xC3, /* 0xC5 */ - 0x1F, 0xC5, 0x02, 0x40, 0x90, 0x47, 0xDF, 0x04, 0x42, 0x10, 0x87, 0xC0, /* 0xC6 */ - 0x3E, 0x61, 0xC0, 0x80, 0x80, 0x80, 0xC1, 0x63, 0x3E, 0x0C, 0x04, 0x1C, /* 0xC7 */ - 0x20, 0x40, 0x3F, 0x82, 0x0F, 0xA0, 0x83, 0xF0, /* 0xC8 */ - 0x08, 0x40, 0x3F, 0x82, 0x0F, 0xA0, 0x83, 0xF0, /* 0xC9 */ - 0x10, 0xA0, 0x3F, 0x82, 0x0F, 0xA0, 0x83, 0xF0, /* 0xCA */ - 0x28, 0x0F, 0xE0, 0x83, 0xE8, 0x20, 0x83, 0xF0, /* 0xCB */ - 0x91, 0x55, 0x50, /* 0xCC */ - 0x62, 0xAA, 0xA0, /* 0xCD */ - 0x54, 0x24, 0x92, 0x48, /* 0xCE */ - 0xA1, 0x24, 0x92, 0x48, /* 0xCF */ - 0x7C, 0x42, 0x41, 0x41, 0xF1, 0x41, 0x41, 0x42, 0x7C, /* 0xD0 */ - 0x14, 0x53, 0x0F, 0x1B, 0x32, 0x66, 0xC7, 0x87, 0x04, /* 0xD1 */ - 0x10, 0x04, 0x0F, 0x8C, 0x6C, 0x1C, 0x06, 0x03, 0x83, 0x63, 0x1F, 0x00, /* 0xD2 */ - 0x04, 0x04, 0x0F, 0x8C, 0x6C, 0x1C, 0x06, 0x03, 0x83, 0x63, 0x1F, 0x00, /* 0xD3 */ - 0x08, 0x0A, 0x00, 0x07, 0xC6, 0x36, 0x0E, 0x03, 0x01, 0xC1, 0xB1, 0x8F, 0x80, /* 0xD4 */ - 0x1A, 0x0B, 0x00, 0x07, 0xC6, 0x36, 0x0E, 0x03, 0x01, 0xC1, 0xB1, 0x8F, 0x80, /* 0xD5 */ - 0x14, 0x00, 0x00, 0x07, 0xC6, 0x36, 0x0E, 0x03, 0x01, 0xC1, 0xB1, 0x8F, 0x80, /* 0xD6 */ - 0x8A, 0x88, 0xA8, 0x80, /* 0xD7 */ - 0x3E, 0xB1, 0xB0, 0xF0, 0x98, 0x8C, 0x87, 0x86, 0xC6, 0xBE, 0x00, /* 0xD8 */ - 0x20, 0x22, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0xC6, 0xF8, /* 0xD9 */ - 0x08, 0x22, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0xC6, 0xF8, /* 0xDA */ - 0x10, 0x52, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0xC6, 0xF8, /* 0xDB */ - 0x29, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0xC6, 0xF8, /* 0xDC */ - 0x09, 0x25, 0x12, 0x22, 0x87, 0x04, 0x08, 0x10, 0x20, /* 0xDD */ - 0x83, 0xE8, 0x61, 0x87, 0xE8, 0x20, 0x80, /* 0xDE */ - 0x7A, 0x18, 0x61, 0x8A, 0x18, 0x61, 0xB8, /* 0xDF */ - 0x20, 0x20, 0x03, 0xC8, 0x40, 0x8F, 0x62, 0x8C, 0xEC, /* 0xE0 */ - 0x10, 0x40, 0x03, 0xC8, 0x40, 0x8F, 0x62, 0x8C, 0xEC, /* 0xE1 */ - 0x10, 0x50, 0x03, 0xC8, 0x40, 0x8F, 0x62, 0x8C, 0xEC, /* 0xE2 */ - 0x68, 0xB0, 0x03, 0xC8, 0x40, 0x8F, 0x62, 0x8C, 0xEC, /* 0xE3 */ - 0x28, 0x01, 0xE4, 0x20, 0x47, 0xB1, 0x46, 0x76, /* 0xE4 */ - 0x10, 0x50, 0x43, 0xC8, 0x40, 0x8F, 0x62, 0x8C, 0xEC, /* 0xE5 */ - 0x7B, 0xA1, 0x90, 0x45, 0xFF, 0x84, 0x23, 0x17, 0x38, /* 0xE6 */ - 0x7B, 0x18, 0x20, 0x83, 0x17, 0x8C, 0x11, 0xC0, /* 0xE7 */ - 0x20, 0x40, 0x1E, 0xCE, 0x1F, 0xE0, 0xC5, 0xE0, /* 0xE8 */ - 0x10, 0x80, 0x1E, 0xCE, 0x1F, 0xE0, 0xC5, 0xE0, /* 0xE9 */ - 0x10, 0xA0, 0x1E, 0xCE, 0x1F, 0xE0, 0xC5, 0xE0, /* 0xEA */ - 0x28, 0x07, 0xB3, 0x87, 0xF8, 0x31, 0x78, /* 0xEB */ - 0x91, 0x55, 0x50, /* 0xEC */ - 0x62, 0xAA, 0xA0, /* 0xED */ - 0x54, 0x24, 0x92, 0x48, /* 0xEE */ - 0xA1, 0x24, 0x92, 0x40, /* 0xEF */ - 0x28, 0x42, 0x8F, 0x46, 0x18, 0x52, 0x30, /* 0xF0 */ - 0x6A, 0xC1, 0x6C, 0xC6, 0x31, 0x8C, 0x40, /* 0xF1 */ - 0x20, 0x40, 0x1E, 0xCE, 0x18, 0x61, 0xCD, 0xE0, /* 0xF2 */ - 0x10, 0x80, 0x1E, 0xCE, 0x18, 0x61, 0xCD, 0xE0, /* 0xF3 */ - 0x10, 0xA0, 0x1E, 0xCE, 0x18, 0x61, 0xCD, 0xE0, /* 0xF4 */ - 0x69, 0x60, 0x1E, 0xCE, 0x18, 0x61, 0xCD, 0xE0, /* 0xF5 */ - 0x28, 0x07, 0xB3, 0x86, 0x18, 0x73, 0x78, /* 0xF6 */ - 0x20, 0x3E, 0x02, 0x00, /* 0xF7 */ - 0x7F, 0x39, 0x69, 0xC7, 0x3F, 0x80, /* 0xF8 */ - 0x41, 0x23, 0x18, 0xC6, 0x33, 0x68, /* 0xF9 */ - 0x11, 0x23, 0x18, 0xC6, 0x33, 0x68, /* 0xFA */ - 0x22, 0x81, 0x18, 0xC6, 0x31, 0x9B, 0x40, /* 0xFB */ - 0x50, 0x23, 0x18, 0xC6, 0x33, 0x68, /* 0xFC */ - 0x10, 0x88, 0x52, 0x49, 0x23, 0x0C, 0x30, 0x82, 0x18, /* 0xFD */ - 0x84, 0x3D, 0xB8, 0xC6, 0x3B, 0xF4, 0x20, /* 0xFE */ - 0x28, 0x08, 0x52, 0x49, 0x23, 0x0C, 0x30, 0x82, 0x18, /* 0xFF */ +/* 0x01 */ 0x1C, 0x0A, 0x05, 0x04, 0xFE, 0x08, 0x1C, 0x02, 0x07, 0xE0, 0x9F, 0xC0, +/* 0x02 */ 0x3F, 0xF0, 0x40, 0xE0, 0x10, 0x3F, 0x04, 0x9E, 0x28, 0x14, 0x0E, 0x00, +/* 0x03 */ 0x3F, 0x10, 0x28, 0x06, 0x49, 0x80, 0x60, 0x19, 0x26, 0x31, 0x40, 0x8F, 0xC0, +/* 0x04 */ 0x3F, 0x10, 0x2A, 0x16, 0x49, 0xA1, 0x60, 0x19, 0xE6, 0x31, 0x40, 0x8F, 0xC0, +/* 0x05 */ 0x28, 0x15, 0x2A, 0xB5, 0x55, 0xA8, 0x54, 0x12, 0x04, 0x41, 0x08, 0x81, 0xC0, +/* 0x06 */ 0x04, 0x08, 0x88, 0x82, 0x07, 0x01, 0x11, 0xA2, 0xC4, 0x40, 0x70, 0x20, 0x88, 0x88, 0x10, 0x00, +/* 0x07 */ +/* 0x08 */ 0x03, 0x83, 0x44, 0x48, 0x28, 0x01, 0x80, 0x17, 0xFE, 0x08, 0x45, 0x28, 0x84, 0x00, +/* 0x09 */ 0x01, 0xC0, 0x68, 0x82, 0x41, 0x10, 0x02, 0x80, 0x06, 0x00, 0x14, 0x00, 0x8F, 0xFC, +/* 0x0A */ +/* 0x0B */ 0x22, 0x2A, 0xA2, 0x30, 0x18, 0x0A, 0x09, 0x04, 0x44, 0x14, 0x04, 0x00, +/* 0x0C */ 0x46, 0x00, 0x19, 0x03, 0x21, 0x20, 0x93, 0x04, 0x20, 0x11, 0x80, 0x50, 0x02, 0x7F, 0xE0, +/* 0x0D */ +/* 0x0E */ 0x08, 0x0E, 0x08, 0x88, 0x24, 0x12, 0x09, 0x05, 0x01, 0xFF, 0x8A, 0x02, 0x00, +/* 0x0F */ 0x3F, 0x14, 0xAA, 0x16, 0x01, 0x92, 0x60, 0x18, 0xC6, 0x49, 0x40, 0x8F, 0xC0, +/* 0x10 */ 0x1B, 0x02, 0xA0, 0x54, 0x12, 0x42, 0x48, 0x49, 0x31, 0x1E, 0x23, 0xEA, 0xFE, 0x3C, +/* 0x11 */ 0x3F, 0x02, 0x00, 0x20, 0x6D, 0x27, 0xF8, 0x3F, 0xC1, 0xFE, 0x37, 0xD0, 0xBE, 0x40, 0xE1, 0xE2, 0x00, +/* 0x12 */ 0x12, 0x42, 0x20, 0x24, 0xC0, 0x29, 0x99, 0x05, 0x23, 0x30, 0xB0, 0x30, 0x00, +/* 0x13 */ 0x3F, 0x88, 0x0A, 0x44, 0xD5, 0x58, 0x03, 0x00, 0x67, 0xCC, 0x71, 0x40, 0x47, 0xF0, +/* 0x14 */ 0x3F, 0x18, 0x69, 0x26, 0x85, 0xA1, 0x6C, 0xD8, 0x06, 0x31, 0x40, 0x8F, 0xC0, +/* 0x15 */ 0x3F, 0x11, 0x00, 0xE8, 0x03, 0xA0, 0x1F, 0xB3, 0x7E, 0x00, 0xE9, 0xE0, 0x23, 0x00, 0x40, 0x40, 0xFE, 0x00, +/* 0x16 */ 0x30, 0x38, 0x3A, 0x3E, 0x6E, 0xEB, 0xC3, 0xC3, 0x66, 0x3C, +/* 0x17 */ 0x3F, 0x04, 0x00, 0x82, 0x88, 0x5C, 0xA4, 0x49, 0x22, 0x81, 0x98, 0xC4, 0x40, 0xA3, 0xF0, +/* 0x18 */ 0x07, 0x80, 0x42, 0x04, 0x08, 0x21, 0x41, 0x42, 0x60, 0x0E, 0x8C, 0xB2, 0x89, 0x50, 0x52, 0x82, 0x80, +/* 0x19 */ 0x3F, 0xC4, 0x02, 0x80, 0x18, 0x01, 0xB3, 0x1B, 0xB9, 0x80, 0x19, 0xE1, 0x40, 0x23, 0xFC, +/* 0x1A */ 0xFF, 0xC0, 0x67, 0x34, 0x58, 0x4C, 0x46, 0x03, 0x11, 0x80, 0xFF, 0xC0, +/* 0x1B */ 0x0F, 0xC0, 0x40, 0x82, 0x49, 0x08, 0x04, 0x00, 0x00, 0x12, 0x02, 0x31, 0x34, 0x0B, 0x88, 0x45, 0x00, 0x20, +/* 0x1C */ 0x3F, 0x88, 0x0A, 0x44, 0xC9, 0x19, 0x3B, 0x00, 0x60, 0x4C, 0x71, 0x40, 0x47, 0xF0, +/* 0x1D */ 0x3F, 0x8B, 0x0A, 0x00, 0xC8, 0x18, 0x13, 0x00, 0x48, 0xCA, 0xC1, 0x44, 0x53, 0x30, +/* 0x1E */ 0x19, 0xC2, 0x02, 0x50, 0x1E, 0x49, 0x80, 0x12, 0x01, 0x27, 0x92, 0x01, 0x10, 0x20, 0xFC, +/* 0x1F */ 0x30, 0x1C, 0x0C, 0x3E, 0x7E, 0xCF, 0x07, 0xC7, 0x7F, 0x3F, +/* ' ' 0x20 */ +/* '!' 0x21 */ 0xFC, 0x80, +/* '"' 0x22 */ 0xB6, 0x80, +/* '#' 0x23 */ 0x24, 0x51, 0xF9, 0x42, 0x9F, 0x92, 0x28, +/* '$' 0x24 */ 0x10, 0xE5, 0x55, 0x50, 0xE1, 0x65, 0x55, 0xE1, 0x00, +/* '%' 0x25 */ 0x71, 0x24, 0x89, 0x22, 0x50, 0x74, 0x02, 0x70, 0xA4, 0x49, 0x11, 0xC0, +/* '&' 0x26 */ 0x71, 0x24, 0x9C, 0x62, 0x58, 0xA7, 0xF4, +/* ''' 0x27 */ 0xE0, +/* '(' 0x28 */ 0x5A, 0xAA, 0x94, +/* ')' 0x29 */ 0x89, 0x12, 0x49, 0x29, 0x00, +/* '*' 0x2A */ 0x5E, 0x80, +/* '+' 0x2B */ 0x21, 0x3E, 0x42, 0x00, +/* ',' 0x2C */ 0xE0, +/* '-' 0x2D */ 0xC0, +/* '.' 0x2E */ 0x80, +/* '/' 0x2F */ 0x24, 0xA4, 0xA4, 0x80, +/* '0' 0x30 */ 0x76, 0xE3, 0x18, 0xC6, 0x3B, 0x70, +/* '1' 0x31 */ 0x27, 0x92, 0x49, 0x20, +/* '2' 0x32 */ 0x79, 0x10, 0x41, 0x08, 0xC6, 0x10, 0xFC, +/* '3' 0x33 */ 0x79, 0x30, 0x43, 0x18, 0x10, 0x71, 0x78, +/* '4' 0x34 */ 0x08, 0x61, 0x8A, 0x49, 0x2F, 0xC2, 0x08, +/* '5' 0x35 */ 0xFC, 0x21, 0xE8, 0x84, 0x31, 0xF0, +/* '6' 0x36 */ 0x74, 0x61, 0xE8, 0xC6, 0x31, 0x70, +/* '7' 0x37 */ 0xF8, 0x44, 0x22, 0x11, 0x08, 0x40, +/* '8' 0x38 */ 0x39, 0x34, 0x53, 0x39, 0x1C, 0x51, 0x38, +/* '9' 0x39 */ 0x39, 0x3C, 0x71, 0x4C, 0xF0, 0x53, 0x78, +/* ':' 0x3A */ 0x82, +/* ';' 0x3B */ 0x87, +/* '<' 0x3C */ 0x3E, 0x30, 0x60, 0x80, +/* '=' 0x3D */ 0xF8, 0x3E, +/* '>' 0x3E */ 0xE0, 0xC6, 0xC8, 0x00, +/* '?' 0x3F */ 0x74, 0x42, 0x11, 0x10, 0x80, 0x20, +/* '@' 0x40 */ 0x0F, 0x86, 0x19, 0x9A, 0xA4, 0xD9, 0x13, 0x22, 0x56, 0xDA, 0x6E, 0x60, 0x06, 0x00, 0x3C, 0x00, +/* 'A' 0x41 */ 0x18, 0x18, 0x24, 0x24, 0x24, 0x7E, 0x42, 0x42, 0xC3, +/* 'B' 0x42 */ 0xFA, 0x18, 0x61, 0xFA, 0x18, 0x61, 0xFC, +/* 'C' 0x43 */ 0x3E, 0x63, 0x40, 0x40, 0xC0, 0x40, 0x41, 0x63, 0x3E, +/* 'D' 0x44 */ 0xF9, 0x0A, 0x1C, 0x18, 0x30, 0x61, 0xC2, 0xF8, +/* 'E' 0x45 */ 0xFE, 0x08, 0x20, 0xFE, 0x08, 0x20, 0xFC, +/* 'F' 0x46 */ 0xFE, 0x08, 0x20, 0xFA, 0x08, 0x20, 0x80, +/* 'G' 0x47 */ 0x1E, 0x61, 0x40, 0x40, 0xC7, 0x41, 0x41, 0x63, 0x1D, +/* 'H' 0x48 */ 0x83, 0x06, 0x0C, 0x1F, 0xF0, 0x60, 0xC1, 0x82, +/* 'I' 0x49 */ 0xFF, 0x80, +/* 'J' 0x4A */ 0x08, 0x42, 0x10, 0x87, 0x29, 0x70, +/* 'K' 0x4B */ 0x85, 0x12, 0x45, 0x0D, 0x13, 0x22, 0x42, 0x86, +/* 'L' 0x4C */ 0x84, 0x21, 0x08, 0x42, 0x10, 0xF8, +/* 'M' 0x4D */ 0xC3, 0xC3, 0xC3, 0xA5, 0xA5, 0xA5, 0x99, 0x99, 0x99, +/* 'N' 0x4E */ 0x83, 0x86, 0x8D, 0x19, 0x33, 0x62, 0xC3, 0x86, +/* 'O' 0x4F */ 0x1E, 0x31, 0x90, 0x68, 0x1C, 0x0A, 0x05, 0x06, 0xC6, 0x1E, 0x00, +/* 'P' 0x50 */ 0xFA, 0x18, 0x61, 0xFA, 0x08, 0x20, 0x80, +/* 'Q' 0x51 */ 0x1E, 0x31, 0x90, 0x68, 0x1C, 0x0A, 0x05, 0x16, 0xC6, 0x1F, 0x00, 0x40, +/* 'R' 0x52 */ 0xFD, 0x0E, 0x1C, 0x2F, 0x90, 0xA1, 0x42, 0x86, +/* 'S' 0x53 */ 0x7A, 0x18, 0x30, 0x78, 0x38, 0x61, 0x78, +/* 'T' 0x54 */ 0xFE, 0x20, 0x40, 0x81, 0x02, 0x04, 0x08, 0x10, +/* 'U' 0x55 */ 0x83, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xE2, 0x78, +/* 'V' 0x56 */ 0xC2, 0x85, 0x0B, 0x22, 0x44, 0x8E, 0x0C, 0x18, +/* 'W' 0x57 */ 0xC4, 0x28, 0xCD, 0x29, 0x25, 0x24, 0xA4, 0x52, 0x8C, 0x61, 0x8C, 0x31, 0x80, +/* 'X' 0x58 */ 0x87, 0x34, 0x8C, 0x30, 0xC4, 0xA3, 0x84, +/* 'Y' 0x59 */ 0xC3, 0x42, 0x24, 0x34, 0x18, 0x08, 0x08, 0x08, 0x08, +/* 'Z' 0x5A */ 0x7E, 0x0C, 0x30, 0x41, 0x06, 0x18, 0x20, 0xFE, +/* '[' 0x5B */ 0xEA, 0xAA, 0xAB, +/* '\' 0x5C */ 0x92, 0x24, 0x89, 0x20, +/* ']' 0x5D */ 0xD5, 0x55, 0x57, +/* '^' 0x5E */ 0x46, 0xA9, +/* '_' 0x5F */ 0xFE, +/* '`' 0x60 */ 0x80, +/* 'a' 0x61 */ 0x79, 0x20, 0x4F, 0xC6, 0x37, 0x40, +/* 'b' 0x62 */ 0x84, 0x3D, 0x18, 0xC6, 0x31, 0xF0, +/* 'c' 0x63 */ 0x39, 0x3C, 0x20, 0xC1, 0x33, 0x80, +/* 'd' 0x64 */ 0x04, 0x13, 0xD3, 0xC6, 0x1C, 0x53, 0x3C, +/* 'e' 0x65 */ 0x39, 0x38, 0x7F, 0x81, 0x13, 0x80, +/* 'f' 0x66 */ 0x6B, 0xA4, 0x92, 0x40, +/* 'g' 0x67 */ 0x35, 0x3C, 0x61, 0xC5, 0x33, 0x41, 0x4D, 0xE0, +/* 'h' 0x68 */ 0x84, 0x3D, 0x38, 0xC6, 0x31, 0x88, +/* 'i' 0x69 */ 0xBF, 0x80, +/* 'j' 0x6A */ 0x45, 0x55, 0x57, +/* 'k' 0x6B */ 0x84, 0x25, 0x4E, 0x52, 0xD2, 0x88, +/* 'l' 0x6C */ 0xFF, 0x80, +/* 'm' 0x6D */ 0xF7, 0x99, 0x91, 0x91, 0x91, 0x91, 0x91, +/* 'n' 0x6E */ 0xF4, 0x63, 0x18, 0xC6, 0x20, +/* 'o' 0x6F */ 0x39, 0x3C, 0x61, 0xC5, 0x33, 0x80, +/* 'p' 0x70 */ 0xF4, 0x63, 0x18, 0xC7, 0xD0, 0x80, +/* 'q' 0x71 */ 0x3D, 0x3C, 0x61, 0xC5, 0x37, 0x41, 0x04, +/* 'r' 0x72 */ 0xF2, 0x49, 0x20, +/* 's' 0x73 */ 0x7A, 0x50, 0xE0, 0xE5, 0xE0, +/* 't' 0x74 */ 0x5D, 0x24, 0x93, +/* 'u' 0x75 */ 0x8C, 0x63, 0x18, 0xCF, 0xA0, +/* 'v' 0x76 */ 0x85, 0x24, 0x92, 0x30, 0xC3, 0x00, +/* 'w' 0x77 */ 0x89, 0x59, 0x59, 0x55, 0x56, 0x26, 0x26, +/* 'x' 0x78 */ 0x4A, 0x4C, 0x43, 0x27, 0x20, +/* 'y' 0x79 */ 0x8A, 0x52, 0xA5, 0x18, 0x84, 0x22, 0x00, +/* 'z' 0x7A */ 0x78, 0x44, 0x46, 0x23, 0xE0, +/* '{' 0x7B */ 0x6A, 0xAA, 0xA9, +/* '|' 0x7C */ 0xFF, 0xE0, +/* '}' 0x7D */ 0x95, 0x55, 0x56, +/* '~' 0x7E */ 0x66, 0x60, +/* 0x7F */ +/* 0x80 */ 0x1C, 0x45, 0x07, 0xE4, 0x1F, 0x10, 0x10, 0x1E, +/* 0x81 */ +/* 0x82 */ 0xE0, +/* 0x83 */ 0x6B, 0xA4, 0x92, 0x49, 0x60, +/* 0x84 */ 0xB6, 0x80, +/* 0x85 */ 0xA8, +/* 0x86 */ 0x21, 0x09, 0xF2, 0x10, 0x84, 0x21, 0x08, +/* 0x87 */ 0x21, 0x09, 0xF2, 0x10, 0x84, 0xF9, 0x08, +/* 0x88 */ 0x54, +/* 0x89 */ 0x62, 0x09, 0x40, 0x98, 0x06, 0x80, 0x10, 0x01, 0x66, 0x29, 0x92, 0x99, 0x06, 0x60, +/* 0x8A */ 0x28, 0x47, 0xA1, 0x83, 0x07, 0x83, 0x87, 0x17, 0x80, +/* 0x8B */ 0x64, +/* 0x8C */ 0x3B, 0xE8, 0xC2, 0x08, 0x41, 0x08, 0x3F, 0x04, 0x20, 0x82, 0x30, 0x3B, 0xE0, +/* 0x8D */ +/* 0x8E */ 0x14, 0x11, 0xF8, 0x30, 0xC1, 0x04, 0x18, 0x61, 0xFC, +/* 0x8F */ +/* 0x90 */ +/* 0x91 */ 0xE0, +/* 0x92 */ 0xE0, +/* 0x93 */ 0xB6, 0x80, +/* 0x94 */ 0xB6, 0x80, +/* 0x95 */ 0xFF, 0x80, +/* 0x96 */ 0xFC, +/* 0x97 */ 0xFF, 0xF0, +/* 0x98 */ 0xDB, +/* 0x99 */ 0xE6, 0x28, 0xCD, 0x19, 0xA3, 0x34, 0x6A, 0x8B, 0x51, 0x68, +/* 0x9A */ 0x52, 0x69, 0x8E, 0x19, 0x60, +/* 0x9B */ 0x98, +/* 0x9C */ 0x7B, 0xD9, 0xCE, 0x10, 0xC3, 0xF8, 0x41, 0x9C, 0x5E, 0xF0, +/* 0x9D */ +/* 0x9E */ 0x51, 0x1E, 0x11, 0x11, 0x88, 0xF8, +/* 0x9F */ 0x29, 0x05, 0x12, 0x22, 0x87, 0x04, 0x08, 0x10, 0x20, +/* 0xA0 */ +/* 0xA1 */ 0xBF, 0x80, +/* 0xA2 */ 0x23, 0xAB, 0x4A, 0x52, 0xAE, 0x20, +/* 0xA3 */ 0x39, 0x14, 0x10, 0xF0, 0x82, 0x1C, 0x4C, +/* 0xA4 */ 0xFC, 0x63, 0xF0, +/* 0xA5 */ 0x8C, 0x54, 0xAF, 0x93, 0xE4, 0x20, +/* 0xA6 */ 0xF9, 0xF0, +/* 0xA7 */ 0x32, 0x91, 0xC9, 0x47, 0x26, 0x14, 0xA4, 0xC0, +/* 0xA8 */ 0xA0, +/* 0xA9 */ 0x3E, 0x3F, 0xB8, 0xF4, 0x1A, 0x0D, 0x17, 0x76, 0xC6, 0x3E, 0x00, +/* 0xAA */ 0x61, 0x79, 0x60, +/* 0xAB */ 0x5A, 0xA5, +/* 0xAC */ 0xFC, 0x10, 0x40, +/* 0xAD */ +/* 0xAE */ 0x3E, 0x31, 0xB7, 0x72, 0x99, 0xCC, 0xC7, 0x56, 0xC6, 0x3E, 0x00, +/* 0xAF */ 0xE0, +/* 0xB0 */ 0x69, 0x96, +/* 0xB1 */ 0x21, 0x3E, 0x42, 0x03, 0xE0, +/* 0xB2 */ 0x69, 0x3C, 0xF0, +/* 0xB3 */ 0x79, 0x29, 0x70, +/* 0xB4 */ 0x80, +/* 0xB5 */ 0x8A, 0x28, 0xA2, 0x8A, 0x6E, 0xE0, 0x80, +/* 0xB6 */ 0x7F, 0xAE, 0xBA, 0x68, 0xA2, 0x8A, 0x28, 0xA0, +/* 0xB7 */ 0x80, +/* 0xB8 */ 0x67, 0x80, +/* 0xB9 */ 0x75, 0x50, +/* 0xBA */ 0x69, 0x96, 0xF0, +/* 0xBB */ 0xA5, 0x5A, +/* 0xBC */ 0x42, 0x30, 0x84, 0x41, 0x10, 0x48, 0x82, 0x61, 0x28, 0x8F, 0x20, 0x80, +/* 0xBD */ 0x40, 0x63, 0x11, 0x09, 0x74, 0xA8, 0x84, 0x44, 0x44, 0x43, 0x80, +/* 0xBE */ 0x71, 0x24, 0x82, 0x20, 0x50, 0x98, 0x9A, 0x61, 0x28, 0x4F, 0x20, 0x80, +/* 0xBF */ 0x20, 0x08, 0x44, 0x42, 0x11, 0x70, +/* 0xC0 */ 0x10, 0x08, 0x00, 0x18, 0x3C, 0x24, 0x24, 0x7E, 0x42, 0xC3, +/* 0xC1 */ 0x08, 0x10, 0x00, 0x18, 0x3C, 0x24, 0x24, 0x7E, 0x42, 0xC3, +/* 0xC2 */ 0x18, 0x24, 0x00, 0x18, 0x3C, 0x24, 0x24, 0x7E, 0x42, 0xC3, +/* 0xC3 */ 0x34, 0x2C, 0x00, 0x18, 0x3C, 0x24, 0x24, 0x7E, 0x42, 0xC3, +/* 0xC4 */ 0x24, 0x00, 0x18, 0x3C, 0x24, 0x24, 0x7E, 0x42, 0x42, 0xC3, +/* 0xC5 */ 0x18, 0x24, 0x18, 0x18, 0x3C, 0x24, 0x24, 0x7E, 0x42, 0xC3, +/* 0xC6 */ 0x1F, 0xC5, 0x02, 0x40, 0x90, 0x47, 0xDF, 0x04, 0x42, 0x10, 0x87, 0xC0, +/* 0xC7 */ 0x3E, 0x61, 0xC0, 0x80, 0x80, 0x80, 0xC1, 0x63, 0x3E, 0x0C, 0x04, 0x1C, +/* 0xC8 */ 0x20, 0x40, 0x3F, 0x82, 0x0F, 0xA0, 0x83, 0xF0, +/* 0xC9 */ 0x08, 0x40, 0x3F, 0x82, 0x0F, 0xA0, 0x83, 0xF0, +/* 0xCA */ 0x10, 0xA0, 0x3F, 0x82, 0x0F, 0xA0, 0x83, 0xF0, +/* 0xCB */ 0x28, 0x0F, 0xE0, 0x83, 0xE8, 0x20, 0x83, 0xF0, +/* 0xCC */ 0x91, 0x55, 0x50, +/* 0xCD */ 0x62, 0xAA, 0xA0, +/* 0xCE */ 0x54, 0x24, 0x92, 0x48, +/* 0xCF */ 0xA1, 0x24, 0x92, 0x48, +/* 0xD0 */ 0x7C, 0x42, 0x41, 0x41, 0xF1, 0x41, 0x41, 0x42, 0x7C, +/* 0xD1 */ 0x14, 0x53, 0x0F, 0x1B, 0x32, 0x66, 0xC7, 0x87, 0x04, +/* 0xD2 */ 0x10, 0x04, 0x0F, 0x8C, 0x6C, 0x1C, 0x06, 0x03, 0x83, 0x63, 0x1F, 0x00, +/* 0xD3 */ 0x04, 0x04, 0x0F, 0x8C, 0x6C, 0x1C, 0x06, 0x03, 0x83, 0x63, 0x1F, 0x00, +/* 0xD4 */ 0x08, 0x0A, 0x00, 0x07, 0xC6, 0x36, 0x0E, 0x03, 0x01, 0xC1, 0xB1, 0x8F, 0x80, +/* 0xD5 */ 0x1A, 0x0B, 0x00, 0x07, 0xC6, 0x36, 0x0E, 0x03, 0x01, 0xC1, 0xB1, 0x8F, 0x80, +/* 0xD6 */ 0x14, 0x00, 0x00, 0x07, 0xC6, 0x36, 0x0E, 0x03, 0x01, 0xC1, 0xB1, 0x8F, 0x80, +/* 0xD7 */ 0x8A, 0x88, 0xA8, 0x80, +/* 0xD8 */ 0x3E, 0xB1, 0xB0, 0xF0, 0x98, 0x8C, 0x87, 0x86, 0xC6, 0xBE, 0x00, +/* 0xD9 */ 0x20, 0x22, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0xC6, 0xF8, +/* 0xDA */ 0x08, 0x22, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0xC6, 0xF8, +/* 0xDB */ 0x10, 0x52, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0xC6, 0xF8, +/* 0xDC */ 0x29, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0xC6, 0xF8, +/* 0xDD */ 0x09, 0x25, 0x12, 0x22, 0x87, 0x04, 0x08, 0x10, 0x20, +/* 0xDE */ 0x83, 0xE8, 0x61, 0x87, 0xE8, 0x20, 0x80, +/* 0xDF */ 0x7A, 0x18, 0x61, 0x8A, 0x18, 0x61, 0xB8, +/* 0xE0 */ 0x20, 0x20, 0x03, 0xC8, 0x40, 0x8F, 0x62, 0x8C, 0xEC, +/* 0xE1 */ 0x10, 0x40, 0x03, 0xC8, 0x40, 0x8F, 0x62, 0x8C, 0xEC, +/* 0xE2 */ 0x10, 0x50, 0x03, 0xC8, 0x40, 0x8F, 0x62, 0x8C, 0xEC, +/* 0xE3 */ 0x68, 0xB0, 0x03, 0xC8, 0x40, 0x8F, 0x62, 0x8C, 0xEC, +/* 0xE4 */ 0x28, 0x01, 0xE4, 0x20, 0x47, 0xB1, 0x46, 0x76, +/* 0xE5 */ 0x10, 0x50, 0x43, 0xC8, 0x40, 0x8F, 0x62, 0x8C, 0xEC, +/* 0xE6 */ 0x7B, 0xA1, 0x90, 0x45, 0xFF, 0x84, 0x23, 0x17, 0x38, +/* 0xE7 */ 0x7B, 0x18, 0x20, 0x83, 0x17, 0x8C, 0x11, 0xC0, +/* 0xE8 */ 0x20, 0x40, 0x1E, 0xCE, 0x1F, 0xE0, 0xC5, 0xE0, +/* 0xE9 */ 0x10, 0x80, 0x1E, 0xCE, 0x1F, 0xE0, 0xC5, 0xE0, +/* 0xEA */ 0x10, 0xA0, 0x1E, 0xCE, 0x1F, 0xE0, 0xC5, 0xE0, +/* 0xEB */ 0x28, 0x07, 0xB3, 0x87, 0xF8, 0x31, 0x78, +/* 0xEC */ 0x91, 0x55, 0x50, +/* 0xED */ 0x62, 0xAA, 0xA0, +/* 0xEE */ 0x54, 0x24, 0x92, 0x48, +/* 0xEF */ 0xA1, 0x24, 0x92, 0x40, +/* 0xF0 */ 0x28, 0x42, 0x8F, 0x46, 0x18, 0x52, 0x30, +/* 0xF1 */ 0x6A, 0xC1, 0x6C, 0xC6, 0x31, 0x8C, 0x40, +/* 0xF2 */ 0x20, 0x40, 0x1E, 0xCE, 0x18, 0x61, 0xCD, 0xE0, +/* 0xF3 */ 0x10, 0x80, 0x1E, 0xCE, 0x18, 0x61, 0xCD, 0xE0, +/* 0xF4 */ 0x10, 0xA0, 0x1E, 0xCE, 0x18, 0x61, 0xCD, 0xE0, +/* 0xF5 */ 0x69, 0x60, 0x1E, 0xCE, 0x18, 0x61, 0xCD, 0xE0, +/* 0xF6 */ 0x28, 0x07, 0xB3, 0x86, 0x18, 0x73, 0x78, +/* 0xF7 */ 0x20, 0x3E, 0x02, 0x00, +/* 0xF8 */ 0x7F, 0x39, 0x69, 0xC7, 0x3F, 0x80, +/* 0xF9 */ 0x41, 0x23, 0x18, 0xC6, 0x33, 0x68, +/* 0xFA */ 0x11, 0x23, 0x18, 0xC6, 0x33, 0x68, +/* 0xFB */ 0x22, 0x81, 0x18, 0xC6, 0x31, 0x9B, 0x40, +/* 0xFC */ 0x50, 0x23, 0x18, 0xC6, 0x33, 0x68, +/* 0xFD */ 0x10, 0x88, 0x52, 0x49, 0x23, 0x0C, 0x30, 0x82, 0x18, +/* 0xFE */ 0x84, 0x3D, 0xB8, 0xC6, 0x3B, 0xF4, 0x20, +/* 0xFF */ 0x28, 0x08, 0x52, 0x49, 0x23, 0x0C, 0x30, 0x82, 0x18, }; const GFXglyph FreeSans6pt_Win1252Glyphs[] PROGMEM = { - /* ' ' 0x20 */ {0, 0, 0, 3, 0, 0}, - /* '!' 0x21 */ {0, 1, 9, 4, 2, -8}, - /* '"' 0x22 */ {2, 3, 3, 4, 0, -8}, - /* '#' 0x23 */ {4, 7, 8, 7, 0, -7}, - /* '$' 0x24 */ {11, 6, 11, 7, 0, -9}, - /* '%' 0x25 */ {20, 10, 9, 11, 0, -8}, - /* '&' 0x26 */ {32, 6, 9, 8, 1, -8}, - /* ''' 0x27 */ {39, 1, 3, 2, 1, -8}, - /* '(' 0x28 */ {40, 2, 11, 4, 1, -8}, - /* ')' 0x29 */ {43, 3, 11, 4, 0, -8}, - /* '*' 0x2A */ {48, 3, 3, 5, 1, -8}, - /* '+' 0x2B */ {50, 5, 5, 7, 1, -4}, - /* ',' 0x2C */ {54, 1, 3, 3, 1, 0}, - /* '-' 0x2D */ {55, 2, 1, 4, 1, -3}, - /* '.' 0x2E */ {56, 1, 1, 3, 1, 0}, - /* '/' 0x2F */ {57, 3, 9, 3, 0, -8}, - /* '0' 0x30 */ {61, 5, 9, 7, 1, -8}, - /* '1' 0x31 */ {67, 3, 9, 7, 1, -8}, - /* '2' 0x32 */ {71, 6, 9, 7, 0, -8}, - /* '3' 0x33 */ {78, 6, 9, 7, 0, -8}, - /* '4' 0x34 */ {85, 6, 9, 7, 0, -8}, - /* '5' 0x35 */ {92, 5, 9, 7, 1, -8}, - /* '6' 0x36 */ {98, 5, 9, 7, 1, -8}, - /* '7' 0x37 */ {104, 5, 9, 7, 1, -8}, - /* '8' 0x38 */ {110, 6, 9, 7, 0, -8}, - /* '9' 0x39 */ {117, 6, 9, 7, 0, -8}, - /* ':' 0x3A */ {124, 1, 7, 3, 1, -6}, - /* ';' 0x3B */ {125, 1, 8, 3, 1, -5}, - /* '<' 0x3C */ {126, 5, 5, 7, 1, -4}, - /* '=' 0x3D */ {130, 5, 3, 7, 1, -3}, - /* '>' 0x3E */ {132, 5, 5, 7, 1, -4}, - /* '?' 0x3F */ {136, 5, 9, 7, 1, -8}, - /* '@' 0x40 */ {142, 11, 11, 12, 0, -8}, - /* 'A' 0x41 */ {158, 8, 9, 8, 0, -8}, - /* 'B' 0x42 */ {167, 6, 9, 8, 1, -8}, - /* 'C' 0x43 */ {174, 8, 9, 9, 0, -8}, - /* 'D' 0x44 */ {183, 7, 9, 8, 1, -8}, - /* 'E' 0x45 */ {191, 6, 9, 8, 1, -8}, - /* 'F' 0x46 */ {198, 6, 9, 7, 1, -8}, - /* 'G' 0x47 */ {205, 8, 9, 9, 0, -8}, - /* 'H' 0x48 */ {214, 7, 9, 9, 1, -8}, - /* 'I' 0x49 */ {222, 1, 9, 3, 1, -8}, - /* 'J' 0x4A */ {224, 5, 9, 6, 0, -8}, - /* 'K' 0x4B */ {230, 7, 9, 8, 1, -8}, - /* 'L' 0x4C */ {238, 5, 9, 7, 1, -8}, - /* 'M' 0x4D */ {244, 8, 9, 10, 1, -8}, - /* 'N' 0x4E */ {253, 7, 9, 9, 1, -8}, - /* 'O' 0x4F */ {261, 9, 9, 9, 0, -8}, - /* 'P' 0x50 */ {272, 6, 9, 8, 1, -8}, - /* 'Q' 0x51 */ {279, 9, 10, 9, 0, -8}, - /* 'R' 0x52 */ {291, 7, 9, 9, 1, -8}, - /* 'S' 0x53 */ {299, 6, 9, 8, 1, -8}, - /* 'T' 0x54 */ {306, 7, 9, 8, 0, -8}, - /* 'U' 0x55 */ {314, 7, 9, 9, 1, -8}, - /* 'V' 0x56 */ {322, 7, 9, 8, 0, -8}, - /* 'W' 0x57 */ {330, 11, 9, 11, 0, -8}, - /* 'X' 0x58 */ {343, 6, 9, 8, 1, -8}, - /* 'Y' 0x59 */ {350, 8, 9, 8, 0, -8}, - /* 'Z' 0x5A */ {359, 7, 9, 7, 0, -8}, - /* '[' 0x5B */ {367, 2, 12, 3, 1, -8}, - /* '\' 0x5C */ {370, 3, 9, 3, 0, -8}, - /* ']' 0x5D */ {374, 2, 12, 3, 0, -8}, - /* '^' 0x5E */ {377, 4, 4, 6, 1, -8}, - /* '_' 0x5F */ {379, 7, 1, 7, 0, 2}, - /* '`' 0x60 */ {380, 1, 1, 3, 1, -8}, - /* 'a' 0x61 */ {381, 6, 7, 7, 0, -6}, - /* 'b' 0x62 */ {387, 5, 9, 7, 1, -8}, - /* 'c' 0x63 */ {393, 6, 7, 6, 0, -6}, - /* 'd' 0x64 */ {399, 6, 9, 7, 0, -8}, - /* 'e' 0x65 */ {406, 6, 7, 6, 0, -6}, - /* 'f' 0x66 */ {412, 3, 9, 3, 0, -8}, - /* 'g' 0x67 */ {416, 6, 10, 7, 0, -6}, - /* 'h' 0x68 */ {424, 5, 9, 6, 1, -8}, - /* 'i' 0x69 */ {430, 1, 9, 3, 1, -8}, - /* 'j' 0x6A */ {432, 2, 12, 3, 0, -8}, - /* 'k' 0x6B */ {435, 5, 9, 6, 1, -8}, - /* 'l' 0x6C */ {441, 1, 9, 3, 1, -8}, - /* 'm' 0x6D */ {443, 8, 7, 10, 1, -6}, - /* 'n' 0x6E */ {450, 5, 7, 6, 1, -6}, - /* 'o' 0x6F */ {455, 6, 7, 6, 0, -6}, - /* 'p' 0x70 */ {461, 5, 9, 7, 1, -6}, - /* 'q' 0x71 */ {467, 6, 9, 7, 0, -6}, - /* 'r' 0x72 */ {474, 3, 7, 4, 1, -6}, - /* 's' 0x73 */ {477, 5, 7, 6, 0, -6}, - /* 't' 0x74 */ {482, 3, 8, 3, 0, -7}, - /* 'u' 0x75 */ {485, 5, 7, 6, 1, -6}, - /* 'v' 0x76 */ {490, 6, 7, 6, 0, -6}, - /* 'w' 0x77 */ {496, 8, 7, 9, 0, -6}, - /* 'x' 0x78 */ {503, 5, 7, 6, 0, -6}, - /* 'y' 0x79 */ {508, 5, 10, 6, 0, -6}, - /* 'z' 0x7A */ {515, 5, 7, 6, 0, -6}, - /* '{' 0x7B */ {520, 2, 12, 4, 1, -8}, - /* '|' 0x7C */ {523, 1, 11, 3, 1, -8}, - /* '}' 0x7D */ {525, 2, 12, 4, 1, -8}, - /* '~' 0x7E */ {528, 6, 2, 6, 0, -4}, - /* 0x7F */ {530, 9, 10, 11, 1, -8}, - /* 0x80 */ {542, 7, 9, 8, 0, -8}, - /* 0x81 */ {550, 0, 0, 8, 0, 0}, - /* 0x82 */ {550, 1, 3, 3, 1, 0}, - /* 0x83 */ {551, 3, 12, 3, 0, -8}, - /* 0x84 */ {556, 3, 3, 5, 1, 0}, - /* 0x85 */ {558, 5, 1, 7, 1, 0}, - /* 0x86 */ {559, 5, 11, 7, 1, -8}, - /* 0x87 */ {566, 5, 11, 7, 1, -8}, - /* 0x88 */ {573, 3, 2, 4, 0, -9}, - /* 0x89 */ {574, 12, 9, 12, 0, -8}, - /* 0x8A */ {588, 6, 11, 8, 1, -9}, - /* 0x8B */ {597, 2, 3, 4, 1, -4}, - /* 0x8C */ {598, 11, 9, 12, 0, -8}, - /* 0x8D */ {611, 0, 0, 8, 0, 0}, - /* 0x8E */ {611, 7, 10, 7, 0, -9}, - /* 0x8F */ {620, 0, 0, 8, 0, 0}, - /* 0x90 */ {620, 0, 0, 8, 0, 0}, - /* 0x91 */ {620, 1, 3, 3, 1, -8}, - /* 0x92 */ {621, 1, 3, 2, 1, -8}, - /* 0x93 */ {622, 3, 3, 5, 1, -8}, - /* 0x94 */ {624, 3, 3, 5, 1, -8}, - /* 0x95 */ {626, 3, 3, 5, 1, -5}, - /* 0x96 */ {628, 6, 1, 6, 0, -3}, - /* 0x97 */ {629, 12, 1, 12, 0, -3}, - /* 0x98 */ {631, 4, 2, 4, 0, -8}, - /* 0x99 */ {632, 11, 7, 12, 1, -8}, - /* 0x9A */ {642, 4, 9, 6, 1, -8}, - /* 0x9B */ {647, 2, 3, 3, 1, -4}, - /* 0x9C */ {648, 11, 7, 11, 0, -6}, - /* 0x9D */ {658, 0, 0, 8, 0, 0}, - /* 0x9E */ {658, 5, 9, 6, 0, -8}, - /* 0x9F */ {664, 7, 10, 8, 1, -9}, - /* 0xA0 */ {673, 0, 0, 3, 0, 0}, - /* 0xA1 */ {673, 1, 9, 4, 1, -5}, - /* 0xA2 */ {675, 5, 9, 7, 1, -7}, - /* 0xA3 */ {681, 6, 9, 7, 0, -8}, - /* 0xA4 */ {688, 5, 4, 7, 1, -5}, - /* 0xA5 */ {691, 5, 9, 7, 1, -8}, - /* 0xA6 */ {697, 1, 12, 3, 1, -8}, - /* 0xA7 */ {699, 5, 12, 7, 1, -8}, - /* 0xA8 */ {707, 3, 1, 4, 0, -7}, - /* 0xA9 */ {708, 9, 9, 10, 0, -8}, - /* 0xAA */ {719, 4, 5, 4, 0, -8}, - /* 0xAB */ {722, 4, 4, 6, 1, -4}, - /* 0xAC */ {724, 6, 3, 7, 1, -4}, - /* 0xAD */ {727, 0, 0, 0, 0, 0}, - /* 0xAE */ {727, 9, 9, 10, 0, -8}, - /* 0xAF */ {738, 3, 1, 4, 0, -8}, - /* 0xB0 */ {739, 4, 4, 7, 2, -8}, - /* 0xB1 */ {741, 5, 7, 7, 1, -6}, - /* 0xB2 */ {746, 4, 5, 4, 0, -9}, - /* 0xB3 */ {749, 4, 5, 4, 0, -9}, - /* 0xB4 */ {752, 1, 1, 4, 1, -8}, - /* 0xB5 */ {753, 6, 9, 7, 1, -6}, - /* 0xB6 */ {760, 6, 10, 6, 1, -8}, - /* 0xB7 */ {768, 1, 1, 3, 1, -2}, - /* 0xB8 */ {769, 3, 3, 4, 1, 1}, - /* 0xB9 */ {771, 2, 6, 4, 1, -9}, - /* 0xBA */ {773, 4, 5, 4, 0, -8}, - /* 0xBB */ {776, 4, 4, 6, 1, -5}, - /* 0xBC */ {778, 10, 9, 10, 1, -8}, - /* 0xBD */ {790, 9, 9, 10, 1, -8}, - /* 0xBE */ {801, 10, 9, 11, 0, -8}, - /* 0xBF */ {813, 5, 9, 7, 1, -5}, - /* 0xC0 */ {819, 8, 10, 8, 0, -9}, - /* 0xC1 */ {829, 8, 10, 8, 0, -9}, - /* 0xC2 */ {839, 8, 10, 8, 0, -9}, - /* 0xC3 */ {849, 8, 10, 8, 0, -9}, - /* 0xC4 */ {859, 8, 10, 8, 0, -9}, - /* 0xC5 */ {869, 8, 10, 8, 0, -9}, - /* 0xC6 */ {879, 10, 9, 12, 1, -8}, - /* 0xC7 */ {891, 8, 12, 9, 0, -8}, - /* 0xC8 */ {903, 6, 10, 8, 1, -9}, - /* 0xC9 */ {911, 6, 10, 8, 1, -9}, - /* 0xCA */ {919, 6, 10, 8, 1, -9}, - /* 0xCB */ {927, 6, 10, 8, 1, -9}, - /* 0xCC */ {935, 2, 10, 3, 0, -9}, - /* 0xCD */ {938, 2, 10, 3, 1, -9}, - /* 0xCE */ {941, 3, 10, 4, 0, -9}, - /* 0xCF */ {945, 3, 10, 4, 0, -9}, - /* 0xD0 */ {949, 8, 9, 8, 0, -8}, - /* 0xD1 */ {958, 7, 10, 9, 1, -9}, - /* 0xD2 */ {967, 9, 10, 9, 0, -9}, - /* 0xD3 */ {979, 9, 10, 9, 0, -9}, - /* 0xD4 */ {991, 9, 11, 9, 0, -10}, - /* 0xD5 */ {1004, 9, 11, 9, 0, -10}, - /* 0xD6 */ {1017, 9, 11, 9, 0, -10}, - /* 0xD7 */ {1030, 5, 5, 7, 1, -5}, - /* 0xD8 */ {1034, 9, 9, 9, 0, -8}, - /* 0xD9 */ {1045, 7, 10, 9, 1, -9}, - /* 0xDA */ {1054, 7, 10, 9, 1, -9}, - /* 0xDB */ {1063, 7, 10, 9, 1, -9}, - /* 0xDC */ {1072, 7, 10, 9, 1, -9}, - /* 0xDD */ {1081, 7, 10, 8, 1, -9}, - /* 0xDE */ {1090, 6, 9, 8, 1, -8}, - /* 0xDF */ {1097, 6, 9, 7, 1, -8}, - /* 0xE0 */ {1104, 7, 10, 7, 0, -9}, - /* 0xE1 */ {1113, 7, 10, 7, 0, -9}, - /* 0xE2 */ {1122, 7, 10, 7, 0, -9}, - /* 0xE3 */ {1131, 7, 10, 7, 0, -9}, - /* 0xE4 */ {1140, 7, 9, 7, 0, -8}, - /* 0xE5 */ {1148, 7, 10, 7, 0, -9}, - /* 0xE6 */ {1157, 10, 7, 10, 0, -6}, - /* 0xE7 */ {1166, 6, 10, 6, 0, -6}, - /* 0xE8 */ {1174, 6, 10, 6, 0, -9}, - /* 0xE9 */ {1182, 6, 10, 6, 0, -9}, - /* 0xEA */ {1190, 6, 10, 6, 0, -9}, - /* 0xEB */ {1198, 6, 9, 6, 0, -8}, - /* 0xEC */ {1205, 2, 10, 3, 0, -9}, - /* 0xED */ {1208, 2, 10, 3, 1, -9}, - /* 0xEE */ {1211, 3, 10, 3, 0, -9}, - /* 0xEF */ {1215, 3, 9, 3, 0, -8}, - /* 0xF0 */ {1219, 6, 9, 6, 0, -8}, - /* 0xF1 */ {1226, 5, 10, 6, 1, -9}, - /* 0xF2 */ {1233, 6, 10, 6, 0, -9}, - /* 0xF3 */ {1241, 6, 10, 6, 0, -9}, - /* 0xF4 */ {1249, 6, 10, 6, 0, -9}, - /* 0xF5 */ {1257, 6, 10, 6, 0, -9}, - /* 0xF6 */ {1265, 6, 9, 6, 0, -8}, - /* 0xF7 */ {1272, 5, 5, 7, 1, -5}, - /* 0xF8 */ {1276, 6, 7, 6, 0, -6}, - /* 0xF9 */ {1282, 5, 9, 6, 1, -8}, - /* 0xFA */ {1288, 5, 9, 6, 1, -8}, - /* 0xFB */ {1294, 5, 10, 6, 1, -9}, - /* 0xFC */ {1301, 5, 9, 6, 1, -8}, - /* 0xFD */ {1307, 6, 12, 6, 0, -8}, - /* 0xFE */ {1316, 5, 11, 7, 1, -8}, - /* 0xFF */ {1323, 6, 12, 6, 0, -8}, +/* 0x01 */ { 0, 9, 10, 11, 1, -9 }, +/* 0x02 */ { 12, 9, 10, 11, 1, -8 }, +/* 0x03 */ { 24, 10, 10, 12, 1, -8 }, +/* 0x04 */ { 37, 10, 10, 12, 1, -8 }, +/* 0x05 */ { 50, 10, 10, 12, 1, -9 }, +/* 0x06 */ { 63, 11, 11, 13, 1, -9 }, +/* 0x07 */ { 79, 0, 0, 8, 0, 0 }, +/* 0x08 */ { 79, 12, 9, 14, 1, -8 }, +/* 0x09 */ { 93, 14, 8, 16, 1, -7 }, +/* 0x0A */ { 107, 0, 0, 8, 0, 0 }, +/* 0x0B */ { 107, 9, 10, 11, 1, -9 }, +/* 0x0C */ { 119, 13, 9, 15, 1, -8 }, +/* 0x0D */ { 134, 0, 0, 8, 0, 0 }, +/* 0x0E */ { 134, 9, 11, 11, 1, -9 }, +/* 0x0F */ { 147, 10, 10, 12, 1, -9 }, +/* 0x10 */ { 160, 11, 10, 13, 1, -9 }, +/* 0x11 */ { 174, 13, 10, 15, 1, -9 }, +/* 0x12 */ { 191, 10, 10, 12, 1, -9 }, +/* 0x13 */ { 204, 11, 10, 13, 1, -9 }, +/* 0x14 */ { 218, 10, 10, 12, 1, -9 }, +/* 0x15 */ { 231, 14, 10, 16, 1, -9 }, +/* 0x16 */ { 249, 8, 10, 10, 1, -9 }, +/* 0x17 */ { 259, 12, 10, 14, 1, -9 }, +/* 0x18 */ { 274, 13, 10, 15, 1, -9 }, +/* 0x19 */ { 291, 12, 10, 14, 1, -9 }, +/* 0x1A */ { 306, 9, 10, 11, 1, -8 }, +/* 0x1B */ { 318, 14, 10, 16, 1, -9 }, +/* 0x1C */ { 336, 11, 10, 13, 1, -9 }, +/* 0x1D */ { 350, 11, 10, 13, 1, -9 }, +/* 0x1E */ { 364, 12, 10, 14, 1, -9 }, +/* 0x1F */ { 379, 8, 10, 11, 2, -9 }, +/* ' ' 0x20 */ { 389, 0, 0, 3, 0, 0 }, +/* '!' 0x21 */ { 389, 1, 9, 4, 2, -8 }, +/* '"' 0x22 */ { 391, 3, 3, 4, 0, -8 }, +/* '#' 0x23 */ { 393, 7, 8, 7, 0, -7 }, +/* '$' 0x24 */ { 400, 6, 11, 7, 0, -9 }, +/* '%' 0x25 */ { 409, 10, 9, 11, 0, -8 }, +/* '&' 0x26 */ { 421, 6, 9, 8, 1, -8 }, +/* ''' 0x27 */ { 428, 1, 3, 2, 1, -8 }, +/* '(' 0x28 */ { 429, 2, 11, 4, 1, -8 }, +/* ')' 0x29 */ { 432, 3, 11, 4, 0, -8 }, +/* '*' 0x2A */ { 437, 3, 3, 5, 1, -8 }, +/* '+' 0x2B */ { 439, 5, 5, 7, 1, -4 }, +/* ',' 0x2C */ { 443, 1, 3, 3, 1, 0 }, +/* '-' 0x2D */ { 444, 2, 1, 4, 1, -3 }, +/* '.' 0x2E */ { 445, 1, 1, 3, 1, 0 }, +/* '/' 0x2F */ { 446, 3, 9, 3, 0, -8 }, +/* '0' 0x30 */ { 450, 5, 9, 7, 1, -8 }, +/* '1' 0x31 */ { 456, 3, 9, 7, 1, -8 }, +/* '2' 0x32 */ { 460, 6, 9, 7, 0, -8 }, +/* '3' 0x33 */ { 467, 6, 9, 7, 0, -8 }, +/* '4' 0x34 */ { 474, 6, 9, 7, 0, -8 }, +/* '5' 0x35 */ { 481, 5, 9, 7, 1, -8 }, +/* '6' 0x36 */ { 487, 5, 9, 7, 1, -8 }, +/* '7' 0x37 */ { 493, 5, 9, 7, 1, -8 }, +/* '8' 0x38 */ { 499, 6, 9, 7, 0, -8 }, +/* '9' 0x39 */ { 506, 6, 9, 7, 0, -8 }, +/* ':' 0x3A */ { 513, 1, 7, 3, 1, -6 }, +/* ';' 0x3B */ { 514, 1, 8, 3, 1, -5 }, +/* '<' 0x3C */ { 515, 5, 5, 7, 1, -4 }, +/* '=' 0x3D */ { 519, 5, 3, 7, 1, -3 }, +/* '>' 0x3E */ { 521, 5, 5, 7, 1, -4 }, +/* '?' 0x3F */ { 525, 5, 9, 7, 1, -8 }, +/* '@' 0x40 */ { 531, 11, 11, 12, 0, -8 }, +/* 'A' 0x41 */ { 547, 8, 9, 8, 0, -8 }, +/* 'B' 0x42 */ { 556, 6, 9, 8, 1, -8 }, +/* 'C' 0x43 */ { 563, 8, 9, 9, 0, -8 }, +/* 'D' 0x44 */ { 572, 7, 9, 8, 1, -8 }, +/* 'E' 0x45 */ { 580, 6, 9, 8, 1, -8 }, +/* 'F' 0x46 */ { 587, 6, 9, 7, 1, -8 }, +/* 'G' 0x47 */ { 594, 8, 9, 9, 0, -8 }, +/* 'H' 0x48 */ { 603, 7, 9, 9, 1, -8 }, +/* 'I' 0x49 */ { 611, 1, 9, 3, 1, -8 }, +/* 'J' 0x4A */ { 613, 5, 9, 6, 0, -8 }, +/* 'K' 0x4B */ { 619, 7, 9, 8, 1, -8 }, +/* 'L' 0x4C */ { 627, 5, 9, 7, 1, -8 }, +/* 'M' 0x4D */ { 633, 8, 9, 10, 1, -8 }, +/* 'N' 0x4E */ { 642, 7, 9, 9, 1, -8 }, +/* 'O' 0x4F */ { 650, 9, 9, 9, 0, -8 }, +/* 'P' 0x50 */ { 661, 6, 9, 8, 1, -8 }, +/* 'Q' 0x51 */ { 668, 9, 10, 9, 0, -8 }, +/* 'R' 0x52 */ { 680, 7, 9, 9, 1, -8 }, +/* 'S' 0x53 */ { 688, 6, 9, 8, 1, -8 }, +/* 'T' 0x54 */ { 695, 7, 9, 8, 0, -8 }, +/* 'U' 0x55 */ { 703, 7, 9, 9, 1, -8 }, +/* 'V' 0x56 */ { 711, 7, 9, 8, 0, -8 }, +/* 'W' 0x57 */ { 719, 11, 9, 11, 0, -8 }, +/* 'X' 0x58 */ { 732, 6, 9, 8, 1, -8 }, +/* 'Y' 0x59 */ { 739, 8, 9, 8, 0, -8 }, +/* 'Z' 0x5A */ { 748, 7, 9, 7, 0, -8 }, +/* '[' 0x5B */ { 756, 2, 12, 3, 1, -8 }, +/* '\' 0x5C */ { 759, 3, 9, 3, 0, -8 }, +/* ']' 0x5D */ { 763, 2, 12, 3, 0, -8 }, +/* '^' 0x5E */ { 766, 4, 4, 6, 1, -8 }, +/* '_' 0x5F */ { 768, 7, 1, 7, 0, 2 }, +/* '`' 0x60 */ { 769, 1, 1, 3, 1, -8 }, +/* 'a' 0x61 */ { 770, 6, 7, 7, 0, -6 }, +/* 'b' 0x62 */ { 776, 5, 9, 7, 1, -8 }, +/* 'c' 0x63 */ { 782, 6, 7, 6, 0, -6 }, +/* 'd' 0x64 */ { 788, 6, 9, 7, 0, -8 }, +/* 'e' 0x65 */ { 795, 6, 7, 6, 0, -6 }, +/* 'f' 0x66 */ { 801, 3, 9, 3, 0, -8 }, +/* 'g' 0x67 */ { 805, 6, 10, 7, 0, -6 }, +/* 'h' 0x68 */ { 813, 5, 9, 6, 1, -8 }, +/* 'i' 0x69 */ { 819, 1, 9, 3, 1, -8 }, +/* 'j' 0x6A */ { 821, 2, 12, 3, 0, -8 }, +/* 'k' 0x6B */ { 824, 5, 9, 6, 1, -8 }, +/* 'l' 0x6C */ { 830, 1, 9, 3, 1, -8 }, +/* 'm' 0x6D */ { 832, 8, 7, 10, 1, -6 }, +/* 'n' 0x6E */ { 839, 5, 7, 6, 1, -6 }, +/* 'o' 0x6F */ { 844, 6, 7, 6, 0, -6 }, +/* 'p' 0x70 */ { 850, 5, 9, 7, 1, -6 }, +/* 'q' 0x71 */ { 856, 6, 9, 7, 0, -6 }, +/* 'r' 0x72 */ { 863, 3, 7, 4, 1, -6 }, +/* 's' 0x73 */ { 866, 5, 7, 6, 0, -6 }, +/* 't' 0x74 */ { 871, 3, 8, 3, 0, -7 }, +/* 'u' 0x75 */ { 874, 5, 7, 6, 1, -6 }, +/* 'v' 0x76 */ { 879, 6, 7, 6, 0, -6 }, +/* 'w' 0x77 */ { 885, 8, 7, 9, 0, -6 }, +/* 'x' 0x78 */ { 892, 5, 7, 6, 0, -6 }, +/* 'y' 0x79 */ { 897, 5, 10, 6, 0, -6 }, +/* 'z' 0x7A */ { 904, 5, 7, 6, 0, -6 }, +/* '{' 0x7B */ { 909, 2, 12, 4, 1, -8 }, +/* '|' 0x7C */ { 912, 1, 11, 3, 1, -8 }, +/* '}' 0x7D */ { 914, 2, 12, 4, 1, -8 }, +/* '~' 0x7E */ { 917, 6, 2, 6, 0, -4 }, +/* 0x7F */ { 919, 0, 0, 0, 0, 0 }, +/* 0x80 */ { 919, 7, 9, 8, 0, -8 }, +/* 0x81 */ { 927, 0, 0, 8, 0, 0 }, +/* 0x82 */ { 927, 1, 3, 3, 1, 0 }, +/* 0x83 */ { 928, 3, 12, 3, 0, -8 }, +/* 0x84 */ { 933, 3, 3, 5, 1, 0 }, +/* 0x85 */ { 935, 5, 1, 7, 1, 0 }, +/* 0x86 */ { 936, 5, 11, 7, 1, -8 }, +/* 0x87 */ { 943, 5, 11, 7, 1, -8 }, +/* 0x88 */ { 950, 3, 2, 4, 0, -9 }, +/* 0x89 */ { 951, 12, 9, 12, 0, -8 }, +/* 0x8A */ { 965, 6, 11, 8, 1, -9 }, +/* 0x8B */ { 974, 2, 3, 4, 1, -4 }, +/* 0x8C */ { 975, 11, 9, 12, 0, -8 }, +/* 0x8D */ { 988, 0, 0, 8, 0, 0 }, +/* 0x8E */ { 988, 7, 10, 7, 0, -9 }, +/* 0x8F */ { 997, 0, 0, 8, 0, 0 }, +/* 0x90 */ { 997, 0, 0, 8, 0, 0 }, +/* 0x91 */ { 997, 1, 3, 3, 1, -8 }, +/* 0x92 */ { 998, 1, 3, 2, 1, -8 }, +/* 0x93 */ { 999, 3, 3, 5, 1, -8 }, +/* 0x94 */ { 1001, 3, 3, 5, 1, -8 }, +/* 0x95 */ { 1003, 3, 3, 5, 1, -5 }, +/* 0x96 */ { 1005, 6, 1, 6, 0, -3 }, +/* 0x97 */ { 1006, 12, 1, 12, 0, -3 }, +/* 0x98 */ { 1008, 4, 2, 4, 0, -8 }, +/* 0x99 */ { 1009, 11, 7, 12, 1, -8 }, +/* 0x9A */ { 1019, 4, 9, 6, 1, -8 }, +/* 0x9B */ { 1024, 2, 3, 3, 1, -4 }, +/* 0x9C */ { 1025, 11, 7, 11, 0, -6 }, +/* 0x9D */ { 1035, 0, 0, 8, 0, 0 }, +/* 0x9E */ { 1035, 5, 9, 6, 0, -8 }, +/* 0x9F */ { 1041, 7, 10, 8, 1, -9 }, +/* 0xA0 */ { 1050, 0, 0, 3, 0, 0 }, +/* 0xA1 */ { 1050, 1, 9, 4, 1, -5 }, +/* 0xA2 */ { 1052, 5, 9, 7, 1, -7 }, +/* 0xA3 */ { 1058, 6, 9, 7, 0, -8 }, +/* 0xA4 */ { 1065, 5, 4, 7, 1, -5 }, +/* 0xA5 */ { 1068, 5, 9, 7, 1, -8 }, +/* 0xA6 */ { 1074, 1, 12, 3, 1, -8 }, +/* 0xA7 */ { 1076, 5, 12, 7, 1, -8 }, +/* 0xA8 */ { 1084, 3, 1, 4, 0, -7 }, +/* 0xA9 */ { 1085, 9, 9, 10, 0, -8 }, +/* 0xAA */ { 1096, 4, 5, 4, 0, -8 }, +/* 0xAB */ { 1099, 4, 4, 6, 1, -4 }, +/* 0xAC */ { 1101, 6, 3, 7, 1, -4 }, +/* 0xAD */ { 1104, 0, 0, 0, 0, 0 }, +/* 0xAE */ { 1104, 9, 9, 10, 0, -8 }, +/* 0xAF */ { 1115, 3, 1, 4, 0, -8 }, +/* 0xB0 */ { 1116, 4, 4, 7, 2, -8 }, +/* 0xB1 */ { 1118, 5, 7, 7, 1, -6 }, +/* 0xB2 */ { 1123, 4, 5, 4, 0, -9 }, +/* 0xB3 */ { 1126, 4, 5, 4, 0, -9 }, +/* 0xB4 */ { 1129, 1, 1, 4, 1, -8 }, +/* 0xB5 */ { 1130, 6, 9, 7, 1, -6 }, +/* 0xB6 */ { 1137, 6, 10, 6, 1, -8 }, +/* 0xB7 */ { 1145, 1, 1, 3, 1, -2 }, +/* 0xB8 */ { 1146, 3, 3, 4, 1, 1 }, +/* 0xB9 */ { 1148, 2, 6, 4, 1, -9 }, +/* 0xBA */ { 1150, 4, 5, 4, 0, -8 }, +/* 0xBB */ { 1153, 4, 4, 6, 1, -5 }, +/* 0xBC */ { 1155, 10, 9, 10, 1, -8 }, +/* 0xBD */ { 1167, 9, 9, 10, 1, -8 }, +/* 0xBE */ { 1178, 10, 9, 11, 0, -8 }, +/* 0xBF */ { 1190, 5, 9, 7, 1, -5 }, +/* 0xC0 */ { 1196, 8, 10, 8, 0, -9 }, +/* 0xC1 */ { 1206, 8, 10, 8, 0, -9 }, +/* 0xC2 */ { 1216, 8, 10, 8, 0, -9 }, +/* 0xC3 */ { 1226, 8, 10, 8, 0, -9 }, +/* 0xC4 */ { 1236, 8, 10, 8, 0, -9 }, +/* 0xC5 */ { 1246, 8, 10, 8, 0, -9 }, +/* 0xC6 */ { 1256, 10, 9, 12, 1, -8 }, +/* 0xC7 */ { 1268, 8, 12, 9, 0, -8 }, +/* 0xC8 */ { 1280, 6, 10, 8, 1, -9 }, +/* 0xC9 */ { 1288, 6, 10, 8, 1, -9 }, +/* 0xCA */ { 1296, 6, 10, 8, 1, -9 }, +/* 0xCB */ { 1304, 6, 10, 8, 1, -9 }, +/* 0xCC */ { 1312, 2, 10, 3, 0, -9 }, +/* 0xCD */ { 1315, 2, 10, 3, 1, -9 }, +/* 0xCE */ { 1318, 3, 10, 4, 0, -9 }, +/* 0xCF */ { 1322, 3, 10, 4, 0, -9 }, +/* 0xD0 */ { 1326, 8, 9, 8, 0, -8 }, +/* 0xD1 */ { 1335, 7, 10, 9, 1, -9 }, +/* 0xD2 */ { 1344, 9, 10, 9, 0, -9 }, +/* 0xD3 */ { 1356, 9, 10, 9, 0, -9 }, +/* 0xD4 */ { 1368, 9, 11, 9, 0, -10 }, +/* 0xD5 */ { 1381, 9, 11, 9, 0, -10 }, +/* 0xD6 */ { 1394, 9, 11, 9, 0, -10 }, +/* 0xD7 */ { 1407, 5, 5, 7, 1, -5 }, +/* 0xD8 */ { 1411, 9, 9, 9, 0, -8 }, +/* 0xD9 */ { 1422, 7, 10, 9, 1, -9 }, +/* 0xDA */ { 1431, 7, 10, 9, 1, -9 }, +/* 0xDB */ { 1440, 7, 10, 9, 1, -9 }, +/* 0xDC */ { 1449, 7, 10, 9, 1, -9 }, +/* 0xDD */ { 1458, 7, 10, 8, 1, -9 }, +/* 0xDE */ { 1467, 6, 9, 8, 1, -8 }, +/* 0xDF */ { 1474, 6, 9, 7, 1, -8 }, +/* 0xE0 */ { 1481, 7, 10, 7, 0, -9 }, +/* 0xE1 */ { 1490, 7, 10, 7, 0, -9 }, +/* 0xE2 */ { 1499, 7, 10, 7, 0, -9 }, +/* 0xE3 */ { 1508, 7, 10, 7, 0, -9 }, +/* 0xE4 */ { 1517, 7, 9, 7, 0, -8 }, +/* 0xE5 */ { 1525, 7, 10, 7, 0, -9 }, +/* 0xE6 */ { 1534, 10, 7, 10, 0, -6 }, +/* 0xE7 */ { 1543, 6, 10, 6, 0, -6 }, +/* 0xE8 */ { 1551, 6, 10, 6, 0, -9 }, +/* 0xE9 */ { 1559, 6, 10, 6, 0, -9 }, +/* 0xEA */ { 1567, 6, 10, 6, 0, -9 }, +/* 0xEB */ { 1575, 6, 9, 6, 0, -8 }, +/* 0xEC */ { 1582, 2, 10, 3, 0, -9 }, +/* 0xED */ { 1585, 2, 10, 3, 1, -9 }, +/* 0xEE */ { 1588, 3, 10, 3, 0, -9 }, +/* 0xEF */ { 1592, 3, 9, 3, 0, -8 }, +/* 0xF0 */ { 1596, 6, 9, 6, 0, -8 }, +/* 0xF1 */ { 1603, 5, 10, 6, 1, -9 }, +/* 0xF2 */ { 1610, 6, 10, 6, 0, -9 }, +/* 0xF3 */ { 1618, 6, 10, 6, 0, -9 }, +/* 0xF4 */ { 1626, 6, 10, 6, 0, -9 }, +/* 0xF5 */ { 1634, 6, 10, 6, 0, -9 }, +/* 0xF6 */ { 1642, 6, 9, 6, 0, -8 }, +/* 0xF7 */ { 1649, 5, 5, 7, 1, -5 }, +/* 0xF8 */ { 1653, 6, 7, 6, 0, -6 }, +/* 0xF9 */ { 1659, 5, 9, 6, 1, -8 }, +/* 0xFA */ { 1665, 5, 9, 6, 1, -8 }, +/* 0xFB */ { 1671, 5, 10, 6, 1, -9 }, +/* 0xFC */ { 1678, 5, 9, 6, 1, -8 }, +/* 0xFD */ { 1684, 6, 12, 6, 0, -8 }, +/* 0xFE */ { 1693, 5, 11, 7, 1, -8 }, +/* 0xFF */ { 1700, 6, 12, 6, 0, -8 }, }; -const GFXfont FreeSans6pt_Win1252 PROGMEM = {(uint8_t *)FreeSans6pt_Win1252Bitmaps, (GFXglyph *)FreeSans6pt_Win1252Glyphs, 0x20, - 0xFF, 14}; +const GFXfont FreeSans6pt_Win1252 PROGMEM = { +(uint8_t*)FreeSans6pt_Win1252Bitmaps, +(GFXglyph*)FreeSans6pt_Win1252Glyphs, +0x01, 0xFF, 10 +}; diff --git a/src/graphics/niche/Fonts/FreeSans9pt_Win1250.h b/src/graphics/niche/Fonts/FreeSans9pt_Win1250.h index 7022939a0..dd66801a1 100644 --- a/src/graphics/niche/Fonts/FreeSans9pt_Win1250.h +++ b/src/graphics/niche/Fonts/FreeSans9pt_Win1250.h @@ -1,494 +1,527 @@ +// trunk-ignore-all(clang-format) #pragma once +/* PROPERTIES + +FONT_NAME FreeSans9pt_Win1250 +*/ const uint8_t FreeSans9pt_Win1250Bitmaps[] PROGMEM = { - /* ' ' 0x20 */ - 0xFF, 0xFF, 0xF0, 0xC0, /* '!' 0x21 */ - 0xDE, 0xF7, 0x20, /* '"' 0x22 */ - 0x09, 0x86, 0x41, 0x91, 0xFF, 0x13, 0x04, 0xC3, 0x20, 0xC8, 0xFF, 0x89, 0x82, 0x61, 0x90, /* '#' 0x23 */ - 0x10, 0x1F, 0x14, 0xDA, 0x3D, 0x1E, 0x83, 0x40, 0x78, 0x17, 0x08, 0xF4, 0x7A, 0x35, 0x33, 0xF0, 0x40, 0x20, /* '$' 0x24 */ - 0x38, 0x10, 0xEC, 0x20, 0xC6, 0x20, 0xC6, 0x40, 0xC6, 0x40, 0x6C, 0x80, 0x39, 0x00, 0x01, 0x3C, 0x02, 0x77, 0x02, 0x63, 0x04, - 0x63, 0x04, 0x77, 0x08, 0x3C, /* '%' 0x25 */ - 0x0E, 0x0C, 0xC3, 0x30, 0xCC, 0x1E, 0x03, 0x03, 0xC1, 0x9B, 0xC2, 0xF0, 0xEC, 0x19, 0x8F, 0x3C, 0x40, /* '&' 0x26 */ - 0xFE, /* ''' 0x27 */ - 0x13, 0x26, 0x6C, 0xCC, 0xCC, 0xC4, 0x66, 0x23, 0x10, /* '(' 0x28 */ - 0x8C, 0x46, 0x63, 0x33, 0x33, 0x32, 0x66, 0x4C, 0x80, /* ')' 0x29 */ - 0x25, 0x7E, 0xA5, 0x00, /* '*' 0x2A */ - 0x30, 0xC3, 0x3F, 0x30, 0xC3, 0x0C, /* '+' 0x2B */ - 0xD6, /* ',' 0x2C */ - 0xF0, /* '-' 0x2D */ - 0xC0, /* '.' 0x2E */ - 0x08, 0x44, 0x21, 0x10, 0x84, 0x42, 0x11, 0x08, 0x00, /* '/' 0x2F */ - 0x3C, 0x66, 0x42, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x42, 0x66, 0x3C, /* '0' 0x30 */ - 0x11, 0x3F, 0x33, 0x33, 0x33, 0x33, 0x30, /* '1' 0x31 */ - 0x3E, 0x31, 0xB0, 0x78, 0x30, 0x18, 0x1C, 0x1C, 0x1C, 0x18, 0x18, 0x10, 0x08, 0x07, 0xF8, /* '2' 0x32 */ - 0x3C, 0x66, 0xC3, 0xC3, 0x03, 0x06, 0x1C, 0x07, 0x03, 0xC3, 0xC3, 0x66, 0x3C, /* '3' 0x33 */ - 0x0C, 0x18, 0x71, 0x62, 0xC9, 0xA3, 0x46, 0xFE, 0x18, 0x30, 0x60, 0xC0, /* '4' 0x34 */ - 0x7F, 0x20, 0x10, 0x08, 0x08, 0x07, 0xF3, 0x8C, 0x03, 0x01, 0x80, 0xF0, 0x6C, 0x63, 0xE0, /* '5' 0x35 */ - 0x1E, 0x31, 0x98, 0x78, 0x0C, 0x06, 0xF3, 0x8D, 0x83, 0xC1, 0xE0, 0xD0, 0x6C, 0x63, 0xE0, /* '6' 0x36 */ - 0xFF, 0x03, 0x02, 0x06, 0x04, 0x0C, 0x08, 0x18, 0x18, 0x18, 0x10, 0x30, 0x30, /* '7' 0x37 */ - 0x3E, 0x31, 0xB0, 0x78, 0x3C, 0x1B, 0x18, 0xF8, 0xC6, 0xC1, 0xE0, 0xF0, 0x6C, 0x63, 0xE0, /* '8' 0x38 */ - 0x3C, 0x66, 0xC2, 0xC3, 0xC3, 0xC3, 0x67, 0x3B, 0x03, 0x03, 0xC2, 0x66, 0x3C, /* '9' 0x39 */ - 0xC0, 0x00, 0x30, /* ':' 0x3A */ - 0xC0, 0x00, 0x00, 0x64, 0xA0, /* ';' 0x3B */ - 0x00, 0x81, 0xC7, 0x8E, 0x0C, 0x07, 0x80, 0x70, 0x0E, 0x01, 0x80, /* '<' 0x3C */ - 0xFF, 0x80, 0x00, 0x1F, 0xF0, /* '=' 0x3D */ - 0xE0, 0x1C, 0x03, 0x80, 0x30, 0x70, 0xE3, 0x81, 0x00, /* '>' 0x3E */ - 0x3E, 0x31, 0xB0, 0x78, 0x30, 0x18, 0x18, 0x38, 0x18, 0x18, 0x0C, 0x00, 0x00, 0x01, 0x80, /* '?' 0x3F */ - 0x03, 0xF0, 0x06, 0x0E, 0x06, 0x01, 0x86, 0x00, 0x66, 0x1D, 0xBB, 0x31, 0xCF, 0x18, 0xC7, 0x98, 0x63, 0xCC, 0x31, 0xE6, 0x11, - 0xB3, 0x99, 0xCC, 0xF7, 0x86, 0x00, 0x01, 0x80, 0x00, 0x70, 0x40, 0x0F, 0xE0, /* '@' 0x40 */ - 0x06, 0x00, 0xF0, 0x0F, 0x00, 0x90, 0x19, 0x81, 0x98, 0x10, 0x83, 0x0C, 0x3F, 0xC2, 0x04, 0x60, 0x66, 0x06, 0xC0, - 0x30, /* 'A' 0x41 */ - 0xFF, 0x18, 0x33, 0x03, 0x60, 0x6C, 0x0D, 0x83, 0x3F, 0xC6, 0x06, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x6F, 0xF8, /* 'B' 0x42 */ - 0x1F, 0x86, 0x19, 0x81, 0xA0, 0x3C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xC0, 0x68, 0x0D, 0x83, 0x18, 0x61, 0xF0, /* 'C' 0x43 */ - 0xFF, 0x18, 0x33, 0x03, 0x60, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x03, 0x60, 0xCF, 0xF0, /* 'D' 0x44 */ - 0xFF, 0xE0, 0x30, 0x18, 0x0C, 0x06, 0x03, 0xFD, 0x80, 0xC0, 0x60, 0x30, 0x18, 0x0F, 0xF8, /* 'E' 0x45 */ - 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFE, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, /* 'F' 0x46 */ - 0x0F, 0x83, 0x0E, 0x60, 0x66, 0x03, 0xC0, 0x0C, 0x00, 0xC1, 0xFC, 0x03, 0xC0, 0x36, 0x03, 0x60, 0x73, 0x0F, 0x0F, - 0x10, /* 'G' 0x47 */ - 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xFF, 0xFE, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x06, /* 'H' 0x48 */ - 0xFF, 0xFF, 0xFF, 0xC0, /* 'I' 0x49 */ - 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x83, 0x07, 0x8F, 0x1E, 0x27, 0x80, /* 'J' 0x4A */ - 0xC0, 0xF0, 0x6C, 0x33, 0x18, 0xCC, 0x37, 0x0F, 0xC3, 0x98, 0xC3, 0x30, 0xCC, 0x1B, 0x03, 0xC0, 0xC0, /* 'K' 0x4B */ - 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, /* 'L' 0x4C */ - 0xE0, 0x3F, 0x01, 0xFC, 0x1F, 0xE0, 0xFD, 0x05, 0xEC, 0x6F, 0x63, 0x79, 0x13, 0xCD, 0x9E, 0x6C, 0xF1, 0x47, 0x8E, 0x3C, 0x71, - 0x80, /* 'M' 0x4D */ - 0xE0, 0x7C, 0x0F, 0xC1, 0xE8, 0x3D, 0x87, 0x98, 0xF1, 0x1E, 0x33, 0xC3, 0x78, 0x6F, 0x07, 0xE0, 0x7C, 0x0E, /* 'N' 0x4E */ - 0x0F, 0x81, 0x83, 0x18, 0x0C, 0xC0, 0x6C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1B, 0x01, 0x98, 0x0C, 0x60, 0xC0, 0xF8, - 0x00, /* 'O' 0x4F */ - 0xFF, 0x30, 0x6C, 0x0F, 0x03, 0xC0, 0xF0, 0x6F, 0xF3, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x00, /* 'P' 0x50 */ - 0x0F, 0x81, 0x83, 0x18, 0x0C, 0xC0, 0x6C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1B, 0x01, 0x98, 0x6C, 0x60, 0xC0, 0xFB, - 0x00, 0x08, /* 'Q' 0x51 */ - 0xFF, 0x8C, 0x0E, 0xC0, 0x6C, 0x06, 0xC0, 0x6C, 0x0C, 0xFF, 0x8C, 0x0E, 0xC0, 0x6C, 0x06, 0xC0, 0x6C, 0x06, 0xC0, - 0x70, /* 'R' 0x52 */ - 0x3F, 0x18, 0x6C, 0x0F, 0x03, 0xC0, 0x1E, 0x01, 0xF0, 0x0E, 0x00, 0xF0, 0x3C, 0x0D, 0x86, 0x3F, 0x00, /* 'S' 0x53 */ - 0xFF, 0x86, 0x03, 0x01, 0x80, 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x80, 0xC0, /* 'T' 0x54 */ - 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xB0, 0x61, 0xF0, /* 'U' 0x55 */ - 0xC0, 0x6C, 0x0D, 0x81, 0x10, 0x63, 0x0C, 0x61, 0x04, 0x60, 0xCC, 0x19, 0x01, 0x60, 0x3C, 0x07, 0x00, 0x60, /* 'V' 0x56 */ - 0xC1, 0x81, 0x61, 0xC3, 0x61, 0xC3, 0x61, 0x43, 0x62, 0x62, 0x22, 0x66, 0x32, 0x26, 0x36, 0x26, 0x14, 0x34, 0x14, 0x34, 0x1C, - 0x1C, 0x18, 0x1C, 0x08, 0x18, /* 'W' 0x57 */ - 0xC0, 0xD8, 0x66, 0x18, 0xCC, 0x1E, 0x07, 0x00, 0xC0, 0x78, 0x32, 0x0C, 0xC6, 0x1B, 0x07, 0xC0, 0xC0, /* 'X' 0x58 */ - 0xC0, 0x36, 0x06, 0x30, 0xC3, 0x0C, 0x19, 0x81, 0xD8, 0x0F, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, - 0x00, /* 'Y' 0x59 */ - 0xFF, 0xC0, 0x60, 0x30, 0x0C, 0x06, 0x03, 0x01, 0xC0, 0x60, 0x30, 0x18, 0x06, 0x03, 0x00, 0xFF, 0xC0, /* 'Z' 0x5A */ - 0xFB, 0x6D, 0xB6, 0xDB, 0x6D, 0xB6, 0xE0, /* '[' 0x5B */ - 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x80, /* '\' 0x5C */ - 0xED, 0xB6, 0xDB, 0x6D, 0xB6, 0xDB, 0xE0, /* ']' 0x5D */ - 0x30, 0x60, 0xA2, 0x44, 0xD8, 0xA1, 0x80, /* '^' 0x5E */ - 0xFF, 0xC0, /* '_' 0x5F */ - 0xC6, 0x30, /* '`' 0x60 */ - 0x7E, 0x71, 0xB0, 0xC0, 0x60, 0xF3, 0xDB, 0x0D, 0x86, 0xC7, 0x3D, 0xC0, /* 'a' 0x61 */ - 0xC0, 0x60, 0x30, 0x1B, 0xCE, 0x36, 0x0F, 0x07, 0x83, 0xC1, 0xE0, 0xF0, 0x7C, 0x6D, 0xE0, /* 'b' 0x62 */ - 0x3C, 0x66, 0xC3, 0xC0, 0xC0, 0xC0, 0xC0, 0xC3, 0x66, 0x3C, /* 'c' 0x63 */ - 0x03, 0x03, 0x03, 0x3B, 0x67, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x67, 0x3B, /* 'd' 0x64 */ - 0x3C, 0x66, 0xC3, 0xC3, 0xFF, 0xC0, 0xC0, 0xC3, 0x66, 0x3C, /* 'e' 0x65 */ - 0x36, 0x6F, 0x66, 0x66, 0x66, 0x66, 0x60, /* 'f' 0x66 */ - 0x3B, 0x67, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x67, 0x3B, 0x03, 0x03, 0xC6, 0x7C, /* 'g' 0x67 */ - 0xC0, 0xC0, 0xC0, 0xDE, 0xE3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, /* 'h' 0x68 */ - 0xC3, 0xFF, 0xFF, 0xC0, /* 'i' 0x69 */ - 0x30, 0x03, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0xE0, /* 'j' 0x6A */ - 0xC0, 0xC0, 0xC0, 0xC2, 0xC4, 0xCC, 0xD8, 0xF8, 0xEC, 0xC4, 0xC6, 0xC3, 0xC3, /* 'k' 0x6B */ - 0xFF, 0xFF, 0xFF, 0xC0, /* 'l' 0x6C */ - 0xDE, 0xF7, 0x1C, 0xF0, 0xC7, 0x86, 0x3C, 0x31, 0xE1, 0x8F, 0x0C, 0x78, 0x63, 0xC3, 0x1E, 0x18, 0xC0, /* 'm' 0x6D */ - 0xDE, 0xE3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, /* 'n' 0x6E */ - 0x3C, 0x66, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x66, 0x3C, /* 'o' 0x6F */ - 0xDE, 0x71, 0xB0, 0x78, 0x3C, 0x1E, 0x0F, 0x07, 0x83, 0xE3, 0x6F, 0x30, 0x18, 0x0C, 0x00, /* 'p' 0x70 */ - 0x3B, 0x67, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x67, 0x3B, 0x03, 0x03, 0x03, /* 'q' 0x71 */ - 0xDF, 0x31, 0x8C, 0x63, 0x18, 0xC6, 0x00, /* 'r' 0x72 */ - 0x3E, 0xE3, 0xC0, 0xC0, 0xE0, 0x3C, 0x07, 0xC3, 0xE3, 0x7E, /* 's' 0x73 */ - 0x66, 0xF6, 0x66, 0x66, 0x66, 0x67, /* 't' 0x74 */ - 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC7, 0x7B, /* 'u' 0x75 */ - 0xC1, 0xA0, 0x98, 0xCC, 0x42, 0x21, 0xB0, 0xD0, 0x28, 0x1C, 0x0C, 0x00, /* 'v' 0x76 */ - 0xC6, 0x1E, 0x38, 0x91, 0xC4, 0xCA, 0x66, 0xD3, 0x16, 0xD0, 0xA6, 0x87, 0x1C, 0x38, 0xC0, 0xC6, 0x00, /* 'w' 0x77 */ - 0x87, 0x89, 0xB1, 0xC3, 0x07, 0x1E, 0x26, 0xC5, 0x0C, /* 'x' 0x78 */ - 0xC1, 0x43, 0x63, 0x62, 0x26, 0x36, 0x34, 0x1C, 0x1C, 0x18, 0x18, 0x18, 0x10, 0x60, /* 'y' 0x79 */ - 0xFE, 0x0C, 0x30, 0xC1, 0x86, 0x18, 0x20, 0xC1, 0xFC, /* 'z' 0x7A */ - 0x36, 0x66, 0x66, 0x6E, 0xCE, 0x66, 0x66, 0x66, 0x30, /* '{' 0x7B */ - 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, /* '|' 0x7C */ - 0xC6, 0x66, 0x66, 0x67, 0x37, 0x66, 0x66, 0x66, 0xC0, /* '}' 0x7D */ - 0x61, 0x24, 0x38, /* '~' 0x7E */ - 0xFF, 0xFC, 0x00, 0x63, 0xE3, 0x31, 0x99, 0x04, 0xC8, 0x66, 0x06, 0x30, 0x61, 0x83, 0x0C, 0x18, 0x60, 0x03, 0x06, 0x18, 0x00, - 0xFF, 0xFC, /* 0x7F */ - 0x07, 0xC6, 0x13, 0x00, 0xC0, 0x60, 0x3F, 0xE6, 0x03, 0xFC, 0x60, 0x0C, 0x03, 0x00, 0x61, 0x07, 0xC0, /* 0x80 */ - /* 0x81 */ - 0xDC, /* 0x82 */ - /* 0x83 */ - 0xDA, 0x76, /* 0x84 */ - 0xCC, 0xC0, /* 0x85 */ - 0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, /* 0x86 */ - 0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18, /* 0x87 */ - /* 0x88 */ - 0x70, 0x80, 0x22, 0x20, 0x08, 0x90, 0x02, 0x24, 0x00, 0x72, 0x00, 0x00, 0x80, 0x00, 0x40, 0x00, 0x10, 0x00, 0x09, 0xC7, 0x84, - 0x8B, 0x31, 0x22, 0x84, 0x88, 0xB3, 0x21, 0xC7, 0x80, /* 0x89 */ - 0x1B, 0x03, 0x83, 0xF1, 0x86, 0xC0, 0xF0, 0x3C, 0x01, 0xE0, 0x1F, 0x00, 0xE0, 0x0F, 0x03, 0xC0, 0xD8, 0x63, 0xF0, /* 0x8A */ - 0x69, /* 0x8B */ - 0x06, 0x03, 0x03, 0xF1, 0x86, 0xC0, 0xF0, 0x3C, 0x01, 0xE0, 0x1F, 0x00, 0xE0, 0x0F, 0x03, 0xC0, 0xD8, 0x63, 0xF0, /* 0x8C */ - 0x33, 0x0F, 0x3F, 0xE1, 0x80, 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x80, 0xC0, 0x60, 0x30, /* 0x8D */ - 0x1B, 0x03, 0x8F, 0xFC, 0x06, 0x03, 0x00, 0xC0, 0x60, 0x30, 0x1C, 0x06, 0x03, 0x01, 0x80, 0x60, 0x30, 0x0F, 0xFC, /* 0x8E */ - 0x0C, 0x06, 0x0F, 0xFC, 0x06, 0x03, 0x00, 0xC0, 0x60, 0x30, 0x1C, 0x06, 0x03, 0x01, 0x80, 0x60, 0x30, 0x0F, 0xFC, /* 0x8F */ - /* 0x90 */ - 0x6B, /* 0x91 */ - 0xD6, /* 0x92 */ - 0x4C, 0xA5, 0xB0, /* 0x93 */ - 0xDA, 0x53, 0x20, /* 0x94 */ - 0x6F, 0xFF, 0x60, /* 0x95 */ - 0xFE, /* 0x96 */ - 0xFF, 0xFF, /* 0x97 */ - /* 0x98 */ - 0xFC, 0xE1, 0xCC, 0x38, 0x73, 0x0E, 0x1C, 0xC3, 0x8F, 0x30, 0xD2, 0xCC, 0x34, 0xB3, 0x0D, 0x6C, 0xC3, 0x53, 0x30, 0xCC, 0xCC, - 0x33, 0x30, /* 0x99 */ - 0x24, 0x3C, 0x18, 0x7E, 0xE3, 0xC0, 0xC0, 0x60, 0x3C, 0x07, 0xC3, 0xE3, 0x7E, /* 0x9A */ - 0x96, /* 0x9B */ - 0x0C, 0x18, 0x10, 0x3E, 0xE3, 0xC0, 0xC0, 0xE0, 0x3C, 0x07, 0xC3, 0xE3, 0x7E, /* 0x9C */ - 0x0D, 0xA7, 0x3C, 0x61, 0x86, 0x18, 0x61, 0x86, 0x18, 0x70, /* 0x9D */ - 0x48, 0xF0, 0xC7, 0xF0, 0x61, 0x86, 0x0C, 0x30, 0xC1, 0x06, 0x0F, 0xE0, /* 0x9E */ - 0x0C, 0x10, 0x47, 0xF0, 0x61, 0x86, 0x0C, 0x30, 0xC1, 0x06, 0x0F, 0xE0, /* 0x9F */ - /* 0xA0 */ - 0x8A, 0x9C, /* 0xA1 */ - 0x85, 0xE0, /* 0xA2 */ - 0x60, 0x30, 0x18, 0x0C, 0x86, 0xC3, 0xC1, 0xC1, 0xC0, 0xE0, 0x30, 0x18, 0x0C, 0x07, 0xF8, /* 0xA3 */ - 0xFF, 0xDF, 0x1E, 0x3E, 0xFF, 0xC0, /* 0xA4 */ - 0x06, 0x00, 0xF0, 0x0F, 0x01, 0x30, 0x13, 0x81, 0x38, 0x21, 0x82, 0x1C, 0x3F, 0xC6, 0x04, 0x60, 0x66, 0x06, 0xC0, 0x30, 0x06, - 0x00, 0xC0, 0x0C, 0x00, 0x70, /* 0xA5 */ - 0xFF, 0xFC, 0x0F, 0xFF, 0xC0, /* 0xA6 */ - 0x0C, 0x09, 0x0C, 0xC6, 0x63, 0x81, 0xE3, 0x19, 0x87, 0xE1, 0xB8, 0xC6, 0x41, 0xC0, 0x73, 0x19, 0x8C, 0x66, 0x1E, - 0x00, /* 0xA7 */ - 0xCC, /* 0xA8 */ - 0x0F, 0xC0, 0x61, 0x87, 0x03, 0x9B, 0xC6, 0xD9, 0x8F, 0x60, 0x3D, 0x00, 0xF4, 0x03, 0xD8, 0x0D, 0xE6, 0x67, 0xF3, 0x86, 0x18, - 0x0F, 0xC0, /* 0xA9 */ - 0x3F, 0x18, 0x6C, 0x0F, 0x03, 0xC0, 0x1E, 0x01, 0xF0, 0x0E, 0x00, 0xF0, 0x3C, 0x0D, 0x86, 0x3F, 0x02, 0x00, 0xE0, 0x18, 0x1C, - 0x00, /* 0xAA */ - 0x22, 0xCF, 0x26, 0x46, 0x64, 0x40, /* 0xAB */ - 0xFF, 0x80, 0xC0, 0x60, 0x30, 0x18, /* 0xAC */ - /* 0xAD */ - 0x0F, 0xC0, 0x61, 0x87, 0x03, 0x9F, 0xE6, 0xD0, 0x8F, 0x42, 0x3D, 0xF0, 0xF4, 0x23, 0xD0, 0x8D, 0xC2, 0x67, 0x0B, 0x86, 0x18, - 0x0F, 0xC0, /* 0xAE */ - 0x0C, 0x00, 0x0F, 0xFC, 0x06, 0x03, 0x00, 0xC0, 0x60, 0x30, 0x1C, 0x06, 0x03, 0x01, 0x80, 0x60, 0x30, 0x0F, 0xFC, /* 0xAF */ - 0x74, 0x63, 0x17, 0x00, /* 0xB0 */ - 0x0C, 0x06, 0x03, 0x07, 0xE0, 0xC0, 0x60, 0x30, 0x18, 0x00, 0x00, 0x3F, 0xE0, /* 0xB1 */ - 0x6C, 0xC7, /* 0xB2 */ - 0x66, 0x66, 0x67, 0x6E, 0x66, 0x66, 0x60, /* 0xB3 */ - 0x36, 0xC0, /* 0xB4 */ - 0xC3, 0x61, 0xB0, 0xD8, 0x6C, 0x36, 0x1B, 0x0D, 0x86, 0xE7, 0x7D, 0xF0, 0x18, 0x0C, 0x00, /* 0xB5 */ - 0x3F, 0x7E, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0x72, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, /* 0xB6 */ - 0xE0, /* 0xB7 */ - 0x21, 0xC7, 0xE0, /* 0xB8 */ - 0x7E, 0x38, 0xCC, 0x30, 0x0C, 0x0F, 0x1E, 0xCC, 0x33, 0x0C, 0xC7, 0x1E, 0xE0, 0x10, 0x0C, 0x03, 0x00, 0x70, /* 0xB9 */ - 0x3E, 0xE3, 0xC0, 0xC0, 0xE0, 0x3C, 0x07, 0xC3, 0xC3, 0x7E, 0x10, 0x1C, 0x0C, 0x38, /* 0xBA */ - 0x89, 0x98, 0x99, 0x3C, 0xD1, 0x00, /* 0xBB */ - 0xC6, 0xC4, 0xC8, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, /* 0xBC */ - 0x6F, 0x69, 0x00, /* 0xBD */ - 0xDE, 0xB9, 0x8C, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x00, /* 0xBE */ - 0x30, 0x03, 0xF8, 0x30, 0xC3, 0x06, 0x18, 0x60, 0x83, 0x07, 0xF0, /* 0xBF */ - 0x06, 0x00, 0xC0, 0xFF, 0x8C, 0x0E, 0xC0, 0x6C, 0x06, 0xC0, 0x6C, 0x0C, 0xFF, 0x8C, 0x0E, 0xC0, 0x6C, 0x06, 0xC0, 0x6C, 0x06, - 0xC0, 0x70, /* 0xC0 */ - 0x06, 0x03, 0x00, 0x00, 0x30, 0x1E, 0x07, 0x81, 0x20, 0xCC, 0x33, 0x0F, 0xC6, 0x19, 0x86, 0x40, 0xB0, 0x30, /* 0xC1 */ - 0x0C, 0x04, 0x80, 0x00, 0x30, 0x1E, 0x07, 0x81, 0x20, 0xCC, 0x33, 0x0F, 0xC6, 0x19, 0x86, 0x40, 0xB0, 0x30, /* 0xC2 */ - 0x21, 0x07, 0x80, 0x00, 0x30, 0x1E, 0x07, 0x81, 0x20, 0xCC, 0x33, 0x0F, 0xC6, 0x19, 0x86, 0x40, 0xB0, 0x30, /* 0xC3 */ - 0x33, 0x00, 0x00, 0xC0, 0x78, 0x1E, 0x04, 0x83, 0x30, 0xCC, 0x33, 0x1F, 0xE6, 0x19, 0x02, 0xC0, 0xF0, 0x30, /* 0xC4 */ - 0x30, 0x60, 0x00, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, /* 0xC5 */ - 0x06, 0x01, 0x80, 0x00, 0x0F, 0xC3, 0x0C, 0xC0, 0xD0, 0x1E, 0x00, 0xC0, 0x18, 0x03, 0x01, 0xA0, 0x36, 0x0C, 0x61, 0x87, - 0xC0, /* 0xC6 */ - 0x1F, 0x06, 0x19, 0x83, 0xA0, 0x3C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xC0, 0x68, 0x0D, 0x83, 0x18, 0xE1, 0xF0, 0x08, 0x01, 0xC0, - 0x18, 0x0E, 0x00, /* 0xC7 */ - 0x19, 0x81, 0xE0, 0x00, 0x0F, 0xC3, 0x0C, 0xC0, 0xF0, 0x1E, 0x00, 0xC0, 0x18, 0x03, 0x01, 0xA0, 0x36, 0x0C, 0x61, 0x87, - 0xC0, /* 0xC8 */ - 0x0C, 0x0C, 0x00, 0x1F, 0xFC, 0x06, 0x03, 0x01, 0x80, 0xFF, 0x60, 0x30, 0x18, 0x0C, 0x07, 0xFC, /* 0xC9 */ - 0xFF, 0xD8, 0x03, 0x00, 0x60, 0x0C, 0x01, 0x80, 0x3F, 0xF6, 0x00, 0xC0, 0x18, 0x03, 0x00, 0x60, 0x0F, 0xFC, 0x01, 0x80, 0x60, - 0x0C, 0x00, 0xE0, /* 0xCA */ - 0x33, 0x00, 0x3F, 0xF8, 0x0C, 0x06, 0x03, 0x01, 0xFE, 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x07, 0xFC, /* 0xCB */ - 0x33, 0x0F, 0x00, 0x1F, 0xFC, 0x06, 0x03, 0x01, 0x80, 0xFF, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0xFE, /* 0xCC */ - 0x78, 0x36, 0xDB, 0x6D, 0xB6, 0xC0, /* 0xCD */ - 0x76, 0xC0, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x18, /* 0xCE */ - 0x66, 0x0F, 0x00, 0x03, 0xF8, 0xC3, 0x30, 0x6C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC1, 0xB0, 0xEF, 0xE0, /* 0xCF */ - 0x7F, 0x0C, 0x31, 0x83, 0x30, 0x36, 0x06, 0xC0, 0xFE, 0x1B, 0x03, 0x60, 0x6C, 0x0D, 0x83, 0x30, 0xE7, 0xF0, /* 0xD0 */ - 0x03, 0x01, 0x83, 0x81, 0xF0, 0x3F, 0x07, 0xA0, 0xF6, 0x1E, 0x63, 0xC4, 0x78, 0xCF, 0x0D, 0xE1, 0xBC, 0x1F, 0x81, - 0xC0, /* 0xD1 */ - 0x19, 0x81, 0xE3, 0x81, 0xF0, 0x3F, 0x07, 0xA0, 0xF6, 0x1E, 0x63, 0xC4, 0x78, 0xCF, 0x0D, 0xE1, 0xBC, 0x1F, 0x81, - 0xC0, /* 0xD2 */ - 0x03, 0x00, 0x60, 0x00, 0x00, 0xF0, 0x39, 0xC6, 0x06, 0x60, 0x6C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x36, 0x06, 0x60, 0x63, 0x9C, - 0x0F, 0x00, /* 0xD3 */ - 0x0F, 0x01, 0x98, 0x00, 0x00, 0xF0, 0x39, 0xC6, 0x06, 0x60, 0x6C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x36, 0x06, 0x60, 0x63, 0x9C, - 0x0F, 0x00, /* 0xD4 */ - 0x0D, 0x81, 0xB0, 0x00, 0x00, 0xF0, 0x39, 0xC6, 0x06, 0x60, 0x6C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x36, 0x06, 0x60, 0x63, 0x9C, - 0x0F, 0x00, /* 0xD5 */ - 0x19, 0x81, 0x98, 0x00, 0x00, 0xF0, 0x39, 0xC6, 0x06, 0x60, 0x6C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x36, 0x06, 0x60, 0x63, 0x9C, - 0x0F, 0x00, /* 0xD6 */ - 0x83, 0x89, 0xA1, 0x83, 0x89, 0xA1, 0x80, /* 0xD7 */ - 0x33, 0x01, 0xE0, 0xFF, 0x8C, 0x0E, 0xC0, 0x6C, 0x06, 0xC0, 0x6C, 0x0C, 0xFF, 0x8C, 0x0E, 0xC0, 0x6C, 0x06, 0xC0, 0x6C, 0x06, - 0xC0, 0x70, /* 0xD8 */ - 0x04, 0x01, 0x43, 0x11, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x36, 0x0C, 0x3E, - 0x00, /* 0xD9 */ - 0x06, 0x01, 0x83, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x36, 0x0C, 0x3E, - 0x00, /* 0xDA */ - 0x0D, 0x83, 0x63, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x36, 0x0C, 0x3E, - 0x00, /* 0xDB */ - 0x1B, 0x00, 0x03, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x36, 0x0C, 0x3E, - 0x00, /* 0xDC */ - 0x03, 0x0C, 0x63, 0x60, 0x63, 0x0C, 0x30, 0xC1, 0x98, 0x1D, 0x80, 0xF0, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, - 0x60, /* 0xDD */ - 0xFF, 0x86, 0x03, 0x01, 0x80, 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x80, 0xC0, 0x40, 0x3C, 0x06, 0x1E, - 0x00, /* 0xDE */ - 0x3C, 0x33, 0x30, 0xD8, 0x6C, 0x36, 0x33, 0x39, 0x86, 0xC1, 0xE0, 0xF0, 0x78, 0x6D, 0xE0, /* 0xDF */ - 0x19, 0x89, 0xBE, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x00, /* 0xE0 */ - 0x0C, 0x04, 0x04, 0x0F, 0xCE, 0x36, 0x18, 0x0C, 0x1E, 0x7B, 0x61, 0xB0, 0xD8, 0xE7, 0xB8, /* 0xE1 */ - 0x10, 0x14, 0x1B, 0x0F, 0xCE, 0x36, 0x18, 0x0C, 0x1E, 0x7B, 0x61, 0xB0, 0xD8, 0xE7, 0xB8, /* 0xE2 */ - 0x66, 0x1E, 0x00, 0x0F, 0xCE, 0x36, 0x18, 0x0C, 0x1E, 0x7B, 0x61, 0xB0, 0xD8, 0xE7, 0xB8, /* 0xE3 */ - 0x66, 0x00, 0x1F, 0x9C, 0x6C, 0x30, 0x18, 0x3C, 0xF6, 0xC3, 0x61, 0xB1, 0xCF, 0x70, /* 0xE4 */ - 0x78, 0x36, 0xDB, 0x6D, 0xB6, 0xD8, /* 0xE5 */ - 0x0C, 0x08, 0x10, 0x3C, 0x66, 0xC3, 0xC0, 0xC0, 0xC0, 0xC0, 0xC3, 0x66, 0x3C, /* 0xE6 */ - 0x3C, 0x66, 0xC3, 0xC0, 0xC0, 0xC0, 0xC0, 0xC3, 0x66, 0x3C, 0x10, 0x1C, 0x0C, 0x38, /* 0xE7 */ - 0x44, 0x28, 0x38, 0x3C, 0x66, 0xC3, 0xC0, 0xC0, 0xC0, 0xC0, 0xC3, 0x66, 0x3C, /* 0xE8 */ - 0x0C, 0x08, 0x18, 0x3C, 0x66, 0xC3, 0xC3, 0xFF, 0xC0, 0xC0, 0xC3, 0x66, 0x3C, /* 0xE9 */ - 0x3C, 0x62, 0xC3, 0xC3, 0xFF, 0xC0, 0xC0, 0xC3, 0x66, 0x3E, 0x04, 0x0C, 0x0C, 0x06, /* 0xEA */ - 0x66, 0x00, 0x3C, 0x66, 0xC3, 0xC3, 0xFF, 0xC0, 0xC0, 0xC3, 0x66, 0x3C, /* 0xEB */ - 0x64, 0x2C, 0x18, 0x3C, 0x66, 0xC3, 0xC3, 0xFF, 0xC0, 0xC0, 0xC3, 0x66, 0x3C, /* 0xEC */ - 0x7A, 0x6D, 0xB6, 0xDB, 0x6C, /* 0xED */ - 0x69, 0x06, 0x66, 0x66, 0x66, 0x66, 0x60, /* 0xEE */ - 0x03, 0x30, 0x32, 0x03, 0x43, 0xB0, 0x67, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x06, 0x70, 0x3B, - 0x00, /* 0xEF */ - 0x03, 0x07, 0xC0, 0xC7, 0x66, 0x76, 0x1B, 0x0D, 0x86, 0xC3, 0x61, 0xB0, 0xCC, 0xE3, 0xB0, /* 0xF0 */ - 0x0C, 0x18, 0x00, 0xDE, 0xE3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, /* 0xF1 */ - 0x66, 0x3C, 0x00, 0xDE, 0xE3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, /* 0xF2 */ - 0x0C, 0x18, 0x00, 0x3C, 0x66, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x66, 0x3C, /* 0xF3 */ - 0x18, 0x24, 0x00, 0x3C, 0x66, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x66, 0x3C, /* 0xF4 */ - 0x36, 0x6C, 0x00, 0x3C, 0x66, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x66, 0x3C, /* 0xF5 */ - 0x66, 0x00, 0x3C, 0x66, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x66, 0x3C, /* 0xF6 */ - 0x18, 0x00, 0x00, 0x1F, 0xF0, 0x00, 0x00, 0x00, 0x30, /* 0xF7 */ - 0xDB, 0x81, 0xBE, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x00, /* 0xF8 */ - 0x10, 0x28, 0x10, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC7, 0x7B, /* 0xF9 */ - 0x06, 0x0C, 0x18, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC7, 0x7B, /* 0xFA */ - 0x36, 0x6C, 0x00, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC7, 0x7B, /* 0xFB */ - 0x66, 0x00, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC7, 0x7B, /* 0xFC */ - 0x06, 0x04, 0x08, 0xC1, 0x43, 0x63, 0x62, 0x26, 0x36, 0x34, 0x1C, 0x1C, 0x18, 0x18, 0x18, 0x10, 0x60, /* 0xFD */ - 0x63, 0x3C, 0xC6, 0x31, 0x8C, 0x63, 0x18, 0xE2, 0x1C, 0x6F, /* 0xFE */ - 0xC0, /* 0xFF */ +/* 0x01 */ 0x07, 0x00, 0x0A, 0x00, 0x24, 0x00, 0x48, 0x01, 0x10, 0x04, 0x40, 0x10, 0xFF, 0x20, 0x02, 0x81, 0xFD, 0x00, 0x06, 0x07, 0xF4, 0x08, 0x24, 0x0F, 0x88, 0x11, 0x0F, 0xDC, 0x00, +/* 0x02 */ 0x3F, 0x70, 0x81, 0x11, 0x03, 0xE4, 0x08, 0x28, 0x1F, 0xD0, 0x00, 0x60, 0x7F, 0x20, 0x02, 0x43, 0xFC, 0x44, 0x00, 0x44, 0x00, 0x48, 0x00, 0x90, 0x00, 0xA0, 0x01, 0xC0, 0x00, +/* 0x03 */ 0x07, 0xC0, 0x30, 0x60, 0x80, 0x22, 0x00, 0x28, 0x00, 0x31, 0x8C, 0x63, 0x18, 0xC0, 0x01, 0x80, 0x03, 0x00, 0x06, 0x20, 0x8C, 0x3E, 0x14, 0x00, 0x44, 0x01, 0x06, 0x0C, 0x03, 0xE0, +/* 0x04 */ 0x07, 0xC0, 0x30, 0x60, 0x80, 0x22, 0x00, 0x28, 0x82, 0x30, 0x88, 0x62, 0x08, 0xC0, 0x01, 0x80, 0x03, 0x00, 0x06, 0x3F, 0x8C, 0x3E, 0x14, 0x00, 0x44, 0x01, 0x06, 0x0C, 0x03, 0xE0, +/* 0x05 */ 0x0B, 0x10, 0x14, 0xA8, 0x12, 0x50, 0x29, 0x42, 0x24, 0xA5, 0x32, 0x95, 0x5A, 0x09, 0x48, 0x09, 0x24, 0x01, 0x10, 0x01, 0x48, 0x02, 0xA4, 0x02, 0x42, 0x04, 0x01, 0x98, 0x00, 0x60, +/* 0x06 */ 0x00, 0x80, 0x22, 0x80, 0x65, 0x00, 0xBE, 0xE1, 0x82, 0x4E, 0x03, 0x24, 0x04, 0x28, 0x06, 0x30, 0x12, 0x20, 0x3C, 0xA0, 0xC3, 0xFE, 0x80, 0x4D, 0x00, 0xA6, 0x01, 0x80, 0x00, +/* 0x07 */ +/* 0x08 */ 0x00, 0xF8, 0x00, 0x82, 0x00, 0x80, 0x83, 0xE0, 0x41, 0x10, 0x21, 0x04, 0x1B, 0x00, 0x03, 0x00, 0x01, 0x80, 0x00, 0xE0, 0x00, 0x4F, 0xE1, 0xC0, 0x0F, 0x02, 0x00, 0x03, 0x01, 0x00, 0x09, 0x88, 0x0C, 0x0C, +/* 0x09 */ 0x00, 0xF8, 0x00, 0x82, 0x00, 0x80, 0x83, 0xE0, 0x41, 0x10, 0x21, 0x04, 0x1B, 0x00, 0x03, 0x00, 0x01, 0x80, 0x00, 0xE0, 0x00, 0x4F, 0xE1, 0xC0, 0x0F, 0x00, +/* 0x0A */ +/* 0x0B */ 0x1C, 0x1C, 0x31, 0xB1, 0x90, 0x50, 0x50, 0x10, 0x18, 0x00, 0x0C, 0x00, 0x06, 0x00, 0x02, 0x80, 0x02, 0x40, 0x01, 0x10, 0x01, 0x04, 0x01, 0x01, 0x01, 0x00, 0x41, 0x00, 0x11, 0x00, 0x07, 0x00, 0x01, 0x00, +/* 0x0C */ 0x06, 0x00, 0x0A, 0x00, 0x12, 0x00, 0x32, 0x01, 0x84, 0x04, 0x10, 0x08, 0x98, 0x1C, 0x18, 0x40, 0x48, 0x82, 0x11, 0xF0, 0x74, 0x02, 0x18, 0x70, 0x2F, 0x9F, 0x80, +/* 0x0D */ +/* 0x0E */ 0x01, 0x00, 0x05, 0x00, 0x0A, 0x00, 0x3E, 0x00, 0x82, 0x02, 0x82, 0x06, 0x04, 0x10, 0x04, 0x20, 0x08, 0x40, 0x10, 0xFF, 0x22, 0x00, 0x29, 0xFF, 0x3F, 0x8F, 0xDF, 0x9F, 0x01, 0xC0, +/* 0x0F */ 0x07, 0xC0, 0x30, 0x60, 0x80, 0x22, 0x00, 0x28, 0x82, 0x36, 0x03, 0x60, 0x00, 0xCC, 0x19, 0xA4, 0x4B, 0x00, 0x06, 0x8E, 0x2B, 0x22, 0x66, 0x7C, 0xCC, 0x71, 0x98, 0x03, 0x00, +/* 0x10 */ 0x03, 0x80, 0x07, 0x00, 0x0E, 0x00, 0x1E, 0x00, 0x54, 0x00, 0xA8, 0x01, 0x50, 0x02, 0xA0, 0x05, 0x20, 0x32, 0x61, 0xC4, 0x74, 0x49, 0x10, 0x6C, 0x00, 0xD8, 0x01, 0x10, 0x00, +/* 0x11 */ 0x07, 0xC0, 0x30, 0x60, 0x80, 0x22, 0x40, 0x29, 0x00, 0x31, 0x84, 0x63, 0x18, 0xC0, 0x00, 0x80, 0x15, 0x03, 0x7E, 0x02, 0xFA, 0x04, 0xE4, 0x18, 0x84, 0x00, 0x06, 0x0C, 0x03, 0xE0, +/* 0x12 */ 0x02, 0x08, 0x01, 0x08, 0x40, 0x10, 0xC0, 0x08, 0xC0, 0x60, 0x80, 0x28, 0x04, 0x12, 0x4C, 0x10, 0x80, 0x08, 0x23, 0x0E, 0x08, 0xC4, 0x82, 0x04, 0x20, 0x83, 0x09, 0x82, 0x47, 0x01, 0x1C, 0x01, 0x30, 0x00, 0xE0, 0x00, 0x00, +/* 0x13 */ 0x07, 0xC0, 0x30, 0x60, 0x80, 0x22, 0x00, 0x28, 0x00, 0x31, 0x08, 0x65, 0x28, 0xC0, 0x01, 0x80, 0x03, 0x00, 0x06, 0x3F, 0x8C, 0x3E, 0x14, 0x00, 0x44, 0x01, 0x06, 0x0C, 0x03, 0xE0, +/* 0x14 */ 0x07, 0xC0, 0x30, 0x60, 0x80, 0x22, 0x22, 0x29, 0x83, 0x30, 0x00, 0x65, 0x14, 0xD3, 0x4D, 0xBA, 0xEB, 0x38, 0xE6, 0x00, 0x0A, 0x00, 0x24, 0x38, 0x44, 0x01, 0x07, 0x1C, 0x01, 0xC0, +/* 0x15 */ 0x07, 0xC0, 0x30, 0x18, 0x80, 0x32, 0x00, 0xF8, 0x01, 0xF1, 0x09, 0xA5, 0x28, 0x40, 0x01, 0x80, 0x03, 0x00, 0x06, 0x3F, 0x8C, 0x3E, 0x14, 0x00, 0x44, 0x01, 0x06, 0x0C, 0x03, 0xE0, +/* 0x16 */ 0x0C, 0x00, 0xC0, 0x1C, 0x03, 0x80, 0xF8, 0xBB, 0x36, 0xC7, 0x99, 0xF3, 0xFE, 0x3F, 0xC3, 0xF0, 0x7E, 0x0E, 0xC1, 0x8E, 0xE0, 0x20, +/* 0x17 */ 0x07, 0xC0, 0x30, 0x60, 0x80, 0x22, 0x00, 0x28, 0x00, 0x10, 0x01, 0x20, 0x1D, 0x44, 0x42, 0x84, 0x85, 0x00, 0x86, 0x00, 0xC4, 0x00, 0x44, 0x7C, 0x44, 0x00, 0x06, 0x0C, 0x03, 0xE0, +/* 0x18 */ 0x01, 0xE0, 0x00, 0x84, 0x00, 0x40, 0x80, 0x20, 0x10, 0x08, 0x24, 0x02, 0x41, 0x00, 0x86, 0x03, 0x12, 0x03, 0xB4, 0x03, 0x52, 0x81, 0x23, 0x80, 0x70, 0xA0, 0x14, 0x28, 0x05, 0x0A, 0x01, 0x42, 0x80, 0x50, +/* 0x19 */ 0x07, 0xC0, 0x30, 0x60, 0x80, 0x22, 0x00, 0x28, 0x00, 0x33, 0x18, 0x60, 0x00, 0xDC, 0xE1, 0xB9, 0xC3, 0x7B, 0xC6, 0x63, 0x0A, 0x00, 0x24, 0xF0, 0x44, 0x01, 0x06, 0x0C, 0x03, 0xE0, +/* 0x1A */ 0xFF, 0xFC, 0x00, 0x63, 0xE3, 0x31, 0x99, 0x04, 0xC8, 0x66, 0x06, 0x30, 0x61, 0x82, 0x0C, 0x10, 0x60, 0x03, 0x04, 0x18, 0x00, 0xFF, 0xFC, +/* 0x1B */ 0x07, 0xF0, 0x06, 0x0C, 0x04, 0x01, 0x04, 0x00, 0x44, 0x22, 0x12, 0x2A, 0x89, 0x00, 0x04, 0x80, 0x02, 0x44, 0x11, 0x01, 0xF0, 0x04, 0x01, 0x0D, 0x01, 0x6A, 0x41, 0x2C, 0x00, 0x05, 0xC0, 0x0E, 0x18, 0x18, +/* 0x1C */ 0x07, 0xC0, 0x30, 0x60, 0x80, 0x22, 0xC0, 0x2A, 0x00, 0x33, 0x00, 0x66, 0x00, 0xCC, 0x39, 0x80, 0x83, 0x00, 0x06, 0x00, 0x8C, 0x3E, 0x14, 0x00, 0x44, 0x01, 0x06, 0x0C, 0x03, 0xE0, +/* 0x1D */ 0x07, 0xC0, 0x30, 0x60, 0x80, 0x22, 0x70, 0x28, 0x00, 0x31, 0x80, 0x63, 0x18, 0xC0, 0x31, 0x80, 0x03, 0x00, 0x06, 0x60, 0x0D, 0x33, 0x12, 0x10, 0x48, 0x21, 0x23, 0x8C, 0x00, +/* 0x1E */ 0x03, 0x00, 0x07, 0x9E, 0x07, 0x00, 0x86, 0x00, 0x27, 0xC0, 0x0F, 0xC0, 0x07, 0x8C, 0x62, 0x06, 0x31, 0x20, 0x00, 0x90, 0x00, 0x48, 0x00, 0x24, 0x3E, 0x11, 0x00, 0x10, 0x40, 0x10, 0x18, 0x30, 0x03, 0xE0, +/* 0x1F */ 0x18, 0x02, 0x80, 0x4C, 0x16, 0x41, 0x24, 0x3C, 0x88, 0x6E, 0x65, 0xF2, 0x78, 0x46, 0x88, 0xCF, 0x18, 0x02, 0x80, 0x8C, 0x60, 0x70, +/* ' ' 0x20 */ +/* '!' 0x21 */ 0xFF, 0xFF, 0xF0, 0xC0, +/* '"' 0x22 */ 0xDE, 0xF7, 0x20, +/* '#' 0x23 */ 0x09, 0x86, 0x41, 0x91, 0xFF, 0x13, 0x04, 0xC3, 0x20, 0xC8, 0xFF, 0x89, 0x82, 0x61, 0x90, +/* '$' 0x24 */ 0x10, 0x1F, 0x14, 0xDA, 0x3D, 0x1E, 0x83, 0x40, 0x78, 0x17, 0x08, 0xF4, 0x7A, 0x35, 0x33, 0xF0, 0x40, 0x20, +/* '%' 0x25 */ 0x38, 0x10, 0xEC, 0x20, 0xC6, 0x20, 0xC6, 0x40, 0xC6, 0x40, 0x6C, 0x80, 0x39, 0x00, 0x01, 0x3C, 0x02, 0x77, 0x02, 0x63, 0x04, 0x63, 0x04, 0x77, 0x08, 0x3C, +/* '&' 0x26 */ 0x0E, 0x0C, 0xC3, 0x30, 0xCC, 0x1E, 0x03, 0x03, 0xC1, 0x9B, 0xC2, 0xF0, 0xEC, 0x19, 0x8F, 0x3C, 0x40, +/* ''' 0x27 */ 0xFE, +/* '(' 0x28 */ 0x13, 0x26, 0x6C, 0xCC, 0xCC, 0xC4, 0x66, 0x23, 0x10, +/* ')' 0x29 */ 0x8C, 0x46, 0x63, 0x33, 0x33, 0x32, 0x66, 0x4C, 0x80, +/* '*' 0x2A */ 0x25, 0x7E, 0xA5, 0x00, +/* '+' 0x2B */ 0x30, 0xC3, 0x3F, 0x30, 0xC3, 0x0C, +/* ',' 0x2C */ 0xD6, +/* '-' 0x2D */ 0xF0, +/* '.' 0x2E */ 0xC0, +/* '/' 0x2F */ 0x08, 0x44, 0x21, 0x10, 0x84, 0x42, 0x11, 0x08, 0x00, +/* '0' 0x30 */ 0x3C, 0x66, 0x42, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x42, 0x66, 0x3C, +/* '1' 0x31 */ 0x11, 0x3F, 0x33, 0x33, 0x33, 0x33, 0x30, +/* '2' 0x32 */ 0x3E, 0x31, 0xB0, 0x78, 0x30, 0x18, 0x1C, 0x1C, 0x1C, 0x18, 0x18, 0x10, 0x08, 0x07, 0xF8, +/* '3' 0x33 */ 0x3C, 0x66, 0xC3, 0xC3, 0x03, 0x06, 0x1C, 0x07, 0x03, 0xC3, 0xC3, 0x66, 0x3C, +/* '4' 0x34 */ 0x0C, 0x18, 0x71, 0x62, 0xC9, 0xA3, 0x46, 0xFE, 0x18, 0x30, 0x60, 0xC0, +/* '5' 0x35 */ 0x7F, 0x20, 0x10, 0x08, 0x08, 0x07, 0xF3, 0x8C, 0x03, 0x01, 0x80, 0xF0, 0x6C, 0x63, 0xE0, +/* '6' 0x36 */ 0x1E, 0x31, 0x98, 0x78, 0x0C, 0x06, 0xF3, 0x8D, 0x83, 0xC1, 0xE0, 0xD0, 0x6C, 0x63, 0xE0, +/* '7' 0x37 */ 0xFF, 0x03, 0x02, 0x06, 0x04, 0x0C, 0x08, 0x18, 0x18, 0x18, 0x10, 0x30, 0x30, +/* '8' 0x38 */ 0x3E, 0x31, 0xB0, 0x78, 0x3C, 0x1B, 0x18, 0xF8, 0xC6, 0xC1, 0xE0, 0xF0, 0x6C, 0x63, 0xE0, +/* '9' 0x39 */ 0x3C, 0x66, 0xC2, 0xC3, 0xC3, 0xC3, 0x67, 0x3B, 0x03, 0x03, 0xC2, 0x66, 0x3C, +/* ':' 0x3A */ 0xC0, 0x00, 0x30, +/* ';' 0x3B */ 0xC0, 0x00, 0x00, 0x64, 0xA0, +/* '<' 0x3C */ 0x00, 0x81, 0xC7, 0x8E, 0x0C, 0x07, 0x80, 0x70, 0x0E, 0x01, 0x80, +/* '=' 0x3D */ 0xFF, 0x80, 0x00, 0x1F, 0xF0, +/* '>' 0x3E */ 0xE0, 0x1C, 0x03, 0x80, 0x30, 0x70, 0xE3, 0x81, 0x00, +/* '?' 0x3F */ 0x3E, 0x31, 0xB0, 0x78, 0x30, 0x18, 0x18, 0x38, 0x18, 0x18, 0x0C, 0x00, 0x00, 0x01, 0x80, +/* '@' 0x40 */ 0x03, 0xF0, 0x06, 0x0E, 0x06, 0x01, 0x86, 0x00, 0x66, 0x1D, 0xBB, 0x31, 0xCF, 0x18, 0xC7, 0x98, 0x63, 0xCC, 0x31, 0xE6, 0x11, 0xB3, 0x99, 0xCC, 0xF7, 0x86, 0x00, 0x01, 0x80, 0x00, 0x70, 0x40, 0x0F, 0xE0, +/* 'A' 0x41 */ 0x06, 0x00, 0xF0, 0x0F, 0x00, 0x90, 0x19, 0x81, 0x98, 0x10, 0x83, 0x0C, 0x3F, 0xC2, 0x04, 0x60, 0x66, 0x06, 0xC0, 0x30, +/* 'B' 0x42 */ 0xFF, 0x18, 0x33, 0x03, 0x60, 0x6C, 0x0D, 0x83, 0x3F, 0xC6, 0x06, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x6F, 0xF8, +/* 'C' 0x43 */ 0x1F, 0x86, 0x19, 0x81, 0xA0, 0x3C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xC0, 0x68, 0x0D, 0x83, 0x18, 0x61, 0xF0, +/* 'D' 0x44 */ 0xFF, 0x18, 0x33, 0x03, 0x60, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x03, 0x60, 0xCF, 0xF0, +/* 'E' 0x45 */ 0xFF, 0xE0, 0x30, 0x18, 0x0C, 0x06, 0x03, 0xFD, 0x80, 0xC0, 0x60, 0x30, 0x18, 0x0F, 0xF8, +/* 'F' 0x46 */ 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFE, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, +/* 'G' 0x47 */ 0x0F, 0x83, 0x0E, 0x60, 0x66, 0x03, 0xC0, 0x0C, 0x00, 0xC1, 0xFC, 0x03, 0xC0, 0x36, 0x03, 0x60, 0x73, 0x0F, 0x0F, 0x10, +/* 'H' 0x48 */ 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xFF, 0xFE, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x06, +/* 'I' 0x49 */ 0xFF, 0xFF, 0xFF, 0xC0, +/* 'J' 0x4A */ 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x83, 0x07, 0x8F, 0x1E, 0x27, 0x80, +/* 'K' 0x4B */ 0xC0, 0xF0, 0x6C, 0x33, 0x18, 0xCC, 0x37, 0x0F, 0xC3, 0x98, 0xC3, 0x30, 0xCC, 0x1B, 0x03, 0xC0, 0xC0, +/* 'L' 0x4C */ 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, +/* 'M' 0x4D */ 0xE0, 0x3F, 0x01, 0xFC, 0x1F, 0xE0, 0xFD, 0x05, 0xEC, 0x6F, 0x63, 0x79, 0x13, 0xCD, 0x9E, 0x6C, 0xF1, 0x47, 0x8E, 0x3C, 0x71, 0x80, +/* 'N' 0x4E */ 0xE0, 0x7C, 0x0F, 0xC1, 0xE8, 0x3D, 0x87, 0x98, 0xF1, 0x1E, 0x33, 0xC3, 0x78, 0x6F, 0x07, 0xE0, 0x7C, 0x0E, +/* 'O' 0x4F */ 0x0F, 0x81, 0x83, 0x18, 0x0C, 0xC0, 0x6C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1B, 0x01, 0x98, 0x0C, 0x60, 0xC0, 0xF8, 0x00, +/* 'P' 0x50 */ 0xFF, 0x30, 0x6C, 0x0F, 0x03, 0xC0, 0xF0, 0x6F, 0xF3, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x00, +/* 'Q' 0x51 */ 0x0F, 0x81, 0x83, 0x18, 0x0C, 0xC0, 0x6C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1B, 0x01, 0x98, 0x6C, 0x60, 0xC0, 0xFB, 0x00, 0x08, +/* 'R' 0x52 */ 0xFF, 0x8C, 0x0E, 0xC0, 0x6C, 0x06, 0xC0, 0x6C, 0x0C, 0xFF, 0x8C, 0x0E, 0xC0, 0x6C, 0x06, 0xC0, 0x6C, 0x06, 0xC0, 0x70, +/* 'S' 0x53 */ 0x3F, 0x18, 0x6C, 0x0F, 0x03, 0xC0, 0x1E, 0x01, 0xF0, 0x0E, 0x00, 0xF0, 0x3C, 0x0D, 0x86, 0x3F, 0x00, +/* 'T' 0x54 */ 0xFF, 0x86, 0x03, 0x01, 0x80, 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x80, 0xC0, +/* 'U' 0x55 */ 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xB0, 0x61, 0xF0, +/* 'V' 0x56 */ 0xC0, 0x6C, 0x0D, 0x81, 0x10, 0x63, 0x0C, 0x61, 0x04, 0x60, 0xCC, 0x19, 0x01, 0x60, 0x3C, 0x07, 0x00, 0x60, +/* 'W' 0x57 */ 0xC1, 0x81, 0x61, 0xC3, 0x61, 0xC3, 0x61, 0x43, 0x62, 0x62, 0x22, 0x66, 0x32, 0x26, 0x36, 0x26, 0x14, 0x34, 0x14, 0x34, 0x1C, 0x1C, 0x18, 0x1C, 0x08, 0x18, +/* 'X' 0x58 */ 0xC0, 0xD8, 0x66, 0x18, 0xCC, 0x1E, 0x07, 0x00, 0xC0, 0x78, 0x32, 0x0C, 0xC6, 0x1B, 0x07, 0xC0, 0xC0, +/* 'Y' 0x59 */ 0xC0, 0x36, 0x06, 0x30, 0xC3, 0x0C, 0x19, 0x81, 0xD8, 0x0F, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, +/* 'Z' 0x5A */ 0xFF, 0xC0, 0x60, 0x30, 0x0C, 0x06, 0x03, 0x01, 0xC0, 0x60, 0x30, 0x18, 0x06, 0x03, 0x00, 0xFF, 0xC0, +/* '[' 0x5B */ 0xFB, 0x6D, 0xB6, 0xDB, 0x6D, 0xB6, 0xE0, +/* '\' 0x5C */ 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x80, +/* ']' 0x5D */ 0xED, 0xB6, 0xDB, 0x6D, 0xB6, 0xDB, 0xE0, +/* '^' 0x5E */ 0x30, 0x60, 0xA2, 0x44, 0xD8, 0xA1, 0x80, +/* '_' 0x5F */ 0xFF, 0xC0, +/* '`' 0x60 */ 0xC6, 0x30, +/* 'a' 0x61 */ 0x7E, 0x71, 0xB0, 0xC0, 0x60, 0xF3, 0xDB, 0x0D, 0x86, 0xC7, 0x3D, 0xC0, +/* 'b' 0x62 */ 0xC0, 0x60, 0x30, 0x1B, 0xCE, 0x36, 0x0F, 0x07, 0x83, 0xC1, 0xE0, 0xF0, 0x7C, 0x6D, 0xE0, +/* 'c' 0x63 */ 0x3C, 0x66, 0xC3, 0xC0, 0xC0, 0xC0, 0xC0, 0xC3, 0x66, 0x3C, +/* 'd' 0x64 */ 0x03, 0x03, 0x03, 0x3B, 0x67, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x67, 0x3B, +/* 'e' 0x65 */ 0x3C, 0x66, 0xC3, 0xC3, 0xFF, 0xC0, 0xC0, 0xC3, 0x66, 0x3C, +/* 'f' 0x66 */ 0x36, 0x6F, 0x66, 0x66, 0x66, 0x66, 0x60, +/* 'g' 0x67 */ 0x3B, 0x67, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x67, 0x3B, 0x03, 0x03, 0xC6, 0x7C, +/* 'h' 0x68 */ 0xC0, 0xC0, 0xC0, 0xDE, 0xE3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, +/* 'i' 0x69 */ 0xC3, 0xFF, 0xFF, 0xC0, +/* 'j' 0x6A */ 0x30, 0x03, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0xE0, +/* 'k' 0x6B */ 0xC0, 0xC0, 0xC0, 0xC2, 0xC4, 0xCC, 0xD8, 0xF8, 0xEC, 0xC4, 0xC6, 0xC3, 0xC3, +/* 'l' 0x6C */ 0xFF, 0xFF, 0xFF, 0xC0, +/* 'm' 0x6D */ 0xDE, 0xF7, 0x1C, 0xF0, 0xC7, 0x86, 0x3C, 0x31, 0xE1, 0x8F, 0x0C, 0x78, 0x63, 0xC3, 0x1E, 0x18, 0xC0, +/* 'n' 0x6E */ 0xDE, 0xE3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, +/* 'o' 0x6F */ 0x3C, 0x66, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x66, 0x3C, +/* 'p' 0x70 */ 0xDE, 0x71, 0xB0, 0x78, 0x3C, 0x1E, 0x0F, 0x07, 0x83, 0xE3, 0x6F, 0x30, 0x18, 0x0C, 0x00, +/* 'q' 0x71 */ 0x3B, 0x67, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x67, 0x3B, 0x03, 0x03, 0x03, +/* 'r' 0x72 */ 0xDF, 0x31, 0x8C, 0x63, 0x18, 0xC6, 0x00, +/* 's' 0x73 */ 0x3E, 0xE3, 0xC0, 0xC0, 0xE0, 0x3C, 0x07, 0xC3, 0xE3, 0x7E, +/* 't' 0x74 */ 0x66, 0xF6, 0x66, 0x66, 0x66, 0x67, +/* 'u' 0x75 */ 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC7, 0x7B, +/* 'v' 0x76 */ 0xC1, 0xA0, 0x98, 0xCC, 0x42, 0x21, 0xB0, 0xD0, 0x28, 0x1C, 0x0C, 0x00, +/* 'w' 0x77 */ 0xC6, 0x1E, 0x38, 0x91, 0xC4, 0xCA, 0x66, 0xD3, 0x16, 0xD0, 0xA6, 0x87, 0x1C, 0x38, 0xC0, 0xC6, 0x00, +/* 'x' 0x78 */ 0x87, 0x89, 0xB1, 0xC3, 0x07, 0x1E, 0x26, 0xC5, 0x0C, +/* 'y' 0x79 */ 0xC1, 0x43, 0x63, 0x62, 0x26, 0x36, 0x34, 0x1C, 0x1C, 0x18, 0x18, 0x18, 0x10, 0x60, +/* 'z' 0x7A */ 0xFE, 0x0C, 0x30, 0xC1, 0x86, 0x18, 0x20, 0xC1, 0xFC, +/* '{' 0x7B */ 0x36, 0x66, 0x66, 0x6E, 0xCE, 0x66, 0x66, 0x66, 0x30, +/* '|' 0x7C */ 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, +/* '}' 0x7D */ 0xC6, 0x66, 0x66, 0x67, 0x37, 0x66, 0x66, 0x66, 0xC0, +/* '~' 0x7E */ 0x61, 0x24, 0x38, +/* 0x7F */ 0xFF, 0xFC, 0x00, 0x63, 0xE3, 0x31, 0x99, 0x04, 0xC8, 0x66, 0x06, 0x30, 0x61, 0x83, 0x0C, 0x18, 0x60, 0x03, 0x06, 0x18, 0x00, 0xFF, 0xFC, +/* 0x80 */ 0x07, 0xC6, 0x13, 0x00, 0xC0, 0x60, 0x3F, 0xE6, 0x03, 0xFC, 0x60, 0x0C, 0x03, 0x00, 0x61, 0x07, 0xC0, +/* 0x81 */ +/* 0x82 */ 0xDC, +/* 0x83 */ +/* 0x84 */ 0xDA, 0x76, +/* 0x85 */ 0xCC, 0xC0, +/* 0x86 */ 0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +/* 0x87 */ 0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18, +/* 0x88 */ +/* 0x89 */ 0x70, 0x80, 0x22, 0x20, 0x08, 0x90, 0x02, 0x24, 0x00, 0x72, 0x00, 0x00, 0x80, 0x00, 0x40, 0x00, 0x10, 0x00, 0x09, 0xC7, 0x84, 0x8B, 0x31, 0x22, 0x84, 0x88, 0xB3, 0x21, 0xC7, 0x80, +/* 0x8A */ 0x1B, 0x03, 0x83, 0xF1, 0x86, 0xC0, 0xF0, 0x3C, 0x01, 0xE0, 0x1F, 0x00, 0xE0, 0x0F, 0x03, 0xC0, 0xD8, 0x63, 0xF0, +/* 0x8B */ 0x69, +/* 0x8C */ 0x06, 0x03, 0x03, 0xF1, 0x86, 0xC0, 0xF0, 0x3C, 0x01, 0xE0, 0x1F, 0x00, 0xE0, 0x0F, 0x03, 0xC0, 0xD8, 0x63, 0xF0, +/* 0x8D */ 0x33, 0x0F, 0x3F, 0xE1, 0x80, 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x80, 0xC0, 0x60, 0x30, +/* 0x8E */ 0x1B, 0x03, 0x8F, 0xFC, 0x06, 0x03, 0x00, 0xC0, 0x60, 0x30, 0x1C, 0x06, 0x03, 0x01, 0x80, 0x60, 0x30, 0x0F, 0xFC, +/* 0x8F */ 0x0C, 0x06, 0x0F, 0xFC, 0x06, 0x03, 0x00, 0xC0, 0x60, 0x30, 0x1C, 0x06, 0x03, 0x01, 0x80, 0x60, 0x30, 0x0F, 0xFC, +/* 0x90 */ +/* 0x91 */ 0x6B, +/* 0x92 */ 0xD6, +/* 0x93 */ 0x4C, 0xA5, 0xB0, +/* 0x94 */ 0xDA, 0x53, 0x20, +/* 0x95 */ 0x6F, 0xFF, 0x60, +/* 0x96 */ 0xFE, +/* 0x97 */ 0xFF, 0xFF, +/* 0x98 */ +/* 0x99 */ 0xFC, 0xE1, 0xCC, 0x38, 0x73, 0x0E, 0x1C, 0xC3, 0x8F, 0x30, 0xD2, 0xCC, 0x34, 0xB3, 0x0D, 0x6C, 0xC3, 0x53, 0x30, 0xCC, 0xCC, 0x33, 0x30, +/* 0x9A */ 0x24, 0x3C, 0x18, 0x7E, 0xE3, 0xC0, 0xC0, 0x60, 0x3C, 0x07, 0xC3, 0xE3, 0x7E, +/* 0x9B */ 0x96, +/* 0x9C */ 0x0C, 0x18, 0x10, 0x3E, 0xE3, 0xC0, 0xC0, 0xE0, 0x3C, 0x07, 0xC3, 0xE3, 0x7E, +/* 0x9D */ 0x0D, 0xA7, 0x3C, 0x61, 0x86, 0x18, 0x61, 0x86, 0x18, 0x70, +/* 0x9E */ 0x48, 0xF0, 0xC7, 0xF0, 0x61, 0x86, 0x0C, 0x30, 0xC1, 0x06, 0x0F, 0xE0, +/* 0x9F */ 0x0C, 0x10, 0x47, 0xF0, 0x61, 0x86, 0x0C, 0x30, 0xC1, 0x06, 0x0F, 0xE0, +/* 0xA0 */ +/* 0xA1 */ 0x8A, 0x9C, +/* 0xA2 */ 0x85, 0xE0, +/* 0xA3 */ 0x60, 0x30, 0x18, 0x0C, 0x86, 0xC3, 0xC1, 0xC1, 0xC0, 0xE0, 0x30, 0x18, 0x0C, 0x07, 0xF8, +/* 0xA4 */ 0xFF, 0xDF, 0x1E, 0x3E, 0xFF, 0xC0, +/* 0xA5 */ 0x06, 0x00, 0xF0, 0x0F, 0x01, 0x30, 0x13, 0x81, 0x38, 0x21, 0x82, 0x1C, 0x3F, 0xC6, 0x04, 0x60, 0x66, 0x06, 0xC0, 0x30, 0x06, 0x00, 0xC0, 0x0C, 0x00, 0x70, +/* 0xA6 */ 0xFF, 0xFC, 0x0F, 0xFF, 0xC0, +/* 0xA7 */ 0x0C, 0x09, 0x0C, 0xC6, 0x63, 0x81, 0xE3, 0x19, 0x87, 0xE1, 0xB8, 0xC6, 0x41, 0xC0, 0x73, 0x19, 0x8C, 0x66, 0x1E, 0x00, +/* 0xA8 */ 0xCC, +/* 0xA9 */ 0x0F, 0xC0, 0x61, 0x87, 0x03, 0x9B, 0xC6, 0xD9, 0x8F, 0x60, 0x3D, 0x00, 0xF4, 0x03, 0xD8, 0x0D, 0xE6, 0x67, 0xF3, 0x86, 0x18, 0x0F, 0xC0, +/* 0xAA */ 0x3F, 0x18, 0x6C, 0x0F, 0x03, 0xC0, 0x1E, 0x01, 0xF0, 0x0E, 0x00, 0xF0, 0x3C, 0x0D, 0x86, 0x3F, 0x02, 0x00, 0xE0, 0x18, 0x1C, 0x00, +/* 0xAB */ 0x22, 0xCF, 0x26, 0x46, 0x64, 0x40, +/* 0xAC */ 0xFF, 0x80, 0xC0, 0x60, 0x30, 0x18, +/* 0xAD */ +/* 0xAE */ 0x0F, 0xC0, 0x61, 0x87, 0x03, 0x9F, 0xE6, 0xD0, 0x8F, 0x42, 0x3D, 0xF0, 0xF4, 0x23, 0xD0, 0x8D, 0xC2, 0x67, 0x0B, 0x86, 0x18, 0x0F, 0xC0, +/* 0xAF */ 0x0C, 0x00, 0x0F, 0xFC, 0x06, 0x03, 0x00, 0xC0, 0x60, 0x30, 0x1C, 0x06, 0x03, 0x01, 0x80, 0x60, 0x30, 0x0F, 0xFC, +/* 0xB0 */ 0x74, 0x63, 0x17, 0x00, +/* 0xB1 */ 0x0C, 0x06, 0x03, 0x07, 0xE0, 0xC0, 0x60, 0x30, 0x18, 0x00, 0x00, 0x3F, 0xE0, +/* 0xB2 */ 0x6C, 0xC7, +/* 0xB3 */ 0x66, 0x66, 0x67, 0x6E, 0x66, 0x66, 0x60, +/* 0xB4 */ 0x36, 0xC0, +/* 0xB5 */ 0xC3, 0x61, 0xB0, 0xD8, 0x6C, 0x36, 0x1B, 0x0D, 0x86, 0xE7, 0x7D, 0xF0, 0x18, 0x0C, 0x00, +/* 0xB6 */ 0x3F, 0x7E, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0x72, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, +/* 0xB7 */ 0xE0, +/* 0xB8 */ 0x21, 0xC7, 0xE0, +/* 0xB9 */ 0x7E, 0x38, 0xCC, 0x30, 0x0C, 0x0F, 0x1E, 0xCC, 0x33, 0x0C, 0xC7, 0x1E, 0xE0, 0x10, 0x0C, 0x03, 0x00, 0x70, +/* 0xBA */ 0x3E, 0xE3, 0xC0, 0xC0, 0xE0, 0x3C, 0x07, 0xC3, 0xC3, 0x7E, 0x10, 0x1C, 0x0C, 0x38, +/* 0xBB */ 0x89, 0x98, 0x99, 0x3C, 0xD1, 0x00, +/* 0xBC */ 0xC6, 0xC4, 0xC8, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, +/* 0xBD */ 0x6F, 0x69, 0x00, +/* 0xBE */ 0xDE, 0xB9, 0x8C, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x00, +/* 0xBF */ 0x30, 0x03, 0xF8, 0x30, 0xC3, 0x06, 0x18, 0x60, 0x83, 0x07, 0xF0, +/* 0xC0 */ 0x06, 0x00, 0xC0, 0xFF, 0x8C, 0x0E, 0xC0, 0x6C, 0x06, 0xC0, 0x6C, 0x0C, 0xFF, 0x8C, 0x0E, 0xC0, 0x6C, 0x06, 0xC0, 0x6C, 0x06, 0xC0, 0x70, +/* 0xC1 */ 0x06, 0x03, 0x00, 0x00, 0x30, 0x1E, 0x07, 0x81, 0x20, 0xCC, 0x33, 0x0F, 0xC6, 0x19, 0x86, 0x40, 0xB0, 0x30, +/* 0xC2 */ 0x0C, 0x04, 0x80, 0x00, 0x30, 0x1E, 0x07, 0x81, 0x20, 0xCC, 0x33, 0x0F, 0xC6, 0x19, 0x86, 0x40, 0xB0, 0x30, +/* 0xC3 */ 0x21, 0x07, 0x80, 0x00, 0x30, 0x1E, 0x07, 0x81, 0x20, 0xCC, 0x33, 0x0F, 0xC6, 0x19, 0x86, 0x40, 0xB0, 0x30, +/* 0xC4 */ 0x33, 0x00, 0x00, 0xC0, 0x78, 0x1E, 0x04, 0x83, 0x30, 0xCC, 0x33, 0x1F, 0xE6, 0x19, 0x02, 0xC0, 0xF0, 0x30, +/* 0xC5 */ 0x30, 0x60, 0x00, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, +/* 0xC6 */ 0x06, 0x01, 0x80, 0x00, 0x0F, 0xC3, 0x0C, 0xC0, 0xD0, 0x1E, 0x00, 0xC0, 0x18, 0x03, 0x01, 0xA0, 0x36, 0x0C, 0x61, 0x87, 0xC0, +/* 0xC7 */ 0x1F, 0x06, 0x19, 0x83, 0xA0, 0x3C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xC0, 0x68, 0x0D, 0x83, 0x18, 0xE1, 0xF0, 0x08, 0x01, 0xC0, 0x18, 0x0E, 0x00, +/* 0xC8 */ 0x19, 0x81, 0xE0, 0x00, 0x0F, 0xC3, 0x0C, 0xC0, 0xF0, 0x1E, 0x00, 0xC0, 0x18, 0x03, 0x01, 0xA0, 0x36, 0x0C, 0x61, 0x87, 0xC0, +/* 0xC9 */ 0x0C, 0x0C, 0x00, 0x1F, 0xFC, 0x06, 0x03, 0x01, 0x80, 0xFF, 0x60, 0x30, 0x18, 0x0C, 0x07, 0xFC, +/* 0xCA */ 0xFF, 0xD8, 0x03, 0x00, 0x60, 0x0C, 0x01, 0x80, 0x3F, 0xF6, 0x00, 0xC0, 0x18, 0x03, 0x00, 0x60, 0x0F, 0xFC, 0x01, 0x80, 0x60, 0x0C, 0x00, 0xE0, +/* 0xCB */ 0x33, 0x00, 0x3F, 0xF8, 0x0C, 0x06, 0x03, 0x01, 0xFE, 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x07, 0xFC, +/* 0xCC */ 0x33, 0x0F, 0x00, 0x1F, 0xFC, 0x06, 0x03, 0x01, 0x80, 0xFF, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0xFE, +/* 0xCD */ 0x78, 0x36, 0xDB, 0x6D, 0xB6, 0xC0, +/* 0xCE */ 0x76, 0xC0, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x18, +/* 0xCF */ 0x66, 0x0F, 0x00, 0x03, 0xF8, 0xC3, 0x30, 0x6C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC1, 0xB0, 0xEF, 0xE0, +/* 0xD0 */ 0x7F, 0x0C, 0x31, 0x83, 0x30, 0x36, 0x06, 0xC0, 0xFE, 0x1B, 0x03, 0x60, 0x6C, 0x0D, 0x83, 0x30, 0xE7, 0xF0, +/* 0xD1 */ 0x03, 0x01, 0x83, 0x81, 0xF0, 0x3F, 0x07, 0xA0, 0xF6, 0x1E, 0x63, 0xC4, 0x78, 0xCF, 0x0D, 0xE1, 0xBC, 0x1F, 0x81, 0xC0, +/* 0xD2 */ 0x19, 0x81, 0xE3, 0x81, 0xF0, 0x3F, 0x07, 0xA0, 0xF6, 0x1E, 0x63, 0xC4, 0x78, 0xCF, 0x0D, 0xE1, 0xBC, 0x1F, 0x81, 0xC0, +/* 0xD3 */ 0x03, 0x00, 0x60, 0x00, 0x00, 0xF0, 0x39, 0xC6, 0x06, 0x60, 0x6C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x36, 0x06, 0x60, 0x63, 0x9C, 0x0F, 0x00, +/* 0xD4 */ 0x0F, 0x01, 0x98, 0x00, 0x00, 0xF0, 0x39, 0xC6, 0x06, 0x60, 0x6C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x36, 0x06, 0x60, 0x63, 0x9C, 0x0F, 0x00, +/* 0xD5 */ 0x0D, 0x81, 0xB0, 0x00, 0x00, 0xF0, 0x39, 0xC6, 0x06, 0x60, 0x6C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x36, 0x06, 0x60, 0x63, 0x9C, 0x0F, 0x00, +/* 0xD6 */ 0x19, 0x81, 0x98, 0x00, 0x00, 0xF0, 0x39, 0xC6, 0x06, 0x60, 0x6C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x36, 0x06, 0x60, 0x63, 0x9C, 0x0F, 0x00, +/* 0xD7 */ 0x83, 0x89, 0xA1, 0x83, 0x89, 0xA1, 0x80, +/* 0xD8 */ 0x33, 0x01, 0xE0, 0xFF, 0x8C, 0x0E, 0xC0, 0x6C, 0x06, 0xC0, 0x6C, 0x0C, 0xFF, 0x8C, 0x0E, 0xC0, 0x6C, 0x06, 0xC0, 0x6C, 0x06, 0xC0, 0x70, +/* 0xD9 */ 0x04, 0x01, 0x43, 0x11, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x36, 0x0C, 0x3E, 0x00, +/* 0xDA */ 0x06, 0x01, 0x83, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x36, 0x0C, 0x3E, 0x00, +/* 0xDB */ 0x0D, 0x83, 0x63, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x36, 0x0C, 0x3E, 0x00, +/* 0xDC */ 0x1B, 0x00, 0x03, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x36, 0x0C, 0x3E, 0x00, +/* 0xDD */ 0x03, 0x0C, 0x63, 0x60, 0x63, 0x0C, 0x30, 0xC1, 0x98, 0x1D, 0x80, 0xF0, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, +/* 0xDE */ 0xFF, 0x86, 0x03, 0x01, 0x80, 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x80, 0xC0, 0x40, 0x3C, 0x06, 0x1E, 0x00, +/* 0xDF */ 0x3C, 0x33, 0x30, 0xD8, 0x6C, 0x36, 0x33, 0x39, 0x86, 0xC1, 0xE0, 0xF0, 0x78, 0x6D, 0xE0, +/* 0xE0 */ 0x19, 0x89, 0xBE, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x00, +/* 0xE1 */ 0x0C, 0x04, 0x04, 0x0F, 0xCE, 0x36, 0x18, 0x0C, 0x1E, 0x7B, 0x61, 0xB0, 0xD8, 0xE7, 0xB8, +/* 0xE2 */ 0x10, 0x14, 0x1B, 0x0F, 0xCE, 0x36, 0x18, 0x0C, 0x1E, 0x7B, 0x61, 0xB0, 0xD8, 0xE7, 0xB8, +/* 0xE3 */ 0x66, 0x1E, 0x00, 0x0F, 0xCE, 0x36, 0x18, 0x0C, 0x1E, 0x7B, 0x61, 0xB0, 0xD8, 0xE7, 0xB8, +/* 0xE4 */ 0x66, 0x00, 0x1F, 0x9C, 0x6C, 0x30, 0x18, 0x3C, 0xF6, 0xC3, 0x61, 0xB1, 0xCF, 0x70, +/* 0xE5 */ 0x78, 0x36, 0xDB, 0x6D, 0xB6, 0xD8, +/* 0xE6 */ 0x0C, 0x08, 0x10, 0x3C, 0x66, 0xC3, 0xC0, 0xC0, 0xC0, 0xC0, 0xC3, 0x66, 0x3C, +/* 0xE7 */ 0x3C, 0x66, 0xC3, 0xC0, 0xC0, 0xC0, 0xC0, 0xC3, 0x66, 0x3C, 0x10, 0x1C, 0x0C, 0x38, +/* 0xE8 */ 0x44, 0x28, 0x38, 0x3C, 0x66, 0xC3, 0xC0, 0xC0, 0xC0, 0xC0, 0xC3, 0x66, 0x3C, +/* 0xE9 */ 0x0C, 0x08, 0x18, 0x3C, 0x66, 0xC3, 0xC3, 0xFF, 0xC0, 0xC0, 0xC3, 0x66, 0x3C, +/* 0xEA */ 0x3C, 0x62, 0xC3, 0xC3, 0xFF, 0xC0, 0xC0, 0xC3, 0x66, 0x3E, 0x04, 0x0C, 0x0C, 0x06, +/* 0xEB */ 0x66, 0x00, 0x3C, 0x66, 0xC3, 0xC3, 0xFF, 0xC0, 0xC0, 0xC3, 0x66, 0x3C, +/* 0xEC */ 0x64, 0x2C, 0x18, 0x3C, 0x66, 0xC3, 0xC3, 0xFF, 0xC0, 0xC0, 0xC3, 0x66, 0x3C, +/* 0xED */ 0x7A, 0x6D, 0xB6, 0xDB, 0x6C, +/* 0xEE */ 0x69, 0x06, 0x66, 0x66, 0x66, 0x66, 0x60, +/* 0xEF */ 0x03, 0x30, 0x32, 0x03, 0x43, 0xB0, 0x67, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x06, 0x70, 0x3B, 0x00, +/* 0xF0 */ 0x03, 0x07, 0xC0, 0xC7, 0x66, 0x76, 0x1B, 0x0D, 0x86, 0xC3, 0x61, 0xB0, 0xCC, 0xE3, 0xB0, +/* 0xF1 */ 0x0C, 0x18, 0x00, 0xDE, 0xE3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, +/* 0xF2 */ 0x66, 0x3C, 0x00, 0xDE, 0xE3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, +/* 0xF3 */ 0x0C, 0x18, 0x00, 0x3C, 0x66, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x66, 0x3C, +/* 0xF4 */ 0x18, 0x24, 0x00, 0x3C, 0x66, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x66, 0x3C, +/* 0xF5 */ 0x36, 0x6C, 0x00, 0x3C, 0x66, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x66, 0x3C, +/* 0xF6 */ 0x66, 0x00, 0x3C, 0x66, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x66, 0x3C, +/* 0xF7 */ 0x18, 0x00, 0x00, 0x1F, 0xF0, 0x00, 0x00, 0x00, 0x30, +/* 0xF8 */ 0xDB, 0x81, 0xBE, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x00, +/* 0xF9 */ 0x10, 0x28, 0x10, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC7, 0x7B, +/* 0xFA */ 0x06, 0x0C, 0x18, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC7, 0x7B, +/* 0xFB */ 0x36, 0x6C, 0x00, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC7, 0x7B, +/* 0xFC */ 0x66, 0x00, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC7, 0x7B, +/* 0xFD */ 0x06, 0x04, 0x08, 0xC1, 0x43, 0x63, 0x62, 0x26, 0x36, 0x34, 0x1C, 0x1C, 0x18, 0x18, 0x18, 0x10, 0x60, +/* 0xFE */ 0x63, 0x3C, 0xC6, 0x31, 0x8C, 0x63, 0x18, 0xE2, 0x1C, 0x6F, +/* 0xFF */ 0xC0, }; const GFXglyph FreeSans9pt_Win1250Glyphs[] PROGMEM = { - /* ' ' 0x20 */ {0, 0, 0, 5, 0, 0}, - /* '!' 0x21 */ {0, 2, 13, 6, 2, -12}, - /* '"' 0x22 */ {4, 5, 4, 6, 1, -12}, - /* '#' 0x23 */ {7, 10, 12, 10, 0, -11}, - /* '$' 0x24 */ {22, 9, 16, 10, 1, -13}, - /* '%' 0x25 */ {40, 16, 13, 16, 1, -12}, - /* '&' 0x26 */ {66, 10, 13, 12, 1, -12}, - /* ''' 0x27 */ {83, 2, 4, 4, 1, -12}, - /* '(' 0x28 */ {84, 4, 17, 6, 1, -12}, - /* ')' 0x29 */ {93, 4, 17, 6, 1, -12}, - /* '*' 0x2A */ {102, 5, 5, 7, 1, -12}, - /* '+' 0x2B */ {106, 6, 8, 11, 3, -7}, - /* ',' 0x2C */ {112, 2, 4, 5, 2, 0}, - /* '-' 0x2D */ {113, 4, 1, 6, 1, -4}, - /* '.' 0x2E */ {114, 2, 1, 5, 1, 0}, - /* '/' 0x2F */ {115, 5, 13, 5, 0, -12}, - /* '0' 0x30 */ {124, 8, 13, 10, 1, -12}, - /* '1' 0x31 */ {137, 4, 13, 10, 3, -12}, - /* '2' 0x32 */ {144, 9, 13, 10, 1, -12}, - /* '3' 0x33 */ {159, 8, 13, 10, 1, -12}, - /* '4' 0x34 */ {172, 7, 13, 10, 2, -12}, - /* '5' 0x35 */ {184, 9, 13, 10, 1, -12}, - /* '6' 0x36 */ {199, 9, 13, 10, 1, -12}, - /* '7' 0x37 */ {214, 8, 13, 10, 0, -12}, - /* '8' 0x38 */ {227, 9, 13, 10, 1, -12}, - /* '9' 0x39 */ {242, 8, 13, 10, 1, -12}, - /* ':' 0x3A */ {255, 2, 10, 5, 1, -9}, - /* ';' 0x3B */ {258, 3, 12, 5, 1, -8}, - /* '<' 0x3C */ {263, 9, 9, 11, 1, -8}, - /* '=' 0x3D */ {274, 9, 4, 11, 1, -5}, - /* '>' 0x3E */ {279, 9, 8, 11, 1, -7}, - /* '?' 0x3F */ {288, 9, 13, 10, 1, -12}, - /* '@' 0x40 */ {303, 17, 16, 18, 1, -12}, - /* 'A' 0x41 */ {337, 12, 13, 12, 0, -12}, - /* 'B' 0x42 */ {357, 11, 13, 12, 1, -12}, - /* 'C' 0x43 */ {375, 11, 13, 13, 1, -12}, - /* 'D' 0x44 */ {393, 11, 13, 13, 1, -12}, - /* 'E' 0x45 */ {411, 9, 13, 11, 1, -12}, - /* 'F' 0x46 */ {426, 8, 13, 11, 1, -12}, - /* 'G' 0x47 */ {439, 12, 13, 14, 1, -12}, - /* 'H' 0x48 */ {459, 11, 13, 13, 1, -12}, - /* 'I' 0x49 */ {477, 2, 13, 5, 2, -12}, - /* 'J' 0x4A */ {481, 7, 13, 10, 1, -12}, - /* 'K' 0x4B */ {493, 10, 13, 12, 1, -12}, - /* 'L' 0x4C */ {510, 8, 13, 10, 1, -12}, - /* 'M' 0x4D */ {523, 13, 13, 15, 1, -12}, - /* 'N' 0x4E */ {545, 11, 13, 13, 1, -12}, - /* 'O' 0x4F */ {563, 13, 13, 14, 1, -12}, - /* 'P' 0x50 */ {585, 10, 13, 12, 1, -12}, - /* 'Q' 0x51 */ {602, 13, 14, 14, 1, -12}, - /* 'R' 0x52 */ {625, 12, 13, 13, 1, -12}, - /* 'S' 0x53 */ {645, 10, 13, 12, 1, -12}, - /* 'T' 0x54 */ {662, 9, 13, 11, 1, -12}, - /* 'U' 0x55 */ {677, 11, 13, 13, 1, -12}, - /* 'V' 0x56 */ {695, 11, 13, 11, 0, -12}, - /* 'W' 0x57 */ {713, 16, 13, 17, 0, -12}, - /* 'X' 0x58 */ {739, 10, 13, 12, 1, -12}, - /* 'Y' 0x59 */ {756, 12, 13, 12, 0, -12}, - /* 'Z' 0x5A */ {776, 10, 13, 11, 1, -12}, - /* '[' 0x5B */ {793, 3, 17, 5, 1, -12}, - /* '\' 0x5C */ {800, 5, 13, 5, 0, -12}, - /* ']' 0x5D */ {809, 3, 17, 5, 0, -12}, - /* '^' 0x5E */ {816, 7, 7, 8, 1, -12}, - /* '_' 0x5F */ {823, 10, 1, 10, 0, 3}, - /* '`' 0x60 */ {825, 4, 3, 5, 0, -12}, - /* 'a' 0x61 */ {827, 9, 10, 10, 1, -9}, - /* 'b' 0x62 */ {839, 9, 13, 10, 1, -12}, - /* 'c' 0x63 */ {854, 8, 10, 9, 1, -9}, - /* 'd' 0x64 */ {864, 8, 13, 10, 1, -12}, - /* 'e' 0x65 */ {877, 8, 10, 10, 1, -9}, - /* 'f' 0x66 */ {887, 4, 13, 5, 1, -12}, - /* 'g' 0x67 */ {894, 8, 14, 10, 1, -9}, - /* 'h' 0x68 */ {908, 8, 13, 10, 1, -12}, - /* 'i' 0x69 */ {921, 2, 13, 4, 1, -12}, - /* 'j' 0x6A */ {925, 4, 17, 4, 0, -12}, - /* 'k' 0x6B */ {934, 8, 13, 9, 1, -12}, - /* 'l' 0x6C */ {947, 2, 13, 4, 1, -12}, - /* 'm' 0x6D */ {951, 13, 10, 15, 1, -9}, - /* 'n' 0x6E */ {968, 8, 10, 10, 1, -9}, - /* 'o' 0x6F */ {978, 8, 10, 10, 1, -9}, - /* 'p' 0x70 */ {988, 9, 13, 10, 1, -9}, - /* 'q' 0x71 */ {1003, 8, 13, 10, 1, -9}, - /* 'r' 0x72 */ {1016, 5, 10, 6, 1, -9}, - /* 's' 0x73 */ {1023, 8, 10, 9, 1, -9}, - /* 't' 0x74 */ {1033, 4, 12, 5, 1, -11}, - /* 'u' 0x75 */ {1039, 8, 10, 10, 1, -9}, - /* 'v' 0x76 */ {1049, 9, 10, 9, 0, -9}, - /* 'w' 0x77 */ {1061, 13, 10, 13, 0, -9}, - /* 'x' 0x78 */ {1078, 7, 10, 9, 1, -9}, - /* 'y' 0x79 */ {1087, 8, 14, 9, 0, -9}, - /* 'z' 0x7A */ {1101, 7, 10, 9, 1, -9}, - /* '{' 0x7B */ {1110, 4, 17, 6, 1, -12}, - /* '|' 0x7C */ {1119, 2, 17, 4, 2, -12}, - /* '}' 0x7D */ {1124, 4, 17, 6, 1, -12}, - /* '~' 0x7E */ {1133, 7, 3, 9, 1, -7}, - /* 0x7F */ {1136, 13, 14, 15, 1, -12}, - /* 0x80 */ {1159, 10, 13, 12, 1, -12}, - /* 0x81 */ {1176, 0, 0, 0, 0, 0}, - /* 0x82 */ {1176, 2, 3, 5, 1, 0}, - /* 0x83 */ {1177, 0, 0, 0, 0, 0}, - /* 0x84 */ {1177, 5, 3, 7, 1, 0}, - /* 0x85 */ {1179, 10, 1, 12, 1, 0}, - /* 0x86 */ {1181, 8, 16, 10, 1, -12}, - /* 0x87 */ {1197, 8, 16, 10, 1, -12}, - /* 0x88 */ {1213, 0, 0, 0, 0, 0}, - /* 0x89 */ {1213, 18, 13, 18, 0, -12}, - /* 0x8A */ {1243, 10, 15, 12, 1, -14}, - /* 0x8B */ {1262, 2, 4, 4, 1, -6}, - /* 0x8C */ {1263, 10, 15, 12, 1, -14}, - /* 0x8D */ {1282, 9, 15, 11, 1, -14}, - /* 0x8E */ {1299, 10, 15, 11, 1, -14}, - /* 0x8F */ {1318, 10, 15, 11, 1, -14}, - /* 0x90 */ {1337, 0, 0, 0, 0, 0}, - /* 0x91 */ {1337, 2, 4, 4, 2, -12}, - /* 0x92 */ {1338, 2, 4, 4, 1, -12}, - /* 0x93 */ {1339, 5, 4, 7, 2, -12}, - /* 0x94 */ {1342, 5, 4, 7, 1, -12}, - /* 0x95 */ {1345, 4, 5, 7, 1, -8}, - /* 0x96 */ {1348, 7, 1, 9, 1, -4}, - /* 0x97 */ {1349, 16, 1, 18, 1, -4}, - /* 0x98 */ {1351, 0, 0, 0, 0, 0}, - /* 0x99 */ {1351, 18, 10, 18, 1, -13}, - /* 0x9A */ {1374, 8, 13, 9, 1, -12}, - /* 0x9B */ {1387, 2, 4, 5, 2, -6}, - /* 0x9C */ {1388, 8, 13, 9, 1, -12}, - /* 0x9D */ {1401, 6, 13, 8, 1, -12}, - /* 0x9E */ {1411, 7, 13, 9, 1, -12}, - /* 0x9F */ {1423, 7, 13, 9, 1, -12}, - /* 0xA0 */ {1435, 0, 0, 5, 0, 0}, - /* 0xA1 */ {1435, 5, 3, 6, 0, -12}, - /* 0xA2 */ {1437, 6, 2, 6, 0, -12}, - /* 0xA3 */ {1439, 9, 13, 11, 1, -12}, - /* 0xA4 */ {1454, 7, 6, 10, 2, -8}, - /* 0xA5 */ {1460, 12, 17, 12, 1, -12}, - /* 0xA6 */ {1486, 2, 17, 5, 2, -12}, - /* 0xA7 */ {1491, 9, 17, 10, 1, -12}, - /* 0xA8 */ {1511, 6, 1, 6, 0, -11}, - /* 0xA9 */ {1512, 14, 13, 14, 1, -12}, - /* 0xAA */ {1535, 10, 17, 12, 1, -12}, - /* 0xAB */ {1557, 7, 6, 9, 1, -7}, - /* 0xAC */ {1563, 9, 5, 11, 2, -5}, - /* 0xAD */ {1569, 0, 0, 0, 0, 0}, - /* 0xAE */ {1569, 14, 13, 14, 1, -12}, - /* 0xAF */ {1592, 10, 15, 11, 1, -14}, - /* 0xB0 */ {1611, 5, 5, 11, 3, -11}, - /* 0xB1 */ {1615, 9, 11, 11, 1, -10}, - /* 0xB2 */ {1628, 4, 4, 6, 1, 1}, - /* 0xB3 */ {1630, 4, 13, 5, 1, -12}, - /* 0xB4 */ {1637, 4, 3, 6, 2, -12}, - /* 0xB5 */ {1639, 9, 13, 10, 1, -9}, - /* 0xB6 */ {1654, 8, 16, 10, 2, -12}, - /* 0xB7 */ {1670, 3, 1, 5, 1, -4}, - /* 0xB8 */ {1671, 5, 4, 6, 1, 1}, - /* 0xB9 */ {1674, 10, 14, 10, 1, -9}, - /* 0xBA */ {1692, 8, 14, 9, 1, -9}, - /* 0xBB */ {1706, 7, 6, 9, 1, -7}, - /* 0xBC */ {1712, 8, 13, 10, 1, -12}, - /* 0xBD */ {1725, 6, 3, 6, 0, -12}, - /* 0xBE */ {1728, 5, 13, 7, 1, -12}, - /* 0xBF */ {1737, 7, 12, 9, 1, -11}, - /* 0xC0 */ {1748, 12, 15, 13, 1, -14}, - /* 0xC1 */ {1771, 10, 14, 12, 1, -13}, - /* 0xC2 */ {1789, 10, 14, 12, 1, -13}, - /* 0xC3 */ {1807, 10, 14, 12, 1, -13}, - /* 0xC4 */ {1825, 10, 14, 12, 1, -13}, - /* 0xC5 */ {1843, 8, 14, 10, 1, -13}, - /* 0xC6 */ {1857, 11, 15, 13, 1, -14}, - /* 0xC7 */ {1878, 11, 17, 13, 1, -12}, - /* 0xC8 */ {1902, 11, 15, 13, 1, -14}, - /* 0xC9 */ {1923, 9, 14, 11, 1, -13}, - /* 0xCA */ {1939, 11, 17, 12, 1, -12}, - /* 0xCB */ {1963, 9, 14, 11, 1, -13}, - /* 0xCC */ {1979, 9, 15, 11, 1, -14}, - /* 0xCD */ {1996, 3, 14, 5, 1, -13}, - /* 0xCE */ {2002, 5, 14, 5, 0, -13}, - /* 0xCF */ {2011, 10, 15, 13, 2, -14}, - /* 0xD0 */ {2030, 11, 13, 13, 1, -12}, - /* 0xD1 */ {2048, 11, 14, 13, 1, -13}, - /* 0xD2 */ {2068, 11, 14, 13, 1, -13}, - /* 0xD3 */ {2088, 12, 15, 13, 1, -14}, - /* 0xD4 */ {2111, 12, 15, 13, 1, -14}, - /* 0xD5 */ {2134, 12, 15, 13, 1, -14}, - /* 0xD6 */ {2157, 12, 15, 13, 1, -14}, - /* 0xD7 */ {2180, 7, 7, 11, 2, -7}, - /* 0xD8 */ {2187, 12, 15, 13, 1, -14}, - /* 0xD9 */ {2210, 11, 14, 13, 1, -13}, - /* 0xDA */ {2230, 11, 14, 13, 1, -13}, - /* 0xDB */ {2250, 11, 14, 13, 1, -13}, - /* 0xDC */ {2270, 11, 14, 13, 1, -13}, - /* 0xDD */ {2290, 12, 14, 12, 0, -13}, - /* 0xDE */ {2311, 9, 17, 11, 1, -12}, - /* 0xDF */ {2331, 9, 13, 11, 1, -12}, - /* 0xE0 */ {2346, 5, 13, 6, 1, -12}, - /* 0xE1 */ {2355, 9, 13, 10, 1, -12}, - /* 0xE2 */ {2370, 9, 13, 10, 1, -12}, - /* 0xE3 */ {2385, 9, 13, 10, 1, -12}, - /* 0xE4 */ {2400, 9, 12, 10, 1, -11}, - /* 0xE5 */ {2414, 3, 15, 4, 0, -14}, - /* 0xE6 */ {2420, 8, 13, 9, 1, -12}, - /* 0xE7 */ {2433, 8, 14, 9, 1, -9}, - /* 0xE8 */ {2447, 8, 13, 9, 1, -12}, - /* 0xE9 */ {2460, 8, 13, 10, 1, -12}, - /* 0xEA */ {2473, 8, 14, 10, 1, -9}, - /* 0xEB */ {2487, 8, 12, 10, 1, -11}, - /* 0xEC */ {2499, 8, 13, 10, 1, -12}, - /* 0xED */ {2512, 3, 13, 4, 1, -12}, - /* 0xEE */ {2517, 4, 13, 5, 0, -12}, - /* 0xEF */ {2524, 12, 13, 12, 1, -12}, - /* 0xF0 */ {2544, 9, 13, 10, 1, -12}, - /* 0xF1 */ {2559, 8, 13, 10, 1, -12}, - /* 0xF2 */ {2572, 8, 13, 10, 1, -12}, - /* 0xF3 */ {2585, 8, 13, 10, 1, -12}, - /* 0xF4 */ {2598, 8, 13, 10, 1, -12}, - /* 0xF5 */ {2611, 8, 13, 10, 1, -12}, - /* 0xF6 */ {2624, 8, 12, 10, 1, -11}, - /* 0xF7 */ {2636, 9, 8, 11, 1, -7}, - /* 0xF8 */ {2645, 5, 13, 6, 1, -12}, - /* 0xF9 */ {2654, 8, 13, 10, 1, -12}, - /* 0xFA */ {2667, 8, 13, 10, 1, -12}, - /* 0xFB */ {2680, 8, 13, 10, 1, -12}, - /* 0xFC */ {2693, 8, 12, 10, 1, -11}, - /* 0xFD */ {2705, 8, 17, 9, 0, -12}, - /* 0xFE */ {2722, 5, 16, 5, 1, -11}, - /* 0xFF */ {2732, 2, 1, 6, 2, -11}, +/* 0x01 */ { 0, 15, 15, 17, 1, -13 }, +/* 0x02 */ { 29, 15, 15, 17, 1, -13 }, +/* 0x03 */ { 58, 15, 16, 17, 1, -14 }, +/* 0x04 */ { 88, 15, 16, 17, 1, -14 }, +/* 0x05 */ { 118, 16, 15, 18, 1, -13 }, +/* 0x06 */ { 148, 15, 15, 17, 1, -13 }, +/* 0x07 */ { 177, 0, 0, 8, 0, 0 }, +/* 0x08 */ { 177, 17, 16, 19, 1, -14 }, +/* 0x09 */ { 211, 17, 12, 19, 1, -12 }, +/* 0x0A */ { 237, 0, 0, 8, 0, 0 }, +/* 0x0B */ { 237, 17, 16, 19, 1, -14 }, +/* 0x0C */ { 271, 15, 14, 17, 1, -12 }, +/* 0x0D */ { 298, 0, 0, 8, 0, 0 }, +/* 0x0E */ { 298, 15, 16, 17, 1, -14 }, +/* 0x0F */ { 328, 15, 15, 17, 1, -13 }, +/* 0x10 */ { 357, 15, 15, 17, 1, -13 }, +/* 0x11 */ { 386, 15, 16, 17, 1, -14 }, +/* 0x12 */ { 416, 17, 17, 19, 1, -15 }, +/* 0x13 */ { 453, 15, 16, 17, 1, -14 }, +/* 0x14 */ { 483, 15, 16, 17, 1, -14 }, +/* 0x15 */ { 513, 15, 16, 17, 1, -14 }, +/* 0x16 */ { 543, 11, 16, 13, 1, -14 }, +/* 0x17 */ { 565, 15, 16, 17, 1, -14 }, +/* 0x18 */ { 595, 18, 15, 20, 1, -13 }, +/* 0x19 */ { 629, 15, 16, 17, 1, -14 }, +/* 0x1A */ { 659, 13, 14, 15, 1, -12 }, +/* 0x1B */ { 682, 17, 16, 19, 1, -14 }, +/* 0x1C */ { 716, 15, 16, 17, 1, -14 }, +/* 0x1D */ { 746, 15, 15, 17, 1, -13 }, +/* 0x1E */ { 775, 17, 16, 19, 1, -14 }, +/* 0x1F */ { 809, 11, 16, 13, 1, -14 }, +/* ' ' 0x20 */ { 831, 0, 0, 5, 0, 0 }, +/* '!' 0x21 */ { 831, 2, 13, 6, 2, -12 }, +/* '"' 0x22 */ { 835, 5, 4, 6, 1, -12 }, +/* '#' 0x23 */ { 838, 10, 12, 10, 0, -11 }, +/* '$' 0x24 */ { 853, 9, 16, 10, 1, -13 }, +/* '%' 0x25 */ { 871, 16, 13, 16, 1, -12 }, +/* '&' 0x26 */ { 897, 10, 13, 12, 1, -12 }, +/* ''' 0x27 */ { 914, 2, 4, 4, 1, -12 }, +/* '(' 0x28 */ { 915, 4, 17, 6, 1, -12 }, +/* ')' 0x29 */ { 924, 4, 17, 6, 1, -12 }, +/* '*' 0x2A */ { 933, 5, 5, 7, 1, -12 }, +/* '+' 0x2B */ { 937, 6, 8, 11, 3, -7 }, +/* ',' 0x2C */ { 943, 2, 4, 5, 2, 0 }, +/* '-' 0x2D */ { 944, 4, 1, 6, 1, -4 }, +/* '.' 0x2E */ { 945, 2, 1, 5, 1, 0 }, +/* '/' 0x2F */ { 946, 5, 13, 5, 0, -12 }, +/* '0' 0x30 */ { 955, 8, 13, 10, 1, -12 }, +/* '1' 0x31 */ { 968, 4, 13, 10, 3, -12 }, +/* '2' 0x32 */ { 975, 9, 13, 10, 1, -12 }, +/* '3' 0x33 */ { 990, 8, 13, 10, 1, -12 }, +/* '4' 0x34 */ { 1003, 7, 13, 10, 2, -12 }, +/* '5' 0x35 */ { 1015, 9, 13, 10, 1, -12 }, +/* '6' 0x36 */ { 1030, 9, 13, 10, 1, -12 }, +/* '7' 0x37 */ { 1045, 8, 13, 10, 0, -12 }, +/* '8' 0x38 */ { 1058, 9, 13, 10, 1, -12 }, +/* '9' 0x39 */ { 1073, 8, 13, 10, 1, -12 }, +/* ':' 0x3A */ { 1086, 2, 10, 5, 1, -9 }, +/* ';' 0x3B */ { 1089, 3, 12, 5, 1, -8 }, +/* '<' 0x3C */ { 1094, 9, 9, 11, 1, -8 }, +/* '=' 0x3D */ { 1105, 9, 4, 11, 1, -5 }, +/* '>' 0x3E */ { 1110, 9, 8, 11, 1, -7 }, +/* '?' 0x3F */ { 1119, 9, 13, 10, 1, -12 }, +/* '@' 0x40 */ { 1134, 17, 16, 18, 1, -12 }, +/* 'A' 0x41 */ { 1168, 12, 13, 12, 0, -12 }, +/* 'B' 0x42 */ { 1188, 11, 13, 12, 1, -12 }, +/* 'C' 0x43 */ { 1206, 11, 13, 13, 1, -12 }, +/* 'D' 0x44 */ { 1224, 11, 13, 13, 1, -12 }, +/* 'E' 0x45 */ { 1242, 9, 13, 11, 1, -12 }, +/* 'F' 0x46 */ { 1257, 8, 13, 11, 1, -12 }, +/* 'G' 0x47 */ { 1270, 12, 13, 14, 1, -12 }, +/* 'H' 0x48 */ { 1290, 11, 13, 13, 1, -12 }, +/* 'I' 0x49 */ { 1308, 2, 13, 5, 2, -12 }, +/* 'J' 0x4A */ { 1312, 7, 13, 10, 1, -12 }, +/* 'K' 0x4B */ { 1324, 10, 13, 12, 1, -12 }, +/* 'L' 0x4C */ { 1341, 8, 13, 10, 1, -12 }, +/* 'M' 0x4D */ { 1354, 13, 13, 15, 1, -12 }, +/* 'N' 0x4E */ { 1376, 11, 13, 13, 1, -12 }, +/* 'O' 0x4F */ { 1394, 13, 13, 14, 1, -12 }, +/* 'P' 0x50 */ { 1416, 10, 13, 12, 1, -12 }, +/* 'Q' 0x51 */ { 1433, 13, 14, 14, 1, -12 }, +/* 'R' 0x52 */ { 1456, 12, 13, 13, 1, -12 }, +/* 'S' 0x53 */ { 1476, 10, 13, 12, 1, -12 }, +/* 'T' 0x54 */ { 1493, 9, 13, 11, 1, -12 }, +/* 'U' 0x55 */ { 1508, 11, 13, 13, 1, -12 }, +/* 'V' 0x56 */ { 1526, 11, 13, 11, 0, -12 }, +/* 'W' 0x57 */ { 1544, 16, 13, 17, 0, -12 }, +/* 'X' 0x58 */ { 1570, 10, 13, 12, 1, -12 }, +/* 'Y' 0x59 */ { 1587, 12, 13, 12, 0, -12 }, +/* 'Z' 0x5A */ { 1607, 10, 13, 11, 1, -12 }, +/* '[' 0x5B */ { 1624, 3, 17, 5, 1, -12 }, +/* '\' 0x5C */ { 1631, 5, 13, 5, 0, -12 }, +/* ']' 0x5D */ { 1640, 3, 17, 5, 0, -12 }, +/* '^' 0x5E */ { 1647, 7, 7, 8, 1, -12 }, +/* '_' 0x5F */ { 1654, 10, 1, 10, 0, 3 }, +/* '`' 0x60 */ { 1656, 4, 3, 5, 0, -12 }, +/* 'a' 0x61 */ { 1658, 9, 10, 10, 1, -9 }, +/* 'b' 0x62 */ { 1670, 9, 13, 10, 1, -12 }, +/* 'c' 0x63 */ { 1685, 8, 10, 9, 1, -9 }, +/* 'd' 0x64 */ { 1695, 8, 13, 10, 1, -12 }, +/* 'e' 0x65 */ { 1708, 8, 10, 10, 1, -9 }, +/* 'f' 0x66 */ { 1718, 4, 13, 5, 1, -12 }, +/* 'g' 0x67 */ { 1725, 8, 14, 10, 1, -9 }, +/* 'h' 0x68 */ { 1739, 8, 13, 10, 1, -12 }, +/* 'i' 0x69 */ { 1752, 2, 13, 4, 1, -12 }, +/* 'j' 0x6A */ { 1756, 4, 17, 4, 0, -12 }, +/* 'k' 0x6B */ { 1765, 8, 13, 9, 1, -12 }, +/* 'l' 0x6C */ { 1778, 2, 13, 4, 1, -12 }, +/* 'm' 0x6D */ { 1782, 13, 10, 15, 1, -9 }, +/* 'n' 0x6E */ { 1799, 8, 10, 10, 1, -9 }, +/* 'o' 0x6F */ { 1809, 8, 10, 10, 1, -9 }, +/* 'p' 0x70 */ { 1819, 9, 13, 10, 1, -9 }, +/* 'q' 0x71 */ { 1834, 8, 13, 10, 1, -9 }, +/* 'r' 0x72 */ { 1847, 5, 10, 6, 1, -9 }, +/* 's' 0x73 */ { 1854, 8, 10, 9, 1, -9 }, +/* 't' 0x74 */ { 1864, 4, 12, 5, 1, -11 }, +/* 'u' 0x75 */ { 1870, 8, 10, 10, 1, -9 }, +/* 'v' 0x76 */ { 1880, 9, 10, 9, 0, -9 }, +/* 'w' 0x77 */ { 1892, 13, 10, 13, 0, -9 }, +/* 'x' 0x78 */ { 1909, 7, 10, 9, 1, -9 }, +/* 'y' 0x79 */ { 1918, 8, 14, 9, 0, -9 }, +/* 'z' 0x7A */ { 1932, 7, 10, 9, 1, -9 }, +/* '{' 0x7B */ { 1941, 4, 17, 6, 1, -12 }, +/* '|' 0x7C */ { 1950, 2, 17, 4, 2, -12 }, +/* '}' 0x7D */ { 1955, 4, 17, 6, 1, -12 }, +/* '~' 0x7E */ { 1964, 7, 3, 9, 1, -7 }, +/* 0x7F */ { 1967, 13, 14, 15, 1, -12 }, +/* 0x80 */ { 1990, 10, 13, 12, 1, -12 }, +/* 0x81 */ { 2007, 0, 0, 0, 0, 0 }, +/* 0x82 */ { 2007, 2, 3, 5, 1, 0 }, +/* 0x83 */ { 2008, 0, 0, 0, 0, 0 }, +/* 0x84 */ { 2008, 5, 3, 7, 1, 0 }, +/* 0x85 */ { 2010, 10, 1, 12, 1, 0 }, +/* 0x86 */ { 2012, 8, 16, 10, 1, -12 }, +/* 0x87 */ { 2028, 8, 16, 10, 1, -12 }, +/* 0x88 */ { 2044, 0, 0, 0, 0, 0 }, +/* 0x89 */ { 2044, 18, 13, 18, 0, -12 }, +/* 0x8A */ { 2074, 10, 15, 12, 1, -14 }, +/* 0x8B */ { 2093, 2, 4, 4, 1, -6 }, +/* 0x8C */ { 2094, 10, 15, 12, 1, -14 }, +/* 0x8D */ { 2113, 9, 15, 11, 1, -14 }, +/* 0x8E */ { 2130, 10, 15, 11, 1, -14 }, +/* 0x8F */ { 2149, 10, 15, 11, 1, -14 }, +/* 0x90 */ { 2168, 0, 0, 0, 0, 0 }, +/* 0x91 */ { 2168, 2, 4, 4, 2, -12 }, +/* 0x92 */ { 2169, 2, 4, 4, 1, -12 }, +/* 0x93 */ { 2170, 5, 4, 7, 2, -12 }, +/* 0x94 */ { 2173, 5, 4, 7, 1, -12 }, +/* 0x95 */ { 2176, 4, 5, 7, 1, -8 }, +/* 0x96 */ { 2179, 7, 1, 9, 1, -4 }, +/* 0x97 */ { 2180, 16, 1, 18, 1, -4 }, +/* 0x98 */ { 2182, 0, 0, 0, 0, 0 }, +/* 0x99 */ { 2182, 18, 10, 18, 1, -13 }, +/* 0x9A */ { 2205, 8, 13, 9, 1, -12 }, +/* 0x9B */ { 2218, 2, 4, 5, 2, -6 }, +/* 0x9C */ { 2219, 8, 13, 9, 1, -12 }, +/* 0x9D */ { 2232, 6, 13, 8, 1, -12 }, +/* 0x9E */ { 2242, 7, 13, 9, 1, -12 }, +/* 0x9F */ { 2254, 7, 13, 9, 1, -12 }, +/* 0xA0 */ { 2266, 0, 0, 5, 0, 0 }, +/* 0xA1 */ { 2266, 5, 3, 6, 0, -12 }, +/* 0xA2 */ { 2268, 6, 2, 6, 0, -12 }, +/* 0xA3 */ { 2270, 9, 13, 11, 1, -12 }, +/* 0xA4 */ { 2285, 7, 6, 10, 2, -8 }, +/* 0xA5 */ { 2291, 12, 17, 12, 1, -12 }, +/* 0xA6 */ { 2317, 2, 17, 5, 2, -12 }, +/* 0xA7 */ { 2322, 9, 17, 10, 1, -12 }, +/* 0xA8 */ { 2342, 6, 1, 6, 0, -11 }, +/* 0xA9 */ { 2343, 14, 13, 14, 1, -12 }, +/* 0xAA */ { 2366, 10, 17, 12, 1, -12 }, +/* 0xAB */ { 2388, 7, 6, 9, 1, -7 }, +/* 0xAC */ { 2394, 9, 5, 11, 2, -5 }, +/* 0xAD */ { 2400, 0, 0, 0, 0, 0 }, +/* 0xAE */ { 2400, 14, 13, 14, 1, -12 }, +/* 0xAF */ { 2423, 10, 15, 11, 1, -14 }, +/* 0xB0 */ { 2442, 5, 5, 11, 3, -11 }, +/* 0xB1 */ { 2446, 9, 11, 11, 1, -10 }, +/* 0xB2 */ { 2459, 4, 4, 6, 1, 1 }, +/* 0xB3 */ { 2461, 4, 13, 5, 1, -12 }, +/* 0xB4 */ { 2468, 4, 3, 6, 2, -12 }, +/* 0xB5 */ { 2470, 9, 13, 10, 1, -9 }, +/* 0xB6 */ { 2485, 8, 16, 10, 2, -12 }, +/* 0xB7 */ { 2501, 3, 1, 5, 1, -4 }, +/* 0xB8 */ { 2502, 5, 4, 6, 1, 1 }, +/* 0xB9 */ { 2505, 10, 14, 10, 1, -9 }, +/* 0xBA */ { 2523, 8, 14, 9, 1, -9 }, +/* 0xBB */ { 2537, 7, 6, 9, 1, -7 }, +/* 0xBC */ { 2543, 8, 13, 10, 1, -12 }, +/* 0xBD */ { 2556, 6, 3, 6, 0, -12 }, +/* 0xBE */ { 2559, 5, 13, 7, 1, -12 }, +/* 0xBF */ { 2568, 7, 12, 9, 1, -11 }, +/* 0xC0 */ { 2579, 12, 15, 13, 1, -14 }, +/* 0xC1 */ { 2602, 10, 14, 12, 1, -13 }, +/* 0xC2 */ { 2620, 10, 14, 12, 1, -13 }, +/* 0xC3 */ { 2638, 10, 14, 12, 1, -13 }, +/* 0xC4 */ { 2656, 10, 14, 12, 1, -13 }, +/* 0xC5 */ { 2674, 8, 14, 10, 1, -13 }, +/* 0xC6 */ { 2688, 11, 15, 13, 1, -14 }, +/* 0xC7 */ { 2709, 11, 17, 13, 1, -12 }, +/* 0xC8 */ { 2733, 11, 15, 13, 1, -14 }, +/* 0xC9 */ { 2754, 9, 14, 11, 1, -13 }, +/* 0xCA */ { 2770, 11, 17, 12, 1, -12 }, +/* 0xCB */ { 2794, 9, 14, 11, 1, -13 }, +/* 0xCC */ { 2810, 9, 15, 11, 1, -14 }, +/* 0xCD */ { 2827, 3, 14, 5, 1, -13 }, +/* 0xCE */ { 2833, 5, 14, 5, 0, -13 }, +/* 0xCF */ { 2842, 10, 15, 13, 2, -14 }, +/* 0xD0 */ { 2861, 11, 13, 13, 1, -12 }, +/* 0xD1 */ { 2879, 11, 14, 13, 1, -13 }, +/* 0xD2 */ { 2899, 11, 14, 13, 1, -13 }, +/* 0xD3 */ { 2919, 12, 15, 13, 1, -14 }, +/* 0xD4 */ { 2942, 12, 15, 13, 1, -14 }, +/* 0xD5 */ { 2965, 12, 15, 13, 1, -14 }, +/* 0xD6 */ { 2988, 12, 15, 13, 1, -14 }, +/* 0xD7 */ { 3011, 7, 7, 11, 2, -7 }, +/* 0xD8 */ { 3018, 12, 15, 13, 1, -14 }, +/* 0xD9 */ { 3041, 11, 14, 13, 1, -13 }, +/* 0xDA */ { 3061, 11, 14, 13, 1, -13 }, +/* 0xDB */ { 3081, 11, 14, 13, 1, -13 }, +/* 0xDC */ { 3101, 11, 14, 13, 1, -13 }, +/* 0xDD */ { 3121, 12, 14, 12, 0, -13 }, +/* 0xDE */ { 3142, 9, 17, 11, 1, -12 }, +/* 0xDF */ { 3162, 9, 13, 11, 1, -12 }, +/* 0xE0 */ { 3177, 5, 13, 6, 1, -12 }, +/* 0xE1 */ { 3186, 9, 13, 10, 1, -12 }, +/* 0xE2 */ { 3201, 9, 13, 10, 1, -12 }, +/* 0xE3 */ { 3216, 9, 13, 10, 1, -12 }, +/* 0xE4 */ { 3231, 9, 12, 10, 1, -11 }, +/* 0xE5 */ { 3245, 3, 15, 4, 0, -14 }, +/* 0xE6 */ { 3251, 8, 13, 9, 1, -12 }, +/* 0xE7 */ { 3264, 8, 14, 9, 1, -9 }, +/* 0xE8 */ { 3278, 8, 13, 9, 1, -12 }, +/* 0xE9 */ { 3291, 8, 13, 10, 1, -12 }, +/* 0xEA */ { 3304, 8, 14, 10, 1, -9 }, +/* 0xEB */ { 3318, 8, 12, 10, 1, -11 }, +/* 0xEC */ { 3330, 8, 13, 10, 1, -12 }, +/* 0xED */ { 3343, 3, 13, 4, 1, -12 }, +/* 0xEE */ { 3348, 4, 13, 5, 0, -12 }, +/* 0xEF */ { 3355, 12, 13, 12, 1, -12 }, +/* 0xF0 */ { 3375, 9, 13, 10, 1, -12 }, +/* 0xF1 */ { 3390, 8, 13, 10, 1, -12 }, +/* 0xF2 */ { 3403, 8, 13, 10, 1, -12 }, +/* 0xF3 */ { 3416, 8, 13, 10, 1, -12 }, +/* 0xF4 */ { 3429, 8, 13, 10, 1, -12 }, +/* 0xF5 */ { 3442, 8, 13, 10, 1, -12 }, +/* 0xF6 */ { 3455, 8, 12, 10, 1, -11 }, +/* 0xF7 */ { 3467, 9, 8, 11, 1, -7 }, +/* 0xF8 */ { 3476, 5, 13, 6, 1, -12 }, +/* 0xF9 */ { 3485, 8, 13, 10, 1, -12 }, +/* 0xFA */ { 3498, 8, 13, 10, 1, -12 }, +/* 0xFB */ { 3511, 8, 13, 10, 1, -12 }, +/* 0xFC */ { 3524, 8, 12, 10, 1, -11 }, +/* 0xFD */ { 3536, 8, 17, 9, 0, -12 }, +/* 0xFE */ { 3553, 5, 16, 5, 1, -11 }, +/* 0xFF */ { 3563, 2, 1, 6, 2, -11 }, }; -const GFXfont FreeSans9pt_Win1250 PROGMEM = {(uint8_t *)FreeSans9pt_Win1250Bitmaps, (GFXglyph *)FreeSans9pt_Win1250Glyphs, 0x20, - 0xFF, 21}; +const GFXfont FreeSans9pt_Win1250 PROGMEM = { +(uint8_t*)FreeSans9pt_Win1250Bitmaps, +(GFXglyph*)FreeSans9pt_Win1250Glyphs, +0x01, 0xFF, 21 +}; diff --git a/src/graphics/niche/Fonts/FreeSans9pt_Win1251.h b/src/graphics/niche/Fonts/FreeSans9pt_Win1251.h index 82857cb91..b1511d996 100644 --- a/src/graphics/niche/Fonts/FreeSans9pt_Win1251.h +++ b/src/graphics/niche/Fonts/FreeSans9pt_Win1251.h @@ -1,493 +1,527 @@ +// trunk-ignore-all(clang-format) #pragma once +/* PROPERTIES + +FONT_NAME FreeSans9pt_Win1251 +*/ const uint8_t FreeSans9pt_Win1251Bitmaps[] PROGMEM = { - /* ' ' 0x20 */ - 0xFF, 0xFF, 0xF0, 0xC0, /* '!' 0x21 */ - 0xDE, 0xF7, 0x20, /* '"' 0x22 */ - 0x09, 0x86, 0x41, 0x91, 0xFF, 0x13, 0x04, 0xC3, 0x20, 0xC8, 0xFF, 0x89, 0x82, 0x61, 0x90, /* '#' 0x23 */ - 0x10, 0x1F, 0x14, 0xDA, 0x3D, 0x1E, 0x83, 0x40, 0x78, 0x17, 0x08, 0xF4, 0x7A, 0x35, 0x33, 0xF0, 0x40, 0x20, /* '$' 0x24 */ - 0x38, 0x10, 0xEC, 0x20, 0xC6, 0x20, 0xC6, 0x40, 0xC6, 0x40, 0x6C, 0x80, 0x39, 0x00, 0x01, 0x3C, 0x02, 0x77, 0x02, 0x63, 0x04, - 0x63, 0x04, 0x77, 0x08, 0x3C, /* '%' 0x25 */ - 0x0E, 0x0C, 0xC3, 0x30, 0xCC, 0x1E, 0x03, 0x03, 0xC1, 0x9B, 0xC2, 0xF0, 0xEC, 0x19, 0x8F, 0x3C, 0x40, /* '&' 0x26 */ - 0xFE, /* ''' 0x27 */ - 0x13, 0x26, 0x6C, 0xCC, 0xCC, 0xC4, 0x66, 0x23, 0x10, /* '(' 0x28 */ - 0x8C, 0x46, 0x63, 0x33, 0x33, 0x32, 0x66, 0x4C, 0x80, /* ')' 0x29 */ - 0x25, 0x7E, 0xA5, 0x00, /* '*' 0x2A */ - 0x30, 0xC3, 0x3F, 0x30, 0xC3, 0x0C, /* '+' 0x2B */ - 0xD6, /* ',' 0x2C */ - 0xF0, /* '-' 0x2D */ - 0xC0, /* '.' 0x2E */ - 0x08, 0x44, 0x21, 0x10, 0x84, 0x42, 0x11, 0x08, 0x00, /* '/' 0x2F */ - 0x3C, 0x66, 0x42, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x42, 0x66, 0x3C, /* '0' 0x30 */ - 0x11, 0x3F, 0x33, 0x33, 0x33, 0x33, 0x30, /* '1' 0x31 */ - 0x3E, 0x31, 0xB0, 0x78, 0x30, 0x18, 0x1C, 0x1C, 0x1C, 0x18, 0x18, 0x10, 0x08, 0x07, 0xF8, /* '2' 0x32 */ - 0x3C, 0x66, 0xC3, 0xC3, 0x03, 0x06, 0x1C, 0x07, 0x03, 0xC3, 0xC3, 0x66, 0x3C, /* '3' 0x33 */ - 0x0C, 0x18, 0x71, 0x62, 0xC9, 0xA3, 0x46, 0xFE, 0x18, 0x30, 0x60, 0xC0, /* '4' 0x34 */ - 0x7F, 0x20, 0x10, 0x08, 0x08, 0x07, 0xF3, 0x8C, 0x03, 0x01, 0x80, 0xF0, 0x6C, 0x63, 0xE0, /* '5' 0x35 */ - 0x1E, 0x31, 0x98, 0x78, 0x0C, 0x06, 0xF3, 0x8D, 0x83, 0xC1, 0xE0, 0xD0, 0x6C, 0x63, 0xE0, /* '6' 0x36 */ - 0xFF, 0x03, 0x02, 0x06, 0x04, 0x0C, 0x08, 0x18, 0x18, 0x18, 0x10, 0x30, 0x30, /* '7' 0x37 */ - 0x3E, 0x31, 0xB0, 0x78, 0x3C, 0x1B, 0x18, 0xF8, 0xC6, 0xC1, 0xE0, 0xF0, 0x6C, 0x63, 0xE0, /* '8' 0x38 */ - 0x3C, 0x66, 0xC2, 0xC3, 0xC3, 0xC3, 0x67, 0x3B, 0x03, 0x03, 0xC2, 0x66, 0x3C, /* '9' 0x39 */ - 0xC0, 0x00, 0x30, /* ':' 0x3A */ - 0xC0, 0x00, 0x00, 0x64, 0xA0, /* ';' 0x3B */ - 0x00, 0x81, 0xC7, 0x8E, 0x0C, 0x07, 0x80, 0x70, 0x0E, 0x01, 0x80, /* '<' 0x3C */ - 0xFF, 0x80, 0x00, 0x1F, 0xF0, /* '=' 0x3D */ - 0xE0, 0x1C, 0x03, 0x80, 0x30, 0x70, 0xE3, 0x81, 0x00, /* '>' 0x3E */ - 0x3E, 0x31, 0xB0, 0x78, 0x30, 0x18, 0x18, 0x38, 0x18, 0x18, 0x0C, 0x00, 0x00, 0x01, 0x80, /* '?' 0x3F */ - 0x03, 0xF0, 0x06, 0x0E, 0x06, 0x01, 0x86, 0x00, 0x66, 0x1D, 0xBB, 0x31, 0xCF, 0x18, 0xC7, 0x98, 0x63, 0xCC, 0x31, 0xE6, 0x11, - 0xB3, 0x99, 0xCC, 0xF7, 0x86, 0x00, 0x01, 0x80, 0x00, 0x70, 0x40, 0x0F, 0xE0, /* '@' 0x40 */ - 0x06, 0x00, 0xF0, 0x0F, 0x00, 0x90, 0x19, 0x81, 0x98, 0x10, 0x83, 0x0C, 0x3F, 0xC2, 0x04, 0x60, 0x66, 0x06, 0xC0, - 0x30, /* 'A' 0x41 */ - 0xFF, 0x18, 0x33, 0x03, 0x60, 0x6C, 0x0D, 0x83, 0x3F, 0xC6, 0x06, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x6F, 0xF8, /* 'B' 0x42 */ - 0x1F, 0x86, 0x19, 0x81, 0xA0, 0x3C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xC0, 0x68, 0x0D, 0x83, 0x18, 0x61, 0xF0, /* 'C' 0x43 */ - 0xFF, 0x18, 0x33, 0x03, 0x60, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x03, 0x60, 0xCF, 0xF0, /* 'D' 0x44 */ - 0xFF, 0xE0, 0x30, 0x18, 0x0C, 0x06, 0x03, 0xFD, 0x80, 0xC0, 0x60, 0x30, 0x18, 0x0F, 0xF8, /* 'E' 0x45 */ - 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFE, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, /* 'F' 0x46 */ - 0x0F, 0x83, 0x0E, 0x60, 0x66, 0x03, 0xC0, 0x0C, 0x00, 0xC1, 0xFC, 0x03, 0xC0, 0x36, 0x03, 0x60, 0x73, 0x0F, 0x0F, - 0x10, /* 'G' 0x47 */ - 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xFF, 0xFE, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x06, /* 'H' 0x48 */ - 0xFF, 0xFF, 0xFF, 0xC0, /* 'I' 0x49 */ - 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x83, 0x07, 0x8F, 0x1E, 0x27, 0x80, /* 'J' 0x4A */ - 0xC0, 0xF0, 0x6C, 0x33, 0x18, 0xCC, 0x37, 0x0F, 0xC3, 0x98, 0xC3, 0x30, 0xCC, 0x1B, 0x03, 0xC0, 0xC0, /* 'K' 0x4B */ - 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, /* 'L' 0x4C */ - 0xE0, 0x3F, 0x01, 0xFC, 0x1F, 0xE0, 0xFD, 0x05, 0xEC, 0x6F, 0x63, 0x79, 0x13, 0xCD, 0x9E, 0x6C, 0xF1, 0x47, 0x8E, 0x3C, 0x71, - 0x80, /* 'M' 0x4D */ - 0xE0, 0x7C, 0x0F, 0xC1, 0xE8, 0x3D, 0x87, 0x98, 0xF1, 0x1E, 0x33, 0xC3, 0x78, 0x6F, 0x07, 0xE0, 0x7C, 0x0E, /* 'N' 0x4E */ - 0x0F, 0x81, 0x83, 0x18, 0x0C, 0xC0, 0x6C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1B, 0x01, 0x98, 0x0C, 0x60, 0xC0, 0xF8, - 0x00, /* 'O' 0x4F */ - 0xFF, 0x30, 0x6C, 0x0F, 0x03, 0xC0, 0xF0, 0x6F, 0xF3, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x00, /* 'P' 0x50 */ - 0x0F, 0x81, 0x83, 0x18, 0x0C, 0xC0, 0x6C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1B, 0x01, 0x98, 0x6C, 0x60, 0xC0, 0xFB, - 0x00, 0x08, /* 'Q' 0x51 */ - 0xFF, 0x8C, 0x0E, 0xC0, 0x6C, 0x06, 0xC0, 0x6C, 0x0C, 0xFF, 0x8C, 0x0E, 0xC0, 0x6C, 0x06, 0xC0, 0x6C, 0x06, 0xC0, - 0x70, /* 'R' 0x52 */ - 0x3F, 0x18, 0x6C, 0x0F, 0x03, 0xC0, 0x1E, 0x01, 0xF0, 0x0E, 0x00, 0xF0, 0x3C, 0x0D, 0x86, 0x3F, 0x00, /* 'S' 0x53 */ - 0xFF, 0x86, 0x03, 0x01, 0x80, 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x80, 0xC0, /* 'T' 0x54 */ - 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xB0, 0x61, 0xF0, /* 'U' 0x55 */ - 0xC0, 0x6C, 0x0D, 0x81, 0x10, 0x63, 0x0C, 0x61, 0x04, 0x60, 0xCC, 0x19, 0x01, 0x60, 0x3C, 0x07, 0x00, 0x60, /* 'V' 0x56 */ - 0xC1, 0x81, 0x61, 0xC3, 0x61, 0xC3, 0x61, 0x43, 0x62, 0x62, 0x22, 0x66, 0x32, 0x26, 0x36, 0x26, 0x14, 0x34, 0x14, 0x34, 0x1C, - 0x1C, 0x18, 0x1C, 0x08, 0x18, /* 'W' 0x57 */ - 0xC0, 0xD8, 0x66, 0x18, 0xCC, 0x1E, 0x07, 0x00, 0xC0, 0x78, 0x32, 0x0C, 0xC6, 0x1B, 0x07, 0xC0, 0xC0, /* 'X' 0x58 */ - 0xC0, 0x36, 0x06, 0x30, 0xC3, 0x0C, 0x19, 0x81, 0xD8, 0x0F, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, - 0x00, /* 'Y' 0x59 */ - 0xFF, 0xC0, 0x60, 0x30, 0x0C, 0x06, 0x03, 0x01, 0xC0, 0x60, 0x30, 0x18, 0x06, 0x03, 0x00, 0xFF, 0xC0, /* 'Z' 0x5A */ - 0xFB, 0x6D, 0xB6, 0xDB, 0x6D, 0xB6, 0xE0, /* '[' 0x5B */ - 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x80, /* '\' 0x5C */ - 0xED, 0xB6, 0xDB, 0x6D, 0xB6, 0xDB, 0xE0, /* ']' 0x5D */ - 0x30, 0x60, 0xA2, 0x44, 0xD8, 0xA1, 0x80, /* '^' 0x5E */ - 0xFF, 0xC0, /* '_' 0x5F */ - 0xC6, 0x30, /* '`' 0x60 */ - 0x7E, 0x71, 0xB0, 0xC0, 0x60, 0xF3, 0xDB, 0x0D, 0x86, 0xC7, 0x3D, 0xC0, /* 'a' 0x61 */ - 0xC0, 0x60, 0x30, 0x1B, 0xCE, 0x36, 0x0F, 0x07, 0x83, 0xC1, 0xE0, 0xF0, 0x7C, 0x6D, 0xE0, /* 'b' 0x62 */ - 0x3C, 0x66, 0xC3, 0xC0, 0xC0, 0xC0, 0xC0, 0xC3, 0x66, 0x3C, /* 'c' 0x63 */ - 0x03, 0x03, 0x03, 0x3B, 0x67, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x67, 0x3B, /* 'd' 0x64 */ - 0x3C, 0x66, 0xC3, 0xC3, 0xFF, 0xC0, 0xC0, 0xC3, 0x66, 0x3C, /* 'e' 0x65 */ - 0x36, 0x6F, 0x66, 0x66, 0x66, 0x66, 0x60, /* 'f' 0x66 */ - 0x3B, 0x67, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x67, 0x3B, 0x03, 0x03, 0xC6, 0x7C, /* 'g' 0x67 */ - 0xC0, 0xC0, 0xC0, 0xDE, 0xE3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, /* 'h' 0x68 */ - 0xC3, 0xFF, 0xFF, 0xC0, /* 'i' 0x69 */ - 0x30, 0x03, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0xE0, /* 'j' 0x6A */ - 0xC0, 0xC0, 0xC0, 0xC2, 0xC4, 0xCC, 0xD8, 0xF8, 0xEC, 0xC4, 0xC6, 0xC3, 0xC3, /* 'k' 0x6B */ - 0xFF, 0xFF, 0xFF, 0xC0, /* 'l' 0x6C */ - 0xDE, 0xF7, 0x1C, 0xF0, 0xC7, 0x86, 0x3C, 0x31, 0xE1, 0x8F, 0x0C, 0x78, 0x63, 0xC3, 0x1E, 0x18, 0xC0, /* 'm' 0x6D */ - 0xDE, 0xE3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, /* 'n' 0x6E */ - 0x3C, 0x66, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x66, 0x3C, /* 'o' 0x6F */ - 0xDE, 0x71, 0xB0, 0x78, 0x3C, 0x1E, 0x0F, 0x07, 0x83, 0xE3, 0x6F, 0x30, 0x18, 0x0C, 0x00, /* 'p' 0x70 */ - 0x3B, 0x67, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x67, 0x3B, 0x03, 0x03, 0x03, /* 'q' 0x71 */ - 0xDF, 0x31, 0x8C, 0x63, 0x18, 0xC6, 0x00, /* 'r' 0x72 */ - 0x3E, 0xE3, 0xC0, 0xC0, 0xE0, 0x3C, 0x07, 0xC3, 0xE3, 0x7E, /* 's' 0x73 */ - 0x66, 0xF6, 0x66, 0x66, 0x66, 0x67, /* 't' 0x74 */ - 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC7, 0x7B, /* 'u' 0x75 */ - 0xC1, 0xA0, 0x98, 0xCC, 0x42, 0x21, 0xB0, 0xD0, 0x28, 0x1C, 0x0C, 0x00, /* 'v' 0x76 */ - 0xC6, 0x1E, 0x38, 0x91, 0xC4, 0xCA, 0x66, 0xD3, 0x16, 0xD0, 0xA6, 0x87, 0x1C, 0x38, 0xC0, 0xC6, 0x00, /* 'w' 0x77 */ - 0x87, 0x89, 0xB1, 0xC3, 0x07, 0x1E, 0x26, 0xC5, 0x0C, /* 'x' 0x78 */ - 0xC1, 0x43, 0x63, 0x62, 0x26, 0x36, 0x34, 0x1C, 0x1C, 0x18, 0x18, 0x18, 0x10, 0x60, /* 'y' 0x79 */ - 0xFE, 0x0C, 0x30, 0xC1, 0x86, 0x18, 0x20, 0xC1, 0xFC, /* 'z' 0x7A */ - 0x36, 0x66, 0x66, 0x6E, 0xCE, 0x66, 0x66, 0x66, 0x30, /* '{' 0x7B */ - 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, /* '|' 0x7C */ - 0xC6, 0x66, 0x66, 0x67, 0x37, 0x66, 0x66, 0x66, 0xC0, /* '}' 0x7D */ - 0x61, 0x24, 0x38, /* '~' 0x7E */ - 0xFF, 0xFC, 0x00, 0x63, 0xE3, 0x31, 0x99, 0x04, 0xC8, 0x66, 0x06, 0x30, 0x61, 0x83, 0x0C, 0x18, 0x60, 0x03, 0x06, 0x18, 0x00, - 0xFF, 0xFC, /* 0x7F */ - 0xFF, 0x01, 0x80, 0x18, 0x01, 0x80, 0x18, 0x01, 0xFE, 0x18, 0x31, 0x83, 0x18, 0x31, 0x83, 0x18, 0x31, 0x83, 0x18, 0x30, 0x03, - 0x00, 0x30, 0x0E, /* 0x80 */ - 0x0C, 0x18, 0x00, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, /* 0x81 */ - 0xDC, /* 0x82 */ - 0x18, 0x89, 0xFC, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x00, /* 0x83 */ - 0xDA, 0x76, /* 0x84 */ - 0xCC, 0xC0, /* 0x85 */ - 0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, /* 0x86 */ - 0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18, /* 0x87 */ - 0x07, 0xC6, 0x13, 0x00, 0xC0, 0x60, 0x3F, 0xE6, 0x03, 0xFC, 0x60, 0x0C, 0x03, 0x00, 0x61, 0x07, 0xC0, /* 0x88 */ - 0x70, 0x80, 0x22, 0x20, 0x08, 0x90, 0x02, 0x24, 0x00, 0x72, 0x00, 0x00, 0x80, 0x00, 0x40, 0x00, 0x10, 0x00, 0x09, 0xC7, 0x84, - 0x8B, 0x31, 0x22, 0x84, 0x88, 0xB3, 0x21, 0xC7, 0x80, /* 0x89 */ - 0x3F, 0x80, 0x18, 0xC0, 0x0C, 0x60, 0x06, 0x30, 0x03, 0x18, 0x01, 0x8C, 0x00, 0xC7, 0xF8, 0x63, 0x06, 0x31, 0x81, 0x90, 0xC0, - 0xD8, 0x60, 0x6C, 0x30, 0x6C, 0x1F, 0xE0, /* 0x8A */ - 0x69, /* 0x8B */ - 0xC0, 0xC0, 0x60, 0x60, 0x30, 0x30, 0x18, 0x18, 0x0C, 0x0C, 0x06, 0x06, 0x03, 0xFF, 0xF9, 0x81, 0x86, 0xC0, 0xC1, 0xE0, 0x60, - 0xF0, 0x30, 0x78, 0x18, 0x6C, 0x0F, 0xE0, /* 0x8C */ - 0x0C, 0x06, 0x0C, 0x1B, 0x0C, 0xC6, 0x33, 0x0D, 0x83, 0xC0, 0xF0, 0x3E, 0x0D, 0xC3, 0x38, 0xC7, 0x30, 0xEC, 0x1C, /* 0x8D */ - 0xFF, 0x01, 0x80, 0x18, 0x01, 0x80, 0x18, 0x01, 0xFE, 0x18, 0x31, 0x83, 0x18, 0x31, 0x83, 0x18, 0x31, 0x83, 0x18, - 0x30, /* 0x8E */ - 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3F, 0xFE, 0x0C, 0x01, - 0x80, /* 0x8F */ - 0x60, 0x7C, 0x18, 0x0D, 0xE7, 0x1B, 0x0D, 0x86, 0xC3, 0x61, 0xB0, 0xD8, 0x6C, 0x36, 0x18, 0x18, 0x08, 0x08, /* 0x90 */ - 0x6B, /* 0x91 */ - 0xD6, /* 0x92 */ - 0x4C, 0xA5, 0xB0, /* 0x93 */ - 0xDA, 0x53, 0x20, /* 0x94 */ - 0x6F, 0xFF, 0x60, /* 0x95 */ - 0xFE, /* 0x96 */ - 0xFF, 0xFF, /* 0x97 */ - /* 0x98 */ - 0xFC, 0xE1, 0xCC, 0x38, 0x73, 0x0E, 0x1C, 0xC3, 0x8F, 0x30, 0xD2, 0xCC, 0x34, 0xB3, 0x0D, 0x6C, 0xC3, 0x53, 0x30, 0xCC, 0xCC, - 0x33, 0x30, /* 0x99 */ - 0x7E, 0x03, 0x30, 0x19, 0x80, 0xCC, 0x06, 0x60, 0x33, 0xF9, 0x98, 0x6C, 0xC3, 0x46, 0x1E, 0x3F, 0x80, /* 0x9A */ - 0x96, /* 0x9B */ - 0xC3, 0x03, 0x0C, 0x0C, 0x30, 0x30, 0xC0, 0xC3, 0x03, 0xFF, 0xEC, 0x30, 0xF0, 0xC3, 0xC3, 0x0F, 0x0F, 0xE0, /* 0x9C */ - 0x0C, 0x30, 0x46, 0x3C, 0xDB, 0x34, 0x70, 0xF1, 0xB3, 0x36, 0x3C, 0x20, /* 0x9D */ - 0x60, 0x7C, 0x18, 0x0D, 0xE7, 0x3B, 0x0D, 0x86, 0xC3, 0x61, 0xB0, 0xD8, 0x6C, 0x36, 0x18, /* 0x9E */ - 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xFF, 0x18, 0x18, /* 0x9F */ - /* 0xA0 */ - 0x21, 0x07, 0x8C, 0x0F, 0x06, 0x61, 0x98, 0xC3, 0x30, 0xD8, 0x1E, 0x07, 0x00, 0xC0, 0x60, 0x18, 0x0C, 0x03, 0x00, /* 0xA1 */ - 0x66, 0x18, 0xC1, 0x43, 0x63, 0x62, 0x26, 0x36, 0x34, 0x1C, 0x1C, 0x18, 0x18, 0x18, 0x10, 0x60, /* 0xA2 */ - 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x83, 0x07, 0x8F, 0x1E, 0x27, 0x80, /* 0xA3 */ - 0xFF, 0xDF, 0x1E, 0x3E, 0xFF, 0xC0, /* 0xA4 */ - 0x00, 0xC0, 0x3F, 0xFF, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x00, /* 0xA5 */ - 0xFF, 0xFC, 0x0F, 0xFF, 0xC0, /* 0xA6 */ - 0x0C, 0x09, 0x0C, 0xC6, 0x63, 0x81, 0xE3, 0x19, 0x87, 0xE1, 0xB8, 0xC6, 0x41, 0xC0, 0x73, 0x19, 0x8C, 0x66, 0x1E, - 0x00, /* 0xA7 */ - 0x33, 0x00, 0x3F, 0xF8, 0x0C, 0x06, 0x03, 0x01, 0x80, 0xFF, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0xFE, /* 0xA8 */ - 0x0F, 0xC0, 0x61, 0x87, 0x03, 0x9B, 0xC6, 0xD9, 0x8F, 0x60, 0x3D, 0x00, 0xF4, 0x03, 0xD8, 0x0D, 0xE6, 0x67, 0xF3, 0x86, 0x18, - 0x0F, 0xC0, /* 0xA9 */ - 0x1F, 0x86, 0x19, 0x81, 0xB0, 0x3C, 0x01, 0x80, 0x3F, 0xC6, 0x00, 0xC0, 0x68, 0x0D, 0x83, 0x18, 0x61, 0xF0, /* 0xAA */ - 0x22, 0xCF, 0x26, 0x46, 0x64, 0x40, /* 0xAB */ - 0xFF, 0x80, 0xC0, 0x60, 0x30, 0x18, /* 0xAC */ - /* 0xAD */ - 0x0F, 0xC0, 0x61, 0x87, 0x03, 0x9F, 0xE6, 0xD0, 0x8F, 0x42, 0x3D, 0xF0, 0xF4, 0x23, 0xD0, 0x8D, 0xC2, 0x67, 0x0B, 0x86, 0x18, - 0x0F, 0xC0, /* 0xAE */ - 0xCC, 0x03, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x00, /* 0xAF */ - 0x74, 0x63, 0x17, 0x00, /* 0xB0 */ - 0x0C, 0x06, 0x03, 0x07, 0xE0, 0xC0, 0x60, 0x30, 0x18, 0x00, 0x00, 0x3F, 0xE0, /* 0xB1 */ - 0xFF, 0xFF, 0xFF, 0xC0, /* 0xB2 */ - 0xC3, 0xFF, 0xFF, 0xC0, /* 0xB3 */ - 0x0C, 0x3F, 0xF0, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, /* 0xB4 */ - 0xC3, 0x61, 0xB0, 0xD8, 0x6C, 0x36, 0x1B, 0x0D, 0x86, 0xE7, 0x7D, 0xF0, 0x18, 0x0C, 0x00, /* 0xB5 */ - 0x3F, 0x7E, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0x72, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, /* 0xB6 */ - 0xE0, /* 0xB7 */ - 0x66, 0x00, 0x3C, 0x66, 0xC3, 0xC3, 0xFF, 0xC0, 0xC0, 0xC3, 0x66, 0x3C, /* 0xB8 */ - 0xC1, 0x81, 0x83, 0x03, 0x86, 0x05, 0x0C, 0xEB, 0x1A, 0x32, 0x34, 0x66, 0x68, 0xC4, 0xD1, 0x8D, 0xB3, 0x0B, 0x3A, 0x1E, 0x04, - 0x1C, 0x08, 0x1B, 0xC0, /* 0xB9 */ - 0x3C, 0x46, 0xC3, 0x80, 0xF8, 0x80, 0x80, 0xC3, 0x46, 0x3C, /* 0xBA */ - 0x89, 0x98, 0x99, 0x3C, 0xD1, 0x00, /* 0xBB */ - 0x30, 0x03, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0xE0, /* 0xBC */ - 0x3F, 0x18, 0x6C, 0x0F, 0x03, 0xC0, 0x1E, 0x01, 0xF0, 0x0E, 0x00, 0xF0, 0x3C, 0x0D, 0x86, 0x3F, 0x00, /* 0xBD */ - 0x3E, 0xE3, 0xC0, 0xC0, 0x60, 0x3C, 0x07, 0xC3, 0xE3, 0x7E, /* 0xBE */ - 0xCC, 0x03, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, /* 0xBF */ - 0x06, 0x00, 0xF0, 0x0F, 0x00, 0x90, 0x19, 0x81, 0x98, 0x10, 0x83, 0x0C, 0x3F, 0xC2, 0x04, 0x60, 0x66, 0x06, 0xC0, - 0x30, /* 0xC0 */ - 0xFF, 0x18, 0x03, 0x00, 0x60, 0x0C, 0x01, 0x80, 0x3F, 0xE6, 0x06, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x6F, 0xF8, /* 0xC1 */ - 0xFF, 0x18, 0x33, 0x03, 0x60, 0x6C, 0x0D, 0x83, 0x3F, 0xC6, 0x06, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x6F, 0xF8, /* 0xC2 */ - 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, /* 0xC3 */ - 0x1F, 0xF0, 0x60, 0xC1, 0x83, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x83, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x03, 0x0C, 0x0C, - 0xFF, 0xFF, 0x00, 0x3C, 0x00, 0xF0, 0x03, /* 0xC4 */ - 0xFF, 0xE0, 0x30, 0x18, 0x0C, 0x06, 0x03, 0xFD, 0x80, 0xC0, 0x60, 0x30, 0x18, 0x0F, 0xF8, /* 0xC5 */ - 0x61, 0x86, 0x31, 0x8C, 0x19, 0x98, 0x19, 0x98, 0x0D, 0xB0, 0x07, 0xE0, 0x03, 0xC0, 0x07, 0xE0, 0x0D, 0xB0, 0x19, 0x98, 0x31, - 0x8C, 0x61, 0x86, 0xC1, 0x83, /* 0xC6 */ - 0x3F, 0x18, 0x6C, 0x0F, 0x03, 0x00, 0xC0, 0x60, 0xF0, 0x06, 0x00, 0xF0, 0x3C, 0x0D, 0x86, 0x3F, 0x00, /* 0xC7 */ - 0xC0, 0xF8, 0x1F, 0x07, 0xE0, 0xBC, 0x37, 0x8C, 0xF1, 0x1E, 0x63, 0xD8, 0x7A, 0x0F, 0xC1, 0xF0, 0x3E, 0x06, /* 0xC8 */ - 0x11, 0x03, 0xE0, 0x00, 0x60, 0x7C, 0x0F, 0x83, 0xF0, 0x5E, 0x1B, 0xC6, 0x78, 0x8F, 0x31, 0xEC, 0x3D, 0x07, 0xE0, 0xF8, 0x1F, - 0x03, /* 0xC9 */ - 0xC1, 0xB0, 0xCC, 0x63, 0x30, 0xD8, 0x3C, 0x0F, 0x03, 0xE0, 0xDC, 0x33, 0x8C, 0x73, 0x0E, 0xC1, 0xC0, /* 0xCA */ - 0x3F, 0xCC, 0x33, 0x0C, 0xC3, 0x30, 0xCC, 0x33, 0x0C, 0xC3, 0x30, 0xC8, 0x36, 0x0D, 0x83, 0xC0, 0xC0, /* 0xCB */ - 0xE0, 0x3F, 0x01, 0xFC, 0x1F, 0xE0, 0xFD, 0x05, 0xEC, 0x6F, 0x63, 0x79, 0x13, 0xCD, 0x9E, 0x6C, 0xF1, 0x47, 0x8E, 0x3C, 0x71, - 0x80, /* 0xCC */ - 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xFF, 0xFE, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x06, /* 0xCD */ - 0x0F, 0x81, 0x83, 0x18, 0x0C, 0xC0, 0x6C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1B, 0x01, 0x98, 0x0C, 0x60, 0xC0, 0xF8, - 0x00, /* 0xCE */ - 0xFF, 0xF8, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x06, /* 0xCF */ - 0xFF, 0x30, 0x6C, 0x0F, 0x03, 0xC0, 0xF0, 0x6F, 0xF3, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x00, /* 0xD0 */ - 0x1F, 0x86, 0x19, 0x81, 0xA0, 0x3C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xC0, 0x68, 0x0D, 0x83, 0x18, 0x61, 0xF0, /* 0xD1 */ - 0xFF, 0x86, 0x03, 0x01, 0x80, 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x80, 0xC0, /* 0xD2 */ - 0xC0, 0xF0, 0x66, 0x19, 0x8C, 0x33, 0x0D, 0x81, 0xE0, 0x70, 0x0C, 0x06, 0x01, 0x80, 0xC0, 0x30, 0x00, /* 0xD3 */ - 0x03, 0x00, 0x0C, 0x01, 0xFE, 0x1C, 0xCE, 0xE3, 0x1F, 0x0C, 0x3C, 0x30, 0xF0, 0xC3, 0xE3, 0x1D, 0xCC, 0xE3, 0xFF, 0x00, 0xC0, - 0x03, 0x00, /* 0xD4 */ - 0xC0, 0xD8, 0x66, 0x18, 0xCC, 0x1E, 0x07, 0x00, 0xC0, 0x78, 0x32, 0x0C, 0xC6, 0x1B, 0x07, 0xC0, 0xC0, /* 0xD5 */ - 0xC0, 0x66, 0x03, 0x30, 0x19, 0x80, 0xCC, 0x06, 0x60, 0x33, 0x01, 0x98, 0x0C, 0xC0, 0x66, 0x03, 0x30, 0x19, 0x80, 0xCF, 0xFF, - 0x80, 0x0C, 0x00, 0x60, /* 0xD6 */ - 0xC1, 0xE0, 0xF0, 0x78, 0x3C, 0x1E, 0x0F, 0x06, 0xFF, 0x01, 0x80, 0xC0, 0x60, 0x30, 0x18, /* 0xD7 */ - 0xC3, 0x1E, 0x18, 0xF0, 0xC7, 0x86, 0x3C, 0x31, 0xE1, 0x8F, 0x0C, 0x78, 0x63, 0xC3, 0x1E, 0x18, 0xF0, 0xC7, 0x86, 0x3F, 0xFF, - 0x80, /* 0xD8 */ - 0xC3, 0x19, 0x86, 0x33, 0x0C, 0x66, 0x18, 0xCC, 0x31, 0x98, 0x63, 0x30, 0xC6, 0x61, 0x8C, 0xC3, 0x19, 0x86, 0x33, 0x0C, 0x66, - 0x18, 0xCF, 0xFF, 0xE0, 0x00, 0xC0, 0x01, 0x80, /* 0xD9 */ - 0xF8, 0x00, 0xC0, 0x06, 0x00, 0x30, 0x01, 0x80, 0x0F, 0xF0, 0x60, 0xC3, 0x03, 0x18, 0x18, 0xC0, 0xC6, 0x06, 0x30, 0x61, 0xFE, - 0x00, /* 0xDA */ - 0xC0, 0x0F, 0x00, 0x3C, 0x00, 0xF0, 0x03, 0xC0, 0x0F, 0xFE, 0x3C, 0x0C, 0xF0, 0x1B, 0xC0, 0x6F, 0x01, 0xBC, 0x06, 0xF0, 0x33, - 0xFF, 0x8C, /* 0xDB */ - 0xC0, 0x18, 0x03, 0x00, 0x60, 0x0C, 0x01, 0xFF, 0x30, 0x36, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x6F, 0xF8, /* 0xDC */ - 0x3F, 0x0C, 0x33, 0x83, 0x60, 0x20, 0x06, 0x00, 0x47, 0xF8, 0x01, 0xC0, 0x78, 0x0D, 0x81, 0x30, 0xC1, 0xF0, /* 0xDD */ - 0xC0, 0xF8, 0x61, 0x83, 0x31, 0x80, 0xD8, 0xC0, 0x6C, 0xC0, 0x1E, 0x60, 0x0F, 0xF0, 0x07, 0x98, 0x03, 0xCC, 0x01, 0xE3, 0x01, - 0xB1, 0x80, 0xD8, 0x60, 0xCC, 0x0F, 0x80, /* 0xDE */ - 0x3F, 0xD8, 0x3C, 0x0F, 0x03, 0xC0, 0xD8, 0x33, 0xFC, 0x33, 0x18, 0xCC, 0x36, 0x0D, 0x83, 0xC0, 0xC0, /* 0xDF */ - 0x7E, 0x71, 0xB0, 0xC0, 0x60, 0xF3, 0xDB, 0x0D, 0x86, 0xC7, 0x3D, 0xC0, /* 0xE0 */ - 0x03, 0x1F, 0x78, 0x40, 0xFC, 0xE6, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x66, 0x3C, /* 0xE1 */ - 0xFD, 0x8F, 0x0E, 0x3F, 0xDF, 0xB1, 0xE1, 0xC7, 0xF8, /* 0xE2 */ - 0xFE, 0x31, 0x8C, 0x63, 0x18, 0xC6, 0x00, /* 0xE3 */ - 0x1F, 0x83, 0x30, 0x66, 0x0C, 0xC1, 0x98, 0x33, 0x06, 0x61, 0x8C, 0x31, 0x9F, 0xFF, 0x01, 0xE0, 0x30, /* 0xE4 */ - 0x3C, 0x66, 0xC3, 0xC3, 0xFF, 0xC0, 0xC0, 0xC3, 0x66, 0x3C, /* 0xE5 */ - 0xC6, 0x36, 0x66, 0x36, 0xC1, 0xF8, 0x0F, 0x01, 0xF8, 0x36, 0xC6, 0x66, 0xC6, 0x38, 0x61, /* 0xE6 */ - 0x79, 0x8C, 0x18, 0x30, 0x43, 0x01, 0xE3, 0xC6, 0xF8, /* 0xE7 */ - 0xC7, 0xC7, 0xCF, 0xCB, 0xCB, 0xD3, 0xD3, 0xF3, 0xE3, 0xE3, /* 0xE8 */ - 0x66, 0x18, 0xC7, 0xC7, 0xCF, 0xCB, 0xCB, 0xD3, 0xD3, 0xF3, 0xE3, 0xE3, /* 0xE9 */ - 0xC7, 0x9B, 0x66, 0x8E, 0x1E, 0x36, 0x66, 0xC7, 0x84, /* 0xEA */ - 0x7E, 0xCD, 0x9B, 0x36, 0x6C, 0xD9, 0xA3, 0xC7, 0x0C, /* 0xEB */ - 0xE3, 0xF1, 0xF8, 0xFE, 0xFF, 0x7E, 0xAF, 0x77, 0x93, 0xC9, 0xE0, 0xC0, /* 0xEC */ - 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xFF, 0xC3, 0xC3, 0xC3, 0xC3, /* 0xED */ - 0x3C, 0x66, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x66, 0x3C, /* 0xEE */ - 0xFF, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, /* 0xEF */ - 0xDE, 0x71, 0xB0, 0x78, 0x3C, 0x1E, 0x0F, 0x07, 0x83, 0xE3, 0x6F, 0x30, 0x18, 0x0C, 0x00, /* 0xF0 */ - 0x3C, 0x66, 0xC3, 0xC0, 0xC0, 0xC0, 0xC0, 0xC3, 0x66, 0x3C, /* 0xF1 */ - 0xFC, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC0, /* 0xF2 */ - 0xC1, 0x43, 0x63, 0x62, 0x26, 0x36, 0x34, 0x1C, 0x1C, 0x18, 0x18, 0x18, 0x10, 0x60, /* 0xF3 */ - 0x03, 0x00, 0x0C, 0x03, 0xB7, 0x19, 0xE6, 0xC3, 0x0F, 0x0C, 0x3C, 0x30, 0xF0, 0xC3, 0xC3, 0x0F, 0x0C, 0x36, 0x79, 0x8E, 0xDC, - 0x03, 0x00, 0x0C, 0x00, 0x30, 0x00, /* 0xF4 */ - 0x87, 0x89, 0xB1, 0xC3, 0x07, 0x1E, 0x26, 0xC5, 0x0C, /* 0xF5 */ - 0xC3, 0x30, 0xCC, 0x33, 0x0C, 0xC3, 0x30, 0xCC, 0x33, 0x0C, 0xC3, 0x3F, 0xF0, 0x0C, 0x03, /* 0xF6 */ - 0xC7, 0x8F, 0x1E, 0x3C, 0x6F, 0xC1, 0x83, 0x06, 0x0C, /* 0xF7 */ - 0xCC, 0xF3, 0x3C, 0xCF, 0x33, 0xCC, 0xF3, 0x3C, 0xCF, 0x33, 0xCC, 0xFF, 0xF0, /* 0xF8 */ - 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCF, 0xFF, 0x00, 0x30, 0x03, /* 0xF9 */ - 0xF0, 0x18, 0x0C, 0x06, 0x03, 0xF1, 0x8C, 0xC6, 0x63, 0x31, 0x9F, 0x80, /* 0xFA */ - 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xFE, 0xF0, 0xFC, 0x3F, 0x0F, 0xC3, 0xFF, 0xB0, /* 0xFB */ - 0xC0, 0xC0, 0xC0, 0xC0, 0xFE, 0xC3, 0xC3, 0xC3, 0xC3, 0xFE, /* 0xFC */ - 0x3C, 0x62, 0xC3, 0x01, 0x1F, 0x01, 0x01, 0xC3, 0x62, 0x3C, /* 0xFD */ - 0xC7, 0xCC, 0xC6, 0xD8, 0x3D, 0x83, 0xF8, 0x3D, 0x83, 0xD8, 0x3C, 0xC2, 0xCC, 0x6C, 0x7C, /* 0xFE */ - 0x7F, 0xC3, 0xC3, 0xC3, 0x7F, 0x13, 0x33, 0x63, 0xC3, 0x83, /* 0xFF */ +/* 0x01 */ 0x07, 0x00, 0x0A, 0x00, 0x24, 0x00, 0x48, 0x01, 0x10, 0x04, 0x40, 0x10, 0xFF, 0x20, 0x02, 0x81, 0xFD, 0x00, 0x06, 0x07, 0xF4, 0x08, 0x24, 0x0F, 0x88, 0x11, 0x0F, 0xDC, 0x00, +/* 0x02 */ 0x3F, 0x70, 0x81, 0x11, 0x03, 0xE4, 0x08, 0x28, 0x1F, 0xD0, 0x00, 0x60, 0x7F, 0x20, 0x02, 0x43, 0xFC, 0x44, 0x00, 0x44, 0x00, 0x48, 0x00, 0x90, 0x00, 0xA0, 0x01, 0xC0, 0x00, +/* 0x03 */ 0x07, 0xC0, 0x30, 0x60, 0x80, 0x22, 0x00, 0x28, 0x00, 0x31, 0x8C, 0x63, 0x18, 0xC0, 0x01, 0x80, 0x03, 0x00, 0x06, 0x20, 0x8C, 0x3E, 0x14, 0x00, 0x44, 0x01, 0x06, 0x0C, 0x03, 0xE0, +/* 0x04 */ 0x07, 0xC0, 0x30, 0x60, 0x80, 0x22, 0x00, 0x28, 0x82, 0x30, 0x88, 0x62, 0x08, 0xC0, 0x01, 0x80, 0x03, 0x00, 0x06, 0x3F, 0x8C, 0x3E, 0x14, 0x00, 0x44, 0x01, 0x06, 0x0C, 0x03, 0xE0, +/* 0x05 */ 0x0B, 0x10, 0x14, 0xA8, 0x12, 0x50, 0x29, 0x42, 0x24, 0xA5, 0x32, 0x95, 0x5A, 0x09, 0x48, 0x09, 0x24, 0x01, 0x10, 0x01, 0x48, 0x02, 0xA4, 0x02, 0x42, 0x04, 0x01, 0x98, 0x00, 0x60, +/* 0x06 */ 0x00, 0x80, 0x22, 0x80, 0x65, 0x00, 0xBE, 0xE1, 0x82, 0x4E, 0x03, 0x24, 0x04, 0x28, 0x06, 0x30, 0x12, 0x20, 0x3C, 0xA0, 0xC3, 0xFE, 0x80, 0x4D, 0x00, 0xA6, 0x01, 0x80, 0x00, +/* 0x07 */ +/* 0x08 */ 0x00, 0xF8, 0x00, 0x82, 0x00, 0x80, 0x83, 0xE0, 0x41, 0x10, 0x21, 0x04, 0x1B, 0x00, 0x03, 0x00, 0x01, 0x80, 0x00, 0xE0, 0x00, 0x4F, 0xE1, 0xC0, 0x0F, 0x02, 0x00, 0x03, 0x01, 0x00, 0x09, 0x88, 0x0C, 0x0C, +/* 0x09 */ 0x00, 0xF8, 0x00, 0x82, 0x00, 0x80, 0x83, 0xE0, 0x41, 0x10, 0x21, 0x04, 0x1B, 0x00, 0x03, 0x00, 0x01, 0x80, 0x00, 0xE0, 0x00, 0x4F, 0xE1, 0xC0, 0x0F, 0x00, +/* 0x0A */ +/* 0x0B */ 0x1C, 0x1C, 0x31, 0xB1, 0x90, 0x50, 0x50, 0x10, 0x18, 0x00, 0x0C, 0x00, 0x06, 0x00, 0x02, 0x80, 0x02, 0x40, 0x01, 0x10, 0x01, 0x04, 0x01, 0x01, 0x01, 0x00, 0x41, 0x00, 0x11, 0x00, 0x07, 0x00, 0x01, 0x00, +/* 0x0C */ 0x06, 0x00, 0x0A, 0x00, 0x12, 0x00, 0x32, 0x01, 0x84, 0x04, 0x10, 0x08, 0x98, 0x1C, 0x18, 0x40, 0x48, 0x82, 0x11, 0xF0, 0x74, 0x02, 0x18, 0x70, 0x2F, 0x9F, 0x80, +/* 0x0D */ +/* 0x0E */ 0x01, 0x00, 0x05, 0x00, 0x0A, 0x00, 0x3E, 0x00, 0x82, 0x02, 0x82, 0x06, 0x04, 0x10, 0x04, 0x20, 0x08, 0x40, 0x10, 0xFF, 0x22, 0x00, 0x29, 0xFF, 0x3F, 0x8F, 0xDF, 0x9F, 0x01, 0xC0, +/* 0x0F */ 0x07, 0xC0, 0x30, 0x60, 0x80, 0x22, 0x00, 0x28, 0x82, 0x36, 0x03, 0x60, 0x00, 0xCC, 0x19, 0xA4, 0x4B, 0x00, 0x06, 0x8E, 0x2B, 0x22, 0x66, 0x7C, 0xCC, 0x71, 0x98, 0x03, 0x00, +/* 0x10 */ 0x03, 0x80, 0x07, 0x00, 0x0E, 0x00, 0x1E, 0x00, 0x54, 0x00, 0xA8, 0x01, 0x50, 0x02, 0xA0, 0x05, 0x20, 0x32, 0x61, 0xC4, 0x74, 0x49, 0x10, 0x6C, 0x00, 0xD8, 0x01, 0x10, 0x00, +/* 0x11 */ 0x07, 0xC0, 0x30, 0x60, 0x80, 0x22, 0x40, 0x29, 0x00, 0x31, 0x84, 0x63, 0x18, 0xC0, 0x00, 0x80, 0x15, 0x03, 0x7E, 0x02, 0xFA, 0x04, 0xE4, 0x18, 0x84, 0x00, 0x06, 0x0C, 0x03, 0xE0, +/* 0x12 */ 0x02, 0x08, 0x01, 0x08, 0x40, 0x10, 0xC0, 0x08, 0xC0, 0x60, 0x80, 0x28, 0x04, 0x12, 0x4C, 0x10, 0x80, 0x08, 0x23, 0x0E, 0x08, 0xC4, 0x82, 0x04, 0x20, 0x83, 0x09, 0x82, 0x47, 0x01, 0x1C, 0x01, 0x30, 0x00, 0xE0, 0x00, 0x00, +/* 0x13 */ 0x07, 0xC0, 0x30, 0x60, 0x80, 0x22, 0x00, 0x28, 0x00, 0x31, 0x08, 0x65, 0x28, 0xC0, 0x01, 0x80, 0x03, 0x00, 0x06, 0x3F, 0x8C, 0x3E, 0x14, 0x00, 0x44, 0x01, 0x06, 0x0C, 0x03, 0xE0, +/* 0x14 */ 0x07, 0xC0, 0x30, 0x60, 0x80, 0x22, 0x22, 0x29, 0x83, 0x30, 0x00, 0x65, 0x14, 0xD3, 0x4D, 0xBA, 0xEB, 0x38, 0xE6, 0x00, 0x0A, 0x00, 0x24, 0x38, 0x44, 0x01, 0x07, 0x1C, 0x01, 0xC0, +/* 0x15 */ 0x07, 0xC0, 0x30, 0x18, 0x80, 0x32, 0x00, 0xF8, 0x01, 0xF1, 0x09, 0xA5, 0x28, 0x40, 0x01, 0x80, 0x03, 0x00, 0x06, 0x3F, 0x8C, 0x3E, 0x14, 0x00, 0x44, 0x01, 0x06, 0x0C, 0x03, 0xE0, +/* 0x16 */ 0x0C, 0x00, 0xC0, 0x1C, 0x03, 0x80, 0xF8, 0xBB, 0x36, 0xC7, 0x99, 0xF3, 0xFE, 0x3F, 0xC3, 0xF0, 0x7E, 0x0E, 0xC1, 0x8E, 0xE0, 0x20, +/* 0x17 */ 0x07, 0xC0, 0x30, 0x60, 0x80, 0x22, 0x00, 0x28, 0x00, 0x10, 0x01, 0x20, 0x1D, 0x44, 0x42, 0x84, 0x85, 0x00, 0x86, 0x00, 0xC4, 0x00, 0x44, 0x7C, 0x44, 0x00, 0x06, 0x0C, 0x03, 0xE0, +/* 0x18 */ 0x01, 0xE0, 0x00, 0x84, 0x00, 0x40, 0x80, 0x20, 0x10, 0x08, 0x24, 0x02, 0x41, 0x00, 0x86, 0x03, 0x12, 0x03, 0xB4, 0x03, 0x52, 0x81, 0x23, 0x80, 0x70, 0xA0, 0x14, 0x28, 0x05, 0x0A, 0x01, 0x42, 0x80, 0x50, +/* 0x19 */ 0x07, 0xC0, 0x30, 0x60, 0x80, 0x22, 0x00, 0x28, 0x00, 0x33, 0x18, 0x60, 0x00, 0xDC, 0xE1, 0xB9, 0xC3, 0x7B, 0xC6, 0x63, 0x0A, 0x00, 0x24, 0xF0, 0x44, 0x01, 0x06, 0x0C, 0x03, 0xE0, +/* 0x1A */ 0xFF, 0xFC, 0x00, 0x63, 0xE3, 0x31, 0x99, 0x04, 0xC8, 0x66, 0x06, 0x30, 0x61, 0x82, 0x0C, 0x10, 0x60, 0x03, 0x04, 0x18, 0x00, 0xFF, 0xFC, +/* 0x1B */ 0x07, 0xF0, 0x06, 0x0C, 0x04, 0x01, 0x04, 0x00, 0x44, 0x22, 0x12, 0x2A, 0x89, 0x00, 0x04, 0x80, 0x02, 0x44, 0x11, 0x01, 0xF0, 0x04, 0x01, 0x0D, 0x01, 0x6A, 0x41, 0x2C, 0x00, 0x05, 0xC0, 0x0E, 0x18, 0x18, +/* 0x1C */ 0x07, 0xC0, 0x30, 0x60, 0x80, 0x22, 0xC0, 0x2A, 0x00, 0x33, 0x00, 0x66, 0x00, 0xCC, 0x39, 0x80, 0x83, 0x00, 0x06, 0x00, 0x8C, 0x3E, 0x14, 0x00, 0x44, 0x01, 0x06, 0x0C, 0x03, 0xE0, +/* 0x1D */ 0x07, 0xC0, 0x30, 0x60, 0x80, 0x22, 0x70, 0x28, 0x00, 0x31, 0x80, 0x63, 0x18, 0xC0, 0x31, 0x80, 0x03, 0x00, 0x06, 0x60, 0x0D, 0x33, 0x12, 0x10, 0x48, 0x21, 0x23, 0x8C, 0x00, +/* 0x1E */ 0x03, 0x00, 0x07, 0x9E, 0x07, 0x00, 0x86, 0x00, 0x27, 0xC0, 0x0F, 0xC0, 0x07, 0x8C, 0x62, 0x06, 0x31, 0x20, 0x00, 0x90, 0x00, 0x48, 0x00, 0x24, 0x3E, 0x11, 0x00, 0x10, 0x40, 0x10, 0x18, 0x30, 0x03, 0xE0, +/* 0x1F */ 0x18, 0x02, 0x80, 0x4C, 0x16, 0x41, 0x24, 0x3C, 0x88, 0x6E, 0x65, 0xF2, 0x78, 0x46, 0x88, 0xCF, 0x18, 0x02, 0x80, 0x8C, 0x60, 0x70, +/* ' ' 0x20 */ +/* '!' 0x21 */ 0xFF, 0xFF, 0xF0, 0xC0, +/* '"' 0x22 */ 0xDE, 0xF7, 0x20, +/* '#' 0x23 */ 0x09, 0x86, 0x41, 0x91, 0xFF, 0x13, 0x04, 0xC3, 0x20, 0xC8, 0xFF, 0x89, 0x82, 0x61, 0x90, +/* '$' 0x24 */ 0x10, 0x1F, 0x14, 0xDA, 0x3D, 0x1E, 0x83, 0x40, 0x78, 0x17, 0x08, 0xF4, 0x7A, 0x35, 0x33, 0xF0, 0x40, 0x20, +/* '%' 0x25 */ 0x38, 0x10, 0xEC, 0x20, 0xC6, 0x20, 0xC6, 0x40, 0xC6, 0x40, 0x6C, 0x80, 0x39, 0x00, 0x01, 0x3C, 0x02, 0x77, 0x02, 0x63, 0x04, 0x63, 0x04, 0x77, 0x08, 0x3C, +/* '&' 0x26 */ 0x0E, 0x0C, 0xC3, 0x30, 0xCC, 0x1E, 0x03, 0x03, 0xC1, 0x9B, 0xC2, 0xF0, 0xEC, 0x19, 0x8F, 0x3C, 0x40, +/* ''' 0x27 */ 0xFE, +/* '(' 0x28 */ 0x13, 0x26, 0x6C, 0xCC, 0xCC, 0xC4, 0x66, 0x23, 0x10, +/* ')' 0x29 */ 0x8C, 0x46, 0x63, 0x33, 0x33, 0x32, 0x66, 0x4C, 0x80, +/* '*' 0x2A */ 0x25, 0x7E, 0xA5, 0x00, +/* '+' 0x2B */ 0x30, 0xC3, 0x3F, 0x30, 0xC3, 0x0C, +/* ',' 0x2C */ 0xD6, +/* '-' 0x2D */ 0xF0, +/* '.' 0x2E */ 0xC0, +/* '/' 0x2F */ 0x08, 0x44, 0x21, 0x10, 0x84, 0x42, 0x11, 0x08, 0x00, +/* '0' 0x30 */ 0x3C, 0x66, 0x42, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x42, 0x66, 0x3C, +/* '1' 0x31 */ 0x11, 0x3F, 0x33, 0x33, 0x33, 0x33, 0x30, +/* '2' 0x32 */ 0x3E, 0x31, 0xB0, 0x78, 0x30, 0x18, 0x1C, 0x1C, 0x1C, 0x18, 0x18, 0x10, 0x08, 0x07, 0xF8, +/* '3' 0x33 */ 0x3C, 0x66, 0xC3, 0xC3, 0x03, 0x06, 0x1C, 0x07, 0x03, 0xC3, 0xC3, 0x66, 0x3C, +/* '4' 0x34 */ 0x0C, 0x18, 0x71, 0x62, 0xC9, 0xA3, 0x46, 0xFE, 0x18, 0x30, 0x60, 0xC0, +/* '5' 0x35 */ 0x7F, 0x20, 0x10, 0x08, 0x08, 0x07, 0xF3, 0x8C, 0x03, 0x01, 0x80, 0xF0, 0x6C, 0x63, 0xE0, +/* '6' 0x36 */ 0x1E, 0x31, 0x98, 0x78, 0x0C, 0x06, 0xF3, 0x8D, 0x83, 0xC1, 0xE0, 0xD0, 0x6C, 0x63, 0xE0, +/* '7' 0x37 */ 0xFF, 0x03, 0x02, 0x06, 0x04, 0x0C, 0x08, 0x18, 0x18, 0x18, 0x10, 0x30, 0x30, +/* '8' 0x38 */ 0x3E, 0x31, 0xB0, 0x78, 0x3C, 0x1B, 0x18, 0xF8, 0xC6, 0xC1, 0xE0, 0xF0, 0x6C, 0x63, 0xE0, +/* '9' 0x39 */ 0x3C, 0x66, 0xC2, 0xC3, 0xC3, 0xC3, 0x67, 0x3B, 0x03, 0x03, 0xC2, 0x66, 0x3C, +/* ':' 0x3A */ 0xC0, 0x00, 0x30, +/* ';' 0x3B */ 0xC0, 0x00, 0x00, 0x64, 0xA0, +/* '<' 0x3C */ 0x00, 0x81, 0xC7, 0x8E, 0x0C, 0x07, 0x80, 0x70, 0x0E, 0x01, 0x80, +/* '=' 0x3D */ 0xFF, 0x80, 0x00, 0x1F, 0xF0, +/* '>' 0x3E */ 0xE0, 0x1C, 0x03, 0x80, 0x30, 0x70, 0xE3, 0x81, 0x00, +/* '?' 0x3F */ 0x3E, 0x31, 0xB0, 0x78, 0x30, 0x18, 0x18, 0x38, 0x18, 0x18, 0x0C, 0x00, 0x00, 0x01, 0x80, +/* '@' 0x40 */ 0x03, 0xF0, 0x06, 0x0E, 0x06, 0x01, 0x86, 0x00, 0x66, 0x1D, 0xBB, 0x31, 0xCF, 0x18, 0xC7, 0x98, 0x63, 0xCC, 0x31, 0xE6, 0x11, 0xB3, 0x99, 0xCC, 0xF7, 0x86, 0x00, 0x01, 0x80, 0x00, 0x70, 0x40, 0x0F, 0xE0, +/* 'A' 0x41 */ 0x06, 0x00, 0xF0, 0x0F, 0x00, 0x90, 0x19, 0x81, 0x98, 0x10, 0x83, 0x0C, 0x3F, 0xC2, 0x04, 0x60, 0x66, 0x06, 0xC0, 0x30, +/* 'B' 0x42 */ 0xFF, 0x18, 0x33, 0x03, 0x60, 0x6C, 0x0D, 0x83, 0x3F, 0xC6, 0x06, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x6F, 0xF8, +/* 'C' 0x43 */ 0x1F, 0x86, 0x19, 0x81, 0xA0, 0x3C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xC0, 0x68, 0x0D, 0x83, 0x18, 0x61, 0xF0, +/* 'D' 0x44 */ 0xFF, 0x18, 0x33, 0x03, 0x60, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x03, 0x60, 0xCF, 0xF0, +/* 'E' 0x45 */ 0xFF, 0xE0, 0x30, 0x18, 0x0C, 0x06, 0x03, 0xFD, 0x80, 0xC0, 0x60, 0x30, 0x18, 0x0F, 0xF8, +/* 'F' 0x46 */ 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFE, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, +/* 'G' 0x47 */ 0x0F, 0x83, 0x0E, 0x60, 0x66, 0x03, 0xC0, 0x0C, 0x00, 0xC1, 0xFC, 0x03, 0xC0, 0x36, 0x03, 0x60, 0x73, 0x0F, 0x0F, 0x10, +/* 'H' 0x48 */ 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xFF, 0xFE, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x06, +/* 'I' 0x49 */ 0xFF, 0xFF, 0xFF, 0xC0, +/* 'J' 0x4A */ 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x83, 0x07, 0x8F, 0x1E, 0x27, 0x80, +/* 'K' 0x4B */ 0xC0, 0xF0, 0x6C, 0x33, 0x18, 0xCC, 0x37, 0x0F, 0xC3, 0x98, 0xC3, 0x30, 0xCC, 0x1B, 0x03, 0xC0, 0xC0, +/* 'L' 0x4C */ 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, +/* 'M' 0x4D */ 0xE0, 0x3F, 0x01, 0xFC, 0x1F, 0xE0, 0xFD, 0x05, 0xEC, 0x6F, 0x63, 0x79, 0x13, 0xCD, 0x9E, 0x6C, 0xF1, 0x47, 0x8E, 0x3C, 0x71, 0x80, +/* 'N' 0x4E */ 0xE0, 0x7C, 0x0F, 0xC1, 0xE8, 0x3D, 0x87, 0x98, 0xF1, 0x1E, 0x33, 0xC3, 0x78, 0x6F, 0x07, 0xE0, 0x7C, 0x0E, +/* 'O' 0x4F */ 0x0F, 0x81, 0x83, 0x18, 0x0C, 0xC0, 0x6C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1B, 0x01, 0x98, 0x0C, 0x60, 0xC0, 0xF8, 0x00, +/* 'P' 0x50 */ 0xFF, 0x30, 0x6C, 0x0F, 0x03, 0xC0, 0xF0, 0x6F, 0xF3, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x00, +/* 'Q' 0x51 */ 0x0F, 0x81, 0x83, 0x18, 0x0C, 0xC0, 0x6C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1B, 0x01, 0x98, 0x6C, 0x60, 0xC0, 0xFB, 0x00, 0x08, +/* 'R' 0x52 */ 0xFF, 0x8C, 0x0E, 0xC0, 0x6C, 0x06, 0xC0, 0x6C, 0x0C, 0xFF, 0x8C, 0x0E, 0xC0, 0x6C, 0x06, 0xC0, 0x6C, 0x06, 0xC0, 0x70, +/* 'S' 0x53 */ 0x3F, 0x18, 0x6C, 0x0F, 0x03, 0xC0, 0x1E, 0x01, 0xF0, 0x0E, 0x00, 0xF0, 0x3C, 0x0D, 0x86, 0x3F, 0x00, +/* 'T' 0x54 */ 0xFF, 0x86, 0x03, 0x01, 0x80, 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x80, 0xC0, +/* 'U' 0x55 */ 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xB0, 0x61, 0xF0, +/* 'V' 0x56 */ 0xC0, 0x6C, 0x0D, 0x81, 0x10, 0x63, 0x0C, 0x61, 0x04, 0x60, 0xCC, 0x19, 0x01, 0x60, 0x3C, 0x07, 0x00, 0x60, +/* 'W' 0x57 */ 0xC1, 0x81, 0x61, 0xC3, 0x61, 0xC3, 0x61, 0x43, 0x62, 0x62, 0x22, 0x66, 0x32, 0x26, 0x36, 0x26, 0x14, 0x34, 0x14, 0x34, 0x1C, 0x1C, 0x18, 0x1C, 0x08, 0x18, +/* 'X' 0x58 */ 0xC0, 0xD8, 0x66, 0x18, 0xCC, 0x1E, 0x07, 0x00, 0xC0, 0x78, 0x32, 0x0C, 0xC6, 0x1B, 0x07, 0xC0, 0xC0, +/* 'Y' 0x59 */ 0xC0, 0x36, 0x06, 0x30, 0xC3, 0x0C, 0x19, 0x81, 0xD8, 0x0F, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, +/* 'Z' 0x5A */ 0xFF, 0xC0, 0x60, 0x30, 0x0C, 0x06, 0x03, 0x01, 0xC0, 0x60, 0x30, 0x18, 0x06, 0x03, 0x00, 0xFF, 0xC0, +/* '[' 0x5B */ 0xFB, 0x6D, 0xB6, 0xDB, 0x6D, 0xB6, 0xE0, +/* '\' 0x5C */ 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x80, +/* ']' 0x5D */ 0xED, 0xB6, 0xDB, 0x6D, 0xB6, 0xDB, 0xE0, +/* '^' 0x5E */ 0x30, 0x60, 0xA2, 0x44, 0xD8, 0xA1, 0x80, +/* '_' 0x5F */ 0xFF, 0xC0, +/* '`' 0x60 */ 0xC6, 0x30, +/* 'a' 0x61 */ 0x7E, 0x71, 0xB0, 0xC0, 0x60, 0xF3, 0xDB, 0x0D, 0x86, 0xC7, 0x3D, 0xC0, +/* 'b' 0x62 */ 0xC0, 0x60, 0x30, 0x1B, 0xCE, 0x36, 0x0F, 0x07, 0x83, 0xC1, 0xE0, 0xF0, 0x7C, 0x6D, 0xE0, +/* 'c' 0x63 */ 0x3C, 0x66, 0xC3, 0xC0, 0xC0, 0xC0, 0xC0, 0xC3, 0x66, 0x3C, +/* 'd' 0x64 */ 0x03, 0x03, 0x03, 0x3B, 0x67, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x67, 0x3B, +/* 'e' 0x65 */ 0x3C, 0x66, 0xC3, 0xC3, 0xFF, 0xC0, 0xC0, 0xC3, 0x66, 0x3C, +/* 'f' 0x66 */ 0x36, 0x6F, 0x66, 0x66, 0x66, 0x66, 0x60, +/* 'g' 0x67 */ 0x3B, 0x67, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x67, 0x3B, 0x03, 0x03, 0xC6, 0x7C, +/* 'h' 0x68 */ 0xC0, 0xC0, 0xC0, 0xDE, 0xE3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, +/* 'i' 0x69 */ 0xC3, 0xFF, 0xFF, 0xC0, +/* 'j' 0x6A */ 0x30, 0x03, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0xE0, +/* 'k' 0x6B */ 0xC0, 0xC0, 0xC0, 0xC2, 0xC4, 0xCC, 0xD8, 0xF8, 0xEC, 0xC4, 0xC6, 0xC3, 0xC3, +/* 'l' 0x6C */ 0xFF, 0xFF, 0xFF, 0xC0, +/* 'm' 0x6D */ 0xDE, 0xF7, 0x1C, 0xF0, 0xC7, 0x86, 0x3C, 0x31, 0xE1, 0x8F, 0x0C, 0x78, 0x63, 0xC3, 0x1E, 0x18, 0xC0, +/* 'n' 0x6E */ 0xDE, 0xE3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, +/* 'o' 0x6F */ 0x3C, 0x66, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x66, 0x3C, +/* 'p' 0x70 */ 0xDE, 0x71, 0xB0, 0x78, 0x3C, 0x1E, 0x0F, 0x07, 0x83, 0xE3, 0x6F, 0x30, 0x18, 0x0C, 0x00, +/* 'q' 0x71 */ 0x3B, 0x67, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x67, 0x3B, 0x03, 0x03, 0x03, +/* 'r' 0x72 */ 0xDF, 0x31, 0x8C, 0x63, 0x18, 0xC6, 0x00, +/* 's' 0x73 */ 0x3E, 0xE3, 0xC0, 0xC0, 0xE0, 0x3C, 0x07, 0xC3, 0xE3, 0x7E, +/* 't' 0x74 */ 0x66, 0xF6, 0x66, 0x66, 0x66, 0x67, +/* 'u' 0x75 */ 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC7, 0x7B, +/* 'v' 0x76 */ 0xC1, 0xA0, 0x98, 0xCC, 0x42, 0x21, 0xB0, 0xD0, 0x28, 0x1C, 0x0C, 0x00, +/* 'w' 0x77 */ 0xC6, 0x1E, 0x38, 0x91, 0xC4, 0xCA, 0x66, 0xD3, 0x16, 0xD0, 0xA6, 0x87, 0x1C, 0x38, 0xC0, 0xC6, 0x00, +/* 'x' 0x78 */ 0x87, 0x89, 0xB1, 0xC3, 0x07, 0x1E, 0x26, 0xC5, 0x0C, +/* 'y' 0x79 */ 0xC1, 0x43, 0x63, 0x62, 0x26, 0x36, 0x34, 0x1C, 0x1C, 0x18, 0x18, 0x18, 0x10, 0x60, +/* 'z' 0x7A */ 0xFE, 0x0C, 0x30, 0xC1, 0x86, 0x18, 0x20, 0xC1, 0xFC, +/* '{' 0x7B */ 0x36, 0x66, 0x66, 0x6E, 0xCE, 0x66, 0x66, 0x66, 0x30, +/* '|' 0x7C */ 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, +/* '}' 0x7D */ 0xC6, 0x66, 0x66, 0x67, 0x37, 0x66, 0x66, 0x66, 0xC0, +/* '~' 0x7E */ 0x61, 0x24, 0x38, +/* 0x7F */ 0xFF, 0xFC, 0x00, 0x63, 0xE3, 0x31, 0x99, 0x04, 0xC8, 0x66, 0x06, 0x30, 0x61, 0x83, 0x0C, 0x18, 0x60, 0x03, 0x06, 0x18, 0x00, 0xFF, 0xFC, +/* 0x80 */ 0xFF, 0x01, 0x80, 0x18, 0x01, 0x80, 0x18, 0x01, 0xFE, 0x18, 0x31, 0x83, 0x18, 0x31, 0x83, 0x18, 0x31, 0x83, 0x18, 0x30, 0x03, 0x00, 0x30, 0x0E, +/* 0x81 */ 0x0C, 0x18, 0x00, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, +/* 0x82 */ 0xDC, +/* 0x83 */ 0x18, 0x89, 0xFC, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x00, +/* 0x84 */ 0xDA, 0x76, +/* 0x85 */ 0xCC, 0xC0, +/* 0x86 */ 0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +/* 0x87 */ 0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18, +/* 0x88 */ 0x07, 0xC6, 0x13, 0x00, 0xC0, 0x60, 0x3F, 0xE6, 0x03, 0xFC, 0x60, 0x0C, 0x03, 0x00, 0x61, 0x07, 0xC0, +/* 0x89 */ 0x70, 0x80, 0x22, 0x20, 0x08, 0x90, 0x02, 0x24, 0x00, 0x72, 0x00, 0x00, 0x80, 0x00, 0x40, 0x00, 0x10, 0x00, 0x09, 0xC7, 0x84, 0x8B, 0x31, 0x22, 0x84, 0x88, 0xB3, 0x21, 0xC7, 0x80, +/* 0x8A */ 0x3F, 0x80, 0x18, 0xC0, 0x0C, 0x60, 0x06, 0x30, 0x03, 0x18, 0x01, 0x8C, 0x00, 0xC7, 0xF8, 0x63, 0x06, 0x31, 0x81, 0x90, 0xC0, 0xD8, 0x60, 0x6C, 0x30, 0x6C, 0x1F, 0xE0, +/* 0x8B */ 0x69, +/* 0x8C */ 0xC0, 0xC0, 0x60, 0x60, 0x30, 0x30, 0x18, 0x18, 0x0C, 0x0C, 0x06, 0x06, 0x03, 0xFF, 0xF9, 0x81, 0x86, 0xC0, 0xC1, 0xE0, 0x60, 0xF0, 0x30, 0x78, 0x18, 0x6C, 0x0F, 0xE0, +/* 0x8D */ 0x0C, 0x06, 0x0C, 0x1B, 0x0C, 0xC6, 0x33, 0x0D, 0x83, 0xC0, 0xF0, 0x3E, 0x0D, 0xC3, 0x38, 0xC7, 0x30, 0xEC, 0x1C, +/* 0x8E */ 0xFF, 0x01, 0x80, 0x18, 0x01, 0x80, 0x18, 0x01, 0xFE, 0x18, 0x31, 0x83, 0x18, 0x31, 0x83, 0x18, 0x31, 0x83, 0x18, 0x30, +/* 0x8F */ 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3F, 0xFE, 0x0C, 0x01, 0x80, +/* 0x90 */ 0x60, 0x7C, 0x18, 0x0D, 0xE7, 0x1B, 0x0D, 0x86, 0xC3, 0x61, 0xB0, 0xD8, 0x6C, 0x36, 0x18, 0x18, 0x08, 0x08, +/* 0x91 */ 0x6B, +/* 0x92 */ 0xD6, +/* 0x93 */ 0x4C, 0xA5, 0xB0, +/* 0x94 */ 0xDA, 0x53, 0x20, +/* 0x95 */ 0x6F, 0xFF, 0x60, +/* 0x96 */ 0xFE, +/* 0x97 */ 0xFF, 0xFF, +/* 0x98 */ +/* 0x99 */ 0xFC, 0xE1, 0xCC, 0x38, 0x73, 0x0E, 0x1C, 0xC3, 0x8F, 0x30, 0xD2, 0xCC, 0x34, 0xB3, 0x0D, 0x6C, 0xC3, 0x53, 0x30, 0xCC, 0xCC, 0x33, 0x30, +/* 0x9A */ 0x7E, 0x03, 0x30, 0x19, 0x80, 0xCC, 0x06, 0x60, 0x33, 0xF9, 0x98, 0x6C, 0xC3, 0x46, 0x1E, 0x3F, 0x80, +/* 0x9B */ 0x96, +/* 0x9C */ 0xC3, 0x03, 0x0C, 0x0C, 0x30, 0x30, 0xC0, 0xC3, 0x03, 0xFF, 0xEC, 0x30, 0xF0, 0xC3, 0xC3, 0x0F, 0x0F, 0xE0, +/* 0x9D */ 0x0C, 0x30, 0x46, 0x3C, 0xDB, 0x34, 0x70, 0xF1, 0xB3, 0x36, 0x3C, 0x20, +/* 0x9E */ 0x60, 0x7C, 0x18, 0x0D, 0xE7, 0x3B, 0x0D, 0x86, 0xC3, 0x61, 0xB0, 0xD8, 0x6C, 0x36, 0x18, +/* 0x9F */ 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xFF, 0x18, 0x18, +/* 0xA0 */ +/* 0xA1 */ 0x21, 0x07, 0x8C, 0x0F, 0x06, 0x61, 0x98, 0xC3, 0x30, 0xD8, 0x1E, 0x07, 0x00, 0xC0, 0x60, 0x18, 0x0C, 0x03, 0x00, +/* 0xA2 */ 0x66, 0x18, 0xC1, 0x43, 0x63, 0x62, 0x26, 0x36, 0x34, 0x1C, 0x1C, 0x18, 0x18, 0x18, 0x10, 0x60, +/* 0xA3 */ 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x83, 0x07, 0x8F, 0x1E, 0x27, 0x80, +/* 0xA4 */ 0xFF, 0xDF, 0x1E, 0x3E, 0xFF, 0xC0, +/* 0xA5 */ 0x00, 0xC0, 0x3F, 0xFF, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x00, +/* 0xA6 */ 0xFF, 0xFC, 0x0F, 0xFF, 0xC0, +/* 0xA7 */ 0x0C, 0x09, 0x0C, 0xC6, 0x63, 0x81, 0xE3, 0x19, 0x87, 0xE1, 0xB8, 0xC6, 0x41, 0xC0, 0x73, 0x19, 0x8C, 0x66, 0x1E, 0x00, +/* 0xA8 */ 0x33, 0x00, 0x3F, 0xF8, 0x0C, 0x06, 0x03, 0x01, 0x80, 0xFF, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0xFE, +/* 0xA9 */ 0x0F, 0xC0, 0x61, 0x87, 0x03, 0x9B, 0xC6, 0xD9, 0x8F, 0x60, 0x3D, 0x00, 0xF4, 0x03, 0xD8, 0x0D, 0xE6, 0x67, 0xF3, 0x86, 0x18, 0x0F, 0xC0, +/* 0xAA */ 0x1F, 0x86, 0x19, 0x81, 0xB0, 0x3C, 0x01, 0x80, 0x3F, 0xC6, 0x00, 0xC0, 0x68, 0x0D, 0x83, 0x18, 0x61, 0xF0, +/* 0xAB */ 0x22, 0xCF, 0x26, 0x46, 0x64, 0x40, +/* 0xAC */ 0xFF, 0x80, 0xC0, 0x60, 0x30, 0x18, +/* 0xAD */ +/* 0xAE */ 0x0F, 0xC0, 0x61, 0x87, 0x03, 0x9F, 0xE6, 0xD0, 0x8F, 0x42, 0x3D, 0xF0, 0xF4, 0x23, 0xD0, 0x8D, 0xC2, 0x67, 0x0B, 0x86, 0x18, 0x0F, 0xC0, +/* 0xAF */ 0xCC, 0x03, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x00, +/* 0xB0 */ 0x74, 0x63, 0x17, 0x00, +/* 0xB1 */ 0x0C, 0x06, 0x03, 0x07, 0xE0, 0xC0, 0x60, 0x30, 0x18, 0x00, 0x00, 0x3F, 0xE0, +/* 0xB2 */ 0xFF, 0xFF, 0xFF, 0xC0, +/* 0xB3 */ 0xC3, 0xFF, 0xFF, 0xC0, +/* 0xB4 */ 0x0C, 0x3F, 0xF0, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, +/* 0xB5 */ 0xC3, 0x61, 0xB0, 0xD8, 0x6C, 0x36, 0x1B, 0x0D, 0x86, 0xE7, 0x7D, 0xF0, 0x18, 0x0C, 0x00, +/* 0xB6 */ 0x3F, 0x7E, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0x72, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, +/* 0xB7 */ 0xE0, +/* 0xB8 */ 0x66, 0x00, 0x3C, 0x66, 0xC3, 0xC3, 0xFF, 0xC0, 0xC0, 0xC3, 0x66, 0x3C, +/* 0xB9 */ 0xC1, 0x81, 0x83, 0x03, 0x86, 0x05, 0x0C, 0xEB, 0x1A, 0x32, 0x34, 0x66, 0x68, 0xC4, 0xD1, 0x8D, 0xB3, 0x0B, 0x3A, 0x1E, 0x04, 0x1C, 0x08, 0x1B, 0xC0, +/* 0xBA */ 0x3C, 0x46, 0xC3, 0x80, 0xF8, 0x80, 0x80, 0xC3, 0x46, 0x3C, +/* 0xBB */ 0x89, 0x98, 0x99, 0x3C, 0xD1, 0x00, +/* 0xBC */ 0x30, 0x03, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0xE0, +/* 0xBD */ 0x3F, 0x18, 0x6C, 0x0F, 0x03, 0xC0, 0x1E, 0x01, 0xF0, 0x0E, 0x00, 0xF0, 0x3C, 0x0D, 0x86, 0x3F, 0x00, +/* 0xBE */ 0x3E, 0xE3, 0xC0, 0xC0, 0x60, 0x3C, 0x07, 0xC3, 0xE3, 0x7E, +/* 0xBF */ 0xCC, 0x03, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, +/* 0xC0 */ 0x06, 0x00, 0xF0, 0x0F, 0x00, 0x90, 0x19, 0x81, 0x98, 0x10, 0x83, 0x0C, 0x3F, 0xC2, 0x04, 0x60, 0x66, 0x06, 0xC0, 0x30, +/* 0xC1 */ 0xFF, 0x18, 0x03, 0x00, 0x60, 0x0C, 0x01, 0x80, 0x3F, 0xE6, 0x06, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x6F, 0xF8, +/* 0xC2 */ 0xFF, 0x18, 0x33, 0x03, 0x60, 0x6C, 0x0D, 0x83, 0x3F, 0xC6, 0x06, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x6F, 0xF8, +/* 0xC3 */ 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, +/* 0xC4 */ 0x1F, 0xF0, 0x60, 0xC1, 0x83, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x83, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x03, 0x0C, 0x0C, 0xFF, 0xFF, 0x00, 0x3C, 0x00, 0xF0, 0x03, +/* 0xC5 */ 0xFF, 0xE0, 0x30, 0x18, 0x0C, 0x06, 0x03, 0xFD, 0x80, 0xC0, 0x60, 0x30, 0x18, 0x0F, 0xF8, +/* 0xC6 */ 0x61, 0x86, 0x31, 0x8C, 0x19, 0x98, 0x19, 0x98, 0x0D, 0xB0, 0x07, 0xE0, 0x03, 0xC0, 0x07, 0xE0, 0x0D, 0xB0, 0x19, 0x98, 0x31, 0x8C, 0x61, 0x86, 0xC1, 0x83, +/* 0xC7 */ 0x3F, 0x18, 0x6C, 0x0F, 0x03, 0x00, 0xC0, 0x60, 0xF0, 0x06, 0x00, 0xF0, 0x3C, 0x0D, 0x86, 0x3F, 0x00, +/* 0xC8 */ 0xC0, 0xF8, 0x1F, 0x07, 0xE0, 0xBC, 0x37, 0x8C, 0xF1, 0x1E, 0x63, 0xD8, 0x7A, 0x0F, 0xC1, 0xF0, 0x3E, 0x06, +/* 0xC9 */ 0x11, 0x03, 0xE0, 0x00, 0x60, 0x7C, 0x0F, 0x83, 0xF0, 0x5E, 0x1B, 0xC6, 0x78, 0x8F, 0x31, 0xEC, 0x3D, 0x07, 0xE0, 0xF8, 0x1F, 0x03, +/* 0xCA */ 0xC1, 0xB0, 0xCC, 0x63, 0x30, 0xD8, 0x3C, 0x0F, 0x03, 0xE0, 0xDC, 0x33, 0x8C, 0x73, 0x0E, 0xC1, 0xC0, +/* 0xCB */ 0x3F, 0xCC, 0x33, 0x0C, 0xC3, 0x30, 0xCC, 0x33, 0x0C, 0xC3, 0x30, 0xC8, 0x36, 0x0D, 0x83, 0xC0, 0xC0, +/* 0xCC */ 0xE0, 0x3F, 0x01, 0xFC, 0x1F, 0xE0, 0xFD, 0x05, 0xEC, 0x6F, 0x63, 0x79, 0x13, 0xCD, 0x9E, 0x6C, 0xF1, 0x47, 0x8E, 0x3C, 0x71, 0x80, +/* 0xCD */ 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xFF, 0xFE, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x06, +/* 0xCE */ 0x0F, 0x81, 0x83, 0x18, 0x0C, 0xC0, 0x6C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1B, 0x01, 0x98, 0x0C, 0x60, 0xC0, 0xF8, 0x00, +/* 0xCF */ 0xFF, 0xF8, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x06, +/* 0xD0 */ 0xFF, 0x30, 0x6C, 0x0F, 0x03, 0xC0, 0xF0, 0x6F, 0xF3, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x00, +/* 0xD1 */ 0x1F, 0x86, 0x19, 0x81, 0xA0, 0x3C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xC0, 0x68, 0x0D, 0x83, 0x18, 0x61, 0xF0, +/* 0xD2 */ 0xFF, 0x86, 0x03, 0x01, 0x80, 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x80, 0xC0, +/* 0xD3 */ 0xC0, 0xF0, 0x66, 0x19, 0x8C, 0x33, 0x0D, 0x81, 0xE0, 0x70, 0x0C, 0x06, 0x01, 0x80, 0xC0, 0x30, 0x00, +/* 0xD4 */ 0x03, 0x00, 0x0C, 0x01, 0xFE, 0x1C, 0xCE, 0xE3, 0x1F, 0x0C, 0x3C, 0x30, 0xF0, 0xC3, 0xE3, 0x1D, 0xCC, 0xE3, 0xFF, 0x00, 0xC0, 0x03, 0x00, +/* 0xD5 */ 0xC0, 0xD8, 0x66, 0x18, 0xCC, 0x1E, 0x07, 0x00, 0xC0, 0x78, 0x32, 0x0C, 0xC6, 0x1B, 0x07, 0xC0, 0xC0, +/* 0xD6 */ 0xC0, 0x66, 0x03, 0x30, 0x19, 0x80, 0xCC, 0x06, 0x60, 0x33, 0x01, 0x98, 0x0C, 0xC0, 0x66, 0x03, 0x30, 0x19, 0x80, 0xCF, 0xFF, 0x80, 0x0C, 0x00, 0x60, +/* 0xD7 */ 0xC1, 0xE0, 0xF0, 0x78, 0x3C, 0x1E, 0x0F, 0x06, 0xFF, 0x01, 0x80, 0xC0, 0x60, 0x30, 0x18, +/* 0xD8 */ 0xC3, 0x1E, 0x18, 0xF0, 0xC7, 0x86, 0x3C, 0x31, 0xE1, 0x8F, 0x0C, 0x78, 0x63, 0xC3, 0x1E, 0x18, 0xF0, 0xC7, 0x86, 0x3F, 0xFF, 0x80, +/* 0xD9 */ 0xC3, 0x19, 0x86, 0x33, 0x0C, 0x66, 0x18, 0xCC, 0x31, 0x98, 0x63, 0x30, 0xC6, 0x61, 0x8C, 0xC3, 0x19, 0x86, 0x33, 0x0C, 0x66, 0x18, 0xCF, 0xFF, 0xE0, 0x00, 0xC0, 0x01, 0x80, +/* 0xDA */ 0xF8, 0x00, 0xC0, 0x06, 0x00, 0x30, 0x01, 0x80, 0x0F, 0xF0, 0x60, 0xC3, 0x03, 0x18, 0x18, 0xC0, 0xC6, 0x06, 0x30, 0x61, 0xFE, 0x00, +/* 0xDB */ 0xC0, 0x0F, 0x00, 0x3C, 0x00, 0xF0, 0x03, 0xC0, 0x0F, 0xFE, 0x3C, 0x0C, 0xF0, 0x1B, 0xC0, 0x6F, 0x01, 0xBC, 0x06, 0xF0, 0x33, 0xFF, 0x8C, +/* 0xDC */ 0xC0, 0x18, 0x03, 0x00, 0x60, 0x0C, 0x01, 0xFF, 0x30, 0x36, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x6F, 0xF8, +/* 0xDD */ 0x3F, 0x0C, 0x33, 0x83, 0x60, 0x20, 0x06, 0x00, 0x47, 0xF8, 0x01, 0xC0, 0x78, 0x0D, 0x81, 0x30, 0xC1, 0xF0, +/* 0xDE */ 0xC0, 0xF8, 0x61, 0x83, 0x31, 0x80, 0xD8, 0xC0, 0x6C, 0xC0, 0x1E, 0x60, 0x0F, 0xF0, 0x07, 0x98, 0x03, 0xCC, 0x01, 0xE3, 0x01, 0xB1, 0x80, 0xD8, 0x60, 0xCC, 0x0F, 0x80, +/* 0xDF */ 0x3F, 0xD8, 0x3C, 0x0F, 0x03, 0xC0, 0xD8, 0x33, 0xFC, 0x33, 0x18, 0xCC, 0x36, 0x0D, 0x83, 0xC0, 0xC0, +/* 0xE0 */ 0x7E, 0x71, 0xB0, 0xC0, 0x60, 0xF3, 0xDB, 0x0D, 0x86, 0xC7, 0x3D, 0xC0, +/* 0xE1 */ 0x03, 0x1F, 0x78, 0x40, 0xFC, 0xE6, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x66, 0x3C, +/* 0xE2 */ 0xFD, 0x8F, 0x0E, 0x3F, 0xDF, 0xB1, 0xE1, 0xC7, 0xF8, +/* 0xE3 */ 0xFE, 0x31, 0x8C, 0x63, 0x18, 0xC6, 0x00, +/* 0xE4 */ 0x1F, 0x83, 0x30, 0x66, 0x0C, 0xC1, 0x98, 0x33, 0x06, 0x61, 0x8C, 0x31, 0x9F, 0xFF, 0x01, 0xE0, 0x30, +/* 0xE5 */ 0x3C, 0x66, 0xC3, 0xC3, 0xFF, 0xC0, 0xC0, 0xC3, 0x66, 0x3C, +/* 0xE6 */ 0xC6, 0x36, 0x66, 0x36, 0xC1, 0xF8, 0x0F, 0x01, 0xF8, 0x36, 0xC6, 0x66, 0xC6, 0x38, 0x61, +/* 0xE7 */ 0x79, 0x8C, 0x18, 0x30, 0x43, 0x01, 0xE3, 0xC6, 0xF8, +/* 0xE8 */ 0xC7, 0xC7, 0xCF, 0xCB, 0xCB, 0xD3, 0xD3, 0xF3, 0xE3, 0xE3, +/* 0xE9 */ 0x66, 0x18, 0xC7, 0xC7, 0xCF, 0xCB, 0xCB, 0xD3, 0xD3, 0xF3, 0xE3, 0xE3, +/* 0xEA */ 0xC7, 0x9B, 0x66, 0x8E, 0x1E, 0x36, 0x66, 0xC7, 0x84, +/* 0xEB */ 0x7E, 0xCD, 0x9B, 0x36, 0x6C, 0xD9, 0xA3, 0xC7, 0x0C, +/* 0xEC */ 0xE3, 0xF1, 0xF8, 0xFE, 0xFF, 0x7E, 0xAF, 0x77, 0x93, 0xC9, 0xE0, 0xC0, +/* 0xED */ 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xFF, 0xC3, 0xC3, 0xC3, 0xC3, +/* 0xEE */ 0x3C, 0x66, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x66, 0x3C, +/* 0xEF */ 0xFF, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, +/* 0xF0 */ 0xDE, 0x71, 0xB0, 0x78, 0x3C, 0x1E, 0x0F, 0x07, 0x83, 0xE3, 0x6F, 0x30, 0x18, 0x0C, 0x00, +/* 0xF1 */ 0x3C, 0x66, 0xC3, 0xC0, 0xC0, 0xC0, 0xC0, 0xC3, 0x66, 0x3C, +/* 0xF2 */ 0xFC, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC0, +/* 0xF3 */ 0xC1, 0x43, 0x63, 0x62, 0x26, 0x36, 0x34, 0x1C, 0x1C, 0x18, 0x18, 0x18, 0x10, 0x60, +/* 0xF4 */ 0x03, 0x00, 0x0C, 0x03, 0xB7, 0x19, 0xE6, 0xC3, 0x0F, 0x0C, 0x3C, 0x30, 0xF0, 0xC3, 0xC3, 0x0F, 0x0C, 0x36, 0x79, 0x8E, 0xDC, 0x03, 0x00, 0x0C, 0x00, 0x30, 0x00, +/* 0xF5 */ 0x87, 0x89, 0xB1, 0xC3, 0x07, 0x1E, 0x26, 0xC5, 0x0C, +/* 0xF6 */ 0xC3, 0x30, 0xCC, 0x33, 0x0C, 0xC3, 0x30, 0xCC, 0x33, 0x0C, 0xC3, 0x3F, 0xF0, 0x0C, 0x03, +/* 0xF7 */ 0xC7, 0x8F, 0x1E, 0x3C, 0x6F, 0xC1, 0x83, 0x06, 0x0C, +/* 0xF8 */ 0xCC, 0xF3, 0x3C, 0xCF, 0x33, 0xCC, 0xF3, 0x3C, 0xCF, 0x33, 0xCC, 0xFF, 0xF0, +/* 0xF9 */ 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCF, 0xFF, 0x00, 0x30, 0x03, +/* 0xFA */ 0xF0, 0x18, 0x0C, 0x06, 0x03, 0xF1, 0x8C, 0xC6, 0x63, 0x31, 0x9F, 0x80, +/* 0xFB */ 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xFE, 0xF0, 0xFC, 0x3F, 0x0F, 0xC3, 0xFF, 0xB0, +/* 0xFC */ 0xC0, 0xC0, 0xC0, 0xC0, 0xFE, 0xC3, 0xC3, 0xC3, 0xC3, 0xFE, +/* 0xFD */ 0x3C, 0x62, 0xC3, 0x01, 0x1F, 0x01, 0x01, 0xC3, 0x62, 0x3C, +/* 0xFE */ 0xC7, 0xCC, 0xC6, 0xD8, 0x3D, 0x83, 0xF8, 0x3D, 0x83, 0xD8, 0x3C, 0xC2, 0xCC, 0x6C, 0x7C, +/* 0xFF */ 0x7F, 0xC3, 0xC3, 0xC3, 0x7F, 0x13, 0x33, 0x63, 0xC3, 0x83, }; const GFXglyph FreeSans9pt_Win1251Glyphs[] PROGMEM = { - /* ' ' 0x20 */ {0, 0, 0, 5, 0, 0}, - /* '!' 0x21 */ {0, 2, 13, 6, 2, -12}, - /* '"' 0x22 */ {4, 5, 4, 6, 1, -12}, - /* '#' 0x23 */ {7, 10, 12, 10, 0, -11}, - /* '$' 0x24 */ {22, 9, 16, 10, 1, -13}, - /* '%' 0x25 */ {40, 16, 13, 16, 1, -12}, - /* '&' 0x26 */ {66, 10, 13, 12, 1, -12}, - /* ''' 0x27 */ {83, 2, 4, 4, 1, -12}, - /* '(' 0x28 */ {84, 4, 17, 6, 1, -12}, - /* ')' 0x29 */ {93, 4, 17, 6, 1, -12}, - /* '*' 0x2A */ {102, 5, 5, 7, 1, -12}, - /* '+' 0x2B */ {106, 6, 8, 11, 3, -7}, - /* ',' 0x2C */ {112, 2, 4, 5, 2, 0}, - /* '-' 0x2D */ {113, 4, 1, 6, 1, -4}, - /* '.' 0x2E */ {114, 2, 1, 5, 1, 0}, - /* '/' 0x2F */ {115, 5, 13, 5, 0, -12}, - /* '0' 0x30 */ {124, 8, 13, 10, 1, -12}, - /* '1' 0x31 */ {137, 4, 13, 10, 3, -12}, - /* '2' 0x32 */ {144, 9, 13, 10, 1, -12}, - /* '3' 0x33 */ {159, 8, 13, 10, 1, -12}, - /* '4' 0x34 */ {172, 7, 13, 10, 2, -12}, - /* '5' 0x35 */ {184, 9, 13, 10, 1, -12}, - /* '6' 0x36 */ {199, 9, 13, 10, 1, -12}, - /* '7' 0x37 */ {214, 8, 13, 10, 0, -12}, - /* '8' 0x38 */ {227, 9, 13, 10, 1, -12}, - /* '9' 0x39 */ {242, 8, 13, 10, 1, -12}, - /* ':' 0x3A */ {255, 2, 10, 5, 1, -9}, - /* ';' 0x3B */ {258, 3, 12, 5, 1, -8}, - /* '<' 0x3C */ {263, 9, 9, 11, 1, -8}, - /* '=' 0x3D */ {274, 9, 4, 11, 1, -5}, - /* '>' 0x3E */ {279, 9, 8, 11, 1, -7}, - /* '?' 0x3F */ {288, 9, 13, 10, 1, -12}, - /* '@' 0x40 */ {303, 17, 16, 18, 1, -12}, - /* 'A' 0x41 */ {337, 12, 13, 12, 0, -12}, - /* 'B' 0x42 */ {357, 11, 13, 12, 1, -12}, - /* 'C' 0x43 */ {375, 11, 13, 13, 1, -12}, - /* 'D' 0x44 */ {393, 11, 13, 13, 1, -12}, - /* 'E' 0x45 */ {411, 9, 13, 11, 1, -12}, - /* 'F' 0x46 */ {426, 8, 13, 11, 1, -12}, - /* 'G' 0x47 */ {439, 12, 13, 14, 1, -12}, - /* 'H' 0x48 */ {459, 11, 13, 13, 1, -12}, - /* 'I' 0x49 */ {477, 2, 13, 5, 2, -12}, - /* 'J' 0x4A */ {481, 7, 13, 10, 1, -12}, - /* 'K' 0x4B */ {493, 10, 13, 12, 1, -12}, - /* 'L' 0x4C */ {510, 8, 13, 10, 1, -12}, - /* 'M' 0x4D */ {523, 13, 13, 15, 1, -12}, - /* 'N' 0x4E */ {545, 11, 13, 13, 1, -12}, - /* 'O' 0x4F */ {563, 13, 13, 14, 1, -12}, - /* 'P' 0x50 */ {585, 10, 13, 12, 1, -12}, - /* 'Q' 0x51 */ {602, 13, 14, 14, 1, -12}, - /* 'R' 0x52 */ {625, 12, 13, 13, 1, -12}, - /* 'S' 0x53 */ {645, 10, 13, 12, 1, -12}, - /* 'T' 0x54 */ {662, 9, 13, 11, 1, -12}, - /* 'U' 0x55 */ {677, 11, 13, 13, 1, -12}, - /* 'V' 0x56 */ {695, 11, 13, 11, 0, -12}, - /* 'W' 0x57 */ {713, 16, 13, 17, 0, -12}, - /* 'X' 0x58 */ {739, 10, 13, 12, 1, -12}, - /* 'Y' 0x59 */ {756, 12, 13, 12, 0, -12}, - /* 'Z' 0x5A */ {776, 10, 13, 11, 1, -12}, - /* '[' 0x5B */ {793, 3, 17, 5, 1, -12}, - /* '\' 0x5C */ {800, 5, 13, 5, 0, -12}, - /* ']' 0x5D */ {809, 3, 17, 5, 0, -12}, - /* '^' 0x5E */ {816, 7, 7, 8, 1, -12}, - /* '_' 0x5F */ {823, 10, 1, 10, 0, 3}, - /* '`' 0x60 */ {825, 4, 3, 5, 0, -12}, - /* 'a' 0x61 */ {827, 9, 10, 10, 1, -9}, - /* 'b' 0x62 */ {839, 9, 13, 10, 1, -12}, - /* 'c' 0x63 */ {854, 8, 10, 9, 1, -9}, - /* 'd' 0x64 */ {864, 8, 13, 10, 1, -12}, - /* 'e' 0x65 */ {877, 8, 10, 10, 1, -9}, - /* 'f' 0x66 */ {887, 4, 13, 5, 1, -12}, - /* 'g' 0x67 */ {894, 8, 14, 10, 1, -9}, - /* 'h' 0x68 */ {908, 8, 13, 10, 1, -12}, - /* 'i' 0x69 */ {921, 2, 13, 4, 1, -12}, - /* 'j' 0x6A */ {925, 4, 17, 4, 0, -12}, - /* 'k' 0x6B */ {934, 8, 13, 9, 1, -12}, - /* 'l' 0x6C */ {947, 2, 13, 4, 1, -12}, - /* 'm' 0x6D */ {951, 13, 10, 15, 1, -9}, - /* 'n' 0x6E */ {968, 8, 10, 10, 1, -9}, - /* 'o' 0x6F */ {978, 8, 10, 10, 1, -9}, - /* 'p' 0x70 */ {988, 9, 13, 10, 1, -9}, - /* 'q' 0x71 */ {1003, 8, 13, 10, 1, -9}, - /* 'r' 0x72 */ {1016, 5, 10, 6, 1, -9}, - /* 's' 0x73 */ {1023, 8, 10, 9, 1, -9}, - /* 't' 0x74 */ {1033, 4, 12, 5, 1, -11}, - /* 'u' 0x75 */ {1039, 8, 10, 10, 1, -9}, - /* 'v' 0x76 */ {1049, 9, 10, 9, 0, -9}, - /* 'w' 0x77 */ {1061, 13, 10, 13, 0, -9}, - /* 'x' 0x78 */ {1078, 7, 10, 9, 1, -9}, - /* 'y' 0x79 */ {1087, 8, 14, 9, 0, -9}, - /* 'z' 0x7A */ {1101, 7, 10, 9, 1, -9}, - /* '{' 0x7B */ {1110, 4, 17, 6, 1, -12}, - /* '|' 0x7C */ {1119, 2, 17, 4, 2, -12}, - /* '}' 0x7D */ {1124, 4, 17, 6, 1, -12}, - /* '~' 0x7E */ {1133, 7, 3, 9, 1, -7}, - /* 0x7F */ {1136, 13, 14, 15, 1, -12}, - /* 0x80 */ {1159, 12, 16, 14, 1, -12}, - /* 0x81 */ {1183, 8, 15, 11, 1, -14}, - /* 0x82 */ {1198, 2, 3, 5, 1, 0}, - /* 0x83 */ {1199, 5, 13, 7, 1, -12}, - /* 0x84 */ {1208, 5, 3, 7, 1, 0}, - /* 0x85 */ {1210, 10, 1, 12, 1, 0}, - /* 0x86 */ {1212, 8, 16, 10, 1, -12}, - /* 0x87 */ {1228, 8, 16, 10, 1, -12}, - /* 0x88 */ {1244, 10, 13, 12, 1, -12}, - /* 0x89 */ {1261, 18, 13, 18, 0, -12}, - /* 0x8A */ {1291, 17, 13, 18, 1, -12}, - /* 0x8B */ {1319, 2, 4, 4, 1, -6}, - /* 0x8C */ {1320, 17, 13, 18, 1, -12}, - /* 0x8D */ {1348, 10, 15, 11, 1, -14}, - /* 0x8E */ {1367, 12, 13, 14, 1, -12}, - /* 0x8F */ {1387, 11, 15, 13, 1, -12}, - /* 0x90 */ {1408, 9, 16, 10, 1, -12}, - /* 0x91 */ {1426, 2, 4, 4, 2, -12}, - /* 0x92 */ {1427, 2, 4, 4, 1, -12}, - /* 0x93 */ {1428, 5, 4, 7, 2, -12}, - /* 0x94 */ {1431, 5, 4, 7, 1, -12}, - /* 0x95 */ {1434, 4, 5, 7, 1, -8}, - /* 0x96 */ {1437, 7, 1, 9, 1, -4}, - /* 0x97 */ {1438, 16, 1, 18, 1, -4}, - /* 0x98 */ {1440, 0, 0, 0, 0, 0}, - /* 0x99 */ {1440, 18, 10, 18, 1, -13}, - /* 0x9A */ {1463, 13, 10, 14, 1, -9}, - /* 0x9B */ {1480, 2, 4, 5, 2, -6}, - /* 0x9C */ {1481, 14, 10, 15, 1, -9}, - /* 0x9D */ {1499, 7, 13, 9, 1, -12}, - /* 0x9E */ {1511, 9, 13, 10, 1, -12}, - /* 0x9F */ {1526, 8, 12, 10, 1, -9}, - /* 0xA0 */ {1538, 0, 0, 5, 0, 0}, - /* 0xA1 */ {1538, 10, 15, 11, 1, -14}, - /* 0xA2 */ {1557, 8, 16, 9, 0, -11}, - /* 0xA3 */ {1573, 7, 13, 10, 1, -12}, - /* 0xA4 */ {1585, 7, 6, 10, 2, -8}, - /* 0xA5 */ {1591, 10, 14, 11, 1, -13}, - /* 0xA6 */ {1609, 2, 17, 5, 2, -12}, - /* 0xA7 */ {1614, 9, 17, 10, 1, -12}, - /* 0xA8 */ {1634, 9, 15, 12, 1, -14}, - /* 0xA9 */ {1651, 14, 13, 14, 1, -12}, - /* 0xAA */ {1674, 11, 13, 13, 1, -12}, - /* 0xAB */ {1692, 7, 6, 9, 1, -7}, - /* 0xAC */ {1698, 9, 5, 11, 2, -5}, - /* 0xAD */ {1704, 0, 0, 0, 0, 0}, - /* 0xAE */ {1704, 14, 13, 14, 1, -12}, - /* 0xAF */ {1727, 6, 15, 5, 0, -14}, - /* 0xB0 */ {1739, 5, 5, 11, 3, -11}, - /* 0xB1 */ {1743, 9, 11, 11, 1, -10}, - /* 0xB2 */ {1756, 2, 13, 4, 1, -12}, - /* 0xB3 */ {1760, 2, 13, 4, 1, -12}, - /* 0xB4 */ {1764, 6, 12, 7, 1, -11}, - /* 0xB5 */ {1773, 9, 13, 10, 1, -9}, - /* 0xB6 */ {1788, 8, 16, 10, 2, -12}, - /* 0xB7 */ {1804, 3, 1, 5, 1, -4}, - /* 0xB8 */ {1805, 8, 12, 10, 1, -11}, - /* 0xB9 */ {1817, 15, 13, 17, 1, -12}, - /* 0xBA */ {1842, 8, 10, 9, 1, -9}, - /* 0xBB */ {1852, 7, 6, 9, 1, -7}, - /* 0xBC */ {1858, 4, 17, 4, 0, -12}, - /* 0xBD */ {1867, 10, 13, 12, 1, -12}, - /* 0xBE */ {1884, 8, 10, 9, 1, -9}, - /* 0xBF */ {1894, 6, 12, 5, -1, -11}, - /* 0xC0 */ {1903, 12, 13, 12, 0, -12}, - /* 0xC1 */ {1923, 11, 13, 12, 1, -12}, - /* 0xC2 */ {1941, 11, 13, 12, 1, -12}, - /* 0xC3 */ {1959, 8, 13, 8, 1, -12}, - /* 0xC4 */ {1972, 14, 16, 15, 1, -12}, - /* 0xC5 */ {2000, 9, 13, 12, 1, -12}, - /* 0xC6 */ {2015, 16, 13, 16, 0, -12}, - /* 0xC7 */ {2041, 10, 13, 12, 1, -12}, - /* 0xC8 */ {2058, 11, 13, 13, 1, -12}, - /* 0xC9 */ {2076, 11, 16, 13, 1, -15}, - /* 0xCA */ {2098, 10, 13, 11, 1, -12}, - /* 0xCB */ {2115, 10, 13, 12, 1, -12}, - /* 0xCC */ {2132, 13, 13, 15, 1, -12}, - /* 0xCD */ {2154, 11, 13, 13, 1, -12}, - /* 0xCE */ {2172, 13, 13, 14, 1, -12}, - /* 0xCF */ {2194, 11, 13, 13, 1, -12}, - /* 0xD0 */ {2212, 10, 13, 12, 1, -12}, - /* 0xD1 */ {2229, 11, 13, 13, 1, -12}, - /* 0xD2 */ {2247, 9, 13, 11, 1, -12}, - /* 0xD3 */ {2262, 10, 13, 11, 1, -12}, - /* 0xD4 */ {2279, 14, 13, 15, 1, -12}, - /* 0xD5 */ {2302, 10, 13, 12, 1, -12}, - /* 0xD6 */ {2319, 13, 15, 13, 1, -12}, - /* 0xD7 */ {2344, 9, 13, 11, 1, -12}, - /* 0xD8 */ {2359, 13, 13, 15, 1, -12}, - /* 0xD9 */ {2381, 15, 15, 15, 1, -12}, - /* 0xDA */ {2410, 13, 13, 15, 2, -12}, - /* 0xDB */ {2432, 14, 13, 16, 1, -12}, - /* 0xDC */ {2455, 11, 13, 12, 1, -12}, - /* 0xDD */ {2473, 11, 13, 13, 1, -12}, - /* 0xDE */ {2491, 17, 13, 18, 1, -12}, - /* 0xDF */ {2519, 10, 13, 12, 1, -12}, - /* 0xE0 */ {2536, 9, 10, 10, 1, -9}, - /* 0xE1 */ {2548, 8, 14, 10, 1, -13}, - /* 0xE2 */ {2562, 7, 10, 9, 1, -9}, - /* 0xE3 */ {2571, 5, 10, 7, 1, -9}, - /* 0xE4 */ {2578, 11, 12, 10, 0, -9}, - /* 0xE5 */ {2595, 8, 10, 10, 1, -9}, - /* 0xE6 */ {2605, 12, 10, 14, 1, -9}, - /* 0xE7 */ {2620, 7, 10, 9, 1, -9}, - /* 0xE8 */ {2629, 8, 10, 10, 1, -9}, - /* 0xE9 */ {2639, 8, 12, 10, 1, -11}, - /* 0xEA */ {2651, 7, 10, 9, 1, -9}, - /* 0xEB */ {2660, 7, 10, 8, 0, -9}, - /* 0xEC */ {2669, 9, 10, 11, 1, -9}, - /* 0xED */ {2681, 8, 10, 10, 1, -9}, - /* 0xEE */ {2691, 8, 10, 10, 1, -9}, - /* 0xEF */ {2701, 8, 10, 10, 1, -9}, - /* 0xF0 */ {2711, 9, 13, 10, 1, -9}, - /* 0xF1 */ {2726, 8, 10, 9, 1, -9}, - /* 0xF2 */ {2736, 6, 10, 7, 1, -9}, - /* 0xF3 */ {2744, 8, 14, 9, 0, -9}, - /* 0xF4 */ {2758, 14, 15, 15, 1, -11}, - /* 0xF5 */ {2785, 7, 10, 9, 1, -9}, - /* 0xF6 */ {2794, 10, 12, 10, 1, -9}, - /* 0xF7 */ {2809, 7, 10, 9, 1, -9}, - /* 0xF8 */ {2818, 10, 10, 12, 1, -9}, - /* 0xF9 */ {2831, 12, 12, 13, 1, -9}, - /* 0xFA */ {2849, 9, 10, 12, 2, -9}, - /* 0xFB */ {2861, 10, 10, 12, 1, -9}, - /* 0xFC */ {2874, 8, 10, 9, 1, -9}, - /* 0xFD */ {2884, 8, 10, 9, 1, -9}, - /* 0xFE */ {2894, 12, 10, 13, 1, -9}, - /* 0xFF */ {2909, 8, 10, 10, 1, -9}, +/* 0x01 */ { 0, 15, 15, 17, 1, -13 }, +/* 0x02 */ { 29, 15, 15, 17, 1, -13 }, +/* 0x03 */ { 58, 15, 16, 17, 1, -14 }, +/* 0x04 */ { 88, 15, 16, 17, 1, -14 }, +/* 0x05 */ { 118, 16, 15, 18, 1, -13 }, +/* 0x06 */ { 148, 15, 15, 17, 1, -13 }, +/* 0x07 */ { 177, 0, 0, 8, 0, 0 }, +/* 0x08 */ { 177, 17, 16, 19, 1, -14 }, +/* 0x09 */ { 211, 17, 12, 19, 1, -12 }, +/* 0x0A */ { 237, 0, 0, 8, 0, 0 }, +/* 0x0B */ { 237, 17, 16, 19, 1, -14 }, +/* 0x0C */ { 271, 15, 14, 17, 1, -12 }, +/* 0x0D */ { 298, 0, 0, 8, 0, 0 }, +/* 0x0E */ { 298, 15, 16, 17, 1, -14 }, +/* 0x0F */ { 328, 15, 15, 17, 1, -13 }, +/* 0x10 */ { 357, 15, 15, 17, 1, -13 }, +/* 0x11 */ { 386, 15, 16, 17, 1, -14 }, +/* 0x12 */ { 416, 17, 17, 19, 1, -15 }, +/* 0x13 */ { 453, 15, 16, 17, 1, -14 }, +/* 0x14 */ { 483, 15, 16, 17, 1, -14 }, +/* 0x15 */ { 513, 15, 16, 17, 1, -14 }, +/* 0x16 */ { 543, 11, 16, 13, 1, -14 }, +/* 0x17 */ { 565, 15, 16, 17, 1, -14 }, +/* 0x18 */ { 595, 18, 15, 20, 1, -13 }, +/* 0x19 */ { 629, 15, 16, 17, 1, -14 }, +/* 0x1A */ { 659, 13, 14, 15, 1, -12 }, +/* 0x1B */ { 682, 17, 16, 19, 1, -14 }, +/* 0x1C */ { 716, 15, 16, 17, 1, -14 }, +/* 0x1D */ { 746, 15, 15, 17, 1, -13 }, +/* 0x1E */ { 775, 17, 16, 19, 1, -14 }, +/* 0x1F */ { 809, 11, 16, 13, 1, -14 }, +/* ' ' 0x20 */ { 831, 0, 0, 5, 0, 0 }, +/* '!' 0x21 */ { 831, 2, 13, 6, 2, -12 }, +/* '"' 0x22 */ { 835, 5, 4, 6, 1, -12 }, +/* '#' 0x23 */ { 838, 10, 12, 10, 0, -11 }, +/* '$' 0x24 */ { 853, 9, 16, 10, 1, -13 }, +/* '%' 0x25 */ { 871, 16, 13, 16, 1, -12 }, +/* '&' 0x26 */ { 897, 10, 13, 12, 1, -12 }, +/* ''' 0x27 */ { 914, 2, 4, 4, 1, -12 }, +/* '(' 0x28 */ { 915, 4, 17, 6, 1, -12 }, +/* ')' 0x29 */ { 924, 4, 17, 6, 1, -12 }, +/* '*' 0x2A */ { 933, 5, 5, 7, 1, -12 }, +/* '+' 0x2B */ { 937, 6, 8, 11, 3, -7 }, +/* ',' 0x2C */ { 943, 2, 4, 5, 2, 0 }, +/* '-' 0x2D */ { 944, 4, 1, 6, 1, -4 }, +/* '.' 0x2E */ { 945, 2, 1, 5, 1, 0 }, +/* '/' 0x2F */ { 946, 5, 13, 5, 0, -12 }, +/* '0' 0x30 */ { 955, 8, 13, 10, 1, -12 }, +/* '1' 0x31 */ { 968, 4, 13, 10, 3, -12 }, +/* '2' 0x32 */ { 975, 9, 13, 10, 1, -12 }, +/* '3' 0x33 */ { 990, 8, 13, 10, 1, -12 }, +/* '4' 0x34 */ { 1003, 7, 13, 10, 2, -12 }, +/* '5' 0x35 */ { 1015, 9, 13, 10, 1, -12 }, +/* '6' 0x36 */ { 1030, 9, 13, 10, 1, -12 }, +/* '7' 0x37 */ { 1045, 8, 13, 10, 0, -12 }, +/* '8' 0x38 */ { 1058, 9, 13, 10, 1, -12 }, +/* '9' 0x39 */ { 1073, 8, 13, 10, 1, -12 }, +/* ':' 0x3A */ { 1086, 2, 10, 5, 1, -9 }, +/* ';' 0x3B */ { 1089, 3, 12, 5, 1, -8 }, +/* '<' 0x3C */ { 1094, 9, 9, 11, 1, -8 }, +/* '=' 0x3D */ { 1105, 9, 4, 11, 1, -5 }, +/* '>' 0x3E */ { 1110, 9, 8, 11, 1, -7 }, +/* '?' 0x3F */ { 1119, 9, 13, 10, 1, -12 }, +/* '@' 0x40 */ { 1134, 17, 16, 18, 1, -12 }, +/* 'A' 0x41 */ { 1168, 12, 13, 12, 0, -12 }, +/* 'B' 0x42 */ { 1188, 11, 13, 12, 1, -12 }, +/* 'C' 0x43 */ { 1206, 11, 13, 13, 1, -12 }, +/* 'D' 0x44 */ { 1224, 11, 13, 13, 1, -12 }, +/* 'E' 0x45 */ { 1242, 9, 13, 11, 1, -12 }, +/* 'F' 0x46 */ { 1257, 8, 13, 11, 1, -12 }, +/* 'G' 0x47 */ { 1270, 12, 13, 14, 1, -12 }, +/* 'H' 0x48 */ { 1290, 11, 13, 13, 1, -12 }, +/* 'I' 0x49 */ { 1308, 2, 13, 5, 2, -12 }, +/* 'J' 0x4A */ { 1312, 7, 13, 10, 1, -12 }, +/* 'K' 0x4B */ { 1324, 10, 13, 12, 1, -12 }, +/* 'L' 0x4C */ { 1341, 8, 13, 10, 1, -12 }, +/* 'M' 0x4D */ { 1354, 13, 13, 15, 1, -12 }, +/* 'N' 0x4E */ { 1376, 11, 13, 13, 1, -12 }, +/* 'O' 0x4F */ { 1394, 13, 13, 14, 1, -12 }, +/* 'P' 0x50 */ { 1416, 10, 13, 12, 1, -12 }, +/* 'Q' 0x51 */ { 1433, 13, 14, 14, 1, -12 }, +/* 'R' 0x52 */ { 1456, 12, 13, 13, 1, -12 }, +/* 'S' 0x53 */ { 1476, 10, 13, 12, 1, -12 }, +/* 'T' 0x54 */ { 1493, 9, 13, 11, 1, -12 }, +/* 'U' 0x55 */ { 1508, 11, 13, 13, 1, -12 }, +/* 'V' 0x56 */ { 1526, 11, 13, 11, 0, -12 }, +/* 'W' 0x57 */ { 1544, 16, 13, 17, 0, -12 }, +/* 'X' 0x58 */ { 1570, 10, 13, 12, 1, -12 }, +/* 'Y' 0x59 */ { 1587, 12, 13, 12, 0, -12 }, +/* 'Z' 0x5A */ { 1607, 10, 13, 11, 1, -12 }, +/* '[' 0x5B */ { 1624, 3, 17, 5, 1, -12 }, +/* '\' 0x5C */ { 1631, 5, 13, 5, 0, -12 }, +/* ']' 0x5D */ { 1640, 3, 17, 5, 0, -12 }, +/* '^' 0x5E */ { 1647, 7, 7, 8, 1, -12 }, +/* '_' 0x5F */ { 1654, 10, 1, 10, 0, 3 }, +/* '`' 0x60 */ { 1656, 4, 3, 5, 0, -12 }, +/* 'a' 0x61 */ { 1658, 9, 10, 10, 1, -9 }, +/* 'b' 0x62 */ { 1670, 9, 13, 10, 1, -12 }, +/* 'c' 0x63 */ { 1685, 8, 10, 9, 1, -9 }, +/* 'd' 0x64 */ { 1695, 8, 13, 10, 1, -12 }, +/* 'e' 0x65 */ { 1708, 8, 10, 10, 1, -9 }, +/* 'f' 0x66 */ { 1718, 4, 13, 5, 1, -12 }, +/* 'g' 0x67 */ { 1725, 8, 14, 10, 1, -9 }, +/* 'h' 0x68 */ { 1739, 8, 13, 10, 1, -12 }, +/* 'i' 0x69 */ { 1752, 2, 13, 4, 1, -12 }, +/* 'j' 0x6A */ { 1756, 4, 17, 4, 0, -12 }, +/* 'k' 0x6B */ { 1765, 8, 13, 9, 1, -12 }, +/* 'l' 0x6C */ { 1778, 2, 13, 4, 1, -12 }, +/* 'm' 0x6D */ { 1782, 13, 10, 15, 1, -9 }, +/* 'n' 0x6E */ { 1799, 8, 10, 10, 1, -9 }, +/* 'o' 0x6F */ { 1809, 8, 10, 10, 1, -9 }, +/* 'p' 0x70 */ { 1819, 9, 13, 10, 1, -9 }, +/* 'q' 0x71 */ { 1834, 8, 13, 10, 1, -9 }, +/* 'r' 0x72 */ { 1847, 5, 10, 6, 1, -9 }, +/* 's' 0x73 */ { 1854, 8, 10, 9, 1, -9 }, +/* 't' 0x74 */ { 1864, 4, 12, 5, 1, -11 }, +/* 'u' 0x75 */ { 1870, 8, 10, 10, 1, -9 }, +/* 'v' 0x76 */ { 1880, 9, 10, 9, 0, -9 }, +/* 'w' 0x77 */ { 1892, 13, 10, 13, 0, -9 }, +/* 'x' 0x78 */ { 1909, 7, 10, 9, 1, -9 }, +/* 'y' 0x79 */ { 1918, 8, 14, 9, 0, -9 }, +/* 'z' 0x7A */ { 1932, 7, 10, 9, 1, -9 }, +/* '{' 0x7B */ { 1941, 4, 17, 6, 1, -12 }, +/* '|' 0x7C */ { 1950, 2, 17, 4, 2, -12 }, +/* '}' 0x7D */ { 1955, 4, 17, 6, 1, -12 }, +/* '~' 0x7E */ { 1964, 7, 3, 9, 1, -7 }, +/* 0x7F */ { 1967, 13, 14, 15, 1, -12 }, +/* 0x80 */ { 1990, 12, 16, 14, 1, -12 }, +/* 0x81 */ { 2014, 8, 15, 11, 1, -14 }, +/* 0x82 */ { 2029, 2, 3, 5, 1, 0 }, +/* 0x83 */ { 2030, 5, 13, 7, 1, -12 }, +/* 0x84 */ { 2039, 5, 3, 7, 1, 0 }, +/* 0x85 */ { 2041, 10, 1, 12, 1, 0 }, +/* 0x86 */ { 2043, 8, 16, 10, 1, -12 }, +/* 0x87 */ { 2059, 8, 16, 10, 1, -12 }, +/* 0x88 */ { 2075, 10, 13, 12, 1, -12 }, +/* 0x89 */ { 2092, 18, 13, 18, 0, -12 }, +/* 0x8A */ { 2122, 17, 13, 18, 1, -12 }, +/* 0x8B */ { 2150, 2, 4, 4, 1, -6 }, +/* 0x8C */ { 2151, 17, 13, 18, 1, -12 }, +/* 0x8D */ { 2179, 10, 15, 11, 1, -14 }, +/* 0x8E */ { 2198, 12, 13, 14, 1, -12 }, +/* 0x8F */ { 2218, 11, 15, 13, 1, -12 }, +/* 0x90 */ { 2239, 9, 16, 10, 1, -12 }, +/* 0x91 */ { 2257, 2, 4, 4, 2, -12 }, +/* 0x92 */ { 2258, 2, 4, 4, 1, -12 }, +/* 0x93 */ { 2259, 5, 4, 7, 2, -12 }, +/* 0x94 */ { 2262, 5, 4, 7, 1, -12 }, +/* 0x95 */ { 2265, 4, 5, 7, 1, -8 }, +/* 0x96 */ { 2268, 7, 1, 9, 1, -4 }, +/* 0x97 */ { 2269, 16, 1, 18, 1, -4 }, +/* 0x98 */ { 2271, 0, 0, 0, 0, 0 }, +/* 0x99 */ { 2271, 18, 10, 18, 1, -13 }, +/* 0x9A */ { 2294, 13, 10, 14, 1, -9 }, +/* 0x9B */ { 2311, 2, 4, 5, 2, -6 }, +/* 0x9C */ { 2312, 14, 10, 15, 1, -9 }, +/* 0x9D */ { 2330, 7, 13, 9, 1, -12 }, +/* 0x9E */ { 2342, 9, 13, 10, 1, -12 }, +/* 0x9F */ { 2357, 8, 12, 10, 1, -9 }, +/* 0xA0 */ { 2369, 0, 0, 5, 0, 0 }, +/* 0xA1 */ { 2369, 10, 15, 11, 1, -14 }, +/* 0xA2 */ { 2388, 8, 16, 9, 0, -11 }, +/* 0xA3 */ { 2404, 7, 13, 10, 1, -12 }, +/* 0xA4 */ { 2416, 7, 6, 10, 2, -8 }, +/* 0xA5 */ { 2422, 10, 14, 11, 1, -13 }, +/* 0xA6 */ { 2440, 2, 17, 5, 2, -12 }, +/* 0xA7 */ { 2445, 9, 17, 10, 1, -12 }, +/* 0xA8 */ { 2465, 9, 15, 12, 1, -14 }, +/* 0xA9 */ { 2482, 14, 13, 14, 1, -12 }, +/* 0xAA */ { 2505, 11, 13, 13, 1, -12 }, +/* 0xAB */ { 2523, 7, 6, 9, 1, -7 }, +/* 0xAC */ { 2529, 9, 5, 11, 2, -5 }, +/* 0xAD */ { 2535, 0, 0, 0, 0, 0 }, +/* 0xAE */ { 2535, 14, 13, 14, 1, -12 }, +/* 0xAF */ { 2558, 6, 15, 5, 0, -14 }, +/* 0xB0 */ { 2570, 5, 5, 11, 3, -11 }, +/* 0xB1 */ { 2574, 9, 11, 11, 1, -10 }, +/* 0xB2 */ { 2587, 2, 13, 4, 1, -12 }, +/* 0xB3 */ { 2591, 2, 13, 4, 1, -12 }, +/* 0xB4 */ { 2595, 6, 12, 7, 1, -11 }, +/* 0xB5 */ { 2604, 9, 13, 10, 1, -9 }, +/* 0xB6 */ { 2619, 8, 16, 10, 2, -12 }, +/* 0xB7 */ { 2635, 3, 1, 5, 1, -4 }, +/* 0xB8 */ { 2636, 8, 12, 10, 1, -11 }, +/* 0xB9 */ { 2648, 15, 13, 17, 1, -12 }, +/* 0xBA */ { 2673, 8, 10, 9, 1, -9 }, +/* 0xBB */ { 2683, 7, 6, 9, 1, -7 }, +/* 0xBC */ { 2689, 4, 17, 4, 0, -12 }, +/* 0xBD */ { 2698, 10, 13, 12, 1, -12 }, +/* 0xBE */ { 2715, 8, 10, 9, 1, -9 }, +/* 0xBF */ { 2725, 6, 12, 5, -1, -11 }, +/* 0xC0 */ { 2734, 12, 13, 12, 0, -12 }, +/* 0xC1 */ { 2754, 11, 13, 12, 1, -12 }, +/* 0xC2 */ { 2772, 11, 13, 12, 1, -12 }, +/* 0xC3 */ { 2790, 8, 13, 8, 1, -12 }, +/* 0xC4 */ { 2803, 14, 16, 15, 1, -12 }, +/* 0xC5 */ { 2831, 9, 13, 12, 1, -12 }, +/* 0xC6 */ { 2846, 16, 13, 16, 0, -12 }, +/* 0xC7 */ { 2872, 10, 13, 12, 1, -12 }, +/* 0xC8 */ { 2889, 11, 13, 13, 1, -12 }, +/* 0xC9 */ { 2907, 11, 16, 13, 1, -15 }, +/* 0xCA */ { 2929, 10, 13, 11, 1, -12 }, +/* 0xCB */ { 2946, 10, 13, 12, 1, -12 }, +/* 0xCC */ { 2963, 13, 13, 15, 1, -12 }, +/* 0xCD */ { 2985, 11, 13, 13, 1, -12 }, +/* 0xCE */ { 3003, 13, 13, 14, 1, -12 }, +/* 0xCF */ { 3025, 11, 13, 13, 1, -12 }, +/* 0xD0 */ { 3043, 10, 13, 12, 1, -12 }, +/* 0xD1 */ { 3060, 11, 13, 13, 1, -12 }, +/* 0xD2 */ { 3078, 9, 13, 11, 1, -12 }, +/* 0xD3 */ { 3093, 10, 13, 11, 1, -12 }, +/* 0xD4 */ { 3110, 14, 13, 15, 1, -12 }, +/* 0xD5 */ { 3133, 10, 13, 12, 1, -12 }, +/* 0xD6 */ { 3150, 13, 15, 13, 1, -12 }, +/* 0xD7 */ { 3175, 9, 13, 11, 1, -12 }, +/* 0xD8 */ { 3190, 13, 13, 15, 1, -12 }, +/* 0xD9 */ { 3212, 15, 15, 15, 1, -12 }, +/* 0xDA */ { 3241, 13, 13, 15, 2, -12 }, +/* 0xDB */ { 3263, 14, 13, 16, 1, -12 }, +/* 0xDC */ { 3286, 11, 13, 12, 1, -12 }, +/* 0xDD */ { 3304, 11, 13, 13, 1, -12 }, +/* 0xDE */ { 3322, 17, 13, 18, 1, -12 }, +/* 0xDF */ { 3350, 10, 13, 12, 1, -12 }, +/* 0xE0 */ { 3367, 9, 10, 10, 1, -9 }, +/* 0xE1 */ { 3379, 8, 14, 10, 1, -13 }, +/* 0xE2 */ { 3393, 7, 10, 9, 1, -9 }, +/* 0xE3 */ { 3402, 5, 10, 7, 1, -9 }, +/* 0xE4 */ { 3409, 11, 12, 10, 0, -9 }, +/* 0xE5 */ { 3426, 8, 10, 10, 1, -9 }, +/* 0xE6 */ { 3436, 12, 10, 14, 1, -9 }, +/* 0xE7 */ { 3451, 7, 10, 9, 1, -9 }, +/* 0xE8 */ { 3460, 8, 10, 10, 1, -9 }, +/* 0xE9 */ { 3470, 8, 12, 10, 1, -11 }, +/* 0xEA */ { 3482, 7, 10, 9, 1, -9 }, +/* 0xEB */ { 3491, 7, 10, 8, 0, -9 }, +/* 0xEC */ { 3500, 9, 10, 11, 1, -9 }, +/* 0xED */ { 3512, 8, 10, 10, 1, -9 }, +/* 0xEE */ { 3522, 8, 10, 10, 1, -9 }, +/* 0xEF */ { 3532, 8, 10, 10, 1, -9 }, +/* 0xF0 */ { 3542, 9, 13, 10, 1, -9 }, +/* 0xF1 */ { 3557, 8, 10, 9, 1, -9 }, +/* 0xF2 */ { 3567, 6, 10, 7, 1, -9 }, +/* 0xF3 */ { 3575, 8, 14, 9, 0, -9 }, +/* 0xF4 */ { 3589, 14, 15, 15, 1, -11 }, +/* 0xF5 */ { 3616, 7, 10, 9, 1, -9 }, +/* 0xF6 */ { 3625, 10, 12, 10, 1, -9 }, +/* 0xF7 */ { 3640, 7, 10, 9, 1, -9 }, +/* 0xF8 */ { 3649, 10, 10, 12, 1, -9 }, +/* 0xF9 */ { 3662, 12, 12, 13, 1, -9 }, +/* 0xFA */ { 3680, 9, 10, 12, 2, -9 }, +/* 0xFB */ { 3692, 10, 10, 12, 1, -9 }, +/* 0xFC */ { 3705, 8, 10, 9, 1, -9 }, +/* 0xFD */ { 3715, 8, 10, 9, 1, -9 }, +/* 0xFE */ { 3725, 12, 10, 13, 1, -9 }, +/* 0xFF */ { 3740, 8, 10, 10, 1, -9 }, }; -const GFXfont FreeSans9pt_Win1251 PROGMEM = {(uint8_t *)FreeSans9pt_Win1251Bitmaps, (GFXglyph *)FreeSans9pt_Win1251Glyphs, 0x20, - 0xFF, 21}; +const GFXfont FreeSans9pt_Win1251 PROGMEM = { +(uint8_t*)FreeSans9pt_Win1251Bitmaps, +(GFXglyph*)FreeSans9pt_Win1251Glyphs, +0x01, 0xFF, 21 +}; diff --git a/src/graphics/niche/Fonts/FreeSans9pt_Win1252.h b/src/graphics/niche/Fonts/FreeSans9pt_Win1252.h index 20f2ddc2f..8bc656632 100644 --- a/src/graphics/niche/Fonts/FreeSans9pt_Win1252.h +++ b/src/graphics/niche/Fonts/FreeSans9pt_Win1252.h @@ -1,494 +1,527 @@ +// trunk-ignore-all(clang-format) #pragma once +/* PROPERTIES + +FONT_NAME FreeSans9pt_Win1252 +*/ const uint8_t FreeSans9pt_Win1252Bitmaps[] PROGMEM = { - /* ' ' 0x20 */ - 0xFF, 0xFF, 0xF0, 0xC0, /* '!' 0x21 */ - 0xDE, 0xF7, 0x20, /* '"' 0x22 */ - 0x09, 0x86, 0x41, 0x91, 0xFF, 0x13, 0x04, 0xC3, 0x20, 0xC8, 0xFF, 0x89, 0x82, 0x61, 0x90, /* '#' 0x23 */ - 0x10, 0x1F, 0x14, 0xDA, 0x3D, 0x1E, 0x83, 0x40, 0x78, 0x17, 0x08, 0xF4, 0x7A, 0x35, 0x33, 0xF0, 0x40, 0x20, /* '$' 0x24 */ - 0x38, 0x10, 0xEC, 0x20, 0xC6, 0x20, 0xC6, 0x40, 0xC6, 0x40, 0x6C, 0x80, 0x39, 0x00, 0x01, 0x3C, 0x02, 0x77, 0x02, 0x63, 0x04, - 0x63, 0x04, 0x77, 0x08, 0x3C, /* '%' 0x25 */ - 0x0E, 0x0C, 0xC3, 0x30, 0xCC, 0x1E, 0x03, 0x03, 0xC1, 0x9B, 0xC2, 0xF0, 0xEC, 0x19, 0x8F, 0x3C, 0x40, /* '&' 0x26 */ - 0xFE, /* ''' 0x27 */ - 0x13, 0x26, 0x6C, 0xCC, 0xCC, 0xC4, 0x66, 0x23, 0x10, /* '(' 0x28 */ - 0x8C, 0x46, 0x63, 0x33, 0x33, 0x32, 0x66, 0x4C, 0x80, /* ')' 0x29 */ - 0x25, 0x7E, 0xA5, 0x00, /* '*' 0x2A */ - 0x30, 0xC3, 0x3F, 0x30, 0xC3, 0x0C, /* '+' 0x2B */ - 0xD6, /* ',' 0x2C */ - 0xF0, /* '-' 0x2D */ - 0xC0, /* '.' 0x2E */ - 0x08, 0x44, 0x21, 0x10, 0x84, 0x42, 0x11, 0x08, 0x00, /* '/' 0x2F */ - 0x3C, 0x66, 0x42, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x42, 0x66, 0x3C, /* '0' 0x30 */ - 0x11, 0x3F, 0x33, 0x33, 0x33, 0x33, 0x30, /* '1' 0x31 */ - 0x3E, 0x31, 0xB0, 0x78, 0x30, 0x18, 0x1C, 0x1C, 0x1C, 0x18, 0x18, 0x10, 0x08, 0x07, 0xF8, /* '2' 0x32 */ - 0x3C, 0x66, 0xC3, 0xC3, 0x03, 0x06, 0x1C, 0x07, 0x03, 0xC3, 0xC3, 0x66, 0x3C, /* '3' 0x33 */ - 0x0C, 0x18, 0x71, 0x62, 0xC9, 0xA3, 0x46, 0xFE, 0x18, 0x30, 0x60, 0xC0, /* '4' 0x34 */ - 0x7F, 0x20, 0x10, 0x08, 0x08, 0x07, 0xF3, 0x8C, 0x03, 0x01, 0x80, 0xF0, 0x6C, 0x63, 0xE0, /* '5' 0x35 */ - 0x1E, 0x31, 0x98, 0x78, 0x0C, 0x06, 0xF3, 0x8D, 0x83, 0xC1, 0xE0, 0xD0, 0x6C, 0x63, 0xE0, /* '6' 0x36 */ - 0xFF, 0x03, 0x02, 0x06, 0x04, 0x0C, 0x08, 0x18, 0x18, 0x18, 0x10, 0x30, 0x30, /* '7' 0x37 */ - 0x3E, 0x31, 0xB0, 0x78, 0x3C, 0x1B, 0x18, 0xF8, 0xC6, 0xC1, 0xE0, 0xF0, 0x6C, 0x63, 0xE0, /* '8' 0x38 */ - 0x3C, 0x66, 0xC2, 0xC3, 0xC3, 0xC3, 0x67, 0x3B, 0x03, 0x03, 0xC2, 0x66, 0x3C, /* '9' 0x39 */ - 0xC0, 0x00, 0x30, /* ':' 0x3A */ - 0xC0, 0x00, 0x00, 0x64, 0xA0, /* ';' 0x3B */ - 0x00, 0x81, 0xC7, 0x8E, 0x0C, 0x07, 0x80, 0x70, 0x0E, 0x01, 0x80, /* '<' 0x3C */ - 0xFF, 0x80, 0x00, 0x1F, 0xF0, /* '=' 0x3D */ - 0xE0, 0x1C, 0x03, 0x80, 0x30, 0x70, 0xE3, 0x81, 0x00, /* '>' 0x3E */ - 0x3E, 0x31, 0xB0, 0x78, 0x30, 0x18, 0x18, 0x38, 0x18, 0x18, 0x0C, 0x00, 0x00, 0x01, 0x80, /* '?' 0x3F */ - 0x03, 0xF0, 0x06, 0x0E, 0x06, 0x01, 0x86, 0x00, 0x66, 0x1D, 0xBB, 0x31, 0xCF, 0x18, 0xC7, 0x98, 0x63, 0xCC, 0x31, 0xE6, 0x11, - 0xB3, 0x99, 0xCC, 0xF7, 0x86, 0x00, 0x01, 0x80, 0x00, 0x70, 0x40, 0x0F, 0xE0, /* '@' 0x40 */ - 0x06, 0x00, 0xF0, 0x0F, 0x00, 0x90, 0x19, 0x81, 0x98, 0x10, 0x83, 0x0C, 0x3F, 0xC2, 0x04, 0x60, 0x66, 0x06, 0xC0, - 0x30, /* 'A' 0x41 */ - 0xFF, 0x18, 0x33, 0x03, 0x60, 0x6C, 0x0D, 0x83, 0x3F, 0xC6, 0x06, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x6F, 0xF8, /* 'B' 0x42 */ - 0x1F, 0x86, 0x19, 0x81, 0xA0, 0x3C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xC0, 0x68, 0x0D, 0x83, 0x18, 0x61, 0xF0, /* 'C' 0x43 */ - 0xFF, 0x18, 0x33, 0x03, 0x60, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x03, 0x60, 0xCF, 0xF0, /* 'D' 0x44 */ - 0xFF, 0xE0, 0x30, 0x18, 0x0C, 0x06, 0x03, 0xFD, 0x80, 0xC0, 0x60, 0x30, 0x18, 0x0F, 0xF8, /* 'E' 0x45 */ - 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFE, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, /* 'F' 0x46 */ - 0x0F, 0x83, 0x0E, 0x60, 0x66, 0x03, 0xC0, 0x0C, 0x00, 0xC1, 0xFC, 0x03, 0xC0, 0x36, 0x03, 0x60, 0x73, 0x0F, 0x0F, - 0x10, /* 'G' 0x47 */ - 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xFF, 0xFE, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x06, /* 'H' 0x48 */ - 0xFF, 0xFF, 0xFF, 0xC0, /* 'I' 0x49 */ - 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x83, 0x07, 0x8F, 0x1E, 0x27, 0x80, /* 'J' 0x4A */ - 0xC0, 0xF0, 0x6C, 0x33, 0x18, 0xCC, 0x37, 0x0F, 0xC3, 0x98, 0xC3, 0x30, 0xCC, 0x1B, 0x03, 0xC0, 0xC0, /* 'K' 0x4B */ - 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, /* 'L' 0x4C */ - 0xE0, 0x3F, 0x01, 0xFC, 0x1F, 0xE0, 0xFD, 0x05, 0xEC, 0x6F, 0x63, 0x79, 0x13, 0xCD, 0x9E, 0x6C, 0xF1, 0x47, 0x8E, 0x3C, 0x71, - 0x80, /* 'M' 0x4D */ - 0xE0, 0x7C, 0x0F, 0xC1, 0xE8, 0x3D, 0x87, 0x98, 0xF1, 0x1E, 0x33, 0xC3, 0x78, 0x6F, 0x07, 0xE0, 0x7C, 0x0E, /* 'N' 0x4E */ - 0x0F, 0x81, 0x83, 0x18, 0x0C, 0xC0, 0x6C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1B, 0x01, 0x98, 0x0C, 0x60, 0xC0, 0xF8, - 0x00, /* 'O' 0x4F */ - 0xFF, 0x30, 0x6C, 0x0F, 0x03, 0xC0, 0xF0, 0x6F, 0xF3, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x00, /* 'P' 0x50 */ - 0x0F, 0x81, 0x83, 0x18, 0x0C, 0xC0, 0x6C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1B, 0x01, 0x98, 0x6C, 0x60, 0xC0, 0xFB, - 0x00, 0x08, /* 'Q' 0x51 */ - 0xFF, 0x8C, 0x0E, 0xC0, 0x6C, 0x06, 0xC0, 0x6C, 0x0C, 0xFF, 0x8C, 0x0E, 0xC0, 0x6C, 0x06, 0xC0, 0x6C, 0x06, 0xC0, - 0x70, /* 'R' 0x52 */ - 0x3F, 0x18, 0x6C, 0x0F, 0x03, 0xC0, 0x1E, 0x01, 0xF0, 0x0E, 0x00, 0xF0, 0x3C, 0x0D, 0x86, 0x3F, 0x00, /* 'S' 0x53 */ - 0xFF, 0x86, 0x03, 0x01, 0x80, 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x80, 0xC0, /* 'T' 0x54 */ - 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xB0, 0x61, 0xF0, /* 'U' 0x55 */ - 0xC0, 0x6C, 0x0D, 0x81, 0x10, 0x63, 0x0C, 0x61, 0x04, 0x60, 0xCC, 0x19, 0x01, 0x60, 0x3C, 0x07, 0x00, 0x60, /* 'V' 0x56 */ - 0xC1, 0x81, 0x61, 0xC3, 0x61, 0xC3, 0x61, 0x43, 0x62, 0x62, 0x22, 0x66, 0x32, 0x26, 0x36, 0x26, 0x14, 0x34, 0x14, 0x34, 0x1C, - 0x1C, 0x18, 0x1C, 0x08, 0x18, /* 'W' 0x57 */ - 0xC0, 0xD8, 0x66, 0x18, 0xCC, 0x1E, 0x07, 0x00, 0xC0, 0x78, 0x32, 0x0C, 0xC6, 0x1B, 0x07, 0xC0, 0xC0, /* 'X' 0x58 */ - 0xC0, 0x36, 0x06, 0x30, 0xC3, 0x0C, 0x19, 0x81, 0xD8, 0x0F, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, - 0x00, /* 'Y' 0x59 */ - 0xFF, 0xC0, 0x60, 0x30, 0x0C, 0x06, 0x03, 0x01, 0xC0, 0x60, 0x30, 0x18, 0x06, 0x03, 0x00, 0xFF, 0xC0, /* 'Z' 0x5A */ - 0xFB, 0x6D, 0xB6, 0xDB, 0x6D, 0xB6, 0xE0, /* '[' 0x5B */ - 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x80, /* '\' 0x5C */ - 0xED, 0xB6, 0xDB, 0x6D, 0xB6, 0xDB, 0xE0, /* ']' 0x5D */ - 0x30, 0x60, 0xA2, 0x44, 0xD8, 0xA1, 0x80, /* '^' 0x5E */ - 0xFF, 0xC0, /* '_' 0x5F */ - 0xC6, 0x30, /* '`' 0x60 */ - 0x7E, 0x71, 0xB0, 0xC0, 0x60, 0xF3, 0xDB, 0x0D, 0x86, 0xC7, 0x3D, 0xC0, /* 'a' 0x61 */ - 0xC0, 0x60, 0x30, 0x1B, 0xCE, 0x36, 0x0F, 0x07, 0x83, 0xC1, 0xE0, 0xF0, 0x7C, 0x6D, 0xE0, /* 'b' 0x62 */ - 0x3C, 0x66, 0xC3, 0xC0, 0xC0, 0xC0, 0xC0, 0xC3, 0x66, 0x3C, /* 'c' 0x63 */ - 0x03, 0x03, 0x03, 0x3B, 0x67, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x67, 0x3B, /* 'd' 0x64 */ - 0x3C, 0x66, 0xC3, 0xC3, 0xFF, 0xC0, 0xC0, 0xC3, 0x66, 0x3C, /* 'e' 0x65 */ - 0x36, 0x6F, 0x66, 0x66, 0x66, 0x66, 0x60, /* 'f' 0x66 */ - 0x3B, 0x67, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x67, 0x3B, 0x03, 0x03, 0xC6, 0x7C, /* 'g' 0x67 */ - 0xC0, 0xC0, 0xC0, 0xDE, 0xE3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, /* 'h' 0x68 */ - 0xC3, 0xFF, 0xFF, 0xC0, /* 'i' 0x69 */ - 0x30, 0x03, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0xE0, /* 'j' 0x6A */ - 0xC0, 0xC0, 0xC0, 0xC2, 0xC4, 0xCC, 0xD8, 0xF8, 0xEC, 0xC4, 0xC6, 0xC3, 0xC3, /* 'k' 0x6B */ - 0xFF, 0xFF, 0xFF, 0xC0, /* 'l' 0x6C */ - 0xDE, 0xF7, 0x1C, 0xF0, 0xC7, 0x86, 0x3C, 0x31, 0xE1, 0x8F, 0x0C, 0x78, 0x63, 0xC3, 0x1E, 0x18, 0xC0, /* 'm' 0x6D */ - 0xDE, 0xE3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, /* 'n' 0x6E */ - 0x3C, 0x66, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x66, 0x3C, /* 'o' 0x6F */ - 0xDE, 0x71, 0xB0, 0x78, 0x3C, 0x1E, 0x0F, 0x07, 0x83, 0xE3, 0x6F, 0x30, 0x18, 0x0C, 0x00, /* 'p' 0x70 */ - 0x3B, 0x67, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x67, 0x3B, 0x03, 0x03, 0x03, /* 'q' 0x71 */ - 0xDF, 0x31, 0x8C, 0x63, 0x18, 0xC6, 0x00, /* 'r' 0x72 */ - 0x3E, 0xE3, 0xC0, 0xC0, 0xE0, 0x3C, 0x07, 0xC3, 0xE3, 0x7E, /* 's' 0x73 */ - 0x66, 0xF6, 0x66, 0x66, 0x66, 0x67, /* 't' 0x74 */ - 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC7, 0x7B, /* 'u' 0x75 */ - 0xC1, 0xA0, 0x98, 0xCC, 0x42, 0x21, 0xB0, 0xD0, 0x28, 0x1C, 0x0C, 0x00, /* 'v' 0x76 */ - 0xC6, 0x1E, 0x38, 0x91, 0xC4, 0xCA, 0x66, 0xD3, 0x16, 0xD0, 0xA6, 0x87, 0x1C, 0x38, 0xC0, 0xC6, 0x00, /* 'w' 0x77 */ - 0x87, 0x89, 0xB1, 0xC3, 0x07, 0x1E, 0x26, 0xC5, 0x0C, /* 'x' 0x78 */ - 0xC1, 0x43, 0x63, 0x62, 0x26, 0x36, 0x34, 0x1C, 0x1C, 0x18, 0x18, 0x18, 0x10, 0x60, /* 'y' 0x79 */ - 0xFE, 0x0C, 0x30, 0xC1, 0x86, 0x18, 0x20, 0xC1, 0xFC, /* 'z' 0x7A */ - 0x36, 0x66, 0x66, 0x6E, 0xCE, 0x66, 0x66, 0x66, 0x30, /* '{' 0x7B */ - 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, /* '|' 0x7C */ - 0xC6, 0x66, 0x66, 0x67, 0x37, 0x66, 0x66, 0x66, 0xC0, /* '}' 0x7D */ - 0x61, 0x24, 0x38, /* '~' 0x7E */ - 0xFF, 0xFC, 0x00, 0x63, 0xE3, 0x31, 0x99, 0x04, 0xC8, 0x66, 0x06, 0x30, 0x61, 0x83, 0x0C, 0x18, 0x60, 0x03, 0x06, 0x18, 0x00, - 0xFF, 0xFC, /* 0x7F */ - 0x07, 0xC6, 0x13, 0x00, 0xC0, 0x60, 0x3F, 0xE6, 0x03, 0xFC, 0x60, 0x0C, 0x03, 0x00, 0x61, 0x07, 0xC0, /* 0x80 */ - /* 0x81 */ - 0xDC, /* 0x82 */ - 0x19, 0x8C, 0xF3, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x18, 0xC6, 0xE0, /* 0x83 */ - 0xDA, 0x76, /* 0x84 */ - 0xCC, 0xC0, /* 0x85 */ - 0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, /* 0x86 */ - 0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18, /* 0x87 */ - 0x72, 0xA2, /* 0x88 */ - 0x70, 0x80, 0x22, 0x20, 0x08, 0x90, 0x02, 0x24, 0x00, 0x72, 0x00, 0x00, 0x80, 0x00, 0x40, 0x00, 0x10, 0x00, 0x09, 0xC7, 0x84, - 0x8B, 0x31, 0x22, 0x84, 0x88, 0xB3, 0x21, 0xC7, 0x80, /* 0x89 */ - 0x1B, 0x03, 0x80, 0x00, 0xFC, 0x61, 0xB0, 0x3C, 0x0F, 0x00, 0x78, 0x07, 0xC0, 0x38, 0x03, 0xC0, 0xF0, 0x36, 0x18, - 0xFC, /* 0x8A */ - 0x69, /* 0x8B */ - 0x1E, 0xFE, 0x43, 0x81, 0x83, 0x06, 0x06, 0x0C, 0x0C, 0x18, 0x18, 0x30, 0x3F, 0xE0, 0x60, 0xC0, 0xC1, 0x81, 0x81, 0x83, 0x01, - 0x8E, 0x01, 0xEF, 0xE0, /* 0x8C */ - /* 0x8D */ - 0x1B, 0x03, 0x80, 0x03, 0xFF, 0x01, 0x80, 0xC0, 0x30, 0x18, 0x0C, 0x07, 0x01, 0x80, 0xC0, 0x60, 0x18, 0x0C, 0x03, - 0xFF, /* 0x8E */ - /* 0x8F */ - /* 0x90 */ - 0x6B, /* 0x91 */ - 0xD6, /* 0x92 */ - 0x4C, 0xA5, 0xB0, /* 0x93 */ - 0xDA, 0x53, 0x20, /* 0x94 */ - 0x6F, 0xFF, 0x60, /* 0x95 */ - 0xFE, /* 0x96 */ - 0xFF, 0xFF, /* 0x97 */ - 0x4D, 0xC0, /* 0x98 */ - 0xFC, 0xE1, 0xCC, 0x38, 0x73, 0x0E, 0x1C, 0xC3, 0x8F, 0x30, 0xD2, 0xCC, 0x34, 0xB3, 0x0D, 0x6C, 0xC3, 0x53, 0x30, 0xCC, 0xCC, - 0x33, 0x30, /* 0x99 */ - 0x24, 0x3C, 0x18, 0x7E, 0xE3, 0xC0, 0xC0, 0x60, 0x3C, 0x07, 0xC3, 0xE3, 0x7E, /* 0x9A */ - 0x96, /* 0x9B */ - 0x3C, 0xF8, 0xCF, 0x1B, 0x0C, 0x1E, 0x18, 0x3C, 0x3F, 0xF8, 0x60, 0x30, 0xC0, 0x61, 0x83, 0x67, 0x8C, 0x79, 0xF0, /* 0x9C */ - /* 0x9D */ - 0x48, 0xF0, 0xC7, 0xF0, 0x61, 0x86, 0x0C, 0x30, 0xC1, 0x06, 0x0F, 0xE0, /* 0x9E */ - 0x19, 0x80, 0x00, 0xC0, 0x36, 0x06, 0x30, 0xC3, 0x0C, 0x19, 0x81, 0xD8, 0x0F, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, - 0x60, /* 0x9F */ - /* 0xA0 */ - 0xCF, 0xFF, 0xFF, 0xC0, /* 0xA1 */ - 0x08, 0x04, 0x0F, 0x8D, 0x6C, 0x9E, 0x43, 0x21, 0x90, 0xC8, 0x64, 0xDA, 0xC7, 0xC0, 0x80, 0x40, /* 0xA2 */ - 0x1F, 0x0C, 0x66, 0x0D, 0x83, 0x60, 0x0C, 0x0F, 0xC0, 0x60, 0x18, 0x06, 0x03, 0x01, 0xF1, 0x43, 0xC0, /* 0xA3 */ - 0xFF, 0xDF, 0x1E, 0x3E, 0xFF, 0xC0, /* 0xA4 */ - 0xC3, 0x42, 0x42, 0x24, 0x24, 0x3C, 0x18, 0x7E, 0x18, 0x7E, 0x18, 0x18, 0x18, /* 0xA5 */ - 0xFF, 0xFC, 0x0F, 0xFF, 0xC0, /* 0xA6 */ - 0x0C, 0x09, 0x0C, 0xC6, 0x63, 0x81, 0xE3, 0x19, 0x87, 0xE1, 0xB8, 0xC6, 0x41, 0xC0, 0x73, 0x19, 0x8C, 0x66, 0x1E, - 0x00, /* 0xA7 */ - 0xCC, /* 0xA8 */ - 0x0F, 0xC0, 0x61, 0x87, 0x03, 0x9B, 0xC6, 0xD9, 0x8F, 0x60, 0x3D, 0x00, 0xF4, 0x03, 0xD8, 0x0D, 0xE6, 0x67, 0xF3, 0x86, 0x18, - 0x0F, 0xC0, /* 0xA9 */ - 0x74, 0x8D, 0xA9, 0x7C, 0x1F, /* 0xAA */ - 0x22, 0xCF, 0x26, 0x46, 0x64, 0x40, /* 0xAB */ - 0xFF, 0x80, 0xC0, 0x60, 0x30, 0x18, /* 0xAC */ - /* 0xAD */ - 0x0F, 0xC0, 0x61, 0x87, 0x03, 0x9F, 0xE6, 0xD0, 0x8F, 0x42, 0x3D, 0xF0, 0xF4, 0x23, 0xD0, 0x8D, 0xC2, 0x67, 0x0B, 0x86, 0x18, - 0x0F, 0xC0, /* 0xAE */ - 0xF8, /* 0xAF */ - 0x74, 0x63, 0x17, 0x00, /* 0xB0 */ - 0x0C, 0x06, 0x03, 0x07, 0xE0, 0xC0, 0x60, 0x30, 0x18, 0x00, 0x00, 0x3F, 0xE0, /* 0xB1 */ - 0x7B, 0x30, 0xC3, 0x11, 0x84, 0x3F, /* 0xB2 */ - 0x7D, 0x8C, 0x18, 0xC0, 0x60, 0xF1, 0xBE, /* 0xB3 */ - 0x36, 0xC0, /* 0xB4 */ - 0xC3, 0x61, 0xB0, 0xD8, 0x6C, 0x36, 0x1B, 0x0D, 0x86, 0xE7, 0x7D, 0xF0, 0x18, 0x0C, 0x00, /* 0xB5 */ - 0x3F, 0x7E, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0x72, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, /* 0xB6 */ - 0xE0, /* 0xB7 */ - 0x21, 0xC7, 0xE0, /* 0xB8 */ - 0x3D, 0xB6, 0xD8, /* 0xB9 */ - 0x74, 0x63, 0x18, 0xB8, 0x1F, /* 0xBA */ - 0x89, 0x98, 0x99, 0x3C, 0xD1, 0x00, /* 0xBB */ - 0x20, 0x43, 0x81, 0x06, 0x08, 0x18, 0x20, 0x61, 0x01, 0x84, 0x06, 0x21, 0x80, 0x86, 0x04, 0x78, 0x32, 0x60, 0x87, 0xC4, 0x06, - 0x10, 0x18, /* 0xBC */ - 0x20, 0x43, 0x81, 0x06, 0x08, 0x18, 0x20, 0x61, 0x01, 0x8D, 0xE6, 0x2C, 0xC1, 0x03, 0x0C, 0x0C, 0x20, 0x41, 0x86, 0x0C, 0x30, - 0x20, 0xFC, /* 0xBD */ - 0x78, 0x11, 0x98, 0x40, 0x31, 0x00, 0x82, 0x00, 0xC8, 0x01, 0x90, 0x33, 0x43, 0x3D, 0x06, 0x02, 0x3C, 0x08, 0x98, 0x10, 0xF8, - 0x40, 0x61, 0x00, 0xC0, /* 0xBE */ - 0x0C, 0x00, 0x00, 0x01, 0x80, 0xC0, 0xC0, 0xE0, 0xC0, 0xC0, 0x60, 0xF0, 0x6C, 0x63, 0xE0, /* 0xBF */ - 0x18, 0x03, 0x00, 0x00, 0x30, 0x1E, 0x07, 0x81, 0x20, 0xCC, 0x33, 0x0F, 0xC6, 0x19, 0x86, 0x40, 0xB0, 0x30, /* 0xC0 */ - 0x06, 0x03, 0x00, 0x00, 0x30, 0x1E, 0x07, 0x81, 0x20, 0xCC, 0x33, 0x0F, 0xC6, 0x19, 0x86, 0x40, 0xB0, 0x30, /* 0xC1 */ - 0x0C, 0x04, 0x80, 0x00, 0x30, 0x1E, 0x07, 0x81, 0x20, 0xCC, 0x33, 0x0F, 0xC6, 0x19, 0x86, 0x40, 0xB0, 0x30, /* 0xC2 */ - 0x19, 0x09, 0x80, 0x00, 0x30, 0x1E, 0x07, 0x81, 0x20, 0xCC, 0x33, 0x0F, 0xC6, 0x19, 0x86, 0x40, 0xB0, 0x30, /* 0xC3 */ - 0x33, 0x00, 0x00, 0xC0, 0x78, 0x1E, 0x04, 0x83, 0x30, 0xCC, 0x33, 0x1F, 0xE6, 0x19, 0x02, 0xC0, 0xF0, 0x30, /* 0xC4 */ - 0x0C, 0x04, 0x81, 0x20, 0x30, 0x1E, 0x07, 0x81, 0x20, 0xCC, 0x33, 0x0F, 0xC6, 0x19, 0x86, 0x40, 0xB0, 0x30, /* 0xC5 */ - 0x07, 0xFF, 0x04, 0xC0, 0x0C, 0xC0, 0x08, 0xC0, 0x18, 0xC0, 0x18, 0xC0, 0x30, 0xFF, 0x30, 0xC0, 0x3F, 0xC0, 0x60, 0xC0, 0x60, - 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, /* 0xC6 */ - 0x1F, 0x06, 0x19, 0x83, 0xA0, 0x3C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xC0, 0x68, 0x0D, 0x83, 0x18, 0xE1, 0xF0, 0x08, 0x01, 0xC0, - 0x18, 0x0E, 0x00, /* 0xC7 */ - 0x18, 0x06, 0x00, 0x1F, 0xFC, 0x06, 0x03, 0x01, 0x80, 0xFF, 0x60, 0x30, 0x18, 0x0C, 0x07, 0xFC, /* 0xC8 */ - 0x0C, 0x0C, 0x00, 0x1F, 0xFC, 0x06, 0x03, 0x01, 0x80, 0xFF, 0x60, 0x30, 0x18, 0x0C, 0x07, 0xFC, /* 0xC9 */ - 0x1C, 0x1B, 0x00, 0x1F, 0xFC, 0x06, 0x03, 0x01, 0x80, 0xFF, 0x60, 0x30, 0x18, 0x0C, 0x07, 0xFC, /* 0xCA */ - 0x33, 0x00, 0x3F, 0xF8, 0x0C, 0x06, 0x03, 0x01, 0xFE, 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x07, 0xFC, /* 0xCB */ - 0xCC, 0x36, 0xDB, 0x6D, 0xB6, 0xD8, /* 0xCC */ - 0x78, 0x36, 0xDB, 0x6D, 0xB6, 0xC0, /* 0xCD */ - 0x76, 0xC0, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x18, /* 0xCE */ - 0xCC, 0x03, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC0, /* 0xCF */ - 0x7F, 0x0C, 0x31, 0x83, 0x30, 0x36, 0x06, 0xC0, 0xFE, 0x1B, 0x03, 0x60, 0x6C, 0x0D, 0x83, 0x30, 0xE7, 0xF0, /* 0xD0 */ - 0x19, 0x02, 0xC3, 0x81, 0xF0, 0x3F, 0x07, 0xA0, 0xF6, 0x1E, 0x63, 0xC4, 0x78, 0xCF, 0x0D, 0xE1, 0xBC, 0x1F, 0x81, - 0xC0, /* 0xD1 */ - 0x0C, 0x00, 0x60, 0x00, 0x00, 0xF0, 0x39, 0xC6, 0x06, 0x60, 0x6C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x36, 0x06, 0x60, 0x63, 0x9C, - 0x0F, 0x00, /* 0xD2 */ - 0x03, 0x00, 0x60, 0x00, 0x00, 0xF0, 0x39, 0xC6, 0x06, 0x60, 0x6C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x36, 0x06, 0x60, 0x63, 0x9C, - 0x0F, 0x00, /* 0xD3 */ - 0x0F, 0x01, 0x98, 0x00, 0x00, 0xF0, 0x39, 0xC6, 0x06, 0x60, 0x6C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x36, 0x06, 0x60, 0x63, 0x9C, - 0x0F, 0x00, /* 0xD4 */ - 0x1C, 0x81, 0x38, 0x00, 0x00, 0xF0, 0x39, 0xC6, 0x06, 0x60, 0x6C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x36, 0x06, 0x60, 0x63, 0x9C, - 0x0F, 0x00, /* 0xD5 */ - 0x19, 0x81, 0x98, 0x00, 0x00, 0xF0, 0x39, 0xC6, 0x06, 0x60, 0x6C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x36, 0x06, 0x60, 0x63, 0x9C, - 0x0F, 0x00, /* 0xD6 */ - 0x83, 0x89, 0xA1, 0x83, 0x89, 0xA1, 0x80, /* 0xD7 */ - 0x0F, 0xD9, 0x83, 0x18, 0x1C, 0xC1, 0xEC, 0x19, 0xE0, 0x8F, 0x08, 0x78, 0x83, 0xC8, 0x1B, 0x81, 0x98, 0x0C, 0xE0, 0xC8, 0xF8, - 0x00, /* 0xD8 */ - 0x0C, 0x00, 0xC3, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x36, 0x0C, 0x3E, - 0x00, /* 0xD9 */ - 0x06, 0x01, 0x83, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x36, 0x0C, 0x3E, - 0x00, /* 0xDA */ - 0x0E, 0x03, 0x63, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x36, 0x0C, 0x3E, - 0x00, /* 0xDB */ - 0x1B, 0x00, 0x03, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x36, 0x0C, 0x3E, - 0x00, /* 0xDC */ - 0x03, 0x0C, 0x63, 0x60, 0x63, 0x0C, 0x30, 0xC1, 0x98, 0x1D, 0x80, 0xF0, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, - 0x60, /* 0xDD */ - 0xC0, 0x30, 0x0F, 0xF3, 0x06, 0xC0, 0xF0, 0x3C, 0x0F, 0x06, 0xFF, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x00, /* 0xDE */ - 0x3C, 0x33, 0x30, 0xD8, 0x6C, 0x36, 0x33, 0x39, 0x86, 0xC1, 0xE0, 0xF0, 0x78, 0x6D, 0xE0, /* 0xDF */ - 0x60, 0x18, 0x06, 0x0F, 0xCE, 0x36, 0x18, 0x0C, 0x1E, 0x7B, 0x61, 0xB0, 0xD8, 0xE7, 0xB8, /* 0xE0 */ - 0x0C, 0x04, 0x04, 0x0F, 0xCE, 0x36, 0x18, 0x0C, 0x1E, 0x7B, 0x61, 0xB0, 0xD8, 0xE7, 0xB8, /* 0xE1 */ - 0x10, 0x14, 0x1B, 0x0F, 0xCE, 0x36, 0x18, 0x0C, 0x1E, 0x7B, 0x61, 0xB0, 0xD8, 0xE7, 0xB8, /* 0xE2 */ - 0x24, 0x2E, 0x00, 0x0F, 0xCE, 0x36, 0x18, 0x0C, 0x1E, 0x7B, 0x61, 0xB0, 0xD8, 0xE7, 0xB8, /* 0xE3 */ - 0x66, 0x00, 0x1F, 0x9C, 0x6C, 0x30, 0x18, 0x3C, 0xF6, 0xC3, 0x61, 0xB1, 0xCF, 0x70, /* 0xE4 */ - 0x1C, 0x1B, 0x0D, 0x83, 0x87, 0xE7, 0x1B, 0x0C, 0x06, 0x0F, 0x3D, 0xB0, 0xD8, 0x6C, 0x73, 0xDC, /* 0xE5 */ - 0x7E, 0xF9, 0xC7, 0x1B, 0x0C, 0x18, 0x18, 0x33, 0xFF, 0xFC, 0x60, 0x30, 0xC0, 0x61, 0x83, 0xC7, 0x8C, 0xF1, 0xF0, /* 0xE6 */ - 0x3C, 0x66, 0xC3, 0xC0, 0xC0, 0xC0, 0xC0, 0xC3, 0x66, 0x3C, 0x10, 0x1C, 0x0C, 0x38, /* 0xE7 */ - 0x60, 0x30, 0x18, 0x3C, 0x66, 0xC3, 0xC3, 0xFF, 0xC0, 0xC0, 0xC3, 0x66, 0x3C, /* 0xE8 */ - 0x0C, 0x08, 0x18, 0x3C, 0x66, 0xC3, 0xC3, 0xFF, 0xC0, 0xC0, 0xC3, 0x66, 0x3C, /* 0xE9 */ - 0x10, 0x28, 0x6C, 0x3C, 0x66, 0xC3, 0xC3, 0xFF, 0xC0, 0xC0, 0xC3, 0x66, 0x3C, /* 0xEA */ - 0x66, 0x00, 0x3C, 0x66, 0xC3, 0xC3, 0xFF, 0xC0, 0xC0, 0xC3, 0x66, 0x3C, /* 0xEB */ - 0xCC, 0xB6, 0xDB, 0x6D, 0xB6, /* 0xEC */ - 0x7A, 0x6D, 0xB6, 0xDB, 0x6C, /* 0xED */ - 0x6E, 0x96, 0x66, 0x66, 0x66, 0x66, 0x60, /* 0xEE */ - 0xCC, 0x03, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, /* 0xEF */ - 0x34, 0x0C, 0x16, 0x03, 0x3F, 0x67, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x66, 0x3C, /* 0xF0 */ - 0x24, 0x5C, 0x00, 0xDE, 0xE3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, /* 0xF1 */ - 0x30, 0x18, 0x00, 0x3C, 0x66, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x66, 0x3C, /* 0xF2 */ - 0x0C, 0x18, 0x00, 0x3C, 0x66, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x66, 0x3C, /* 0xF3 */ - 0x18, 0x24, 0x00, 0x3C, 0x66, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x66, 0x3C, /* 0xF4 */ - 0x34, 0x2C, 0x00, 0x3C, 0x66, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x66, 0x3C, /* 0xF5 */ - 0x66, 0x00, 0x3C, 0x66, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x66, 0x3C, /* 0xF6 */ - 0x18, 0x00, 0x00, 0x1F, 0xF0, 0x00, 0x00, 0x00, 0x30, /* 0xF7 */ - 0x3D, 0x66, 0xC7, 0xCB, 0xCB, 0xD3, 0xD3, 0xE3, 0x66, 0xBC, /* 0xF8 */ - 0x60, 0x30, 0x18, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC7, 0x7B, /* 0xF9 */ - 0x06, 0x0C, 0x18, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC7, 0x7B, /* 0xFA */ - 0x3C, 0x66, 0x00, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC7, 0x7B, /* 0xFB */ - 0x66, 0x00, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC7, 0x7B, /* 0xFC */ - 0x06, 0x04, 0x08, 0xC1, 0x43, 0x63, 0x62, 0x26, 0x36, 0x34, 0x1C, 0x1C, 0x18, 0x18, 0x18, 0x10, 0x60, /* 0xFD */ - 0xC0, 0x60, 0x30, 0x1B, 0xCE, 0x36, 0x0F, 0x07, 0x83, 0xC1, 0xE0, 0xF0, 0x7C, 0x6D, 0xE6, 0x03, 0x01, 0x80, /* 0xFE */ - 0x33, 0x00, 0xC1, 0x43, 0x63, 0x62, 0x26, 0x36, 0x34, 0x1C, 0x1C, 0x18, 0x18, 0x18, 0x10, 0x60, /* 0xFF */ +/* 0x01 */ 0x07, 0x00, 0x0A, 0x00, 0x24, 0x00, 0x48, 0x01, 0x10, 0x04, 0x40, 0x10, 0xFF, 0x20, 0x02, 0x81, 0xFD, 0x00, 0x06, 0x07, 0xF4, 0x08, 0x24, 0x0F, 0x88, 0x11, 0x0F, 0xDC, 0x00, +/* 0x02 */ 0x3F, 0x70, 0x81, 0x11, 0x03, 0xE4, 0x08, 0x28, 0x1F, 0xD0, 0x00, 0x60, 0x7F, 0x20, 0x02, 0x43, 0xFC, 0x44, 0x00, 0x44, 0x00, 0x48, 0x00, 0x90, 0x00, 0xA0, 0x01, 0xC0, 0x00, +/* 0x03 */ 0x07, 0xC0, 0x30, 0x60, 0x80, 0x22, 0x00, 0x28, 0x00, 0x31, 0x8C, 0x63, 0x18, 0xC0, 0x01, 0x80, 0x03, 0x00, 0x06, 0x20, 0x8C, 0x3E, 0x14, 0x00, 0x44, 0x01, 0x06, 0x0C, 0x03, 0xE0, +/* 0x04 */ 0x07, 0xC0, 0x30, 0x60, 0x80, 0x22, 0x00, 0x28, 0x82, 0x30, 0x88, 0x62, 0x08, 0xC0, 0x01, 0x80, 0x03, 0x00, 0x06, 0x3F, 0x8C, 0x3E, 0x14, 0x00, 0x44, 0x01, 0x06, 0x0C, 0x03, 0xE0, +/* 0x05 */ 0x0B, 0x10, 0x14, 0xA8, 0x12, 0x50, 0x29, 0x42, 0x24, 0xA5, 0x32, 0x95, 0x5A, 0x09, 0x48, 0x09, 0x24, 0x01, 0x10, 0x01, 0x48, 0x02, 0xA4, 0x02, 0x42, 0x04, 0x01, 0x98, 0x00, 0x60, +/* 0x06 */ 0x00, 0x80, 0x22, 0x80, 0x65, 0x00, 0xBE, 0xE1, 0x82, 0x4E, 0x03, 0x24, 0x04, 0x28, 0x06, 0x30, 0x12, 0x20, 0x3C, 0xA0, 0xC3, 0xFE, 0x80, 0x4D, 0x00, 0xA6, 0x01, 0x80, 0x00, +/* 0x07 */ +/* 0x08 */ 0x00, 0xF8, 0x00, 0x82, 0x00, 0x80, 0x83, 0xE0, 0x41, 0x10, 0x21, 0x04, 0x1B, 0x00, 0x03, 0x00, 0x01, 0x80, 0x00, 0xE0, 0x00, 0x4F, 0xE1, 0xC0, 0x0F, 0x02, 0x00, 0x03, 0x01, 0x00, 0x09, 0x88, 0x0C, 0x0C, +/* 0x09 */ 0x00, 0xF8, 0x00, 0x82, 0x00, 0x80, 0x83, 0xE0, 0x41, 0x10, 0x21, 0x04, 0x1B, 0x00, 0x03, 0x00, 0x01, 0x80, 0x00, 0xE0, 0x00, 0x4F, 0xE1, 0xC0, 0x0F, 0x00, +/* 0x0A */ +/* 0x0B */ 0x1C, 0x1C, 0x31, 0xB1, 0x90, 0x50, 0x50, 0x10, 0x18, 0x00, 0x0C, 0x00, 0x06, 0x00, 0x02, 0x80, 0x02, 0x40, 0x01, 0x10, 0x01, 0x04, 0x01, 0x01, 0x01, 0x00, 0x41, 0x00, 0x11, 0x00, 0x07, 0x00, 0x01, 0x00, +/* 0x0C */ 0x06, 0x00, 0x0A, 0x00, 0x12, 0x00, 0x32, 0x01, 0x84, 0x04, 0x10, 0x08, 0x98, 0x1C, 0x18, 0x40, 0x48, 0x82, 0x11, 0xF0, 0x74, 0x02, 0x18, 0x70, 0x2F, 0x9F, 0x80, +/* 0x0D */ +/* 0x0E */ 0x01, 0x00, 0x05, 0x00, 0x0A, 0x00, 0x3E, 0x00, 0x82, 0x02, 0x82, 0x06, 0x04, 0x10, 0x04, 0x20, 0x08, 0x40, 0x10, 0xFF, 0x22, 0x00, 0x29, 0xFF, 0x3F, 0x8F, 0xDF, 0x9F, 0x01, 0xC0, +/* 0x0F */ 0x07, 0xC0, 0x30, 0x60, 0x80, 0x22, 0x00, 0x28, 0x82, 0x36, 0x03, 0x60, 0x00, 0xCC, 0x19, 0xA4, 0x4B, 0x00, 0x06, 0x8E, 0x2B, 0x22, 0x66, 0x7C, 0xCC, 0x71, 0x98, 0x03, 0x00, +/* 0x10 */ 0x03, 0x80, 0x07, 0x00, 0x0E, 0x00, 0x1E, 0x00, 0x54, 0x00, 0xA8, 0x01, 0x50, 0x02, 0xA0, 0x05, 0x20, 0x32, 0x61, 0xC4, 0x74, 0x49, 0x10, 0x6C, 0x00, 0xD8, 0x01, 0x10, 0x00, +/* 0x11 */ 0x07, 0xC0, 0x30, 0x60, 0x80, 0x22, 0x40, 0x29, 0x00, 0x31, 0x84, 0x63, 0x18, 0xC0, 0x00, 0x80, 0x15, 0x03, 0x7E, 0x02, 0xFA, 0x04, 0xE4, 0x18, 0x84, 0x00, 0x06, 0x0C, 0x03, 0xE0, +/* 0x12 */ 0x02, 0x08, 0x01, 0x08, 0x40, 0x10, 0xC0, 0x08, 0xC0, 0x60, 0x80, 0x28, 0x04, 0x12, 0x4C, 0x10, 0x80, 0x08, 0x23, 0x0E, 0x08, 0xC4, 0x82, 0x04, 0x20, 0x83, 0x09, 0x82, 0x47, 0x01, 0x1C, 0x01, 0x30, 0x00, 0xE0, 0x00, 0x00, +/* 0x13 */ 0x07, 0xC0, 0x30, 0x60, 0x80, 0x22, 0x00, 0x28, 0x00, 0x31, 0x08, 0x65, 0x28, 0xC0, 0x01, 0x80, 0x03, 0x00, 0x06, 0x3F, 0x8C, 0x3E, 0x14, 0x00, 0x44, 0x01, 0x06, 0x0C, 0x03, 0xE0, +/* 0x14 */ 0x07, 0xC0, 0x30, 0x60, 0x80, 0x22, 0x22, 0x29, 0x83, 0x30, 0x00, 0x65, 0x14, 0xD3, 0x4D, 0xBA, 0xEB, 0x38, 0xE6, 0x00, 0x0A, 0x00, 0x24, 0x38, 0x44, 0x01, 0x07, 0x1C, 0x01, 0xC0, +/* 0x15 */ 0x07, 0xC0, 0x30, 0x18, 0x80, 0x32, 0x00, 0xF8, 0x01, 0xF1, 0x09, 0xA5, 0x28, 0x40, 0x01, 0x80, 0x03, 0x00, 0x06, 0x3F, 0x8C, 0x3E, 0x14, 0x00, 0x44, 0x01, 0x06, 0x0C, 0x03, 0xE0, +/* 0x16 */ 0x0C, 0x00, 0xC0, 0x1C, 0x03, 0x80, 0xF8, 0xBB, 0x36, 0xC7, 0x99, 0xF3, 0xFE, 0x3F, 0xC3, 0xF0, 0x7E, 0x0E, 0xC1, 0x8E, 0xE0, 0x20, +/* 0x17 */ 0x07, 0xC0, 0x30, 0x60, 0x80, 0x22, 0x00, 0x28, 0x00, 0x10, 0x01, 0x20, 0x1D, 0x44, 0x42, 0x84, 0x85, 0x00, 0x86, 0x00, 0xC4, 0x00, 0x44, 0x7C, 0x44, 0x00, 0x06, 0x0C, 0x03, 0xE0, +/* 0x18 */ 0x01, 0xE0, 0x00, 0x84, 0x00, 0x40, 0x80, 0x20, 0x10, 0x08, 0x24, 0x02, 0x41, 0x00, 0x86, 0x03, 0x12, 0x03, 0xB4, 0x03, 0x52, 0x81, 0x23, 0x80, 0x70, 0xA0, 0x14, 0x28, 0x05, 0x0A, 0x01, 0x42, 0x80, 0x50, +/* 0x19 */ 0x07, 0xC0, 0x30, 0x60, 0x80, 0x22, 0x00, 0x28, 0x00, 0x33, 0x18, 0x60, 0x00, 0xDC, 0xE1, 0xB9, 0xC3, 0x7B, 0xC6, 0x63, 0x0A, 0x00, 0x24, 0xF0, 0x44, 0x01, 0x06, 0x0C, 0x03, 0xE0, +/* 0x1A */ 0xFF, 0xFC, 0x00, 0x63, 0xE3, 0x31, 0x99, 0x04, 0xC8, 0x66, 0x06, 0x30, 0x61, 0x82, 0x0C, 0x10, 0x60, 0x03, 0x04, 0x18, 0x00, 0xFF, 0xFC, +/* 0x1B */ 0x07, 0xF0, 0x06, 0x0C, 0x04, 0x01, 0x04, 0x00, 0x44, 0x22, 0x12, 0x2A, 0x89, 0x00, 0x04, 0x80, 0x02, 0x44, 0x11, 0x01, 0xF0, 0x04, 0x01, 0x0D, 0x01, 0x6A, 0x41, 0x2C, 0x00, 0x05, 0xC0, 0x0E, 0x18, 0x18, +/* 0x1C */ 0x07, 0xC0, 0x30, 0x60, 0x80, 0x22, 0xC0, 0x2A, 0x00, 0x33, 0x00, 0x66, 0x00, 0xCC, 0x39, 0x80, 0x83, 0x00, 0x06, 0x00, 0x8C, 0x3E, 0x14, 0x00, 0x44, 0x01, 0x06, 0x0C, 0x03, 0xE0, +/* 0x1D */ 0x07, 0xC0, 0x30, 0x60, 0x80, 0x22, 0x70, 0x28, 0x00, 0x31, 0x80, 0x63, 0x18, 0xC0, 0x31, 0x80, 0x03, 0x00, 0x06, 0x60, 0x0D, 0x33, 0x12, 0x10, 0x48, 0x21, 0x23, 0x8C, 0x00, +/* 0x1E */ 0x03, 0x00, 0x07, 0x9E, 0x07, 0x00, 0x86, 0x00, 0x27, 0xC0, 0x0F, 0xC0, 0x07, 0x8C, 0x62, 0x06, 0x31, 0x20, 0x00, 0x90, 0x00, 0x48, 0x00, 0x24, 0x3E, 0x11, 0x00, 0x10, 0x40, 0x10, 0x18, 0x30, 0x03, 0xE0, +/* 0x1F */ 0x18, 0x02, 0x80, 0x4C, 0x16, 0x41, 0x24, 0x3C, 0x88, 0x6E, 0x65, 0xF2, 0x78, 0x46, 0x88, 0xCF, 0x18, 0x02, 0x80, 0x8C, 0x60, 0x70, +/* ' ' 0x20 */ +/* '!' 0x21 */ 0xFF, 0xFF, 0xF0, 0xC0, +/* '"' 0x22 */ 0xDE, 0xF7, 0x20, +/* '#' 0x23 */ 0x09, 0x86, 0x41, 0x91, 0xFF, 0x13, 0x04, 0xC3, 0x20, 0xC8, 0xFF, 0x89, 0x82, 0x61, 0x90, +/* '$' 0x24 */ 0x10, 0x1F, 0x14, 0xDA, 0x3D, 0x1E, 0x83, 0x40, 0x78, 0x17, 0x08, 0xF4, 0x7A, 0x35, 0x33, 0xF0, 0x40, 0x20, +/* '%' 0x25 */ 0x38, 0x10, 0xEC, 0x20, 0xC6, 0x20, 0xC6, 0x40, 0xC6, 0x40, 0x6C, 0x80, 0x39, 0x00, 0x01, 0x3C, 0x02, 0x77, 0x02, 0x63, 0x04, 0x63, 0x04, 0x77, 0x08, 0x3C, +/* '&' 0x26 */ 0x0E, 0x0C, 0xC3, 0x30, 0xCC, 0x1E, 0x03, 0x03, 0xC1, 0x9B, 0xC2, 0xF0, 0xEC, 0x19, 0x8F, 0x3C, 0x40, +/* ''' 0x27 */ 0xFE, +/* '(' 0x28 */ 0x13, 0x26, 0x6C, 0xCC, 0xCC, 0xC4, 0x66, 0x23, 0x10, +/* ')' 0x29 */ 0x8C, 0x46, 0x63, 0x33, 0x33, 0x32, 0x66, 0x4C, 0x80, +/* '*' 0x2A */ 0x25, 0x7E, 0xA5, 0x00, +/* '+' 0x2B */ 0x30, 0xC3, 0x3F, 0x30, 0xC3, 0x0C, +/* ',' 0x2C */ 0xD6, +/* '-' 0x2D */ 0xF0, +/* '.' 0x2E */ 0xC0, +/* '/' 0x2F */ 0x08, 0x44, 0x21, 0x10, 0x84, 0x42, 0x11, 0x08, 0x00, +/* '0' 0x30 */ 0x3C, 0x66, 0x42, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x42, 0x66, 0x3C, +/* '1' 0x31 */ 0x11, 0x3F, 0x33, 0x33, 0x33, 0x33, 0x30, +/* '2' 0x32 */ 0x3E, 0x31, 0xB0, 0x78, 0x30, 0x18, 0x1C, 0x1C, 0x1C, 0x18, 0x18, 0x10, 0x08, 0x07, 0xF8, +/* '3' 0x33 */ 0x3C, 0x66, 0xC3, 0xC3, 0x03, 0x06, 0x1C, 0x07, 0x03, 0xC3, 0xC3, 0x66, 0x3C, +/* '4' 0x34 */ 0x0C, 0x18, 0x71, 0x62, 0xC9, 0xA3, 0x46, 0xFE, 0x18, 0x30, 0x60, 0xC0, +/* '5' 0x35 */ 0x7F, 0x20, 0x10, 0x08, 0x08, 0x07, 0xF3, 0x8C, 0x03, 0x01, 0x80, 0xF0, 0x6C, 0x63, 0xE0, +/* '6' 0x36 */ 0x1E, 0x31, 0x98, 0x78, 0x0C, 0x06, 0xF3, 0x8D, 0x83, 0xC1, 0xE0, 0xD0, 0x6C, 0x63, 0xE0, +/* '7' 0x37 */ 0xFF, 0x03, 0x02, 0x06, 0x04, 0x0C, 0x08, 0x18, 0x18, 0x18, 0x10, 0x30, 0x30, +/* '8' 0x38 */ 0x3E, 0x31, 0xB0, 0x78, 0x3C, 0x1B, 0x18, 0xF8, 0xC6, 0xC1, 0xE0, 0xF0, 0x6C, 0x63, 0xE0, +/* '9' 0x39 */ 0x3C, 0x66, 0xC2, 0xC3, 0xC3, 0xC3, 0x67, 0x3B, 0x03, 0x03, 0xC2, 0x66, 0x3C, +/* ':' 0x3A */ 0xC0, 0x00, 0x30, +/* ';' 0x3B */ 0xC0, 0x00, 0x00, 0x64, 0xA0, +/* '<' 0x3C */ 0x00, 0x81, 0xC7, 0x8E, 0x0C, 0x07, 0x80, 0x70, 0x0E, 0x01, 0x80, +/* '=' 0x3D */ 0xFF, 0x80, 0x00, 0x1F, 0xF0, +/* '>' 0x3E */ 0xE0, 0x1C, 0x03, 0x80, 0x30, 0x70, 0xE3, 0x81, 0x00, +/* '?' 0x3F */ 0x3E, 0x31, 0xB0, 0x78, 0x30, 0x18, 0x18, 0x38, 0x18, 0x18, 0x0C, 0x00, 0x00, 0x01, 0x80, +/* '@' 0x40 */ 0x03, 0xF0, 0x06, 0x0E, 0x06, 0x01, 0x86, 0x00, 0x66, 0x1D, 0xBB, 0x31, 0xCF, 0x18, 0xC7, 0x98, 0x63, 0xCC, 0x31, 0xE6, 0x11, 0xB3, 0x99, 0xCC, 0xF7, 0x86, 0x00, 0x01, 0x80, 0x00, 0x70, 0x40, 0x0F, 0xE0, +/* 'A' 0x41 */ 0x06, 0x00, 0xF0, 0x0F, 0x00, 0x90, 0x19, 0x81, 0x98, 0x10, 0x83, 0x0C, 0x3F, 0xC2, 0x04, 0x60, 0x66, 0x06, 0xC0, 0x30, +/* 'B' 0x42 */ 0xFF, 0x18, 0x33, 0x03, 0x60, 0x6C, 0x0D, 0x83, 0x3F, 0xC6, 0x06, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x6F, 0xF8, +/* 'C' 0x43 */ 0x1F, 0x86, 0x19, 0x81, 0xA0, 0x3C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xC0, 0x68, 0x0D, 0x83, 0x18, 0x61, 0xF0, +/* 'D' 0x44 */ 0xFF, 0x18, 0x33, 0x03, 0x60, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x03, 0x60, 0xCF, 0xF0, +/* 'E' 0x45 */ 0xFF, 0xE0, 0x30, 0x18, 0x0C, 0x06, 0x03, 0xFD, 0x80, 0xC0, 0x60, 0x30, 0x18, 0x0F, 0xF8, +/* 'F' 0x46 */ 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFE, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, +/* 'G' 0x47 */ 0x0F, 0x83, 0x0E, 0x60, 0x66, 0x03, 0xC0, 0x0C, 0x00, 0xC1, 0xFC, 0x03, 0xC0, 0x36, 0x03, 0x60, 0x73, 0x0F, 0x0F, 0x10, +/* 'H' 0x48 */ 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xFF, 0xFE, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x06, +/* 'I' 0x49 */ 0xFF, 0xFF, 0xFF, 0xC0, +/* 'J' 0x4A */ 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x83, 0x07, 0x8F, 0x1E, 0x27, 0x80, +/* 'K' 0x4B */ 0xC0, 0xF0, 0x6C, 0x33, 0x18, 0xCC, 0x37, 0x0F, 0xC3, 0x98, 0xC3, 0x30, 0xCC, 0x1B, 0x03, 0xC0, 0xC0, +/* 'L' 0x4C */ 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, +/* 'M' 0x4D */ 0xE0, 0x3F, 0x01, 0xFC, 0x1F, 0xE0, 0xFD, 0x05, 0xEC, 0x6F, 0x63, 0x79, 0x13, 0xCD, 0x9E, 0x6C, 0xF1, 0x47, 0x8E, 0x3C, 0x71, 0x80, +/* 'N' 0x4E */ 0xE0, 0x7C, 0x0F, 0xC1, 0xE8, 0x3D, 0x87, 0x98, 0xF1, 0x1E, 0x33, 0xC3, 0x78, 0x6F, 0x07, 0xE0, 0x7C, 0x0E, +/* 'O' 0x4F */ 0x0F, 0x81, 0x83, 0x18, 0x0C, 0xC0, 0x6C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1B, 0x01, 0x98, 0x0C, 0x60, 0xC0, 0xF8, 0x00, +/* 'P' 0x50 */ 0xFF, 0x30, 0x6C, 0x0F, 0x03, 0xC0, 0xF0, 0x6F, 0xF3, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x00, +/* 'Q' 0x51 */ 0x0F, 0x81, 0x83, 0x18, 0x0C, 0xC0, 0x6C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1B, 0x01, 0x98, 0x6C, 0x60, 0xC0, 0xFB, 0x00, 0x08, +/* 'R' 0x52 */ 0xFF, 0x8C, 0x0E, 0xC0, 0x6C, 0x06, 0xC0, 0x6C, 0x0C, 0xFF, 0x8C, 0x0E, 0xC0, 0x6C, 0x06, 0xC0, 0x6C, 0x06, 0xC0, 0x70, +/* 'S' 0x53 */ 0x3F, 0x18, 0x6C, 0x0F, 0x03, 0xC0, 0x1E, 0x01, 0xF0, 0x0E, 0x00, 0xF0, 0x3C, 0x0D, 0x86, 0x3F, 0x00, +/* 'T' 0x54 */ 0xFF, 0x86, 0x03, 0x01, 0x80, 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x80, 0xC0, +/* 'U' 0x55 */ 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xB0, 0x61, 0xF0, +/* 'V' 0x56 */ 0xC0, 0x6C, 0x0D, 0x81, 0x10, 0x63, 0x0C, 0x61, 0x04, 0x60, 0xCC, 0x19, 0x01, 0x60, 0x3C, 0x07, 0x00, 0x60, +/* 'W' 0x57 */ 0xC1, 0x81, 0x61, 0xC3, 0x61, 0xC3, 0x61, 0x43, 0x62, 0x62, 0x22, 0x66, 0x32, 0x26, 0x36, 0x26, 0x14, 0x34, 0x14, 0x34, 0x1C, 0x1C, 0x18, 0x1C, 0x08, 0x18, +/* 'X' 0x58 */ 0xC0, 0xD8, 0x66, 0x18, 0xCC, 0x1E, 0x07, 0x00, 0xC0, 0x78, 0x32, 0x0C, 0xC6, 0x1B, 0x07, 0xC0, 0xC0, +/* 'Y' 0x59 */ 0xC0, 0x36, 0x06, 0x30, 0xC3, 0x0C, 0x19, 0x81, 0xD8, 0x0F, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, +/* 'Z' 0x5A */ 0xFF, 0xC0, 0x60, 0x30, 0x0C, 0x06, 0x03, 0x01, 0xC0, 0x60, 0x30, 0x18, 0x06, 0x03, 0x00, 0xFF, 0xC0, +/* '[' 0x5B */ 0xFB, 0x6D, 0xB6, 0xDB, 0x6D, 0xB6, 0xE0, +/* '\' 0x5C */ 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x80, +/* ']' 0x5D */ 0xED, 0xB6, 0xDB, 0x6D, 0xB6, 0xDB, 0xE0, +/* '^' 0x5E */ 0x30, 0x60, 0xA2, 0x44, 0xD8, 0xA1, 0x80, +/* '_' 0x5F */ 0xFF, 0xC0, +/* '`' 0x60 */ 0xC6, 0x30, +/* 'a' 0x61 */ 0x7E, 0x71, 0xB0, 0xC0, 0x60, 0xF3, 0xDB, 0x0D, 0x86, 0xC7, 0x3D, 0xC0, +/* 'b' 0x62 */ 0xC0, 0x60, 0x30, 0x1B, 0xCE, 0x36, 0x0F, 0x07, 0x83, 0xC1, 0xE0, 0xF0, 0x7C, 0x6D, 0xE0, +/* 'c' 0x63 */ 0x3C, 0x66, 0xC3, 0xC0, 0xC0, 0xC0, 0xC0, 0xC3, 0x66, 0x3C, +/* 'd' 0x64 */ 0x03, 0x03, 0x03, 0x3B, 0x67, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x67, 0x3B, +/* 'e' 0x65 */ 0x3C, 0x66, 0xC3, 0xC3, 0xFF, 0xC0, 0xC0, 0xC3, 0x66, 0x3C, +/* 'f' 0x66 */ 0x36, 0x6F, 0x66, 0x66, 0x66, 0x66, 0x60, +/* 'g' 0x67 */ 0x3B, 0x67, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x67, 0x3B, 0x03, 0x03, 0xC6, 0x7C, +/* 'h' 0x68 */ 0xC0, 0xC0, 0xC0, 0xDE, 0xE3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, +/* 'i' 0x69 */ 0xC3, 0xFF, 0xFF, 0xC0, +/* 'j' 0x6A */ 0x30, 0x03, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0xE0, +/* 'k' 0x6B */ 0xC0, 0xC0, 0xC0, 0xC2, 0xC4, 0xCC, 0xD8, 0xF8, 0xEC, 0xC4, 0xC6, 0xC3, 0xC3, +/* 'l' 0x6C */ 0xFF, 0xFF, 0xFF, 0xC0, +/* 'm' 0x6D */ 0xDE, 0xF7, 0x1C, 0xF0, 0xC7, 0x86, 0x3C, 0x31, 0xE1, 0x8F, 0x0C, 0x78, 0x63, 0xC3, 0x1E, 0x18, 0xC0, +/* 'n' 0x6E */ 0xDE, 0xE3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, +/* 'o' 0x6F */ 0x3C, 0x66, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x66, 0x3C, +/* 'p' 0x70 */ 0xDE, 0x71, 0xB0, 0x78, 0x3C, 0x1E, 0x0F, 0x07, 0x83, 0xE3, 0x6F, 0x30, 0x18, 0x0C, 0x00, +/* 'q' 0x71 */ 0x3B, 0x67, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x67, 0x3B, 0x03, 0x03, 0x03, +/* 'r' 0x72 */ 0xDF, 0x31, 0x8C, 0x63, 0x18, 0xC6, 0x00, +/* 's' 0x73 */ 0x3E, 0xE3, 0xC0, 0xC0, 0xE0, 0x3C, 0x07, 0xC3, 0xE3, 0x7E, +/* 't' 0x74 */ 0x66, 0xF6, 0x66, 0x66, 0x66, 0x67, +/* 'u' 0x75 */ 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC7, 0x7B, +/* 'v' 0x76 */ 0xC1, 0xA0, 0x98, 0xCC, 0x42, 0x21, 0xB0, 0xD0, 0x28, 0x1C, 0x0C, 0x00, +/* 'w' 0x77 */ 0xC6, 0x1E, 0x38, 0x91, 0xC4, 0xCA, 0x66, 0xD3, 0x16, 0xD0, 0xA6, 0x87, 0x1C, 0x38, 0xC0, 0xC6, 0x00, +/* 'x' 0x78 */ 0x87, 0x89, 0xB1, 0xC3, 0x07, 0x1E, 0x26, 0xC5, 0x0C, +/* 'y' 0x79 */ 0xC1, 0x43, 0x63, 0x62, 0x26, 0x36, 0x34, 0x1C, 0x1C, 0x18, 0x18, 0x18, 0x10, 0x60, +/* 'z' 0x7A */ 0xFE, 0x0C, 0x30, 0xC1, 0x86, 0x18, 0x20, 0xC1, 0xFC, +/* '{' 0x7B */ 0x36, 0x66, 0x66, 0x6E, 0xCE, 0x66, 0x66, 0x66, 0x30, +/* '|' 0x7C */ 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, +/* '}' 0x7D */ 0xC6, 0x66, 0x66, 0x67, 0x37, 0x66, 0x66, 0x66, 0xC0, +/* '~' 0x7E */ 0x61, 0x24, 0x38, +/* 0x7F */ +/* 0x80 */ 0x07, 0xC6, 0x13, 0x00, 0xC0, 0x60, 0x3F, 0xE6, 0x03, 0xFC, 0x60, 0x0C, 0x03, 0x00, 0x61, 0x07, 0xC0, +/* 0x81 */ +/* 0x82 */ 0xDC, +/* 0x83 */ 0x19, 0x8C, 0xF3, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x18, 0xC6, 0xE0, +/* 0x84 */ 0xDA, 0x76, +/* 0x85 */ 0xCC, 0xC0, +/* 0x86 */ 0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +/* 0x87 */ 0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18, +/* 0x88 */ 0x72, 0xA2, +/* 0x89 */ 0x70, 0x80, 0x22, 0x20, 0x08, 0x90, 0x02, 0x24, 0x00, 0x72, 0x00, 0x00, 0x80, 0x00, 0x40, 0x00, 0x10, 0x00, 0x09, 0xC7, 0x84, 0x8B, 0x31, 0x22, 0x84, 0x88, 0xB3, 0x21, 0xC7, 0x80, +/* 0x8A */ 0x1B, 0x03, 0x80, 0x00, 0xFC, 0x61, 0xB0, 0x3C, 0x0F, 0x00, 0x78, 0x07, 0xC0, 0x38, 0x03, 0xC0, 0xF0, 0x36, 0x18, 0xFC, +/* 0x8B */ 0x69, +/* 0x8C */ 0x1E, 0xFE, 0x43, 0x81, 0x83, 0x06, 0x06, 0x0C, 0x0C, 0x18, 0x18, 0x30, 0x3F, 0xE0, 0x60, 0xC0, 0xC1, 0x81, 0x81, 0x83, 0x01, 0x8E, 0x01, 0xEF, 0xE0, +/* 0x8D */ +/* 0x8E */ 0x1B, 0x03, 0x80, 0x03, 0xFF, 0x01, 0x80, 0xC0, 0x30, 0x18, 0x0C, 0x07, 0x01, 0x80, 0xC0, 0x60, 0x18, 0x0C, 0x03, 0xFF, +/* 0x8F */ +/* 0x90 */ +/* 0x91 */ 0x6B, +/* 0x92 */ 0xD6, +/* 0x93 */ 0x4C, 0xA5, 0xB0, +/* 0x94 */ 0xDA, 0x53, 0x20, +/* 0x95 */ 0x6F, 0xFF, 0x60, +/* 0x96 */ 0xFE, +/* 0x97 */ 0xFF, 0xFF, +/* 0x98 */ 0x4D, 0xC0, +/* 0x99 */ 0xFC, 0xE1, 0xCC, 0x38, 0x73, 0x0E, 0x1C, 0xC3, 0x8F, 0x30, 0xD2, 0xCC, 0x34, 0xB3, 0x0D, 0x6C, 0xC3, 0x53, 0x30, 0xCC, 0xCC, 0x33, 0x30, +/* 0x9A */ 0x24, 0x3C, 0x18, 0x7E, 0xE3, 0xC0, 0xC0, 0x60, 0x3C, 0x07, 0xC3, 0xE3, 0x7E, +/* 0x9B */ 0x96, +/* 0x9C */ 0x3C, 0xF8, 0xCF, 0x1B, 0x0C, 0x1E, 0x18, 0x3C, 0x3F, 0xF8, 0x60, 0x30, 0xC0, 0x61, 0x83, 0x67, 0x8C, 0x79, 0xF0, +/* 0x9D */ +/* 0x9E */ 0x48, 0xF0, 0xC7, 0xF0, 0x61, 0x86, 0x0C, 0x30, 0xC1, 0x06, 0x0F, 0xE0, +/* 0x9F */ 0x19, 0x80, 0x00, 0xC0, 0x36, 0x06, 0x30, 0xC3, 0x0C, 0x19, 0x81, 0xD8, 0x0F, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, +/* 0xA0 */ +/* 0xA1 */ 0xCF, 0xFF, 0xFF, 0xC0, +/* 0xA2 */ 0x08, 0x04, 0x0F, 0x8D, 0x6C, 0x9E, 0x43, 0x21, 0x90, 0xC8, 0x64, 0xDA, 0xC7, 0xC0, 0x80, 0x40, +/* 0xA3 */ 0x1F, 0x0C, 0x66, 0x0D, 0x83, 0x60, 0x0C, 0x0F, 0xC0, 0x60, 0x18, 0x06, 0x03, 0x01, 0xF1, 0x43, 0xC0, +/* 0xA4 */ 0xFF, 0xDF, 0x1E, 0x3E, 0xFF, 0xC0, +/* 0xA5 */ 0xC3, 0x42, 0x42, 0x24, 0x24, 0x3C, 0x18, 0x7E, 0x18, 0x7E, 0x18, 0x18, 0x18, +/* 0xA6 */ 0xFF, 0xFC, 0x0F, 0xFF, 0xC0, +/* 0xA7 */ 0x0C, 0x09, 0x0C, 0xC6, 0x63, 0x81, 0xE3, 0x19, 0x87, 0xE1, 0xB8, 0xC6, 0x41, 0xC0, 0x73, 0x19, 0x8C, 0x66, 0x1E, 0x00, +/* 0xA8 */ 0xCC, +/* 0xA9 */ 0x0F, 0xC0, 0x61, 0x87, 0x03, 0x9B, 0xC6, 0xD9, 0x8F, 0x60, 0x3D, 0x00, 0xF4, 0x03, 0xD8, 0x0D, 0xE6, 0x67, 0xF3, 0x86, 0x18, 0x0F, 0xC0, +/* 0xAA */ 0x74, 0x8D, 0xA9, 0x7C, 0x1F, +/* 0xAB */ 0x22, 0xCF, 0x26, 0x46, 0x64, 0x40, +/* 0xAC */ 0xFF, 0x80, 0xC0, 0x60, 0x30, 0x18, +/* 0xAD */ +/* 0xAE */ 0x0F, 0xC0, 0x61, 0x87, 0x03, 0x9F, 0xE6, 0xD0, 0x8F, 0x42, 0x3D, 0xF0, 0xF4, 0x23, 0xD0, 0x8D, 0xC2, 0x67, 0x0B, 0x86, 0x18, 0x0F, 0xC0, +/* 0xAF */ 0xF8, +/* 0xB0 */ 0x74, 0x63, 0x17, 0x00, +/* 0xB1 */ 0x0C, 0x06, 0x03, 0x07, 0xE0, 0xC0, 0x60, 0x30, 0x18, 0x00, 0x00, 0x3F, 0xE0, +/* 0xB2 */ 0x7B, 0x30, 0xC3, 0x11, 0x84, 0x3F, +/* 0xB3 */ 0x7D, 0x8C, 0x18, 0xC0, 0x60, 0xF1, 0xBE, +/* 0xB4 */ 0x36, 0xC0, +/* 0xB5 */ 0xC3, 0x61, 0xB0, 0xD8, 0x6C, 0x36, 0x1B, 0x0D, 0x86, 0xE7, 0x7D, 0xF0, 0x18, 0x0C, 0x00, +/* 0xB6 */ 0x3F, 0x7E, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0x72, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, +/* 0xB7 */ 0xE0, +/* 0xB8 */ 0x21, 0xC7, 0xE0, +/* 0xB9 */ 0x3D, 0xB6, 0xD8, +/* 0xBA */ 0x74, 0x63, 0x18, 0xB8, 0x1F, +/* 0xBB */ 0x89, 0x98, 0x99, 0x3C, 0xD1, 0x00, +/* 0xBC */ 0x20, 0x43, 0x81, 0x06, 0x08, 0x18, 0x20, 0x61, 0x01, 0x84, 0x06, 0x21, 0x80, 0x86, 0x04, 0x78, 0x32, 0x60, 0x87, 0xC4, 0x06, 0x10, 0x18, +/* 0xBD */ 0x20, 0x43, 0x81, 0x06, 0x08, 0x18, 0x20, 0x61, 0x01, 0x8D, 0xE6, 0x2C, 0xC1, 0x03, 0x0C, 0x0C, 0x20, 0x41, 0x86, 0x0C, 0x30, 0x20, 0xFC, +/* 0xBE */ 0x78, 0x11, 0x98, 0x40, 0x31, 0x00, 0x82, 0x00, 0xC8, 0x01, 0x90, 0x33, 0x43, 0x3D, 0x06, 0x02, 0x3C, 0x08, 0x98, 0x10, 0xF8, 0x40, 0x61, 0x00, 0xC0, +/* 0xBF */ 0x0C, 0x00, 0x00, 0x01, 0x80, 0xC0, 0xC0, 0xE0, 0xC0, 0xC0, 0x60, 0xF0, 0x6C, 0x63, 0xE0, +/* 0xC0 */ 0x18, 0x03, 0x00, 0x00, 0x30, 0x1E, 0x07, 0x81, 0x20, 0xCC, 0x33, 0x0F, 0xC6, 0x19, 0x86, 0x40, 0xB0, 0x30, +/* 0xC1 */ 0x06, 0x03, 0x00, 0x00, 0x30, 0x1E, 0x07, 0x81, 0x20, 0xCC, 0x33, 0x0F, 0xC6, 0x19, 0x86, 0x40, 0xB0, 0x30, +/* 0xC2 */ 0x0C, 0x04, 0x80, 0x00, 0x30, 0x1E, 0x07, 0x81, 0x20, 0xCC, 0x33, 0x0F, 0xC6, 0x19, 0x86, 0x40, 0xB0, 0x30, +/* 0xC3 */ 0x19, 0x09, 0x80, 0x00, 0x30, 0x1E, 0x07, 0x81, 0x20, 0xCC, 0x33, 0x0F, 0xC6, 0x19, 0x86, 0x40, 0xB0, 0x30, +/* 0xC4 */ 0x33, 0x00, 0x00, 0xC0, 0x78, 0x1E, 0x04, 0x83, 0x30, 0xCC, 0x33, 0x1F, 0xE6, 0x19, 0x02, 0xC0, 0xF0, 0x30, +/* 0xC5 */ 0x0C, 0x04, 0x81, 0x20, 0x30, 0x1E, 0x07, 0x81, 0x20, 0xCC, 0x33, 0x0F, 0xC6, 0x19, 0x86, 0x40, 0xB0, 0x30, +/* 0xC6 */ 0x07, 0xFF, 0x04, 0xC0, 0x0C, 0xC0, 0x08, 0xC0, 0x18, 0xC0, 0x18, 0xC0, 0x30, 0xFF, 0x30, 0xC0, 0x3F, 0xC0, 0x60, 0xC0, 0x60, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, +/* 0xC7 */ 0x1F, 0x06, 0x19, 0x83, 0xA0, 0x3C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xC0, 0x68, 0x0D, 0x83, 0x18, 0xE1, 0xF0, 0x08, 0x01, 0xC0, 0x18, 0x0E, 0x00, +/* 0xC8 */ 0x18, 0x06, 0x00, 0x1F, 0xFC, 0x06, 0x03, 0x01, 0x80, 0xFF, 0x60, 0x30, 0x18, 0x0C, 0x07, 0xFC, +/* 0xC9 */ 0x0C, 0x0C, 0x00, 0x1F, 0xFC, 0x06, 0x03, 0x01, 0x80, 0xFF, 0x60, 0x30, 0x18, 0x0C, 0x07, 0xFC, +/* 0xCA */ 0x1C, 0x1B, 0x00, 0x1F, 0xFC, 0x06, 0x03, 0x01, 0x80, 0xFF, 0x60, 0x30, 0x18, 0x0C, 0x07, 0xFC, +/* 0xCB */ 0x33, 0x00, 0x3F, 0xF8, 0x0C, 0x06, 0x03, 0x01, 0xFE, 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x07, 0xFC, +/* 0xCC */ 0xCC, 0x36, 0xDB, 0x6D, 0xB6, 0xD8, +/* 0xCD */ 0x78, 0x36, 0xDB, 0x6D, 0xB6, 0xC0, +/* 0xCE */ 0x76, 0xC0, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x18, +/* 0xCF */ 0xCC, 0x03, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC0, +/* 0xD0 */ 0x7F, 0x0C, 0x31, 0x83, 0x30, 0x36, 0x06, 0xC0, 0xFE, 0x1B, 0x03, 0x60, 0x6C, 0x0D, 0x83, 0x30, 0xE7, 0xF0, +/* 0xD1 */ 0x19, 0x02, 0xC3, 0x81, 0xF0, 0x3F, 0x07, 0xA0, 0xF6, 0x1E, 0x63, 0xC4, 0x78, 0xCF, 0x0D, 0xE1, 0xBC, 0x1F, 0x81, 0xC0, +/* 0xD2 */ 0x0C, 0x00, 0x60, 0x00, 0x00, 0xF0, 0x39, 0xC6, 0x06, 0x60, 0x6C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x36, 0x06, 0x60, 0x63, 0x9C, 0x0F, 0x00, +/* 0xD3 */ 0x03, 0x00, 0x60, 0x00, 0x00, 0xF0, 0x39, 0xC6, 0x06, 0x60, 0x6C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x36, 0x06, 0x60, 0x63, 0x9C, 0x0F, 0x00, +/* 0xD4 */ 0x0F, 0x01, 0x98, 0x00, 0x00, 0xF0, 0x39, 0xC6, 0x06, 0x60, 0x6C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x36, 0x06, 0x60, 0x63, 0x9C, 0x0F, 0x00, +/* 0xD5 */ 0x1C, 0x81, 0x38, 0x00, 0x00, 0xF0, 0x39, 0xC6, 0x06, 0x60, 0x6C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x36, 0x06, 0x60, 0x63, 0x9C, 0x0F, 0x00, +/* 0xD6 */ 0x19, 0x81, 0x98, 0x00, 0x00, 0xF0, 0x39, 0xC6, 0x06, 0x60, 0x6C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x36, 0x06, 0x60, 0x63, 0x9C, 0x0F, 0x00, +/* 0xD7 */ 0x83, 0x89, 0xA1, 0x83, 0x89, 0xA1, 0x80, +/* 0xD8 */ 0x0F, 0xD9, 0x83, 0x18, 0x1C, 0xC1, 0xEC, 0x19, 0xE0, 0x8F, 0x08, 0x78, 0x83, 0xC8, 0x1B, 0x81, 0x98, 0x0C, 0xE0, 0xC8, 0xF8, 0x00, +/* 0xD9 */ 0x0C, 0x00, 0xC3, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x36, 0x0C, 0x3E, 0x00, +/* 0xDA */ 0x06, 0x01, 0x83, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x36, 0x0C, 0x3E, 0x00, +/* 0xDB */ 0x0E, 0x03, 0x63, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x36, 0x0C, 0x3E, 0x00, +/* 0xDC */ 0x1B, 0x00, 0x03, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x36, 0x0C, 0x3E, 0x00, +/* 0xDD */ 0x03, 0x0C, 0x63, 0x60, 0x63, 0x0C, 0x30, 0xC1, 0x98, 0x1D, 0x80, 0xF0, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, +/* 0xDE */ 0xC0, 0x30, 0x0F, 0xF3, 0x06, 0xC0, 0xF0, 0x3C, 0x0F, 0x06, 0xFF, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x00, +/* 0xDF */ 0x3C, 0x33, 0x30, 0xD8, 0x6C, 0x36, 0x33, 0x39, 0x86, 0xC1, 0xE0, 0xF0, 0x78, 0x6D, 0xE0, +/* 0xE0 */ 0x60, 0x18, 0x06, 0x0F, 0xCE, 0x36, 0x18, 0x0C, 0x1E, 0x7B, 0x61, 0xB0, 0xD8, 0xE7, 0xB8, +/* 0xE1 */ 0x0C, 0x04, 0x04, 0x0F, 0xCE, 0x36, 0x18, 0x0C, 0x1E, 0x7B, 0x61, 0xB0, 0xD8, 0xE7, 0xB8, +/* 0xE2 */ 0x10, 0x14, 0x1B, 0x0F, 0xCE, 0x36, 0x18, 0x0C, 0x1E, 0x7B, 0x61, 0xB0, 0xD8, 0xE7, 0xB8, +/* 0xE3 */ 0x24, 0x2E, 0x00, 0x0F, 0xCE, 0x36, 0x18, 0x0C, 0x1E, 0x7B, 0x61, 0xB0, 0xD8, 0xE7, 0xB8, +/* 0xE4 */ 0x66, 0x00, 0x1F, 0x9C, 0x6C, 0x30, 0x18, 0x3C, 0xF6, 0xC3, 0x61, 0xB1, 0xCF, 0x70, +/* 0xE5 */ 0x1C, 0x1B, 0x0D, 0x83, 0x87, 0xE7, 0x1B, 0x0C, 0x06, 0x0F, 0x3D, 0xB0, 0xD8, 0x6C, 0x73, 0xDC, +/* 0xE6 */ 0x7E, 0xF9, 0xC7, 0x1B, 0x0C, 0x18, 0x18, 0x33, 0xFF, 0xFC, 0x60, 0x30, 0xC0, 0x61, 0x83, 0xC7, 0x8C, 0xF1, 0xF0, +/* 0xE7 */ 0x3C, 0x66, 0xC3, 0xC0, 0xC0, 0xC0, 0xC0, 0xC3, 0x66, 0x3C, 0x10, 0x1C, 0x0C, 0x38, +/* 0xE8 */ 0x60, 0x30, 0x18, 0x3C, 0x66, 0xC3, 0xC3, 0xFF, 0xC0, 0xC0, 0xC3, 0x66, 0x3C, +/* 0xE9 */ 0x0C, 0x08, 0x18, 0x3C, 0x66, 0xC3, 0xC3, 0xFF, 0xC0, 0xC0, 0xC3, 0x66, 0x3C, +/* 0xEA */ 0x10, 0x28, 0x6C, 0x3C, 0x66, 0xC3, 0xC3, 0xFF, 0xC0, 0xC0, 0xC3, 0x66, 0x3C, +/* 0xEB */ 0x66, 0x00, 0x3C, 0x66, 0xC3, 0xC3, 0xFF, 0xC0, 0xC0, 0xC3, 0x66, 0x3C, +/* 0xEC */ 0xCC, 0xB6, 0xDB, 0x6D, 0xB6, +/* 0xED */ 0x7A, 0x6D, 0xB6, 0xDB, 0x6C, +/* 0xEE */ 0x6E, 0x96, 0x66, 0x66, 0x66, 0x66, 0x60, +/* 0xEF */ 0xCC, 0x03, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, +/* 0xF0 */ 0x34, 0x0C, 0x16, 0x03, 0x3F, 0x67, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x66, 0x3C, +/* 0xF1 */ 0x24, 0x5C, 0x00, 0xDE, 0xE3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, +/* 0xF2 */ 0x30, 0x18, 0x00, 0x3C, 0x66, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x66, 0x3C, +/* 0xF3 */ 0x0C, 0x18, 0x00, 0x3C, 0x66, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x66, 0x3C, +/* 0xF4 */ 0x18, 0x24, 0x00, 0x3C, 0x66, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x66, 0x3C, +/* 0xF5 */ 0x34, 0x2C, 0x00, 0x3C, 0x66, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x66, 0x3C, +/* 0xF6 */ 0x66, 0x00, 0x3C, 0x66, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x66, 0x3C, +/* 0xF7 */ 0x18, 0x00, 0x00, 0x1F, 0xF0, 0x00, 0x00, 0x00, 0x30, +/* 0xF8 */ 0x3D, 0x66, 0xC7, 0xCB, 0xCB, 0xD3, 0xD3, 0xE3, 0x66, 0xBC, +/* 0xF9 */ 0x60, 0x30, 0x18, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC7, 0x7B, +/* 0xFA */ 0x06, 0x0C, 0x18, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC7, 0x7B, +/* 0xFB */ 0x3C, 0x66, 0x00, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC7, 0x7B, +/* 0xFC */ 0x66, 0x00, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC7, 0x7B, +/* 0xFD */ 0x06, 0x04, 0x08, 0xC1, 0x43, 0x63, 0x62, 0x26, 0x36, 0x34, 0x1C, 0x1C, 0x18, 0x18, 0x18, 0x10, 0x60, +/* 0xFE */ 0xC0, 0x60, 0x30, 0x1B, 0xCE, 0x36, 0x0F, 0x07, 0x83, 0xC1, 0xE0, 0xF0, 0x7C, 0x6D, 0xE6, 0x03, 0x01, 0x80, +/* 0xFF */ 0x33, 0x00, 0xC1, 0x43, 0x63, 0x62, 0x26, 0x36, 0x34, 0x1C, 0x1C, 0x18, 0x18, 0x18, 0x10, 0x60, }; const GFXglyph FreeSans9pt_Win1252Glyphs[] PROGMEM = { - /* ' ' 0x20 */ {0, 0, 0, 5, 0, 0}, - /* '!' 0x21 */ {0, 2, 13, 6, 2, -12}, - /* '"' 0x22 */ {4, 5, 4, 6, 1, -12}, - /* '#' 0x23 */ {7, 10, 12, 10, 0, -11}, - /* '$' 0x24 */ {22, 9, 16, 10, 1, -13}, - /* '%' 0x25 */ {40, 16, 13, 16, 1, -12}, - /* '&' 0x26 */ {66, 10, 13, 12, 1, -12}, - /* ''' 0x27 */ {83, 2, 4, 4, 1, -12}, - /* '(' 0x28 */ {84, 4, 17, 6, 1, -12}, - /* ')' 0x29 */ {93, 4, 17, 6, 1, -12}, - /* '*' 0x2A */ {102, 5, 5, 7, 1, -12}, - /* '+' 0x2B */ {106, 6, 8, 11, 3, -7}, - /* ',' 0x2C */ {112, 2, 4, 5, 2, 0}, - /* '-' 0x2D */ {113, 4, 1, 6, 1, -4}, - /* '.' 0x2E */ {114, 2, 1, 5, 1, 0}, - /* '/' 0x2F */ {115, 5, 13, 5, 0, -12}, - /* '0' 0x30 */ {124, 8, 13, 10, 1, -12}, - /* '1' 0x31 */ {137, 4, 13, 10, 3, -12}, - /* '2' 0x32 */ {144, 9, 13, 10, 1, -12}, - /* '3' 0x33 */ {159, 8, 13, 10, 1, -12}, - /* '4' 0x34 */ {172, 7, 13, 10, 2, -12}, - /* '5' 0x35 */ {184, 9, 13, 10, 1, -12}, - /* '6' 0x36 */ {199, 9, 13, 10, 1, -12}, - /* '7' 0x37 */ {214, 8, 13, 10, 0, -12}, - /* '8' 0x38 */ {227, 9, 13, 10, 1, -12}, - /* '9' 0x39 */ {242, 8, 13, 10, 1, -12}, - /* ':' 0x3A */ {255, 2, 10, 5, 1, -9}, - /* ';' 0x3B */ {258, 3, 12, 5, 1, -8}, - /* '<' 0x3C */ {263, 9, 9, 11, 1, -8}, - /* '=' 0x3D */ {274, 9, 4, 11, 1, -5}, - /* '>' 0x3E */ {279, 9, 8, 11, 1, -7}, - /* '?' 0x3F */ {288, 9, 13, 10, 1, -12}, - /* '@' 0x40 */ {303, 17, 16, 18, 1, -12}, - /* 'A' 0x41 */ {337, 12, 13, 12, 0, -12}, - /* 'B' 0x42 */ {357, 11, 13, 12, 1, -12}, - /* 'C' 0x43 */ {375, 11, 13, 13, 1, -12}, - /* 'D' 0x44 */ {393, 11, 13, 13, 1, -12}, - /* 'E' 0x45 */ {411, 9, 13, 11, 1, -12}, - /* 'F' 0x46 */ {426, 8, 13, 11, 1, -12}, - /* 'G' 0x47 */ {439, 12, 13, 14, 1, -12}, - /* 'H' 0x48 */ {459, 11, 13, 13, 1, -12}, - /* 'I' 0x49 */ {477, 2, 13, 5, 2, -12}, - /* 'J' 0x4A */ {481, 7, 13, 10, 1, -12}, - /* 'K' 0x4B */ {493, 10, 13, 12, 1, -12}, - /* 'L' 0x4C */ {510, 8, 13, 10, 1, -12}, - /* 'M' 0x4D */ {523, 13, 13, 15, 1, -12}, - /* 'N' 0x4E */ {545, 11, 13, 13, 1, -12}, - /* 'O' 0x4F */ {563, 13, 13, 14, 1, -12}, - /* 'P' 0x50 */ {585, 10, 13, 12, 1, -12}, - /* 'Q' 0x51 */ {602, 13, 14, 14, 1, -12}, - /* 'R' 0x52 */ {625, 12, 13, 13, 1, -12}, - /* 'S' 0x53 */ {645, 10, 13, 12, 1, -12}, - /* 'T' 0x54 */ {662, 9, 13, 11, 1, -12}, - /* 'U' 0x55 */ {677, 11, 13, 13, 1, -12}, - /* 'V' 0x56 */ {695, 11, 13, 11, 0, -12}, - /* 'W' 0x57 */ {713, 16, 13, 17, 0, -12}, - /* 'X' 0x58 */ {739, 10, 13, 12, 1, -12}, - /* 'Y' 0x59 */ {756, 12, 13, 12, 0, -12}, - /* 'Z' 0x5A */ {776, 10, 13, 11, 1, -12}, - /* '[' 0x5B */ {793, 3, 17, 5, 1, -12}, - /* '\' 0x5C */ {800, 5, 13, 5, 0, -12}, - /* ']' 0x5D */ {809, 3, 17, 5, 0, -12}, - /* '^' 0x5E */ {816, 7, 7, 8, 1, -12}, - /* '_' 0x5F */ {823, 10, 1, 10, 0, 3}, - /* '`' 0x60 */ {825, 4, 3, 5, 0, -12}, - /* 'a' 0x61 */ {827, 9, 10, 10, 1, -9}, - /* 'b' 0x62 */ {839, 9, 13, 10, 1, -12}, - /* 'c' 0x63 */ {854, 8, 10, 9, 1, -9}, - /* 'd' 0x64 */ {864, 8, 13, 10, 1, -12}, - /* 'e' 0x65 */ {877, 8, 10, 10, 1, -9}, - /* 'f' 0x66 */ {887, 4, 13, 5, 1, -12}, - /* 'g' 0x67 */ {894, 8, 14, 10, 1, -9}, - /* 'h' 0x68 */ {908, 8, 13, 10, 1, -12}, - /* 'i' 0x69 */ {921, 2, 13, 4, 1, -12}, - /* 'j' 0x6A */ {925, 4, 17, 4, 0, -12}, - /* 'k' 0x6B */ {934, 8, 13, 9, 1, -12}, - /* 'l' 0x6C */ {947, 2, 13, 4, 1, -12}, - /* 'm' 0x6D */ {951, 13, 10, 15, 1, -9}, - /* 'n' 0x6E */ {968, 8, 10, 10, 1, -9}, - /* 'o' 0x6F */ {978, 8, 10, 10, 1, -9}, - /* 'p' 0x70 */ {988, 9, 13, 10, 1, -9}, - /* 'q' 0x71 */ {1003, 8, 13, 10, 1, -9}, - /* 'r' 0x72 */ {1016, 5, 10, 6, 1, -9}, - /* 's' 0x73 */ {1023, 8, 10, 9, 1, -9}, - /* 't' 0x74 */ {1033, 4, 12, 5, 1, -11}, - /* 'u' 0x75 */ {1039, 8, 10, 10, 1, -9}, - /* 'v' 0x76 */ {1049, 9, 10, 9, 0, -9}, - /* 'w' 0x77 */ {1061, 13, 10, 13, 0, -9}, - /* 'x' 0x78 */ {1078, 7, 10, 9, 1, -9}, - /* 'y' 0x79 */ {1087, 8, 14, 9, 0, -9}, - /* 'z' 0x7A */ {1101, 7, 10, 9, 1, -9}, - /* '{' 0x7B */ {1110, 4, 17, 6, 1, -12}, - /* '|' 0x7C */ {1119, 2, 17, 4, 2, -12}, - /* '}' 0x7D */ {1124, 4, 17, 6, 1, -12}, - /* '~' 0x7E */ {1133, 7, 3, 9, 1, -7}, - /* 0x7F */ {1136, 13, 14, 15, 1, -12}, - /* 0x80 */ {1159, 10, 13, 12, 1, -12}, - /* 0x81 */ {1176, 0, 0, 8, 0, 0}, - /* 0x82 */ {1176, 2, 3, 5, 1, 0}, - /* 0x83 */ {1177, 5, 17, 5, 0, -12}, - /* 0x84 */ {1188, 5, 3, 7, 1, 0}, - /* 0x85 */ {1190, 10, 1, 12, 1, 0}, - /* 0x86 */ {1192, 8, 16, 10, 1, -12}, - /* 0x87 */ {1208, 8, 16, 10, 1, -12}, - /* 0x88 */ {1224, 5, 3, 6, 0, -12}, - /* 0x89 */ {1226, 18, 13, 18, 0, -12}, - /* 0x8A */ {1256, 10, 16, 12, 1, -15}, - /* 0x8B */ {1276, 2, 4, 4, 1, -6}, - /* 0x8C */ {1277, 15, 13, 18, 1, -12}, - /* 0x8D */ {1302, 0, 0, 8, 0, 0}, - /* 0x8E */ {1302, 10, 16, 11, 1, -15}, - /* 0x8F */ {1322, 0, 0, 8, 0, 0}, - /* 0x90 */ {1322, 0, 0, 8, 0, 0}, - /* 0x91 */ {1322, 2, 4, 4, 2, -12}, - /* 0x92 */ {1323, 2, 4, 4, 1, -12}, - /* 0x93 */ {1324, 5, 4, 7, 2, -12}, - /* 0x94 */ {1327, 5, 4, 7, 1, -12}, - /* 0x95 */ {1330, 4, 5, 7, 1, -8}, - /* 0x96 */ {1333, 7, 1, 9, 1, -4}, - /* 0x97 */ {1334, 16, 1, 18, 1, -4}, - /* 0x98 */ {1336, 5, 2, 6, 0, -12}, - /* 0x99 */ {1338, 18, 10, 18, 1, -13}, - /* 0x9A */ {1361, 8, 13, 9, 1, -12}, - /* 0x9B */ {1374, 2, 4, 5, 2, -6}, - /* 0x9C */ {1375, 15, 10, 17, 1, -9}, - /* 0x9D */ {1394, 0, 0, 8, 0, 0}, - /* 0x9E */ {1394, 7, 13, 9, 1, -12}, - /* 0x9F */ {1406, 12, 14, 12, 0, -13}, - /* 0xA0 */ {1427, 0, 0, 5, 0, 0}, - /* 0xA1 */ {1427, 2, 13, 6, 2, -8}, - /* 0xA2 */ {1431, 9, 14, 10, 1, -11}, - /* 0xA3 */ {1447, 10, 13, 10, 0, -12}, - /* 0xA4 */ {1464, 7, 6, 10, 2, -8}, - /* 0xA5 */ {1470, 8, 13, 10, 1, -12}, - /* 0xA6 */ {1483, 2, 17, 5, 2, -12}, - /* 0xA7 */ {1488, 9, 17, 10, 1, -12}, - /* 0xA8 */ {1508, 6, 1, 6, 0, -11}, - /* 0xA9 */ {1509, 14, 13, 14, 1, -12}, - /* 0xAA */ {1532, 5, 8, 7, 1, -12}, - /* 0xAB */ {1537, 7, 6, 9, 1, -7}, - /* 0xAC */ {1543, 9, 5, 11, 2, -5}, - /* 0xAD */ {1549, 0, 0, 0, 0, 0}, - /* 0xAE */ {1549, 14, 13, 14, 1, -12}, - /* 0xAF */ {1572, 5, 1, 6, 0, -12}, - /* 0xB0 */ {1573, 5, 5, 11, 3, -11}, - /* 0xB1 */ {1577, 9, 11, 11, 1, -10}, - /* 0xB2 */ {1590, 6, 8, 6, 1, -13}, - /* 0xB3 */ {1596, 7, 8, 6, 0, -13}, - /* 0xB4 */ {1603, 4, 3, 6, 2, -12}, - /* 0xB5 */ {1605, 9, 13, 10, 1, -9}, - /* 0xB6 */ {1620, 8, 16, 10, 2, -12}, - /* 0xB7 */ {1636, 3, 1, 5, 1, -4}, - /* 0xB8 */ {1637, 5, 4, 6, 1, 1}, - /* 0xB9 */ {1640, 3, 7, 6, 2, -13}, - /* 0xBA */ {1643, 5, 8, 7, 1, -12}, - /* 0xBB */ {1648, 7, 6, 9, 1, -7}, - /* 0xBC */ {1654, 14, 13, 16, 2, -12}, - /* 0xBD */ {1677, 14, 13, 16, 2, -12}, - /* 0xBE */ {1700, 15, 13, 16, 1, -12}, - /* 0xBF */ {1725, 9, 13, 10, 1, -8}, - /* 0xC0 */ {1740, 10, 14, 12, 1, -13}, - /* 0xC1 */ {1758, 10, 14, 12, 1, -13}, - /* 0xC2 */ {1776, 10, 14, 12, 1, -13}, - /* 0xC3 */ {1794, 10, 14, 12, 1, -13}, - /* 0xC4 */ {1812, 10, 14, 12, 1, -13}, - /* 0xC5 */ {1830, 10, 14, 12, 1, -13}, - /* 0xC6 */ {1848, 16, 13, 18, 1, -12}, - /* 0xC7 */ {1874, 11, 17, 13, 1, -12}, - /* 0xC8 */ {1898, 9, 14, 11, 1, -13}, - /* 0xC9 */ {1914, 9, 14, 11, 1, -13}, - /* 0xCA */ {1930, 9, 14, 11, 1, -13}, - /* 0xCB */ {1946, 9, 14, 11, 1, -13}, - /* 0xCC */ {1962, 3, 15, 5, 1, -13}, - /* 0xCD */ {1968, 3, 14, 5, 1, -13}, - /* 0xCE */ {1974, 5, 14, 5, 0, -13}, - /* 0xCF */ {1983, 6, 14, 5, 0, -13}, - /* 0xD0 */ {1994, 11, 13, 13, 1, -12}, - /* 0xD1 */ {2012, 11, 14, 13, 1, -13}, - /* 0xD2 */ {2032, 12, 15, 13, 1, -14}, - /* 0xD3 */ {2055, 12, 15, 13, 1, -14}, - /* 0xD4 */ {2078, 12, 15, 13, 1, -14}, - /* 0xD5 */ {2101, 12, 15, 13, 1, -14}, - /* 0xD6 */ {2124, 12, 15, 13, 1, -14}, - /* 0xD7 */ {2147, 7, 7, 11, 2, -7}, - /* 0xD8 */ {2154, 13, 13, 14, 1, -12}, - /* 0xD9 */ {2176, 11, 14, 13, 1, -13}, - /* 0xDA */ {2196, 11, 14, 13, 1, -13}, - /* 0xDB */ {2216, 11, 14, 13, 1, -13}, - /* 0xDC */ {2236, 11, 14, 13, 1, -13}, - /* 0xDD */ {2256, 12, 14, 12, 0, -13}, - /* 0xDE */ {2277, 10, 13, 12, 1, -12}, - /* 0xDF */ {2294, 9, 13, 11, 1, -12}, - /* 0xE0 */ {2309, 9, 13, 10, 1, -12}, - /* 0xE1 */ {2324, 9, 13, 10, 1, -12}, - /* 0xE2 */ {2339, 9, 13, 10, 1, -12}, - /* 0xE3 */ {2354, 9, 13, 10, 1, -12}, - /* 0xE4 */ {2369, 9, 12, 10, 1, -11}, - /* 0xE5 */ {2383, 9, 14, 10, 1, -13}, - /* 0xE6 */ {2399, 15, 10, 16, 1, -9}, - /* 0xE7 */ {2418, 8, 14, 9, 1, -9}, - /* 0xE8 */ {2432, 8, 13, 10, 1, -12}, - /* 0xE9 */ {2445, 8, 13, 10, 1, -12}, - /* 0xEA */ {2458, 8, 13, 10, 1, -12}, - /* 0xEB */ {2471, 8, 12, 10, 1, -11}, - /* 0xEC */ {2483, 3, 13, 4, 0, -12}, - /* 0xED */ {2488, 3, 13, 4, 1, -12}, - /* 0xEE */ {2493, 4, 13, 5, 0, -12}, - /* 0xEF */ {2500, 6, 12, 5, -1, -11}, - /* 0xF0 */ {2509, 8, 13, 10, 1, -12}, - /* 0xF1 */ {2522, 8, 13, 10, 1, -12}, - /* 0xF2 */ {2535, 8, 13, 10, 1, -12}, - /* 0xF3 */ {2548, 8, 13, 10, 1, -12}, - /* 0xF4 */ {2561, 8, 13, 10, 1, -12}, - /* 0xF5 */ {2574, 8, 13, 10, 1, -12}, - /* 0xF6 */ {2587, 8, 12, 10, 1, -11}, - /* 0xF7 */ {2599, 9, 8, 11, 1, -7}, - /* 0xF8 */ {2608, 8, 10, 10, 1, -9}, - /* 0xF9 */ {2618, 8, 13, 10, 1, -12}, - /* 0xFA */ {2631, 8, 13, 10, 1, -12}, - /* 0xFB */ {2644, 8, 13, 10, 1, -12}, - /* 0xFC */ {2657, 8, 12, 10, 1, -11}, - /* 0xFD */ {2669, 8, 17, 9, 0, -12}, - /* 0xFE */ {2686, 9, 16, 10, 1, -12}, - /* 0xFF */ {2704, 8, 16, 9, 0, -11}, +/* 0x01 */ { 0, 15, 15, 17, 1, -13 }, +/* 0x02 */ { 29, 15, 15, 17, 1, -13 }, +/* 0x03 */ { 58, 15, 16, 17, 1, -14 }, +/* 0x04 */ { 88, 15, 16, 17, 1, -14 }, +/* 0x05 */ { 118, 16, 15, 18, 1, -13 }, +/* 0x06 */ { 148, 15, 15, 17, 1, -13 }, +/* 0x07 */ { 177, 0, 0, 8, 0, 0 }, +/* 0x08 */ { 177, 17, 16, 19, 1, -14 }, +/* 0x09 */ { 211, 17, 12, 19, 1, -12 }, +/* 0x0A */ { 237, 0, 0, 8, 0, 0 }, +/* 0x0B */ { 237, 17, 16, 19, 1, -14 }, +/* 0x0C */ { 271, 15, 14, 17, 1, -12 }, +/* 0x0D */ { 298, 0, 0, 8, 0, 0 }, +/* 0x0E */ { 298, 15, 16, 17, 1, -14 }, +/* 0x0F */ { 328, 15, 15, 17, 1, -13 }, +/* 0x10 */ { 357, 15, 15, 17, 1, -13 }, +/* 0x11 */ { 386, 15, 16, 17, 1, -14 }, +/* 0x12 */ { 416, 17, 17, 19, 1, -15 }, +/* 0x13 */ { 453, 15, 16, 17, 1, -14 }, +/* 0x14 */ { 483, 15, 16, 17, 1, -14 }, +/* 0x15 */ { 513, 15, 16, 17, 1, -14 }, +/* 0x16 */ { 543, 11, 16, 13, 1, -14 }, +/* 0x17 */ { 565, 15, 16, 17, 1, -14 }, +/* 0x18 */ { 595, 18, 15, 20, 1, -13 }, +/* 0x19 */ { 629, 15, 16, 17, 1, -14 }, +/* 0x1A */ { 659, 13, 14, 15, 1, -12 }, +/* 0x1B */ { 682, 17, 16, 19, 1, -14 }, +/* 0x1C */ { 716, 15, 16, 17, 1, -14 }, +/* 0x1D */ { 746, 15, 15, 17, 1, -13 }, +/* 0x1E */ { 775, 17, 16, 19, 1, -14 }, +/* 0x1F */ { 809, 11, 16, 13, 1, -14 }, +/* ' ' 0x20 */ { 831, 0, 0, 5, 0, 0 }, +/* '!' 0x21 */ { 831, 2, 13, 6, 2, -12 }, +/* '"' 0x22 */ { 835, 5, 4, 6, 1, -12 }, +/* '#' 0x23 */ { 838, 10, 12, 10, 0, -11 }, +/* '$' 0x24 */ { 853, 9, 16, 10, 1, -13 }, +/* '%' 0x25 */ { 871, 16, 13, 16, 1, -12 }, +/* '&' 0x26 */ { 897, 10, 13, 12, 1, -12 }, +/* ''' 0x27 */ { 914, 2, 4, 4, 1, -12 }, +/* '(' 0x28 */ { 915, 4, 17, 6, 1, -12 }, +/* ')' 0x29 */ { 924, 4, 17, 6, 1, -12 }, +/* '*' 0x2A */ { 933, 5, 5, 7, 1, -12 }, +/* '+' 0x2B */ { 937, 6, 8, 11, 3, -7 }, +/* ',' 0x2C */ { 943, 2, 4, 5, 2, 0 }, +/* '-' 0x2D */ { 944, 4, 1, 6, 1, -4 }, +/* '.' 0x2E */ { 945, 2, 1, 5, 1, 0 }, +/* '/' 0x2F */ { 946, 5, 13, 5, 0, -12 }, +/* '0' 0x30 */ { 955, 8, 13, 10, 1, -12 }, +/* '1' 0x31 */ { 968, 4, 13, 10, 3, -12 }, +/* '2' 0x32 */ { 975, 9, 13, 10, 1, -12 }, +/* '3' 0x33 */ { 990, 8, 13, 10, 1, -12 }, +/* '4' 0x34 */ { 1003, 7, 13, 10, 2, -12 }, +/* '5' 0x35 */ { 1015, 9, 13, 10, 1, -12 }, +/* '6' 0x36 */ { 1030, 9, 13, 10, 1, -12 }, +/* '7' 0x37 */ { 1045, 8, 13, 10, 0, -12 }, +/* '8' 0x38 */ { 1058, 9, 13, 10, 1, -12 }, +/* '9' 0x39 */ { 1073, 8, 13, 10, 1, -12 }, +/* ':' 0x3A */ { 1086, 2, 10, 5, 1, -9 }, +/* ';' 0x3B */ { 1089, 3, 12, 5, 1, -8 }, +/* '<' 0x3C */ { 1094, 9, 9, 11, 1, -8 }, +/* '=' 0x3D */ { 1105, 9, 4, 11, 1, -5 }, +/* '>' 0x3E */ { 1110, 9, 8, 11, 1, -7 }, +/* '?' 0x3F */ { 1119, 9, 13, 10, 1, -12 }, +/* '@' 0x40 */ { 1134, 17, 16, 18, 1, -12 }, +/* 'A' 0x41 */ { 1168, 12, 13, 12, 0, -12 }, +/* 'B' 0x42 */ { 1188, 11, 13, 12, 1, -12 }, +/* 'C' 0x43 */ { 1206, 11, 13, 13, 1, -12 }, +/* 'D' 0x44 */ { 1224, 11, 13, 13, 1, -12 }, +/* 'E' 0x45 */ { 1242, 9, 13, 11, 1, -12 }, +/* 'F' 0x46 */ { 1257, 8, 13, 11, 1, -12 }, +/* 'G' 0x47 */ { 1270, 12, 13, 14, 1, -12 }, +/* 'H' 0x48 */ { 1290, 11, 13, 13, 1, -12 }, +/* 'I' 0x49 */ { 1308, 2, 13, 5, 2, -12 }, +/* 'J' 0x4A */ { 1312, 7, 13, 10, 1, -12 }, +/* 'K' 0x4B */ { 1324, 10, 13, 12, 1, -12 }, +/* 'L' 0x4C */ { 1341, 8, 13, 10, 1, -12 }, +/* 'M' 0x4D */ { 1354, 13, 13, 15, 1, -12 }, +/* 'N' 0x4E */ { 1376, 11, 13, 13, 1, -12 }, +/* 'O' 0x4F */ { 1394, 13, 13, 14, 1, -12 }, +/* 'P' 0x50 */ { 1416, 10, 13, 12, 1, -12 }, +/* 'Q' 0x51 */ { 1433, 13, 14, 14, 1, -12 }, +/* 'R' 0x52 */ { 1456, 12, 13, 13, 1, -12 }, +/* 'S' 0x53 */ { 1476, 10, 13, 12, 1, -12 }, +/* 'T' 0x54 */ { 1493, 9, 13, 11, 1, -12 }, +/* 'U' 0x55 */ { 1508, 11, 13, 13, 1, -12 }, +/* 'V' 0x56 */ { 1526, 11, 13, 11, 0, -12 }, +/* 'W' 0x57 */ { 1544, 16, 13, 17, 0, -12 }, +/* 'X' 0x58 */ { 1570, 10, 13, 12, 1, -12 }, +/* 'Y' 0x59 */ { 1587, 12, 13, 12, 0, -12 }, +/* 'Z' 0x5A */ { 1607, 10, 13, 11, 1, -12 }, +/* '[' 0x5B */ { 1624, 3, 17, 5, 1, -12 }, +/* '\' 0x5C */ { 1631, 5, 13, 5, 0, -12 }, +/* ']' 0x5D */ { 1640, 3, 17, 5, 0, -12 }, +/* '^' 0x5E */ { 1647, 7, 7, 8, 1, -12 }, +/* '_' 0x5F */ { 1654, 10, 1, 10, 0, 3 }, +/* '`' 0x60 */ { 1656, 4, 3, 5, 0, -12 }, +/* 'a' 0x61 */ { 1658, 9, 10, 10, 1, -9 }, +/* 'b' 0x62 */ { 1670, 9, 13, 10, 1, -12 }, +/* 'c' 0x63 */ { 1685, 8, 10, 9, 1, -9 }, +/* 'd' 0x64 */ { 1695, 8, 13, 10, 1, -12 }, +/* 'e' 0x65 */ { 1708, 8, 10, 10, 1, -9 }, +/* 'f' 0x66 */ { 1718, 4, 13, 5, 1, -12 }, +/* 'g' 0x67 */ { 1725, 8, 14, 10, 1, -9 }, +/* 'h' 0x68 */ { 1739, 8, 13, 10, 1, -12 }, +/* 'i' 0x69 */ { 1752, 2, 13, 4, 1, -12 }, +/* 'j' 0x6A */ { 1756, 4, 17, 4, 0, -12 }, +/* 'k' 0x6B */ { 1765, 8, 13, 9, 1, -12 }, +/* 'l' 0x6C */ { 1778, 2, 13, 4, 1, -12 }, +/* 'm' 0x6D */ { 1782, 13, 10, 15, 1, -9 }, +/* 'n' 0x6E */ { 1799, 8, 10, 10, 1, -9 }, +/* 'o' 0x6F */ { 1809, 8, 10, 10, 1, -9 }, +/* 'p' 0x70 */ { 1819, 9, 13, 10, 1, -9 }, +/* 'q' 0x71 */ { 1834, 8, 13, 10, 1, -9 }, +/* 'r' 0x72 */ { 1847, 5, 10, 6, 1, -9 }, +/* 's' 0x73 */ { 1854, 8, 10, 9, 1, -9 }, +/* 't' 0x74 */ { 1864, 4, 12, 5, 1, -11 }, +/* 'u' 0x75 */ { 1870, 8, 10, 10, 1, -9 }, +/* 'v' 0x76 */ { 1880, 9, 10, 9, 0, -9 }, +/* 'w' 0x77 */ { 1892, 13, 10, 13, 0, -9 }, +/* 'x' 0x78 */ { 1909, 7, 10, 9, 1, -9 }, +/* 'y' 0x79 */ { 1918, 8, 14, 9, 0, -9 }, +/* 'z' 0x7A */ { 1932, 7, 10, 9, 1, -9 }, +/* '{' 0x7B */ { 1941, 4, 17, 6, 1, -12 }, +/* '|' 0x7C */ { 1950, 2, 17, 4, 2, -12 }, +/* '}' 0x7D */ { 1955, 4, 17, 6, 1, -12 }, +/* '~' 0x7E */ { 1964, 7, 3, 9, 1, -7 }, +/* 0x7F */ { 1967, 0, 0, 0, 0, 0 }, +/* 0x80 */ { 1967, 10, 13, 12, 1, -12 }, +/* 0x81 */ { 1984, 0, 0, 8, 0, 0 }, +/* 0x82 */ { 1984, 2, 3, 5, 1, 0 }, +/* 0x83 */ { 1985, 5, 17, 5, 0, -12 }, +/* 0x84 */ { 1996, 5, 3, 7, 1, 0 }, +/* 0x85 */ { 1998, 10, 1, 12, 1, 0 }, +/* 0x86 */ { 2000, 8, 16, 10, 1, -12 }, +/* 0x87 */ { 2016, 8, 16, 10, 1, -12 }, +/* 0x88 */ { 2032, 5, 3, 6, 0, -12 }, +/* 0x89 */ { 2034, 18, 13, 18, 0, -12 }, +/* 0x8A */ { 2064, 10, 16, 12, 1, -15 }, +/* 0x8B */ { 2084, 2, 4, 4, 1, -6 }, +/* 0x8C */ { 2085, 15, 13, 18, 1, -12 }, +/* 0x8D */ { 2110, 0, 0, 8, 0, 0 }, +/* 0x8E */ { 2110, 10, 16, 11, 1, -15 }, +/* 0x8F */ { 2130, 0, 0, 8, 0, 0 }, +/* 0x90 */ { 2130, 0, 0, 8, 0, 0 }, +/* 0x91 */ { 2130, 2, 4, 4, 2, -12 }, +/* 0x92 */ { 2131, 2, 4, 4, 1, -12 }, +/* 0x93 */ { 2132, 5, 4, 7, 2, -12 }, +/* 0x94 */ { 2135, 5, 4, 7, 1, -12 }, +/* 0x95 */ { 2138, 4, 5, 7, 1, -8 }, +/* 0x96 */ { 2141, 7, 1, 9, 1, -4 }, +/* 0x97 */ { 2142, 16, 1, 18, 1, -4 }, +/* 0x98 */ { 2144, 5, 2, 6, 0, -12 }, +/* 0x99 */ { 2146, 18, 10, 18, 1, -13 }, +/* 0x9A */ { 2169, 8, 13, 9, 1, -12 }, +/* 0x9B */ { 2182, 2, 4, 5, 2, -6 }, +/* 0x9C */ { 2183, 15, 10, 17, 1, -9 }, +/* 0x9D */ { 2202, 0, 0, 8, 0, 0 }, +/* 0x9E */ { 2202, 7, 13, 9, 1, -12 }, +/* 0x9F */ { 2214, 12, 14, 12, 0, -13 }, +/* 0xA0 */ { 2235, 0, 0, 5, 0, 0 }, +/* 0xA1 */ { 2235, 2, 13, 6, 2, -8 }, +/* 0xA2 */ { 2239, 9, 14, 10, 1, -11 }, +/* 0xA3 */ { 2255, 10, 13, 10, 0, -12 }, +/* 0xA4 */ { 2272, 7, 6, 10, 2, -8 }, +/* 0xA5 */ { 2278, 8, 13, 10, 1, -12 }, +/* 0xA6 */ { 2291, 2, 17, 5, 2, -12 }, +/* 0xA7 */ { 2296, 9, 17, 10, 1, -12 }, +/* 0xA8 */ { 2316, 6, 1, 6, 0, -11 }, +/* 0xA9 */ { 2317, 14, 13, 14, 1, -12 }, +/* 0xAA */ { 2340, 5, 8, 7, 1, -12 }, +/* 0xAB */ { 2345, 7, 6, 9, 1, -7 }, +/* 0xAC */ { 2351, 9, 5, 11, 2, -5 }, +/* 0xAD */ { 2357, 0, 0, 0, 0, 0 }, +/* 0xAE */ { 2357, 14, 13, 14, 1, -12 }, +/* 0xAF */ { 2380, 5, 1, 6, 0, -12 }, +/* 0xB0 */ { 2381, 5, 5, 11, 3, -11 }, +/* 0xB1 */ { 2385, 9, 11, 11, 1, -10 }, +/* 0xB2 */ { 2398, 6, 8, 6, 1, -13 }, +/* 0xB3 */ { 2404, 7, 8, 6, 0, -13 }, +/* 0xB4 */ { 2411, 4, 3, 6, 2, -12 }, +/* 0xB5 */ { 2413, 9, 13, 10, 1, -9 }, +/* 0xB6 */ { 2428, 8, 16, 10, 2, -12 }, +/* 0xB7 */ { 2444, 3, 1, 5, 1, -4 }, +/* 0xB8 */ { 2445, 5, 4, 6, 1, 1 }, +/* 0xB9 */ { 2448, 3, 7, 6, 2, -13 }, +/* 0xBA */ { 2451, 5, 8, 7, 1, -12 }, +/* 0xBB */ { 2456, 7, 6, 9, 1, -7 }, +/* 0xBC */ { 2462, 14, 13, 16, 2, -12 }, +/* 0xBD */ { 2485, 14, 13, 16, 2, -12 }, +/* 0xBE */ { 2508, 15, 13, 16, 1, -12 }, +/* 0xBF */ { 2533, 9, 13, 10, 1, -8 }, +/* 0xC0 */ { 2548, 10, 14, 12, 1, -13 }, +/* 0xC1 */ { 2566, 10, 14, 12, 1, -13 }, +/* 0xC2 */ { 2584, 10, 14, 12, 1, -13 }, +/* 0xC3 */ { 2602, 10, 14, 12, 1, -13 }, +/* 0xC4 */ { 2620, 10, 14, 12, 1, -13 }, +/* 0xC5 */ { 2638, 10, 14, 12, 1, -13 }, +/* 0xC6 */ { 2656, 16, 13, 18, 1, -12 }, +/* 0xC7 */ { 2682, 11, 17, 13, 1, -12 }, +/* 0xC8 */ { 2706, 9, 14, 11, 1, -13 }, +/* 0xC9 */ { 2722, 9, 14, 11, 1, -13 }, +/* 0xCA */ { 2738, 9, 14, 11, 1, -13 }, +/* 0xCB */ { 2754, 9, 14, 11, 1, -13 }, +/* 0xCC */ { 2770, 3, 15, 5, 1, -13 }, +/* 0xCD */ { 2776, 3, 14, 5, 1, -13 }, +/* 0xCE */ { 2782, 5, 14, 5, 0, -13 }, +/* 0xCF */ { 2791, 6, 14, 5, 0, -13 }, +/* 0xD0 */ { 2802, 11, 13, 13, 1, -12 }, +/* 0xD1 */ { 2820, 11, 14, 13, 1, -13 }, +/* 0xD2 */ { 2840, 12, 15, 13, 1, -14 }, +/* 0xD3 */ { 2863, 12, 15, 13, 1, -14 }, +/* 0xD4 */ { 2886, 12, 15, 13, 1, -14 }, +/* 0xD5 */ { 2909, 12, 15, 13, 1, -14 }, +/* 0xD6 */ { 2932, 12, 15, 13, 1, -14 }, +/* 0xD7 */ { 2955, 7, 7, 11, 2, -7 }, +/* 0xD8 */ { 2962, 13, 13, 14, 1, -12 }, +/* 0xD9 */ { 2984, 11, 14, 13, 1, -13 }, +/* 0xDA */ { 3004, 11, 14, 13, 1, -13 }, +/* 0xDB */ { 3024, 11, 14, 13, 1, -13 }, +/* 0xDC */ { 3044, 11, 14, 13, 1, -13 }, +/* 0xDD */ { 3064, 12, 14, 12, 0, -13 }, +/* 0xDE */ { 3085, 10, 13, 12, 1, -12 }, +/* 0xDF */ { 3102, 9, 13, 11, 1, -12 }, +/* 0xE0 */ { 3117, 9, 13, 10, 1, -12 }, +/* 0xE1 */ { 3132, 9, 13, 10, 1, -12 }, +/* 0xE2 */ { 3147, 9, 13, 10, 1, -12 }, +/* 0xE3 */ { 3162, 9, 13, 10, 1, -12 }, +/* 0xE4 */ { 3177, 9, 12, 10, 1, -11 }, +/* 0xE5 */ { 3191, 9, 14, 10, 1, -13 }, +/* 0xE6 */ { 3207, 15, 10, 16, 1, -9 }, +/* 0xE7 */ { 3226, 8, 14, 9, 1, -9 }, +/* 0xE8 */ { 3240, 8, 13, 10, 1, -12 }, +/* 0xE9 */ { 3253, 8, 13, 10, 1, -12 }, +/* 0xEA */ { 3266, 8, 13, 10, 1, -12 }, +/* 0xEB */ { 3279, 8, 12, 10, 1, -11 }, +/* 0xEC */ { 3291, 3, 13, 4, 0, -12 }, +/* 0xED */ { 3296, 3, 13, 4, 1, -12 }, +/* 0xEE */ { 3301, 4, 13, 5, 0, -12 }, +/* 0xEF */ { 3308, 6, 12, 5, -1, -11 }, +/* 0xF0 */ { 3317, 8, 13, 10, 1, -12 }, +/* 0xF1 */ { 3330, 8, 13, 10, 1, -12 }, +/* 0xF2 */ { 3343, 8, 13, 10, 1, -12 }, +/* 0xF3 */ { 3356, 8, 13, 10, 1, -12 }, +/* 0xF4 */ { 3369, 8, 13, 10, 1, -12 }, +/* 0xF5 */ { 3382, 8, 13, 10, 1, -12 }, +/* 0xF6 */ { 3395, 8, 12, 10, 1, -11 }, +/* 0xF7 */ { 3407, 9, 8, 11, 1, -7 }, +/* 0xF8 */ { 3416, 8, 10, 10, 1, -9 }, +/* 0xF9 */ { 3426, 8, 13, 10, 1, -12 }, +/* 0xFA */ { 3439, 8, 13, 10, 1, -12 }, +/* 0xFB */ { 3452, 8, 13, 10, 1, -12 }, +/* 0xFC */ { 3465, 8, 12, 10, 1, -11 }, +/* 0xFD */ { 3477, 8, 17, 9, 0, -12 }, +/* 0xFE */ { 3494, 9, 16, 10, 1, -12 }, +/* 0xFF */ { 3512, 8, 16, 9, 0, -11 }, }; -const GFXfont FreeSans9pt_Win1252 PROGMEM = {(uint8_t *)FreeSans9pt_Win1252Bitmaps, (GFXglyph *)FreeSans9pt_Win1252Glyphs, 0x20, - 0xFF, 21}; +const GFXfont FreeSans9pt_Win1252 PROGMEM = { +(uint8_t*)FreeSans9pt_Win1252Bitmaps, +(GFXglyph*)FreeSans9pt_Win1252Glyphs, +0x01, 0xFF, 16 +}; diff --git a/src/graphics/niche/InkHUD/Applet.cpp b/src/graphics/niche/InkHUD/Applet.cpp index f63bd4bbe..1e89ebe1b 100644 --- a/src/graphics/niche/InkHUD/Applet.cpp +++ b/src/graphics/niche/InkHUD/Applet.cpp @@ -8,8 +8,9 @@ using namespace NicheGraphics; -InkHUD::AppletFont InkHUD::Applet::fontLarge; // General purpose font. Set by setDefaultFonts -InkHUD::AppletFont InkHUD::Applet::fontSmall; // General purpose font. Set by setDefaultFonts +InkHUD::AppletFont InkHUD::Applet::fontLarge; // General purpose fonts. Set in nicheGraphics.h +InkHUD::AppletFont InkHUD::Applet::fontMedium; +InkHUD::AppletFont InkHUD::Applet::fontSmall; constexpr float InkHUD::Applet::LOGO_ASPECT_RATIO; // Ratio of the Meshtastic logo InkHUD::Applet::Applet() : GFX(0, 0) @@ -353,10 +354,9 @@ std::string InkHUD::Applet::parseShortName(meshtastic_NodeInfoLite *node) // Determine if all characters of a string are printable using the current font bool InkHUD::Applet::isPrintable(std::string text) { - // Scan for DEL (0x7F), which is the value assigned by AppletFont::applyEncoding if a unicode character is not handled - // Todo: move this to from DEL to SUB, once the fonts have been changed for this + // Scan for SUB (0x1A), which is the value assigned by AppletFont::applyEncoding if a unicode character is not handled for (char &c : text) { - if (c == '\x7F') + if (c == '\x1A') return false; } diff --git a/src/graphics/niche/InkHUD/Applet.h b/src/graphics/niche/InkHUD/Applet.h index c6a8a8aad..802186e6e 100644 --- a/src/graphics/niche/InkHUD/Applet.h +++ b/src/graphics/niche/InkHUD/Applet.h @@ -95,7 +95,7 @@ class Applet : public GFX static uint16_t getHeaderHeight(); // How tall the "standard" applet header is - static AppletFont fontSmall, fontLarge; // The general purpose fonts, used by all applets + static AppletFont fontSmall, fontMedium, fontLarge; // The general purpose fonts, used by all applets const char *name = nullptr; // Shown in applet selection menu. Also used as an identifier by InkHUD::getSystemApplet diff --git a/src/graphics/niche/InkHUD/AppletFont.cpp b/src/graphics/niche/InkHUD/AppletFont.cpp index 88fb4054b..db7097f3f 100644 --- a/src/graphics/niche/InkHUD/AppletFont.cpp +++ b/src/graphics/niche/InkHUD/AppletFont.cpp @@ -616,9 +616,116 @@ char InkHUD::AppletFont::applyEncoding(std::string utf8) } } - // If not handled, return DEL - // Todo: swap this to SUB, and modify the fonts - return '\x7F'; + else /*ASCII or Unhandled*/ { + if (utf8.length() == 1) + return utf8.at(0); + } + + // All single-byte (ASCII) characters should have been handled by now + // Only unhandled multi-byte UTF8 characters should remain + assert(utf8.length() > 1); + + // Parse emoji + // Strip emoji modifiers + switch (toUtf32(utf8)) { + REMAP(0x1F44D, 0x01) // 👍 Thumbs Up + REMAP(0x1F44E, 0x02) // 👎 Thumbs Down + + REMAP(0x1F60A, 0x03) // 😊 Smiling Face with Smiling Eyes + REMAP(0x1F642, 0x03) // 🙂 Slightly Smiling Face + REMAP(0x1F601, 0x03) // 😁 Grinning Face with Smiling Eye + + REMAP(0x1F602, 0x04) // 😂 Face with Tears of Joy + REMAP(0x1F923, 0x04) // 🤣 Rolling on the Floor Laughing + REMAP(0x1F606, 0x04) // 😆 Smiling with Open Mouth and Closed Eyes + + REMAP(0x1F44B, 0x05) // 👋 Waving Hand + + REMAP(0x02600, 0x06) // ☀ Sun + REMAP(0x1F31E, 0x06) // 🌞 Sun with Face + + // 0x07 - Bell character (unused) + REMAP(0x1F327, 0x08) // 🌧️ Cloud with Rain + + REMAP(0x02601, 0x09) // ☁️ Cloud + REMAP(0x1F32B, 0x09) // Fog + + REMAP(0x1F9E1, 0x0B) // 🧡 Orange Heart + REMAP(0x02763, 0x0B) // ❣ Heart Exclamation + REMAP(0x02764, 0x0B) // ❤ Heart + REMAP(0x1F495, 0x0B) // 💕 Two Hearts + REMAP(0x1F496, 0x0B) // 💖 Sparkling Heart + REMAP(0x1F497, 0x0B) // 💗 Growing Heart + REMAP(0x1F498, 0x0B) // 💘 Heart with Arrow + + REMAP(0x1F4A9, 0x0C) // 💩 Pile of Poo + // 0x0D - Carriage return (unused) + REMAP(0x1F514, 0x0E) // 🔔 Bell + + REMAP(0x1F62D, 0x0F) // 😭 Loudly Crying Face + REMAP(0x1F622, 0x0F) // 😢 Crying Face + + REMAP(0x1F64F, 0x10) // 🙏 Person with Folded Hands + REMAP(0x1F618, 0x11) // 😘 Face Throwing a Kiss + REMAP(0x1F389, 0x12) // 🎉 Party Popper + + REMAP(0x1F600, 0x13) // 😀 Grinning Face + REMAP(0x1F603, 0x13) // 😃 Smiling Face with Open Mouth + REMAP(0x1F604, 0x13) // 😄 Smiling Face with Open Mouth and Smiling Eyes + + REMAP(0x1F97A, 0x14) // 🥺 Face with Pleading Eyes + REMAP(0x1F605, 0x15) // 😅 Smiling with Sweat + REMAP(0x1F525, 0x16) // 🔥 Fire + REMAP(0x1F926, 0x17) // 🤦 Face Palm + REMAP(0x1F937, 0x18) // 🤷 Shrug + REMAP(0x1F644, 0x19) // 🙄 Face with Rolling Eyes + // 0x1A Substitution (unused) + REMAP(0x1F917, 0x1B) // 🤗 Hugging Face + + REMAP(0x1F609, 0x1C) // 😉 Winking Face + REMAP(0x1F61C, 0x1C) // 😜 Face with Stuck-Out Tongue and Winking Eye + REMAP(0x1F60F, 0x1C) // 😏 Smirking Face + + REMAP(0x1F914, 0x1D) // 🤔 Thinking Face + REMAP(0x1FAE1, 0x1E) // 🫡 Saluting Face + REMAP(0x1F44C, 0x1F) // 👌 OK Hand Sign + + REMAP(0x02755, '!') // ❕ + REMAP(0x02757, '!') // ❗ + REMAP(0x0203C, '!') // ‼ + REMAP(0x02753, '?') // ❓ + REMAP(0x02754, '?') // ❔ + REMAP(0x02049, '?') // ⁉ + + // Modifiers (deleted) + REMAP(0x02640, 0x7F) // Gender + REMAP(0x02642, 0x7F) + REMAP(0x1F3FB, 0x7F) // Skin Tones + REMAP(0x1F3FC, 0x7F) + REMAP(0x1F3FD, 0x7F) + REMAP(0x1F3FE, 0x7F) + REMAP(0x1F3FF, 0x7F) + REMAP(0x0FE00, 0x7F) // Variation Selectors + REMAP(0x0FE01, 0x7F) + REMAP(0x0FE02, 0x7F) + REMAP(0x0FE03, 0x7F) + REMAP(0x0FE04, 0x7F) + REMAP(0x0FE05, 0x7F) + REMAP(0x0FE06, 0x7F) + REMAP(0x0FE07, 0x7F) + REMAP(0x0FE08, 0x7F) + REMAP(0x0FE09, 0x7F) + REMAP(0x0FE0A, 0x7F) + REMAP(0x0FE0B, 0x7F) + REMAP(0x0FE0C, 0x7F) + REMAP(0x0FE0D, 0x7F) + REMAP(0x0FE0E, 0x7F) + REMAP(0x0FE0F, 0x7F) + REMAP(0x0200D, 0x7F) // Zero Width Joiner + } + + // If not handled, return SUB + return '\x1A'; // Sweep up the syntactic sugar // Don't want ants in the house diff --git a/src/graphics/niche/InkHUD/AppletFont.h b/src/graphics/niche/InkHUD/AppletFont.h index 67348b8d3..e1fe37974 100644 --- a/src/graphics/niche/InkHUD/AppletFont.h +++ b/src/graphics/niche/InkHUD/AppletFont.h @@ -61,20 +61,26 @@ class AppletFont // Line padding has been adjusted manually, to compensate for a few *extra tall* diacritics // Central European +#include "graphics/niche/Fonts/FreeSans12pt_Win1250.h" #include "graphics/niche/Fonts/FreeSans6pt_Win1250.h" #include "graphics/niche/Fonts/FreeSans9pt_Win1250.h" +#define FREESANS_12PT_WIN1250 InkHUD::AppletFont(FreeSans12pt_Win1250, InkHUD::AppletFont::WINDOWS_1250, -3, 1) #define FREESANS_9PT_WIN1250 InkHUD::AppletFont(FreeSans9pt_Win1250, InkHUD::AppletFont::WINDOWS_1250, -1, -1) #define FREESANS_6PT_WIN1250 InkHUD::AppletFont(FreeSans6pt_Win1250, InkHUD::AppletFont::WINDOWS_1250, -1, -2) // Cyrillic +#include "graphics/niche/Fonts/FreeSans12pt_Win1251.h" #include "graphics/niche/Fonts/FreeSans6pt_Win1251.h" #include "graphics/niche/Fonts/FreeSans9pt_Win1251.h" +#define FREESANS_12PT_WIN1251 InkHUD::AppletFont(FreeSans12pt_Win1251, InkHUD::AppletFont::WINDOWS_1251, -3, 1) #define FREESANS_9PT_WIN1251 InkHUD::AppletFont(FreeSans9pt_Win1251, InkHUD::AppletFont::WINDOWS_1251, -2, -1) #define FREESANS_6PT_WIN1251 InkHUD::AppletFont(FreeSans6pt_Win1251, InkHUD::AppletFont::WINDOWS_1251, -1, -2) // Western European +#include "graphics/niche/Fonts/FreeSans12pt_Win1252.h" #include "graphics/niche/Fonts/FreeSans6pt_Win1252.h" #include "graphics/niche/Fonts/FreeSans9pt_Win1252.h" +#define FREESANS_12PT_WIN1252 InkHUD::AppletFont(FreeSans12pt_Win1252, InkHUD::AppletFont::WINDOWS_1252, -3, 1) #define FREESANS_9PT_WIN1252 InkHUD::AppletFont(FreeSans9pt_Win1252, InkHUD::AppletFont::WINDOWS_1252, -2, -1) #define FREESANS_6PT_WIN1252 InkHUD::AppletFont(FreeSans6pt_Win1252, InkHUD::AppletFont::WINDOWS_1252, -1, -2) diff --git a/src/graphics/niche/InkHUD/Applets/Bases/NodeList/NodeListApplet.cpp b/src/graphics/niche/InkHUD/Applets/Bases/NodeList/NodeListApplet.cpp index 7fa31b244..1b0bfa9d0 100644 --- a/src/graphics/niche/InkHUD/Applets/Bases/NodeList/NodeListApplet.cpp +++ b/src/graphics/niche/InkHUD/Applets/Bases/NodeList/NodeListApplet.cpp @@ -168,11 +168,11 @@ void InkHUD::NodeListApplet::onRender() // Define two lines of text for the card // We will center our text on these lines - uint16_t lineAY = cardTopY + (fontLarge.lineHeight() / 2); - uint16_t lineBY = cardTopY + fontLarge.lineHeight() + (fontSmall.lineHeight() / 2); + uint16_t lineAY = cardTopY + (fontMedium.lineHeight() / 2); + uint16_t lineBY = cardTopY + fontMedium.lineHeight() + (fontSmall.lineHeight() / 2); // Print the short name - setFont(fontLarge); + setFont(fontMedium); printAt(0, lineAY, shortName, LEFT, MIDDLE); // Print the distance @@ -182,8 +182,8 @@ void InkHUD::NodeListApplet::onRender() // If we have a direct connection to the node, draw the signal indicator if (hopsAway == 0 && signal != SIGNAL_UNKNOWN) { uint16_t signalW = getTextWidth("Xkm"); // Indicator should be similar width to distance label - uint16_t signalH = fontLarge.lineHeight() * 0.75; - int16_t signalY = lineAY + (fontLarge.lineHeight() / 2) - (fontLarge.lineHeight() * 0.75); + uint16_t signalH = fontMedium.lineHeight() * 0.75; + int16_t signalY = lineAY + (fontMedium.lineHeight() / 2) - (fontMedium.lineHeight() * 0.75); int16_t signalX = width() - signalW; drawSignalIndicator(signalX, signalY, signalW, signalH, signal); } diff --git a/src/graphics/niche/InkHUD/Applets/Bases/NodeList/NodeListApplet.h b/src/graphics/niche/InkHUD/Applets/Bases/NodeList/NodeListApplet.h index 0abcad824..c2340027b 100644 --- a/src/graphics/niche/InkHUD/Applets/Bases/NodeList/NodeListApplet.h +++ b/src/graphics/niche/InkHUD/Applets/Bases/NodeList/NodeListApplet.h @@ -65,8 +65,8 @@ class NodeListApplet : public Applet, public MeshModule // Card Dimensions // - for rendering and for maxCards calc - const uint8_t cardMarginH = fontSmall.lineHeight() / 2; // Gap between cards - const uint16_t cardH = fontLarge.lineHeight() + fontSmall.lineHeight() + cardMarginH; // Height of card + uint8_t cardMarginH = fontSmall.lineHeight() / 2; // Gap between cards + uint16_t cardH = fontMedium.lineHeight() + fontSmall.lineHeight() + cardMarginH; // Height of card }; } // namespace NicheGraphics::InkHUD diff --git a/src/graphics/niche/InkHUD/Applets/System/Logo/LogoApplet.cpp b/src/graphics/niche/InkHUD/Applets/System/Logo/LogoApplet.cpp index fa85deab3..ecaa7cea3 100644 --- a/src/graphics/niche/InkHUD/Applets/System/Logo/LogoApplet.cpp +++ b/src/graphics/niche/InkHUD/Applets/System/Logo/LogoApplet.cpp @@ -14,9 +14,10 @@ InkHUD::LogoApplet::LogoApplet() : concurrency::OSThread("LogoApplet") // During onboarding, show the default short name as well as the version string // This behavior assists manufacturers during mass production, and should not be modified without good reason if (!settings->tips.safeShutdownSeen) { - fontTitle = fontLarge; + meshtastic_NodeInfoLite *ourNode = nodeDB->getMeshNode(nodeDB->getNodeNum()); + fontTitle = fontMedium; textLeft = xstr(APP_VERSION_SHORT); - textRight = owner.short_name; + textRight = parseShortName(ourNode); textTitle = "Meshtastic"; } else { fontTitle = fontSmall; @@ -51,6 +52,40 @@ void InkHUD::LogoApplet::onRender() setTextColor(WHITE); } +#ifdef USERPREFS_OEM_IMAGE_DATA // Custom boot screen, if defined in userPrefs.jsonc + + // Only show the custom screen at startup + // This allows us to draw the usual Meshtastic logo at shutdown + // The effect is similar to the two-stage userPrefs boot screen used by BaseUI + if (millis() < 10 * 1000UL) { + + // Draw the custom logo + const uint8_t logo[] = USERPREFS_OEM_IMAGE_DATA; + drawXBitmap(logoCX - (USERPREFS_OEM_IMAGE_WIDTH / 2), // Left + logoCY - (USERPREFS_OEM_IMAGE_HEIGHT / 2), // Top + logo, // XBM data + USERPREFS_OEM_IMAGE_WIDTH, // Width + USERPREFS_OEM_IMAGE_HEIGHT, // Height + inverted ? WHITE : BLACK // Color + ); + + // Select the largest font which will still comfortably fit the custom text + setFont(fontLarge); + if (getTextWidth(USERPREFS_OEM_TEXT) > 0.8 * width()) + setFont(fontMedium); + if (getTextWidth(USERPREFS_OEM_TEXT) > 0.8 * width()) + setFont(fontSmall); + + // Draw custom text below logo + int16_t logoB = logoCY + (USERPREFS_OEM_IMAGE_HEIGHT / 2); // Bottom of the logo + printAt(X(0.5), logoB + Y(0.1), USERPREFS_OEM_TEXT, CENTER, TOP); + + // Don't draw the normal boot screen, we've already drawn our custom version + return; + } + +#endif + drawLogo(logoCX, logoCY, logoW, logoH, inverted ? WHITE : BLACK); if (!textLeft.empty()) { @@ -115,7 +150,7 @@ void InkHUD::LogoApplet::onShutdown() textLeft = ""; textRight = ""; textTitle = parseShortName(ourNode); - fontTitle = fontLarge; + fontTitle = fontMedium; // This is then drawn by InkHUD::Events::onShutdown, with a blocking FULL update, after InkHUD's flash write is complete } diff --git a/src/graphics/niche/InkHUD/Applets/System/Menu/MenuAction.h b/src/graphics/niche/InkHUD/Applets/System/Menu/MenuAction.h index f42b9dc2c..c84ee09e0 100644 --- a/src/graphics/niche/InkHUD/Applets/System/Menu/MenuAction.h +++ b/src/graphics/niche/InkHUD/Applets/System/Menu/MenuAction.h @@ -33,6 +33,7 @@ enum MenuAction { LAYOUT, TOGGLE_BATTERY_ICON, TOGGLE_NOTIFICATIONS, + TOGGLE_INVERT_COLOR, TOGGLE_12H_CLOCK, }; diff --git a/src/graphics/niche/InkHUD/Applets/System/Menu/MenuApplet.cpp b/src/graphics/niche/InkHUD/Applets/System/Menu/MenuApplet.cpp index 69965972f..a1f79a28f 100644 --- a/src/graphics/niche/InkHUD/Applets/System/Menu/MenuApplet.cpp +++ b/src/graphics/niche/InkHUD/Applets/System/Menu/MenuApplet.cpp @@ -205,6 +205,15 @@ void InkHUD::MenuApplet::execute(MenuItem item) settings->optionalFeatures.notifications = !settings->optionalFeatures.notifications; break; + case TOGGLE_INVERT_COLOR: + if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_INVERTED) + config.display.displaymode = meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT; + else + config.display.displaymode = meshtastic_Config_DisplayConfig_DisplayMode_INVERTED; + + nodeDB->saveToDisk(SEGMENT_CONFIG); + break; + case SET_RECENTS: // Set value of settings.recentlyActiveSeconds // Uses menu cursor to read RECENTS_OPTIONS_MINUTES array (defined at top of this file) @@ -316,6 +325,10 @@ void InkHUD::MenuApplet::showPage(MenuPage page) &settings->optionalFeatures.notifications)); items.push_back(MenuItem("Battery Icon", MenuAction::TOGGLE_BATTERY_ICON, MenuPage::OPTIONS, &settings->optionalFeatures.batteryIcon)); + + invertedColors = (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_INVERTED); + items.push_back(MenuItem("Invert Color", MenuAction::TOGGLE_INVERT_COLOR, MenuPage::OPTIONS, &invertedColors)); + items.push_back( MenuItem("12-Hour Clock", MenuAction::TOGGLE_12H_CLOCK, MenuPage::OPTIONS, &config.display.use_12h_clock)); items.push_back(MenuItem("Exit", MenuPage::EXIT)); @@ -654,11 +667,11 @@ void InkHUD::MenuApplet::drawSystemInfoPanel(int16_t left, int16_t top, uint16_t // ==================== std::string clockString = getTimeString(); if (clockString.length() > 0) { - setFont(fontLarge); + setFont(fontMedium); printAt(width / 2, top, clockString, CENTER, TOP); - height += fontLarge.lineHeight(); - height += fontLarge.lineHeight() * 0.1; // Padding below clock + height += fontMedium.lineHeight(); + height += fontMedium.lineHeight() * 0.1; // Padding below clock } // Stats diff --git a/src/graphics/niche/InkHUD/Applets/System/Menu/MenuApplet.h b/src/graphics/niche/InkHUD/Applets/System/Menu/MenuApplet.h index 4c974672a..8f9280e6f 100644 --- a/src/graphics/niche/InkHUD/Applets/System/Menu/MenuApplet.h +++ b/src/graphics/niche/InkHUD/Applets/System/Menu/MenuApplet.h @@ -91,6 +91,8 @@ class MenuApplet : public SystemApplet, public concurrency::OSThread } cm; Applet *borrowedTileOwner = nullptr; // Which applet we have temporarily replaced while displaying menu + + bool invertedColors = false; // Helper to display current state of config.display.displaymode in InkHUD options }; } // namespace NicheGraphics::InkHUD diff --git a/src/graphics/niche/InkHUD/Applets/System/Pairing/PairingApplet.cpp b/src/graphics/niche/InkHUD/Applets/System/Pairing/PairingApplet.cpp index 3f51c7f88..09931f109 100644 --- a/src/graphics/niche/InkHUD/Applets/System/Pairing/PairingApplet.cpp +++ b/src/graphics/niche/InkHUD/Applets/System/Pairing/PairingApplet.cpp @@ -12,13 +12,13 @@ InkHUD::PairingApplet::PairingApplet() void InkHUD::PairingApplet::onRender() { // Header - setFont(fontLarge); + setFont(fontMedium); printAt(X(0.5), Y(0.25), "Bluetooth", CENTER, BOTTOM); setFont(fontSmall); printAt(X(0.5), Y(0.25), "Enter this code", CENTER, TOP); // Passkey - setFont(fontLarge); + setFont(fontMedium); printThick(X(0.5), Y(0.5), passkey.substr(0, 3) + " " + passkey.substr(3), 3, 2); // Device's bluetooth name, if it will fit diff --git a/src/graphics/niche/InkHUD/Applets/System/Tips/TipsApplet.cpp b/src/graphics/niche/InkHUD/Applets/System/Tips/TipsApplet.cpp index 82a196cb1..ade44ab65 100644 --- a/src/graphics/niche/InkHUD/Applets/System/Tips/TipsApplet.cpp +++ b/src/graphics/niche/InkHUD/Applets/System/Tips/TipsApplet.cpp @@ -50,11 +50,11 @@ void InkHUD::TipsApplet::onRender() break; case Tip::FINISH_SETUP: { - setFont(fontLarge); + setFont(fontMedium); printAt(0, 0, "Tip: Finish Setup"); setFont(fontSmall); - int16_t cursorY = fontLarge.lineHeight() * 1.5; + int16_t cursorY = fontMedium.lineHeight() * 1.5; printAt(0, cursorY, "- connect antenna"); cursorY += fontSmall.lineHeight() * 1.2; @@ -80,7 +80,7 @@ void InkHUD::TipsApplet::onRender() } break; case Tip::SAFE_SHUTDOWN: { - setFont(fontLarge); + setFont(fontMedium); printAt(0, 0, "Tip: Shutdown"); setFont(fontSmall); @@ -88,29 +88,29 @@ void InkHUD::TipsApplet::onRender() shutdown += "Before removing power, please shut down from InkHUD menu, or a client app. \n"; shutdown += "\n"; shutdown += "This ensures data is saved."; - printWrapped(0, fontLarge.lineHeight() * 1.5, width(), shutdown); + printWrapped(0, fontMedium.lineHeight() * 1.5, width(), shutdown); printAt(0, Y(1.0), "Press button to continue", LEFT, BOTTOM); } break; case Tip::CUSTOMIZATION: { - setFont(fontLarge); + setFont(fontMedium); printAt(0, 0, "Tip: Customization"); setFont(fontSmall); - printWrapped(0, fontLarge.lineHeight() * 1.5, width(), + printWrapped(0, fontMedium.lineHeight() * 1.5, width(), "Configure & control display with the InkHUD menu. Optional features, layout, rotation, and more."); printAt(0, Y(1.0), "Press button to continue", LEFT, BOTTOM); } break; case Tip::BUTTONS: { - setFont(fontLarge); + setFont(fontMedium); printAt(0, 0, "Tip: Buttons"); setFont(fontSmall); - int16_t cursorY = fontLarge.lineHeight() * 1.5; + int16_t cursorY = fontMedium.lineHeight() * 1.5; printAt(0, cursorY, "User Button"); cursorY += fontSmall.lineHeight() * 1.2; @@ -123,11 +123,11 @@ void InkHUD::TipsApplet::onRender() } break; case Tip::ROTATION: { - setFont(fontLarge); + setFont(fontMedium); printAt(0, 0, "Tip: Rotation"); setFont(fontSmall); - printWrapped(0, fontLarge.lineHeight() * 1.5, width(), + printWrapped(0, fontMedium.lineHeight() * 1.5, width(), "To rotate the display, use the InkHUD menu. Long-press the user button > Options > Rotate."); printAt(0, Y(1.0), "Press button to continue", LEFT, BOTTOM); @@ -155,7 +155,7 @@ void InkHUD::TipsApplet::renderWelcome() uint16_t logoH = getLogoHeight(logoWLimit, logoHLimit); // Title size - setFont(fontLarge); + setFont(fontMedium); std::string title; if (width() >= 200) // Future proofing: hide if *tiny* display title = "meshtastic.org"; diff --git a/src/graphics/niche/InkHUD/Applets/User/AllMessage/AllMessageApplet.cpp b/src/graphics/niche/InkHUD/Applets/User/AllMessage/AllMessageApplet.cpp index 17d724aee..7c6232f3b 100644 --- a/src/graphics/niche/InkHUD/Applets/User/AllMessage/AllMessageApplet.cpp +++ b/src/graphics/niche/InkHUD/Applets/User/AllMessage/AllMessageApplet.cpp @@ -101,15 +101,25 @@ void InkHUD::AllMessageApplet::onRender() // Extra gap below the header int16_t textTop = headerDivY + padDivH; - // Determine size if printed large + // Attempt to print with fontLarge + uint32_t textHeight; setFont(fontLarge); - uint32_t textHeight = getWrappedTextHeight(0, width(), text); + textHeight = getWrappedTextHeight(0, width(), text); + if (textHeight <= (uint32_t)height()) { + printWrapped(0, textTop, width(), text); + return; + } - // If too large, swap to small font - if (textHeight + textTop > (uint32_t)height()) // (compare signed and unsigned) - setFont(fontSmall); + // Fallback (too large): attempt to print with fontMedium + setFont(fontMedium); + textHeight = getWrappedTextHeight(0, width(), text); + if (textHeight <= (uint32_t)height()) { + printWrapped(0, textTop, width(), text); + return; + } - // Print text + // Fallback (too large): print with fontSmall + setFont(fontSmall); printWrapped(0, textTop, width(), text); } diff --git a/src/graphics/niche/InkHUD/Applets/User/DM/DMApplet.cpp b/src/graphics/niche/InkHUD/Applets/User/DM/DMApplet.cpp index dbf5c08fb..a3b9615a5 100644 --- a/src/graphics/niche/InkHUD/Applets/User/DM/DMApplet.cpp +++ b/src/graphics/niche/InkHUD/Applets/User/DM/DMApplet.cpp @@ -97,15 +97,25 @@ void InkHUD::DMApplet::onRender() // Extra gap below the header int16_t textTop = headerDivY + padDivH; - // Determine size if printed large + // Attempt to print with fontLarge + uint32_t textHeight; setFont(fontLarge); - uint32_t textHeight = getWrappedTextHeight(0, width(), text); + textHeight = getWrappedTextHeight(0, width(), text); + if (textHeight <= (uint32_t)height()) { + printWrapped(0, textTop, width(), text); + return; + } - // If too large, swap to small font - if (textHeight + textTop > (uint32_t)height()) // (compare signed and unsigned) - setFont(fontSmall); + // Fallback (too large): attempt to print with fontMedium + setFont(fontMedium); + textHeight = getWrappedTextHeight(0, width(), text); + if (textHeight <= (uint32_t)height()) { + printWrapped(0, textTop, width(), text); + return; + } - // Print text + // Fallback (too large): print with fontSmall + setFont(fontSmall); printWrapped(0, textTop, width(), text); } diff --git a/src/graphics/niche/InkHUD/DisplayHealth.cpp b/src/graphics/niche/InkHUD/DisplayHealth.cpp index e8849b72e..7e1accafd 100644 --- a/src/graphics/niche/InkHUD/DisplayHealth.cpp +++ b/src/graphics/niche/InkHUD/DisplayHealth.cpp @@ -7,7 +7,12 @@ using namespace NicheGraphics; // Timing for "maintenance" // Paying off full-refresh debt with unprovoked updates, if the display is not very active + +#ifdef SEEED_WIO_TRACKER_L1 +static constexpr uint32_t MAINTENANCE_MS_INITIAL = 5 * 1000UL; +#else static constexpr uint32_t MAINTENANCE_MS_INITIAL = 60 * 1000UL; +#endif static constexpr uint32_t MAINTENANCE_MS = 60 * 60 * 1000UL; InkHUD::DisplayHealth::DisplayHealth() : concurrency::OSThread("Mediator") diff --git a/src/graphics/niche/InkHUD/Events.cpp b/src/graphics/niche/InkHUD/Events.cpp index 2abe30793..cdda1638d 100644 --- a/src/graphics/niche/InkHUD/Events.cpp +++ b/src/graphics/niche/InkHUD/Events.cpp @@ -39,8 +39,8 @@ void InkHUD::Events::begin() void InkHUD::Events::onButtonShort() { // Audio feedback (via buzzer) - // Short low tone - playBoop(); + // Short tone + playChirp(); // Cancel any beeping, buzzing, blinking // Some button handling suppressed if we are dismissing an external notification (see below) bool dismissedExt = dismissExternalNotification(); @@ -64,8 +64,8 @@ void InkHUD::Events::onButtonShort() void InkHUD::Events::onButtonLong() { // Audio feedback (via buzzer) - // Low tone, longer than playBoop - playBeep(); + // Slightly longer than playChirp + playBoop(); // Check which system applet wants to handle the button press (if any) SystemApplet *consumer = nullptr; diff --git a/src/graphics/niche/InkHUD/Renderer.cpp b/src/graphics/niche/InkHUD/Renderer.cpp index c058c4126..072e9dbd6 100644 --- a/src/graphics/niche/InkHUD/Renderer.cpp +++ b/src/graphics/niche/InkHUD/Renderer.cpp @@ -224,6 +224,13 @@ void InkHUD::Renderer::render(bool async) renderPlaceholders(); renderSystemApplets(); + // Invert Buffer if set by user + if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_INVERTED) { + for (size_t i = 0; i < imageBufferWidth * imageBufferHeight; ++i) { + imageBuffer[i] = ~imageBuffer[i]; + } + } + // Tell display to begin process of drawing new image LOG_INFO("Updating display"); driver->update(imageBuffer, updateType); diff --git a/src/graphics/niche/InkHUD/docs/README.md b/src/graphics/niche/InkHUD/docs/README.md index b504d46c1..e7821299e 100644 --- a/src/graphics/niche/InkHUD/docs/README.md +++ b/src/graphics/niche/InkHUD/docs/README.md @@ -1,6 +1,6 @@ # InkHUD -This document is intended as a reference for maintainers. A haphazard collection of notes which _might_ be helpful. +A haphazard collection of notes which _might_ be helpful for developers. self deprecating meme @@ -109,7 +109,7 @@ The display image does not update "automatically". Individual applets are respon (animated diagram) -animated process diagram of InkHUD rendering +animated process diagram of InkHUD rendering An overview: @@ -312,18 +312,19 @@ As a general overview: ## Fonts -InkHUD uses AdafruitGFX fonts. The large and small font which are shared by all applets are set in nicheGraphics.h. +InkHUD uses AdafruitGFX fonts. Three shared fonts (small, medium, large) are available for use by all applets. These are set per-variant in nicheGraphics.h. ```cpp // Prepare fonts -InkHUD::Applet::fontLarge = FREESANS_9PT_WIN1252; +InkHUD::Applet::fontLarge = FREESANS_12PT_WIN1252; +InkHUD::Applet::fontMedium = FREESANS_9PT_WIN1252; InkHUD::Applet::fontSmall = FREESANS_6PT_WIN1252; // Using a generic AdafruitGFX font instead: -// InkHUD::Applet::fontLarge = FreeSerif9pt7b; +// InkHUD::Applet::fontLarge = FreeSerif18pt7b; ``` -Any generic AdafruitGFX font may be used, but the fonts which are bundled with InkHUD have been customized with extended-ASCII character sets. +Any generic AdafruitGFX font may be used, but the fonts which are bundled with InkHUD have been customized with extended-ASCII character sets and emoji. ### Parsing Unicode Text @@ -338,6 +339,8 @@ std::string parsed = parse(greeting); This will re-encode the characters to match whichever extended-ASCII font InkHUD has been built with. +A limited set of emoji have been [wedged into unused code points within the font](#emoji). + ### Localization InkHUD is bundled with extended-ASCII fonts for: @@ -349,10 +352,12 @@ InkHUD is bundled with extended-ASCII fonts for: The default builds use Windows-1252 encoding. This can be changed in nicheGraphics.h. ```cpp -InkHUD::Applet::fontLarge = FREESANS_9PT_WIN1250; +InkHUD::Applet::fontLarge = FREESANS_12PT_WIN1250; +InkHUD::Applet::fontMedium = FREESANS_9PT_WIN1250; InkHUD::Applet::fontSmall = FREESANS_6PT_WIN1250; -InkHUD::Applet::fontLarge = FREESANS_9PT_WIN1251; +InkHUD::Applet::fontLarge = FREESANS_12PT_WIN1251; +InkHUD::Applet::fontMedium = FREESANS_9PT_WIN1251; InkHUD::Applet::fontSmall = FREESANS_6PT_WIN1251; ``` @@ -734,3 +739,36 @@ Some fonts may have a handful of especially tall characters, especially extended // -2 px of padding above, +1 px of padding below InkHUD::AppletFont(FreeSans9pt7b, ASCII, -2, 1); ``` + +#### Emoji + +AdafruitGFX fonts are limited to 255 characters. InkHUD supports a restricted set of emoji, which are stored in the unused code points of the ASCII control characters (`'\x01'`, `'\x02'`, etc). + +Standard AdafruitGFX fonts contain no glyphs below `'\x20'`, so will ignore these attempts to parse emoji. + +This mapping of emoji to control characters is fairly arbitrary. Selection was influenced by [PR #3940 Oled screen emojis](https://github.com/meshtastic/firmware/pull/3940) and [Emoji Frequency Spreadsheet](https://docs.google.com/spreadsheets/d/1Zs13WJYdZL1pNZP0dCIXkWau_tZOjK3mmJz0KNq4I30/). + +| Code Point | Emoji | +| ---------- | ---------------------------------------------- | +| ~~`0x00`~~ | (null term, unused) | +| `0x01` | 👍 | +| `0x02` | 👎 | +| `0x03` | 🙂 | +| `0x04` | 😆 | +| `0x05` | 👋 | +| `0x06` | ☀ | +| ~~`0x07`~~ | (bell char, unused) | +| `0x08` | 🌧 | +| `0x09` | ☁ | +| ~~`0x0A`~~ | (line feed, unused) | +| `0x0B` | ♥ | +| `0x0C` | 💩 | +| ~~`0x0D`~~ | (carriage return, unused) | +| `0x0E` | 🔔 | +| `0x0F` | 😭 | +| `0x1A` | (substitution "⍰", used for unprintable chars) | +| `0x1B` | 🤗 | +| `0x1C` | 😉 | +| `0x1D` | 😏 | +| `0x1E` | 🫡 (saluting face) | +| `0x1F` | 👌 | diff --git a/src/input/ButtonThread.cpp b/src/input/ButtonThread.cpp index bc75e0a54..ad667f003 100644 --- a/src/input/ButtonThread.cpp +++ b/src/input/ButtonThread.cpp @@ -27,28 +27,25 @@ ButtonThread::ButtonThread(const char *name) : OSThread(name) _originName = name; } -bool ButtonThread::initButton(uint8_t pinNumber, bool activeLow, bool activePullup, uint32_t pullupSense, voidFuncPtr intRoutine, - input_broker_event singlePress, input_broker_event longPress, uint16_t longPressTime, - input_broker_event doublePress, input_broker_event longLongPress, uint16_t longLongPressTime, - input_broker_event triplePress, input_broker_event shortLong, bool touchQuirk) +bool ButtonThread::initButton(const ButtonConfig &config) { if (inputBroker) inputBroker->registerSource(this); - _longPressTime = longPressTime; - _longLongPressTime = longLongPressTime; - _pinNum = pinNumber; - _activeLow = activeLow; - _touchQuirk = touchQuirk; - _intRoutine = intRoutine; - _longLongPress = longLongPress; + _longPressTime = config.longPressTime; + _longLongPressTime = config.longLongPressTime; + _pinNum = config.pinNumber; + _activeLow = config.activeLow; + _touchQuirk = config.touchQuirk; + _intRoutine = config.intRoutine; + _longLongPress = config.longLongPress; - userButton = OneButton(pinNumber, activeLow, activePullup); + userButton = OneButton(config.pinNumber, config.activeLow, config.activePullup); - if (pullupSense != 0) { - pinMode(pinNumber, pullupSense); + if (config.pullupSense != 0) { + pinMode(config.pinNumber, config.pullupSense); } - _singlePress = singlePress; + _singlePress = config.singlePress; userButton.attachClick( [](void *callerThread) -> void { ButtonThread *thread = (ButtonThread *)callerThread; @@ -56,26 +53,26 @@ bool ButtonThread::initButton(uint8_t pinNumber, bool activeLow, bool activePull }, this); - if (longPress != INPUT_BROKER_NONE) { - _longPress = longPress; + if (config.longPress != INPUT_BROKER_NONE) { + _longPress = config.longPress; userButton.attachLongPressStart( [](void *callerThread) -> void { ButtonThread *thread = (ButtonThread *)callerThread; - if (millis() > 30000) // hold off 30s after boot - thread->btnEvent = BUTTON_EVENT_LONG_PRESSED; + // if (millis() > 30000) // hold off 30s after boot + thread->btnEvent = BUTTON_EVENT_LONG_PRESSED; }, this); userButton.attachLongPressStop( [](void *callerThread) -> void { ButtonThread *thread = (ButtonThread *)callerThread; - if (millis() > 30000) // hold off 30s after boot - thread->btnEvent = BUTTON_EVENT_LONG_RELEASED; + // if (millis() > 30000) // hold off 30s after boot + thread->btnEvent = BUTTON_EVENT_LONG_RELEASED; }, this); } - if (doublePress != INPUT_BROKER_NONE) { - _doublePress = doublePress; + if (config.doublePress != INPUT_BROKER_NONE) { + _doublePress = config.doublePress; userButton.attachDoubleClick( [](void *callerThread) -> void { ButtonThread *thread = (ButtonThread *)callerThread; @@ -84,8 +81,8 @@ bool ButtonThread::initButton(uint8_t pinNumber, bool activeLow, bool activePull this); } - if (triplePress != INPUT_BROKER_NONE) { - _triplePress = triplePress; + if (config.triplePress != INPUT_BROKER_NONE) { + _triplePress = config.triplePress; userButton.attachMultiClick( [](void *callerThread) -> void { ButtonThread *thread = (ButtonThread *)callerThread; @@ -94,8 +91,8 @@ bool ButtonThread::initButton(uint8_t pinNumber, bool activeLow, bool activePull }, this); } - if (shortLong != INPUT_BROKER_NONE) { - _shortLong = shortLong; + if (config.shortLong != INPUT_BROKER_NONE) { + _shortLong = config.shortLong; } userButton.setDebounceMs(1); @@ -257,7 +254,8 @@ int32_t ButtonThread::runOnce() case BUTTON_EVENT_LONG_RELEASED: { LOG_INFO("LONG PRESS RELEASE"); - if (_longLongPress != INPUT_BROKER_NONE && (millis() - buttonPressStartTime) >= _longLongPressTime) { + if (millis() > 30000 && _longLongPress != INPUT_BROKER_NONE && + (millis() - buttonPressStartTime) >= _longLongPressTime) { evt.inputEvent = _longLongPress; this->notifyObservers(&evt); } @@ -266,6 +264,11 @@ int32_t ButtonThread::runOnce() break; } + + // doesn't handle BUTTON_EVENT_PRESSED_SCREEN BUTTON_EVENT_TOUCH_LONG_PRESSED BUTTON_EVENT_COMBO_SHORT_LONG + default: { + break; + } } } btnEvent = BUTTON_EVENT_NONE; diff --git a/src/input/ButtonThread.h b/src/input/ButtonThread.h index 033f92b8b..949048de1 100644 --- a/src/input/ButtonThread.h +++ b/src/input/ButtonThread.h @@ -7,6 +7,26 @@ typedef void (*voidFuncPtr)(void); +struct ButtonConfig { + uint8_t pinNumber; + bool activeLow = true; + bool activePullup = true; + uint32_t pullupSense = 0; + voidFuncPtr intRoutine = nullptr; + input_broker_event singlePress = INPUT_BROKER_NONE; + input_broker_event longPress = INPUT_BROKER_NONE; + uint16_t longPressTime = 500; + input_broker_event doublePress = INPUT_BROKER_NONE; + input_broker_event longLongPress = INPUT_BROKER_NONE; + uint16_t longLongPressTime = 5000; + input_broker_event triplePress = INPUT_BROKER_NONE; + input_broker_event shortLong = INPUT_BROKER_NONE; + bool touchQuirk = false; + + // Constructor to set required parameter + ButtonConfig(uint8_t pin = 0) : pinNumber(pin) {} +}; + #ifndef BUTTON_CLICK_MS #define BUTTON_CLICK_MS 250 #endif @@ -28,12 +48,7 @@ class ButtonThread : public Observable, public concurrency:: public: const char *_originName; static const uint32_t c_holdOffTime = 30000; // hold off 30s after boot - bool initButton(uint8_t pinNumber, bool activeLow, bool activePullup, uint32_t pullupSense, voidFuncPtr intRoutine, - input_broker_event singlePress, input_broker_event longPress = INPUT_BROKER_NONE, - uint16_t longPressTime = 500, input_broker_event doublePress = INPUT_BROKER_NONE, - input_broker_event longLongPress = INPUT_BROKER_NONE, uint16_t longLongPressTime = 5000, - input_broker_event triplePress = INPUT_BROKER_NONE, input_broker_event shortLong = INPUT_BROKER_NONE, - bool touchQuirk = false); + bool initButton(const ButtonConfig &config); enum ButtonEventType { BUTTON_EVENT_NONE, diff --git a/src/input/ExpressLRSFiveWay.cpp b/src/input/ExpressLRSFiveWay.cpp index 1981a45d4..53bcedc63 100644 --- a/src/input/ExpressLRSFiveWay.cpp +++ b/src/input/ExpressLRSFiveWay.cpp @@ -235,7 +235,7 @@ void ExpressLRSFiveWay::shutdown() { LOG_INFO("Shutdown from long press"); powerFSM.trigger(EVENT_PRESS); - screen->startAlert("Shutting down..."); + screen->startAlert("Shutting Down..."); // Don't set alerting = true. We don't want to auto-dismiss this alert. playShutdownMelody(); // In case user adds a buzzer @@ -250,4 +250,4 @@ void ExpressLRSFiveWay::click() ExpressLRSFiveWay *expressLRSFiveWayInput = nullptr; -#endif \ No newline at end of file +#endif diff --git a/src/input/SeesawRotary.cpp b/src/input/SeesawRotary.cpp new file mode 100644 index 000000000..c212773c4 --- /dev/null +++ b/src/input/SeesawRotary.cpp @@ -0,0 +1,83 @@ +#ifdef ARCH_PORTDUINO +#include "SeesawRotary.h" +#include "input/InputBroker.h" + +using namespace concurrency; + +SeesawRotary *seesawRotary; + +SeesawRotary::SeesawRotary(const char *name) : OSThread(name) +{ + _originName = name; +} + +bool SeesawRotary::init() +{ + if (inputBroker) + inputBroker->registerSource(this); + + if (!ss.begin(SEESAW_ADDR)) { + return false; + } + // attachButtonInterrupts(); + + uint32_t version = ((ss.getVersion() >> 16) & 0xFFFF); + if (version != 4991) { + LOG_WARN("Wrong firmware loaded? %u", version); + } else { + LOG_INFO("Found Product 4991"); + } + /* + #ifdef ARCH_ESP32 + // Register callbacks for before and after lightsleep + // Used to detach and reattach interrupts + lsObserver.observe(¬ifyLightSleep); + lsEndObserver.observe(¬ifyLightSleepEnd); + #endif + */ + ss.pinMode(SS_SWITCH, INPUT_PULLUP); + + // get starting position + encoder_position = ss.getEncoderPosition(); + + ss.setGPIOInterrupts((uint32_t)1 << SS_SWITCH, 1); + ss.enableEncoderInterrupt(); + canSleep = true; // Assume we should not keep the board awake + + return true; +} + +int32_t SeesawRotary::runOnce() +{ + InputEvent e; + e.inputEvent = INPUT_BROKER_NONE; + bool currentlyPressed = !ss.digitalRead(SS_SWITCH); + + if (currentlyPressed && !wasPressed) { + e.inputEvent = INPUT_BROKER_SELECT; + } + wasPressed = currentlyPressed; + + int32_t new_position = ss.getEncoderPosition(); + // did we move arounde? + if (encoder_position != new_position) { + if (encoder_position == 0 && new_position != 1) { + e.inputEvent = INPUT_BROKER_ALT_PRESS; + } else if (new_position == 0 && encoder_position != 1) { + e.inputEvent = INPUT_BROKER_USER_PRESS; + } else if (new_position > encoder_position) { + e.inputEvent = INPUT_BROKER_USER_PRESS; + } else { + e.inputEvent = INPUT_BROKER_ALT_PRESS; + } + encoder_position = new_position; + } + if (e.inputEvent != INPUT_BROKER_NONE) { + e.source = this->_originName; + e.kbchar = 0x00; + this->notifyObservers(&e); + } + + return 50; +} +#endif \ No newline at end of file diff --git a/src/input/SeesawRotary.h b/src/input/SeesawRotary.h new file mode 100644 index 000000000..3812b130a --- /dev/null +++ b/src/input/SeesawRotary.h @@ -0,0 +1,29 @@ +#pragma once +#ifdef ARCH_PORTDUINO + +#include "Adafruit_seesaw.h" +#include "InputBroker.h" +#include "concurrency/OSThread.h" +#include "configuration.h" + +#define SS_SWITCH 24 +#define SS_NEOPIX 6 + +#define SEESAW_ADDR 0x36 + +class SeesawRotary : public Observable, public concurrency::OSThread +{ + public: + const char *_originName; + bool init(); + SeesawRotary(const char *name); + int32_t runOnce() override; + + private: + Adafruit_seesaw ss; + int32_t encoder_position; + bool wasPressed = false; +}; + +extern SeesawRotary *seesawRotary; +#endif \ No newline at end of file diff --git a/src/input/TrackballInterruptBase.h b/src/input/TrackballInterruptBase.h index 2397839b9..92db8720e 100644 --- a/src/input/TrackballInterruptBase.h +++ b/src/input/TrackballInterruptBase.h @@ -4,8 +4,13 @@ #include "mesh/NodeDB.h" #ifndef TB_DIRECTION +#if ARCH_PORTDUINO +#include "PortduinoGlue.h" +#define TB_DIRECTION (PinStatus) settingsMap[tbDirection] +#else #define TB_DIRECTION RISING #endif +#endif class TrackballInterruptBase : public Observable, public concurrency::OSThread { diff --git a/src/main.cpp b/src/main.cpp index cf3200a23..91e957255 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -195,6 +195,8 @@ ScanI2C::DeviceAddress rtc_found = ScanI2C::ADDRESS_NONE; 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); +/// The I2C address of our Air Quality Indicator (if found) +ScanI2C::DeviceAddress aqi_found = ScanI2C::ADDRESS_NONE; #ifdef T_WATCH_S3 Adafruit_DRV2605 drv; @@ -624,6 +626,9 @@ void setup() pmu_found = i2cScanner->exists(ScanI2C::DeviceType::PMU_AXP192_AXP2101); + auto aqiInfo = i2cScanner->firstAQI(); + aqi_found = aqiInfo.type != ScanI2C::DeviceType::NONE ? aqiInfo.address : ScanI2C::ADDRESS_NONE; + /* * There are a bunch of sensors that have no further logic than to be found and stuffed into the * nodeTelemetrySensorsMap singleton. This wraps that logic in a temporary scope to declare the temporary field @@ -692,6 +697,7 @@ void setup() scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::DPS310, meshtastic_TelemetrySensorType_DPS310); scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::RAK12035, meshtastic_TelemetrySensorType_RAK12035); scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::PCT2075, meshtastic_TelemetrySensorType_PCT2075); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::SCD4X, meshtastic_TelemetrySensorType_SCD4X); i2cScanner.reset(); #endif @@ -929,58 +935,81 @@ void setup() LOG_DEBUG("Use GPIO%02d for button", settingsMap[userButtonPin]); UserButtonThread = new ButtonThread("UserButton"); - if (screen) - UserButtonThread->initButton( - settingsMap[userButtonPin], true, true, INPUT_PULLUP, // pull up bias - []() { - UserButtonThread->userButton.tick(); - runASAP = true; - BaseType_t higherWake = 0; - mainDelay.interruptFromISR(&higherWake); - }, - INPUT_BROKER_USER_PRESS, INPUT_BROKER_SELECT); + if (screen) { + ButtonConfig config; + config.pinNumber = (uint8_t)settingsMap[userButtonPin]; + config.activeLow = true; + config.activePullup = true; + config.pullupSense = INPUT_PULLUP; + config.intRoutine = []() { + UserButtonThread->userButton.tick(); + runASAP = true; + BaseType_t higherWake = 0; + mainDelay.interruptFromISR(&higherWake); + }; + config.singlePress = INPUT_BROKER_USER_PRESS; + config.longPress = INPUT_BROKER_SELECT; + UserButtonThread->initButton(config); + } } #endif #ifdef BUTTON_PIN_TOUCH TouchButtonThread = new ButtonThread("BackButton"); - TouchButtonThread->initButton( - BUTTON_PIN_TOUCH, true, true, pullup_sense, - []() { - TouchButtonThread->userButton.tick(); - runASAP = true; - BaseType_t higherWake = 0; - mainDelay.interruptFromISR(&higherWake); - }, - INPUT_BROKER_NONE, INPUT_BROKER_BACK); + ButtonConfig touchConfig; + touchConfig.pinNumber = BUTTON_PIN_TOUCH; + touchConfig.activeLow = true; + touchConfig.activePullup = true; + touchConfig.pullupSense = pullup_sense; + touchConfig.intRoutine = []() { + TouchButtonThread->userButton.tick(); + runASAP = true; + BaseType_t higherWake = 0; + mainDelay.interruptFromISR(&higherWake); + }; + touchConfig.singlePress = INPUT_BROKER_NONE; + touchConfig.longPress = INPUT_BROKER_BACK; + TouchButtonThread->initButton(touchConfig); #endif #if defined(CANCEL_BUTTON_PIN) // Buttons. Moved here cause we need NodeDB to be initialized CancelButtonThread = new ButtonThread("CancelButton"); - CancelButtonThread->initButton( - CANCEL_BUTTON_PIN, CANCEL_BUTTON_ACTIVE_LOW, CANCEL_BUTTON_ACTIVE_PULLUP, pullup_sense, - []() { - CancelButtonThread->userButton.tick(); - runASAP = true; - BaseType_t higherWake = 0; - mainDelay.interruptFromISR(&higherWake); - }, - INPUT_BROKER_CANCEL, INPUT_BROKER_SHUTDOWN, 4000); + ButtonConfig cancelConfig; + cancelConfig.pinNumber = CANCEL_BUTTON_PIN; + cancelConfig.activeLow = CANCEL_BUTTON_ACTIVE_LOW; + cancelConfig.activePullup = CANCEL_BUTTON_ACTIVE_PULLUP; + cancelConfig.pullupSense = pullup_sense; + cancelConfig.intRoutine = []() { + CancelButtonThread->userButton.tick(); + runASAP = true; + BaseType_t higherWake = 0; + mainDelay.interruptFromISR(&higherWake); + }; + cancelConfig.singlePress = INPUT_BROKER_CANCEL; + cancelConfig.longPress = INPUT_BROKER_SHUTDOWN; + cancelConfig.longPressTime = 4000; + CancelButtonThread->initButton(cancelConfig); #endif #if defined(ALT_BUTTON_PIN) // Buttons. Moved here cause we need NodeDB to be initialized BackButtonThread = new ButtonThread("BackButton"); - BackButtonThread->initButton( - ALT_BUTTON_PIN, ALT_BUTTON_ACTIVE_LOW, ALT_BUTTON_ACTIVE_PULLUP, pullup_sense, - []() { - BackButtonThread->userButton.tick(); - runASAP = true; - BaseType_t higherWake = 0; - mainDelay.interruptFromISR(&higherWake); - }, - INPUT_BROKER_ALT_PRESS, INPUT_BROKER_ALT_LONG, 500); + ButtonConfig backConfig; + backConfig.pinNumber = ALT_BUTTON_PIN; + backConfig.activeLow = ALT_BUTTON_ACTIVE_LOW; + backConfig.activePullup = ALT_BUTTON_ACTIVE_PULLUP; + backConfig.pullupSense = pullup_sense; + backConfig.intRoutine = []() { + BackButtonThread->userButton.tick(); + runASAP = true; + BaseType_t higherWake = 0; + mainDelay.interruptFromISR(&higherWake); + }; + backConfig.singlePress = INPUT_BROKER_ALT_PRESS; + backConfig.longPress = INPUT_BROKER_ALT_LONG; + backConfig.longPressTime = 500; + BackButtonThread->initButton(backConfig); #endif #if defined(BUTTON_PIN) @@ -999,26 +1028,42 @@ void setup() // Buttons. Moved here cause we need NodeDB to be initialized // If your variant.h has a BUTTON_PIN defined, go ahead and define BUTTON_ACTIVE_LOW and BUTTON_ACTIVE_PULLUP UserButtonThread = new ButtonThread("UserButton"); - if (screen) - UserButtonThread->initButton( - _pinNum, BUTTON_ACTIVE_LOW, BUTTON_ACTIVE_PULLUP, pullup_sense, - []() { - UserButtonThread->userButton.tick(); - runASAP = true; - BaseType_t higherWake = 0; - mainDelay.interruptFromISR(&higherWake); - }, - INPUT_BROKER_USER_PRESS, INPUT_BROKER_SELECT, 500, INPUT_BROKER_NONE, INPUT_BROKER_SHUTDOWN); - else - UserButtonThread->initButton( - _pinNum, BUTTON_ACTIVE_LOW, BUTTON_ACTIVE_PULLUP, pullup_sense, - []() { - UserButtonThread->userButton.tick(); - runASAP = true; - BaseType_t higherWake = 0; - mainDelay.interruptFromISR(&higherWake); - }, - INPUT_BROKER_USER_PRESS, INPUT_BROKER_SHUTDOWN, 5000, INPUT_BROKER_SEND_PING, INPUT_BROKER_GPS_TOGGLE); + if (screen) { + ButtonConfig userConfig; + userConfig.pinNumber = (uint8_t)_pinNum; + userConfig.activeLow = BUTTON_ACTIVE_LOW; + userConfig.activePullup = BUTTON_ACTIVE_PULLUP; + userConfig.pullupSense = pullup_sense; + userConfig.intRoutine = []() { + UserButtonThread->userButton.tick(); + runASAP = true; + BaseType_t higherWake = 0; + mainDelay.interruptFromISR(&higherWake); + }; + userConfig.singlePress = INPUT_BROKER_USER_PRESS; + userConfig.longPress = INPUT_BROKER_SELECT; + userConfig.longPressTime = 500; + userConfig.longLongPress = INPUT_BROKER_SHUTDOWN; + UserButtonThread->initButton(userConfig); + } else { + ButtonConfig userConfigNoScreen; + userConfigNoScreen.pinNumber = (uint8_t)_pinNum; + userConfigNoScreen.activeLow = BUTTON_ACTIVE_LOW; + userConfigNoScreen.activePullup = BUTTON_ACTIVE_PULLUP; + userConfigNoScreen.pullupSense = pullup_sense; + userConfigNoScreen.intRoutine = []() { + UserButtonThread->userButton.tick(); + runASAP = true; + BaseType_t higherWake = 0; + mainDelay.interruptFromISR(&higherWake); + }; + userConfigNoScreen.singlePress = INPUT_BROKER_USER_PRESS; + userConfigNoScreen.longPress = INPUT_BROKER_SHUTDOWN; + userConfigNoScreen.longPressTime = 5000; + userConfigNoScreen.doublePress = INPUT_BROKER_SEND_PING; + userConfigNoScreen.triplePress = INPUT_BROKER_GPS_TOGGLE; + UserButtonThread->initButton(userConfigNoScreen); + } #endif #endif @@ -1320,7 +1365,7 @@ void setup() if (!rIf->reconfigure()) { LOG_WARN("Reconfigure failed, rebooting"); if (screen) { - screen->showOverlayBanner("Rebooting..."); + screen->showSimpleBanner("Rebooting..."); } rebootAtMsec = millis() + 5000; } @@ -1413,6 +1458,9 @@ void setup() LOG_DEBUG("Free heap : %7d bytes", ESP.getFreeHeap()); LOG_DEBUG("Free PSRAM : %7d bytes", ESP.getFreePsram()); #endif + + // We manually run this to update the NodeStatus + nodeDB->notifyObservers(true); } #endif diff --git a/src/main.h b/src/main.h index da44ae6ce..25943c8b7 100644 --- a/src/main.h +++ b/src/main.h @@ -35,6 +35,7 @@ extern bool kb_found; extern ScanI2C::DeviceAddress rtc_found; extern ScanI2C::DeviceAddress accelerometer_found; extern ScanI2C::FoundDevice rgb_found; +extern ScanI2C::DeviceAddress aqi_found; extern bool eink_found; extern bool pmu_found; @@ -94,4 +95,4 @@ void scannerToSensorsMap(const std::unique_ptr &i2cScanner, Scan #endif // We default to 4MHz SPI, SPI mode 0 -extern SPISettings spiSettings; \ No newline at end of file +extern SPISettings spiSettings; diff --git a/src/mesh/Default.h b/src/mesh/Default.h index fd3f10668..2f05da98d 100644 --- a/src/mesh/Default.h +++ b/src/mesh/Default.h @@ -5,8 +5,10 @@ #define ONE_DAY 24 * 60 * 60 #define ONE_MINUTE_MS 60 * 1000 #define THIRTY_SECONDS_MS 30 * 1000 +#define TWO_SECONDS_MS 2 * 1000 #define FIVE_SECONDS_MS 5 * 1000 #define TEN_SECONDS_MS 10 * 1000 +#define MAX_INTERVAL INT32_MAX // FIXME: INT32_MAX to avoid overflow issues with Apple clients but should be UINT32_MAX #define min_default_telemetry_interval_secs 30 * 60 #define default_gps_update_interval IF_ROUTER(ONE_DAY, 2 * 60) @@ -22,6 +24,11 @@ #define min_node_info_broadcast_secs 60 * 60 // No regular broadcasts of more than once an hour #define min_neighbor_info_broadcast_secs 4 * 60 * 60 #define default_map_publish_interval_secs 60 * 60 +#ifdef USERPREFS_RINGTONE_NAG_SECS +#define default_ringtone_nag_secs USERPREFS_RINGTONE_NAG_SECS +#else +#define default_ringtone_nag_secs 60 +#endif #define default_mqtt_address "mqtt.meshtastic.org" #define default_mqtt_username "meshdev" diff --git a/src/mesh/LR11x0Interface.cpp b/src/mesh/LR11x0Interface.cpp index 91ca38d03..8cc6cbc0f 100644 --- a/src/mesh/LR11x0Interface.cpp +++ b/src/mesh/LR11x0Interface.cpp @@ -74,10 +74,7 @@ template bool LR11x0Interface::init() RadioLibInterface::init(); - limitPower(); - - if (power > LR1110_MAX_POWER) // Clamp power to maximum defined level - power = LR1110_MAX_POWER; + limitPower(LR1110_MAX_POWER); if ((power > LR1120_MAX_POWER) && (config.lora.region == meshtastic_Config_LoRaConfig_RegionCode_LORA_24)) { // clamp again if wide freq range diff --git a/src/mesh/MeshModule.cpp b/src/mesh/MeshModule.cpp index 62d3c82bc..c5748a560 100644 --- a/src/mesh/MeshModule.cpp +++ b/src/mesh/MeshModule.cpp @@ -244,10 +244,13 @@ void setReplyTo(meshtastic_MeshPacket *p, const meshtastic_MeshPacket &to) p->decoded.request_id = to.id; } -std::vector MeshModule::GetMeshModulesWithUIFrames() +std::vector MeshModule::GetMeshModulesWithUIFrames(int startIndex) { - std::vector modulesWithUIFrames; + + // Fill with nullptr up to startIndex + modulesWithUIFrames.resize(startIndex, nullptr); + if (modules) { for (auto i = modules->begin(); i != modules->end(); ++i) { auto &pi = **i; diff --git a/src/mesh/MeshModule.h b/src/mesh/MeshModule.h index f08b8f49c..eda3f8881 100644 --- a/src/mesh/MeshModule.h +++ b/src/mesh/MeshModule.h @@ -75,7 +75,7 @@ class MeshModule */ static void callModules(meshtastic_MeshPacket &mp, RxSource src = RX_SRC_RADIO); - static std::vector GetMeshModulesWithUIFrames(); + static std::vector GetMeshModulesWithUIFrames(int startIndex); static void observeUIEvents(Observer *observer); static AdminMessageHandleResult handleAdminMessageForAllModules(const meshtastic_MeshPacket &mp, meshtastic_AdminMessage *request, diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index d13864bd9..185ea0744 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -339,6 +339,38 @@ NodeDB::NodeDB() moduleConfig.telemetry.health_update_interval = Default::getConfiguredOrMinimumValue( moduleConfig.telemetry.health_update_interval, min_default_telemetry_interval_secs); } + // FIXME: UINT32_MAX intervals overflows Apple clients until they are fully patched + if (config.device.node_info_broadcast_secs > MAX_INTERVAL) + config.device.node_info_broadcast_secs = MAX_INTERVAL; + if (config.position.position_broadcast_secs > MAX_INTERVAL) + config.position.position_broadcast_secs = MAX_INTERVAL; + if (config.position.gps_update_interval > MAX_INTERVAL) + config.position.gps_update_interval = MAX_INTERVAL; + if (config.position.gps_attempt_time > MAX_INTERVAL) + config.position.gps_attempt_time = MAX_INTERVAL; + if (config.position.position_flags > MAX_INTERVAL) + config.position.position_flags = MAX_INTERVAL; + if (config.position.rx_gpio > MAX_INTERVAL) + config.position.rx_gpio = MAX_INTERVAL; + if (config.position.tx_gpio > MAX_INTERVAL) + config.position.tx_gpio = MAX_INTERVAL; + if (config.position.broadcast_smart_minimum_distance > MAX_INTERVAL) + config.position.broadcast_smart_minimum_distance = MAX_INTERVAL; + if (config.position.broadcast_smart_minimum_interval_secs > MAX_INTERVAL) + config.position.broadcast_smart_minimum_interval_secs = MAX_INTERVAL; + if (config.position.gps_en_gpio > MAX_INTERVAL) + config.position.gps_en_gpio = MAX_INTERVAL; + if (moduleConfig.neighbor_info.update_interval > MAX_INTERVAL) + moduleConfig.neighbor_info.update_interval = MAX_INTERVAL; + if (moduleConfig.telemetry.device_update_interval > MAX_INTERVAL) + moduleConfig.telemetry.device_update_interval = MAX_INTERVAL; + if (moduleConfig.telemetry.environment_update_interval > MAX_INTERVAL) + moduleConfig.telemetry.environment_update_interval = MAX_INTERVAL; + if (moduleConfig.telemetry.air_quality_interval > MAX_INTERVAL) + moduleConfig.telemetry.air_quality_interval = MAX_INTERVAL; + if (moduleConfig.telemetry.health_update_interval > MAX_INTERVAL) + moduleConfig.telemetry.health_update_interval = MAX_INTERVAL; + if (moduleConfig.mqtt.has_map_report_settings && moduleConfig.mqtt.map_report_settings.publish_interval_secs < default_map_publish_interval_secs) { moduleConfig.mqtt.map_report_settings.publish_interval_secs = default_map_publish_interval_secs; @@ -353,6 +385,14 @@ NodeDB::NodeDB() config.device.rebroadcast_mode = meshtastic_Config_DeviceConfig_RebroadcastMode_LOCAL_ONLY; } +#if !HAS_TFT + if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_COLOR) { + // On a device without MUI, this display mode makes no sense, and will break logic. + config.display.displaymode = meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT; + config.bluetooth.enabled = true; + } +#endif + if (devicestateCRC != crc32Buffer(&devicestate, sizeof(devicestate))) saveWhat |= SEGMENT_DEVICESTATE; if (nodeDatabaseCRC != crc32Buffer(&nodeDatabase, sizeof(nodeDatabase))) @@ -391,6 +431,7 @@ NodeDB::NodeDB() #endif } #endif + sortMeshDB(); saveToDisk(saveWhat); } @@ -753,16 +794,16 @@ void NodeDB::installDefaultModuleConfig() moduleConfig.external_notification.output_buzzer = PIN_BUZZER; moduleConfig.external_notification.use_pwm = true; moduleConfig.external_notification.alert_message_buzzer = true; - moduleConfig.external_notification.nag_timeout = 60; + moduleConfig.external_notification.nag_timeout = default_ringtone_nag_secs; #endif -#if defined(RAK4630) || defined(RAK11310) +#if defined(RAK4630) || defined(RAK11310) || defined(RAK3312) // Default to RAK led pin 2 (blue) moduleConfig.external_notification.enabled = true; moduleConfig.external_notification.output = PIN_LED2; moduleConfig.external_notification.active = true; moduleConfig.external_notification.alert_message = true; moduleConfig.external_notification.output_ms = 1000; - moduleConfig.external_notification.nag_timeout = 60; + moduleConfig.external_notification.nag_timeout = default_ringtone_nag_secs; #endif #ifdef HAS_I2S @@ -771,10 +812,10 @@ void NodeDB::installDefaultModuleConfig() moduleConfig.external_notification.use_i2s_as_buzzer = true; moduleConfig.external_notification.alert_message_buzzer = true; #if HAS_TFT - if (moduleConfig.external_notification.nag_timeout == 60) + if (moduleConfig.external_notification.nag_timeout == default_ringtone_nag_secs) moduleConfig.external_notification.nag_timeout = 0; #else - moduleConfig.external_notification.nag_timeout = 60; + moduleConfig.external_notification.nag_timeout = default_ringtone_nag_secs; #endif #endif #ifdef NANO_G2_ULTRA @@ -850,10 +891,12 @@ void NodeDB::installRoleDefaults(meshtastic_Config_DeviceConfig_Role role) if (role == meshtastic_Config_DeviceConfig_Role_ROUTER) { initConfigIntervals(); initModuleConfigIntervals(); + moduleConfig.telemetry.device_update_interval = default_telemetry_broadcast_interval_secs; config.device.rebroadcast_mode = meshtastic_Config_DeviceConfig_RebroadcastMode_CORE_PORTNUMS_ONLY; owner.has_is_unmessagable = true; owner.is_unmessagable = true; } else if (role == meshtastic_Config_DeviceConfig_Role_ROUTER_LATE) { + moduleConfig.telemetry.device_update_interval = ONE_DAY; owner.has_is_unmessagable = true; owner.is_unmessagable = true; } else if (role == meshtastic_Config_DeviceConfig_Role_REPEATER) { @@ -864,6 +907,7 @@ void NodeDB::installRoleDefaults(meshtastic_Config_DeviceConfig_Role role) } else if (role == meshtastic_Config_DeviceConfig_Role_SENSOR) { owner.has_is_unmessagable = true; owner.is_unmessagable = true; + moduleConfig.telemetry.device_update_interval = default_telemetry_broadcast_interval_secs; moduleConfig.telemetry.environment_measurement_enabled = true; moduleConfig.telemetry.environment_update_interval = 300; } else if (role == meshtastic_Config_DeviceConfig_Role_LOST_AND_FOUND) { @@ -881,6 +925,7 @@ void NodeDB::installRoleDefaults(meshtastic_Config_DeviceConfig_Role role) } else if (role == meshtastic_Config_DeviceConfig_Role_TRACKER) { owner.has_is_unmessagable = true; owner.is_unmessagable = true; + moduleConfig.telemetry.device_update_interval = default_telemetry_broadcast_interval_secs; } else if (role == meshtastic_Config_DeviceConfig_Role_TAK_TRACKER) { owner.has_is_unmessagable = true; owner.is_unmessagable = true; @@ -896,21 +941,25 @@ void NodeDB::installRoleDefaults(meshtastic_Config_DeviceConfig_Role role) moduleConfig.telemetry.device_update_interval = ONE_DAY; } else if (role == meshtastic_Config_DeviceConfig_Role_CLIENT_HIDDEN) { config.device.rebroadcast_mode = meshtastic_Config_DeviceConfig_RebroadcastMode_LOCAL_ONLY; - config.device.node_info_broadcast_secs = UINT32_MAX; + config.device.node_info_broadcast_secs = MAX_INTERVAL; config.position.position_broadcast_smart_enabled = false; - config.position.position_broadcast_secs = UINT32_MAX; - moduleConfig.neighbor_info.update_interval = UINT32_MAX; - moduleConfig.telemetry.device_update_interval = UINT32_MAX; - moduleConfig.telemetry.environment_update_interval = UINT32_MAX; - moduleConfig.telemetry.air_quality_interval = UINT32_MAX; - moduleConfig.telemetry.health_update_interval = UINT32_MAX; + config.position.position_broadcast_secs = MAX_INTERVAL; + moduleConfig.neighbor_info.update_interval = MAX_INTERVAL; + moduleConfig.telemetry.device_update_interval = MAX_INTERVAL; + moduleConfig.telemetry.environment_update_interval = MAX_INTERVAL; + moduleConfig.telemetry.air_quality_interval = MAX_INTERVAL; + moduleConfig.telemetry.health_update_interval = MAX_INTERVAL; } } void NodeDB::initModuleConfigIntervals() { // Zero out telemetry intervals so that they coalesce to defaults in Default.h - moduleConfig.telemetry.device_update_interval = 0; +#ifdef USERPREFS_CONFIG_DEVICE_TELEM_UPDATE_INTERVAL + moduleConfig.telemetry.device_update_interval = USERPREFS_CONFIG_DEVICE_TELEM_UPDATE_INTERVAL; +#else + moduleConfig.telemetry.device_update_interval = MAX_INTERVAL; +#endif moduleConfig.telemetry.environment_update_interval = 0; moduleConfig.telemetry.air_quality_interval = 0; moduleConfig.telemetry.power_update_interval = 0; @@ -976,7 +1025,10 @@ void NodeDB::cleanupMeshDB() meshNodes->at(i).user.public_key.size = 0; } } - meshNodes->at(newPos++) = meshNodes->at(i); + if (newPos != i) + meshNodes->at(newPos++) = meshNodes->at(i); + else + newPos++; } else { removed++; } @@ -1063,8 +1115,8 @@ LoadFileResult NodeDB::loadProto(const char *filename, size_t protoSize, size_t if (f) { LOG_INFO("Load %s", filename); pb_istream_t stream = {&readcb, &f, protoSize}; - - memset(dest_struct, 0, objSize); + if (fields != &meshtastic_NodeDatabase_msg) // contains a vector object + memset(dest_struct, 0, objSize); if (!pb_decode(&stream, fields, dest_struct)) { LOG_ERROR("Error: can't decode protobuf %s", PB_GET_ERROR(&stream)); state = LoadFileResult::DECODE_FAILED; @@ -1273,6 +1325,13 @@ void NodeDB::loadFromDisk() saveToDisk(SEGMENT_MODULECONFIG); } +#if ARCH_PORTDUINO + // set any config overrides + if (settingsMap[has_configDisplayMode]) { + config.display.displaymode = (_meshtastic_Config_DisplayConfig_DisplayMode)settingsMap[configDisplayMode]; + } + +#endif } /** Save a protobuf from a file, return true for success */ @@ -1558,6 +1617,7 @@ void NodeDB::addFromContact(meshtastic_SharedContact contact) // Mark the node's key as manually verified to indicate trustworthiness. updateGUIforNode = info; // powerFSM.trigger(EVENT_NODEDB_UPDATED); This event has been retired + sortMeshDB(); notifyObservers(true); // Force an update whether or not our node counts have changed } saveNodeDatabaseToDisk(); @@ -1661,6 +1721,52 @@ void NodeDB::updateFrom(const meshtastic_MeshPacket &mp) info->has_hops_away = true; info->hops_away = mp.hop_start - mp.hop_limit; } + sortMeshDB(); + } +} + +void NodeDB::set_favorite(bool is_favorite, uint32_t nodeId) +{ + meshtastic_NodeInfoLite *lite = getMeshNode(nodeId); + if (lite && lite->is_favorite != is_favorite) { + lite->is_favorite = is_favorite; + sortMeshDB(); + saveNodeDatabaseToDisk(); + } +} + +void NodeDB::pause_sort(bool paused) +{ + sortingIsPaused = paused; +} + +void NodeDB::sortMeshDB() +{ + if (!sortingIsPaused && (lastSort == 0 || !Throttle::isWithinTimespanMs(lastSort, 1000 * 5))) { + lastSort = millis(); + bool changed = true; + while (changed) { // dumb reverse bubble sort, but probably not bad for what we're doing + changed = false; + for (int i = numMeshNodes - 1; i > 0; i--) { // lowest case this should examine is i == 1 + if (meshNodes->at(i - 1).num == getNodeNum()) { + // noop + } else if (meshNodes->at(i).num == + getNodeNum()) { // in the oddball case our own node num is not at location 0, put it there + // TODO: Look for at(i-1) also matching own node num, and throw the DB in the trash + std::swap(meshNodes->at(i), meshNodes->at(i - 1)); + changed = true; + } else if (meshNodes->at(i).is_favorite && !meshNodes->at(i - 1).is_favorite) { + std::swap(meshNodes->at(i), meshNodes->at(i - 1)); + changed = true; + } else if (!meshNodes->at(i).is_favorite && meshNodes->at(i - 1).is_favorite) { + // noop + } else if (meshNodes->at(i).last_heard > meshNodes->at(i - 1).last_heard) { + std::swap(meshNodes->at(i), meshNodes->at(i - 1)); + changed = true; + } + } + } + LOG_INFO("Sort took %u milliseconds", millis() - lastSort); } } diff --git a/src/mesh/NodeDB.h b/src/mesh/NodeDB.h index 90ca5aefd..845f42c76 100644 --- a/src/mesh/NodeDB.h +++ b/src/mesh/NodeDB.h @@ -191,6 +191,16 @@ class NodeDB */ bool updateUser(uint32_t nodeId, meshtastic_User &p, uint8_t channelIndex = 0); + /* + * Sets a node either favorite or unfavorite + */ + void set_favorite(bool is_favorite, uint32_t nodeId); + + /** + * Other functions like the node picker can request a pause in the node sorting + */ + void pause_sort(bool paused); + /// @return our node number NodeNum getNodeNum() { return myNodeInfo.my_node_num; } @@ -208,9 +218,6 @@ class NodeDB their denial?) */ - /// pick a provisional nodenum we hope no one is using - void pickNewNodeNum(); - // get channel channel index we heard a nodeNum on, defaults to 0 if not found uint8_t getMeshNodeChannel(NodeNum n); @@ -278,13 +285,6 @@ class NodeDB bool restorePreferences(meshtastic_AdminMessage_BackupLocation location, int restoreWhat = SEGMENT_CONFIG | SEGMENT_MODULECONFIG | SEGMENT_DEVICESTATE | SEGMENT_CHANNELS); - private: - bool duplicateWarned = false; - uint32_t lastNodeDbSave = 0; // when we last saved our db to flash - uint32_t lastBackupAttempt = 0; // when we last tried a backup automatically or manually - /// Find a node in our DB, create an empty NodeInfoLite if missing - meshtastic_NodeInfoLite *getOrCreateMeshNode(NodeNum n); - /// Notify observers of changes to the DB void notifyObservers(bool forceUpdate = false) { @@ -293,6 +293,22 @@ class NodeDB newStatus.notifyObservers(&status); } + private: + bool duplicateWarned = false; + uint32_t lastNodeDbSave = 0; // when we last saved our db to flash + uint32_t lastBackupAttempt = 0; // when we last tried a backup automatically or manually + uint32_t lastSort = 0; // When last sorted the nodeDB + /// Find a node in our DB, create an empty NodeInfoLite if missing + meshtastic_NodeInfoLite *getOrCreateMeshNode(NodeNum n); + + /* + * Internal boolean to track sorting paused + */ + bool sortingIsPaused = false; + + /// pick a provisional nodenum we hope no one is using + void pickNewNodeNum(); + /// read our db from flash void loadFromDisk(); @@ -310,6 +326,7 @@ class NodeDB bool saveChannelsToDisk(); bool saveDeviceStateToDisk(); bool saveNodeDatabaseToDisk(); + void sortMeshDB(); }; extern NodeDB *nodeDB; diff --git a/src/mesh/PacketHistory.cpp b/src/mesh/PacketHistory.cpp index f42b151c8..8cac31a3e 100644 --- a/src/mesh/PacketHistory.cpp +++ b/src/mesh/PacketHistory.cpp @@ -246,8 +246,10 @@ void PacketHistory::insert(PacketRecord &r) #if RECENT_WARN_AGE > 0 if (tu->rxTimeMsec && (OldtrxTimeMsec < RECENT_WARN_AGE)) { if (!(tu->id == r.id && tu->sender == r.sender)) { +#if VERBOSE_PACKET_HISTORY LOG_WARN("Packet History - insert: Reusing slot aged %ds < %ds RECENT_WARN_AGE", OldtrxTimeMsec / 1000, RECENT_WARN_AGE / 1000); +#endif } else { // debug only #if VERBOSE_PACKET_HISTORY @@ -275,7 +277,9 @@ void PacketHistory::insert(PacketRecord &r) #endif if (r.rxTimeMsec == 0) { +#if VERBOSE_PACKET_HISTORY LOG_WARN("Packet History - insert: I will not store packet with rxTimeMsec = 0."); +#endif return; // Return early if we can't update the history } diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp index e2acd8463..287de38fa 100644 --- a/src/mesh/PhoneAPI.cpp +++ b/src/mesh/PhoneAPI.cpp @@ -670,7 +670,8 @@ bool PhoneAPI::handleToRadioPacket(meshtastic_MeshPacket &p) meshtastic_QueueStatus qs = router->getQueueStatus(); service->sendQueueStatusToPhone(qs, 0, p.id); return false; - } else if (IS_ONE_OF(meshtastic_PortNum_POSITION_APP, meshtastic_PortNum_WAYPOINT_APP, meshtastic_PortNum_ALERT_APP) && + } else if (IS_ONE_OF(p.decoded.portnum, meshtastic_PortNum_POSITION_APP, meshtastic_PortNum_WAYPOINT_APP, + meshtastic_PortNum_ALERT_APP, meshtastic_PortNum_TELEMETRY_APP) && lastPortNumToRadio[p.decoded.portnum] && Throttle::isWithinTimespanMs(lastPortNumToRadio[p.decoded.portnum], TEN_SECONDS_MS)) { // TODO: [Issue #6700] Make this rate limit throttling scale up / down with the preset @@ -680,6 +681,13 @@ bool PhoneAPI::handleToRadioPacket(meshtastic_MeshPacket &p) // FIXME: Figure out why this continues to happen // sendNotification(meshtastic_LogRecord_Level_WARNING, p.id, "Position can only be sent once every 5 seconds"); return false; + } else if (p.decoded.portnum == meshtastic_PortNum_TEXT_MESSAGE_APP && lastPortNumToRadio[p.decoded.portnum] && + Throttle::isWithinTimespanMs(lastPortNumToRadio[p.decoded.portnum], TWO_SECONDS_MS)) { + LOG_WARN("Rate limit portnum %d", p.decoded.portnum); + meshtastic_QueueStatus qs = router->getQueueStatus(); + service->sendQueueStatusToPhone(qs, 0, p.id); + sendNotification(meshtastic_LogRecord_Level_WARNING, p.id, "Text messages can only be sent once every 2 seconds"); + return false; } lastPortNumToRadio[p.decoded.portnum] = millis(); service->handleToRadio(p); diff --git a/src/mesh/RF95Interface.cpp b/src/mesh/RF95Interface.cpp index 578cdbdbc..9ed33db41 100644 --- a/src/mesh/RF95Interface.cpp +++ b/src/mesh/RF95Interface.cpp @@ -122,10 +122,7 @@ bool RF95Interface::init() power = dacDbValues.db; #endif - limitPower(); - - if (power > RF95_MAX_POWER) // This chip has lower power limits than some - power = RF95_MAX_POWER; + limitPower(RF95_MAX_POWER); iface = lora = new RadioLibRF95(&module); diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp index f7cd6f4c1..faa67a1c2 100644 --- a/src/mesh/RadioInterface.cpp +++ b/src/mesh/RadioInterface.cpp @@ -12,6 +12,12 @@ #include #include +// Calculate 2^n without calling pow() +uint32_t pow_of_2(uint32_t n) +{ + return 1 << n; +} + #define RDEF(name, freq_start, freq_end, duty_cycle, spacing, power_limit, audio_permitted, frequency_switching, wide_lora) \ { \ meshtastic_Config_LoRaConfig_RegionCode_##name, freq_start, freq_end, duty_cycle, spacing, power_limit, audio_permitted, \ @@ -155,6 +161,14 @@ const RegionInfo regions[] = { RDEF(PH_433, 433.0f, 434.7f, 100, 0, 10, true, false, false), RDEF(PH_868, 868.0f, 869.4f, 100, 0, 14, true, false, false), RDEF(PH_915, 915.0f, 918.0f, 100, 0, 24, true, false, false), + /* + Kazakhstan + 433.075 - 434.775 MHz <10 mW EIRP, Low Powered Devices (LPD) + 863 - 868 MHz <25 mW EIRP, 500kHz channels allowed, must not be used at airfields + https://github.com/meshtastic/firmware/issues/7204 + */ + RDEF(KZ_433, 433.075f, 434.775f, 100, 0, 10, true, false, false), RDEF(KZ_863, 863.0f, 868.0f, 100, 0, 30, true, false, true), + /* 2.4 GHZ WLAN Band equivalent. Only for SX128x chips. */ @@ -246,7 +260,7 @@ uint32_t RadioInterface::getRetransmissionMsec(const meshtastic_MeshPacket *p) float channelUtil = airTime->channelUtilizationPercent(); uint8_t CWsize = map(channelUtil, 0, 100, CWmin, CWmax); // Assuming we pick max. of CWsize and there will be a client with SNR at half the range - return 2 * packetAirtime + (pow(2, CWsize) + 2 * CWmax + pow(2, int((CWmax + CWmin) / 2))) * slotTimeMsec + + return 2 * packetAirtime + (pow_of_2(CWsize) + 2 * CWmax + pow_of_2(int((CWmax + CWmin) / 2))) * slotTimeMsec + PROCESSING_TIME_MSEC; } @@ -259,7 +273,7 @@ uint32_t RadioInterface::getTxDelayMsec() float channelUtil = airTime->channelUtilizationPercent(); uint8_t CWsize = map(channelUtil, 0, 100, CWmin, CWmax); // LOG_DEBUG("Current channel utilization is %f so setting CWsize to %d", channelUtil, CWsize); - return random(0, pow(2, CWsize)) * slotTimeMsec; + return random(0, pow_of_2(CWsize)) * slotTimeMsec; } /** The CW size to use when calculating SNR_based delays */ @@ -279,7 +293,7 @@ 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; + return (2 * CWmax * slotTimeMsec) + pow_of_2(CWsize) * slotTimeMsec; } /** The delay to use when we want to flood a message */ @@ -296,7 +310,7 @@ uint32_t RadioInterface::getTxDelayMsecWeighted(float snr) LOG_DEBUG("rx_snr found in packet. Router: setting tx delay:%d", delay); } else { // offset the maximum delay for routers: (2 * CWmax * slotTimeMsec) - delay = (2 * CWmax * slotTimeMsec) + random(0, pow(2, CWsize)) * slotTimeMsec; + delay = (2 * CWmax * slotTimeMsec) + random(0, pow_of_2(CWsize)) * slotTimeMsec; LOG_DEBUG("rx_snr found in packet. Setting tx delay:%d", delay); } @@ -596,7 +610,7 @@ void RadioInterface::applyModemConfig() uint32_t RadioInterface::computeSlotTimeMsec() { float sumPropagationTurnaroundMACTime = 0.2 + 0.4 + 7; // in milliseconds - float symbolTime = pow(2, sf) / bw; // in milliseconds + float symbolTime = pow_of_2(sf) / bw; // in milliseconds if (myRegion->wideLora) { // CAD duration derived from AN1200.22 of SX1280 @@ -611,7 +625,7 @@ uint32_t RadioInterface::computeSlotTimeMsec() * Some regulatory regions limit xmit power. * This function should be called by subclasses after setting their desired power. It might lower it */ -void RadioInterface::limitPower() +void RadioInterface::limitPower(int8_t loraMaxPower) { uint8_t maxPower = 255; // No limit @@ -628,6 +642,9 @@ void RadioInterface::limitPower() power -= TX_GAIN_LORA; } + if (power > loraMaxPower) // Clamp power to maximum defined level + power = loraMaxPower; + LOG_INFO("Final Tx power: %d dBm", power); } @@ -668,4 +685,4 @@ size_t RadioInterface::beginSending(meshtastic_MeshPacket *p) sendingPacket = p; return p->encrypted.size + sizeof(PacketHeader); -} \ No newline at end of file +} diff --git a/src/mesh/RadioInterface.h b/src/mesh/RadioInterface.h index 68ae09635..c9e71cfa8 100644 --- a/src/mesh/RadioInterface.h +++ b/src/mesh/RadioInterface.h @@ -230,7 +230,7 @@ class RadioInterface * Some regulatory regions limit xmit power. * This function should be called by subclasses after setting their desired power. It might lower it */ - void limitPower(); + void limitPower(int8_t MAX_POWER); /** * Save the frequency we selected for later reuse. diff --git a/src/mesh/STM32WLE5JCInterface.cpp b/src/mesh/STM32WLE5JCInterface.cpp index 3c8bf89c3..d7bc37466 100644 --- a/src/mesh/STM32WLE5JCInterface.cpp +++ b/src/mesh/STM32WLE5JCInterface.cpp @@ -25,10 +25,7 @@ bool STM32WLE5JCInterface::init() lora.setRfSwitchTable(rfswitch_pins, rfswitch_table); - limitPower(); - - if (power > STM32WLx_MAX_POWER) // This chip has lower power limits than some - power = STM32WLx_MAX_POWER; + limitPower(STM32WLx_MAX_POWER); int res = lora.begin(getFreq(), bw, sf, cr, syncWord, power, preambleLength, tcxoVoltage); diff --git a/src/mesh/SX126xInterface.cpp b/src/mesh/SX126xInterface.cpp index ac86a61b0..dd6b4f9a4 100644 --- a/src/mesh/SX126xInterface.cpp +++ b/src/mesh/SX126xInterface.cpp @@ -71,10 +71,7 @@ template bool SX126xInterface::init() RadioLibInterface::init(); - limitPower(); - - if (power > SX126X_MAX_POWER) // Clamp power to maximum defined level - power = SX126X_MAX_POWER; + limitPower(SX126X_MAX_POWER); int res = lora.begin(getFreq(), bw, sf, cr, syncWord, power, preambleLength, tcxoVoltage, useRegulatorLDO); // \todo Display actual typename of the adapter, not just `SX126x` diff --git a/src/mesh/SX128xInterface.cpp b/src/mesh/SX128xInterface.cpp index d24163410..c956ee0b9 100644 --- a/src/mesh/SX128xInterface.cpp +++ b/src/mesh/SX128xInterface.cpp @@ -59,10 +59,7 @@ template bool SX128xInterface::init() RadioLibInterface::init(); - limitPower(); - - if (power > SX128X_MAX_POWER) // This chip has lower power limits than some - power = SX128X_MAX_POWER; + limitPower(SX128X_MAX_POWER); preambleLength = 12; // 12 is the default for this chip, 32 does not RX at all diff --git a/src/mesh/aes-ccm.cpp b/src/mesh/aes-ccm.cpp index a650ba2fc..420d80e9a 100644 --- a/src/mesh/aes-ccm.cpp +++ b/src/mesh/aes-ccm.cpp @@ -10,6 +10,32 @@ #include "aes-ccm.h" #if !MESHTASTIC_EXCLUDE_PKI +/** + * Constant-time comparison of two byte arrays + * + * @param a First byte array to compare + * @param b Second byte array to compare + * @param len Number of bytes to compare + * @return 0 if arrays are equal, -1 if different or if inputs are invalid + */ +static int constant_time_compare(const void *a_, const void *b_, size_t len) +{ + /* Cast to volatile to prevent the compiler from optimizing out their comparison. */ + const volatile uint8_t *volatile a = (const volatile uint8_t *volatile)a_; + const volatile uint8_t *volatile b = (const volatile uint8_t *volatile)b_; + if (len == 0) + return 0; + if (a == NULL || b == NULL) + return -1; + size_t i; + volatile uint8_t d = 0U; + for (i = 0U; i < len; i++) { + d |= (a[i] ^ b[i]); + } + /* Constant time bit arithmetic to convert d > 0 to -1 and d = 0 to 0. */ + return (1 & ((d - 1) >> 8)) - 1; +} + static void WPA_PUT_BE16(uint8_t *a, uint16_t val) { a[0] = val >> 8; @@ -146,7 +172,7 @@ bool aes_ccm_ad(const uint8_t *key, size_t key_len, const uint8_t *nonce, size_t aes_ccm_encr(L, crypt, crypt_len, plain, a); aes_ccm_auth_start(M, L, nonce, aad, aad_len, crypt_len, x); aes_ccm_auth(plain, crypt_len, x); - if (memcmp(x, t, M) != 0) { // FIXME make const comp + if (constant_time_compare(x, t, M) != 0) { return false; } return true; diff --git a/src/mesh/generated/meshtastic/config.pb.h b/src/mesh/generated/meshtastic/config.pb.h index ed1849be8..f28daadbd 100644 --- a/src/mesh/generated/meshtastic/config.pb.h +++ b/src/mesh/generated/meshtastic/config.pb.h @@ -285,7 +285,11 @@ typedef enum _meshtastic_Config_LoRaConfig_RegionCode { /* Philippines 915mhz */ meshtastic_Config_LoRaConfig_RegionCode_PH_915 = 21, /* Australia / New Zealand 433MHz */ - meshtastic_Config_LoRaConfig_RegionCode_ANZ_433 = 22 + meshtastic_Config_LoRaConfig_RegionCode_ANZ_433 = 22, + /* Kazakhstan 433MHz */ + meshtastic_Config_LoRaConfig_RegionCode_KZ_433 = 23, + /* Kazakhstan 863MHz */ + meshtastic_Config_LoRaConfig_RegionCode_KZ_863 = 24 } meshtastic_Config_LoRaConfig_RegionCode; /* Standard predefined channel settings @@ -681,8 +685,8 @@ extern "C" { #define _meshtastic_Config_DisplayConfig_CompassOrientation_ARRAYSIZE ((meshtastic_Config_DisplayConfig_CompassOrientation)(meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_270_INVERTED+1)) #define _meshtastic_Config_LoRaConfig_RegionCode_MIN meshtastic_Config_LoRaConfig_RegionCode_UNSET -#define _meshtastic_Config_LoRaConfig_RegionCode_MAX meshtastic_Config_LoRaConfig_RegionCode_ANZ_433 -#define _meshtastic_Config_LoRaConfig_RegionCode_ARRAYSIZE ((meshtastic_Config_LoRaConfig_RegionCode)(meshtastic_Config_LoRaConfig_RegionCode_ANZ_433+1)) +#define _meshtastic_Config_LoRaConfig_RegionCode_MAX meshtastic_Config_LoRaConfig_RegionCode_KZ_863 +#define _meshtastic_Config_LoRaConfig_RegionCode_ARRAYSIZE ((meshtastic_Config_LoRaConfig_RegionCode)(meshtastic_Config_LoRaConfig_RegionCode_KZ_863+1)) #define _meshtastic_Config_LoRaConfig_ModemPreset_MIN meshtastic_Config_LoRaConfig_ModemPreset_LONG_FAST #define _meshtastic_Config_LoRaConfig_ModemPreset_MAX meshtastic_Config_LoRaConfig_ModemPreset_SHORT_TURBO diff --git a/src/mesh/generated/meshtastic/device_ui.pb.cpp b/src/mesh/generated/meshtastic/device_ui.pb.cpp index 4bb3cc66c..2fc8d9461 100644 --- a/src/mesh/generated/meshtastic/device_ui.pb.cpp +++ b/src/mesh/generated/meshtastic/device_ui.pb.cpp @@ -26,3 +26,5 @@ PB_BIND(meshtastic_Map, meshtastic_Map, AUTO) + + diff --git a/src/mesh/generated/meshtastic/device_ui.pb.h b/src/mesh/generated/meshtastic/device_ui.pb.h index 3a8ddd3a4..8313438f8 100644 --- a/src/mesh/generated/meshtastic/device_ui.pb.h +++ b/src/mesh/generated/meshtastic/device_ui.pb.h @@ -10,6 +10,15 @@ #endif /* Enum definitions */ +typedef enum _meshtastic_CompassMode { + /* Compass with dynamic ring and heading */ + meshtastic_CompassMode_DYNAMIC = 0, + /* Compass with fixed ring and heading */ + meshtastic_CompassMode_FIXED_RING = 1, + /* Compass with heading and freeze option */ + meshtastic_CompassMode_FREEZE_HEADING = 2 +} meshtastic_CompassMode; + typedef enum _meshtastic_Theme { /* Dark */ meshtastic_Theme_DARK = 0, @@ -144,6 +153,14 @@ typedef struct _meshtastic_DeviceUIConfig { /* Map related data */ bool has_map_data; meshtastic_Map map_data; + /* Compass mode */ + meshtastic_CompassMode compass_mode; + /* RGB color for BaseUI + 0xRRGGBB format, e.g. 0xFF0000 for red */ + uint32_t screen_rgb_color; + /* Clockface analog style + true for analog clockface, false for digital clockface */ + bool is_clockface_analog; } meshtastic_DeviceUIConfig; @@ -152,6 +169,10 @@ extern "C" { #endif /* Helper constants for enums */ +#define _meshtastic_CompassMode_MIN meshtastic_CompassMode_DYNAMIC +#define _meshtastic_CompassMode_MAX meshtastic_CompassMode_FREEZE_HEADING +#define _meshtastic_CompassMode_ARRAYSIZE ((meshtastic_CompassMode)(meshtastic_CompassMode_FREEZE_HEADING+1)) + #define _meshtastic_Theme_MIN meshtastic_Theme_DARK #define _meshtastic_Theme_MAX meshtastic_Theme_RED #define _meshtastic_Theme_ARRAYSIZE ((meshtastic_Theme)(meshtastic_Theme_RED+1)) @@ -162,6 +183,7 @@ extern "C" { #define meshtastic_DeviceUIConfig_theme_ENUMTYPE meshtastic_Theme #define meshtastic_DeviceUIConfig_language_ENUMTYPE meshtastic_Language +#define meshtastic_DeviceUIConfig_compass_mode_ENUMTYPE meshtastic_CompassMode @@ -169,12 +191,12 @@ extern "C" { /* Initializer values for message structs */ -#define meshtastic_DeviceUIConfig_init_default {0, 0, 0, 0, 0, 0, _meshtastic_Theme_MIN, 0, 0, 0, _meshtastic_Language_MIN, false, meshtastic_NodeFilter_init_default, false, meshtastic_NodeHighlight_init_default, {0, {0}}, false, meshtastic_Map_init_default} +#define meshtastic_DeviceUIConfig_init_default {0, 0, 0, 0, 0, 0, _meshtastic_Theme_MIN, 0, 0, 0, _meshtastic_Language_MIN, false, meshtastic_NodeFilter_init_default, false, meshtastic_NodeHighlight_init_default, {0, {0}}, false, meshtastic_Map_init_default, _meshtastic_CompassMode_MIN, 0, 0} #define meshtastic_NodeFilter_init_default {0, 0, 0, 0, 0, "", 0} #define meshtastic_NodeHighlight_init_default {0, 0, 0, 0, ""} #define meshtastic_GeoPoint_init_default {0, 0, 0} #define meshtastic_Map_init_default {false, meshtastic_GeoPoint_init_default, "", 0} -#define meshtastic_DeviceUIConfig_init_zero {0, 0, 0, 0, 0, 0, _meshtastic_Theme_MIN, 0, 0, 0, _meshtastic_Language_MIN, false, meshtastic_NodeFilter_init_zero, false, meshtastic_NodeHighlight_init_zero, {0, {0}}, false, meshtastic_Map_init_zero} +#define meshtastic_DeviceUIConfig_init_zero {0, 0, 0, 0, 0, 0, _meshtastic_Theme_MIN, 0, 0, 0, _meshtastic_Language_MIN, false, meshtastic_NodeFilter_init_zero, false, meshtastic_NodeHighlight_init_zero, {0, {0}}, false, meshtastic_Map_init_zero, _meshtastic_CompassMode_MIN, 0, 0} #define meshtastic_NodeFilter_init_zero {0, 0, 0, 0, 0, "", 0} #define meshtastic_NodeHighlight_init_zero {0, 0, 0, 0, ""} #define meshtastic_GeoPoint_init_zero {0, 0, 0} @@ -214,6 +236,9 @@ extern "C" { #define meshtastic_DeviceUIConfig_node_highlight_tag 13 #define meshtastic_DeviceUIConfig_calibration_data_tag 14 #define meshtastic_DeviceUIConfig_map_data_tag 15 +#define meshtastic_DeviceUIConfig_compass_mode_tag 16 +#define meshtastic_DeviceUIConfig_screen_rgb_color_tag 17 +#define meshtastic_DeviceUIConfig_is_clockface_analog_tag 18 /* Struct field encoding specification for nanopb */ #define meshtastic_DeviceUIConfig_FIELDLIST(X, a) \ @@ -231,7 +256,10 @@ X(a, STATIC, SINGULAR, UENUM, language, 11) \ X(a, STATIC, OPTIONAL, MESSAGE, node_filter, 12) \ X(a, STATIC, OPTIONAL, MESSAGE, node_highlight, 13) \ X(a, STATIC, SINGULAR, BYTES, calibration_data, 14) \ -X(a, STATIC, OPTIONAL, MESSAGE, map_data, 15) +X(a, STATIC, OPTIONAL, MESSAGE, map_data, 15) \ +X(a, STATIC, SINGULAR, UENUM, compass_mode, 16) \ +X(a, STATIC, SINGULAR, UINT32, screen_rgb_color, 17) \ +X(a, STATIC, SINGULAR, BOOL, is_clockface_analog, 18) #define meshtastic_DeviceUIConfig_CALLBACK NULL #define meshtastic_DeviceUIConfig_DEFAULT NULL #define meshtastic_DeviceUIConfig_node_filter_MSGTYPE meshtastic_NodeFilter @@ -288,7 +316,7 @@ extern const pb_msgdesc_t meshtastic_Map_msg; /* Maximum encoded size of messages (where known) */ #define MESHTASTIC_MESHTASTIC_DEVICE_UI_PB_H_MAX_SIZE meshtastic_DeviceUIConfig_size -#define meshtastic_DeviceUIConfig_size 188 +#define meshtastic_DeviceUIConfig_size 201 #define meshtastic_GeoPoint_size 33 #define meshtastic_Map_size 58 #define meshtastic_NodeFilter_size 47 diff --git a/src/mesh/generated/meshtastic/mesh.pb.h b/src/mesh/generated/meshtastic/mesh.pb.h index b07c59625..9e0415198 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.h +++ b/src/mesh/generated/meshtastic/mesh.pb.h @@ -267,6 +267,12 @@ typedef enum _meshtastic_HardwareModel { /* * GAT562 Mesh Trial Tracker */ meshtastic_HardwareModel_GAT562_MESH_TRIAL_TRACKER = 104, + /* * + RAKwireless WisMesh Tag */ + meshtastic_HardwareModel_WISMESH_TAG = 105, + /* * + RAKwireless WisBlock Core RAK3312 https://docs.rakwireless.com/product-categories/wisduo/rak3112-module/overview/ */ + meshtastic_HardwareModel_RAK3312 = 106, /* ------------------------------------------------------------------------------------------------------------------------------------------ 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. ------------------------------------------------------------------------------------------------------------------------------------------ */ diff --git a/src/mesh/generated/meshtastic/portnums.pb.h b/src/mesh/generated/meshtastic/portnums.pb.h index 5bd27ef7d..67adc60cc 100644 --- a/src/mesh/generated/meshtastic/portnums.pb.h +++ b/src/mesh/generated/meshtastic/portnums.pb.h @@ -133,6 +133,10 @@ typedef enum _meshtastic_PortNum { /* Reticulum Network Stack Tunnel App ENCODING: Fragmented RNS Packet. Handled by Meshtastic RNS interface */ meshtastic_PortNum_RETICULUM_TUNNEL_APP = 76, + /* App for transporting Cayenne Low Power Payload, popular for LoRaWAN sensor nodes. Offers ability to send + arbitrary telemetry over meshtastic that is not covered by telemetry.proto + ENCODING: CayenneLLP */ + meshtastic_PortNum_CAYENNE_APP = 77, /* Private applications should use portnums >= 256. To simplify initial development and testing you can use "PRIVATE_APP" in your code without needing to rebuild protobuf files (via [regen-protos.sh](https://github.com/meshtastic/firmware/blob/master/bin/regen-protos.sh)) */ diff --git a/src/mesh/generated/meshtastic/telemetry.pb.h b/src/mesh/generated/meshtastic/telemetry.pb.h index 4fa673df8..072a99a24 100644 --- a/src/mesh/generated/meshtastic/telemetry.pb.h +++ b/src/mesh/generated/meshtastic/telemetry.pb.h @@ -91,7 +91,9 @@ typedef enum _meshtastic_TelemetrySensorType { /* MAX17261 lipo battery gauge */ meshtastic_TelemetrySensorType_MAX17261 = 38, /* PCT2075 Temperature Sensor */ - meshtastic_TelemetrySensorType_PCT2075 = 39 + meshtastic_TelemetrySensorType_PCT2075 = 39, + /* ADS1X15 ADC */ + meshtastic_TelemetrySensorType_ADS1X15 = 40 } meshtastic_TelemetrySensorType; /* Struct definitions */ @@ -206,6 +208,36 @@ typedef struct _meshtastic_PowerMetrics { /* Current (Ch3) */ bool has_ch3_current; float ch3_current; + /* Voltage (Ch4) */ + bool has_ch4_voltage; + float ch4_voltage; + /* Current (Ch4) */ + bool has_ch4_current; + float ch4_current; + /* Voltage (Ch5) */ + bool has_ch5_voltage; + float ch5_voltage; + /* Current (Ch5) */ + bool has_ch5_current; + float ch5_current; + /* Voltage (Ch6) */ + bool has_ch6_voltage; + float ch6_voltage; + /* Current (Ch6) */ + bool has_ch6_current; + float ch6_current; + /* Voltage (Ch7) */ + bool has_ch7_voltage; + float ch7_voltage; + /* Current (Ch7) */ + bool has_ch7_current; + float ch7_current; + /* Voltage (Ch8) */ + bool has_ch8_voltage; + float ch8_voltage; + /* Current (Ch8) */ + bool has_ch8_current; + float ch8_current; } meshtastic_PowerMetrics; /* Air quality metrics */ @@ -249,6 +281,12 @@ typedef struct _meshtastic_AirQualityMetrics { /* CO2 concentration in ppm */ bool has_co2; uint32_t co2; + /* CO2 sensor temperature in degC */ + bool has_co2_temperature; + float co2_temperature; + /* CO2 sensor relative humidity in % */ + bool has_co2_humidity; + float co2_humidity; } meshtastic_AirQualityMetrics; /* Local device mesh statistics */ @@ -360,8 +398,8 @@ extern "C" { /* Helper constants for enums */ #define _meshtastic_TelemetrySensorType_MIN meshtastic_TelemetrySensorType_SENSOR_UNSET -#define _meshtastic_TelemetrySensorType_MAX meshtastic_TelemetrySensorType_PCT2075 -#define _meshtastic_TelemetrySensorType_ARRAYSIZE ((meshtastic_TelemetrySensorType)(meshtastic_TelemetrySensorType_PCT2075+1)) +#define _meshtastic_TelemetrySensorType_MAX meshtastic_TelemetrySensorType_ADS1X15 +#define _meshtastic_TelemetrySensorType_ARRAYSIZE ((meshtastic_TelemetrySensorType)(meshtastic_TelemetrySensorType_ADS1X15+1)) @@ -376,8 +414,8 @@ extern "C" { /* Initializer values for message structs */ #define meshtastic_DeviceMetrics_init_default {false, 0, false, 0, false, 0, false, 0, false, 0} #define meshtastic_EnvironmentMetrics_init_default {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} -#define meshtastic_PowerMetrics_init_default {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} -#define meshtastic_AirQualityMetrics_init_default {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} +#define meshtastic_PowerMetrics_init_default {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} +#define meshtastic_AirQualityMetrics_init_default {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} #define meshtastic_LocalStats_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_HealthMetrics_init_default {false, 0, false, 0, false, 0} #define meshtastic_HostMetrics_init_default {0, 0, 0, false, 0, false, 0, 0, 0, 0, false, ""} @@ -385,8 +423,8 @@ extern "C" { #define meshtastic_Nau7802Config_init_default {0, 0} #define meshtastic_DeviceMetrics_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0} #define meshtastic_EnvironmentMetrics_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} -#define meshtastic_PowerMetrics_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} -#define meshtastic_AirQualityMetrics_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} +#define meshtastic_PowerMetrics_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} +#define meshtastic_AirQualityMetrics_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} #define meshtastic_LocalStats_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_HealthMetrics_init_zero {false, 0, false, 0, false, 0} #define meshtastic_HostMetrics_init_zero {0, 0, 0, false, 0, false, 0, 0, 0, 0, false, ""} @@ -427,6 +465,16 @@ extern "C" { #define meshtastic_PowerMetrics_ch2_current_tag 4 #define meshtastic_PowerMetrics_ch3_voltage_tag 5 #define meshtastic_PowerMetrics_ch3_current_tag 6 +#define meshtastic_PowerMetrics_ch4_voltage_tag 7 +#define meshtastic_PowerMetrics_ch4_current_tag 8 +#define meshtastic_PowerMetrics_ch5_voltage_tag 9 +#define meshtastic_PowerMetrics_ch5_current_tag 10 +#define meshtastic_PowerMetrics_ch6_voltage_tag 11 +#define meshtastic_PowerMetrics_ch6_current_tag 12 +#define meshtastic_PowerMetrics_ch7_voltage_tag 13 +#define meshtastic_PowerMetrics_ch7_current_tag 14 +#define meshtastic_PowerMetrics_ch8_voltage_tag 15 +#define meshtastic_PowerMetrics_ch8_current_tag 16 #define meshtastic_AirQualityMetrics_pm10_standard_tag 1 #define meshtastic_AirQualityMetrics_pm25_standard_tag 2 #define meshtastic_AirQualityMetrics_pm100_standard_tag 3 @@ -440,6 +488,8 @@ extern "C" { #define meshtastic_AirQualityMetrics_particles_50um_tag 11 #define meshtastic_AirQualityMetrics_particles_100um_tag 12 #define meshtastic_AirQualityMetrics_co2_tag 13 +#define meshtastic_AirQualityMetrics_co2_temperature_tag 14 +#define meshtastic_AirQualityMetrics_co2_humidity_tag 15 #define meshtastic_LocalStats_uptime_seconds_tag 1 #define meshtastic_LocalStats_channel_utilization_tag 2 #define meshtastic_LocalStats_air_util_tx_tag 3 @@ -518,7 +568,17 @@ X(a, STATIC, OPTIONAL, FLOAT, ch1_current, 2) \ X(a, STATIC, OPTIONAL, FLOAT, ch2_voltage, 3) \ X(a, STATIC, OPTIONAL, FLOAT, ch2_current, 4) \ X(a, STATIC, OPTIONAL, FLOAT, ch3_voltage, 5) \ -X(a, STATIC, OPTIONAL, FLOAT, ch3_current, 6) +X(a, STATIC, OPTIONAL, FLOAT, ch3_current, 6) \ +X(a, STATIC, OPTIONAL, FLOAT, ch4_voltage, 7) \ +X(a, STATIC, OPTIONAL, FLOAT, ch4_current, 8) \ +X(a, STATIC, OPTIONAL, FLOAT, ch5_voltage, 9) \ +X(a, STATIC, OPTIONAL, FLOAT, ch5_current, 10) \ +X(a, STATIC, OPTIONAL, FLOAT, ch6_voltage, 11) \ +X(a, STATIC, OPTIONAL, FLOAT, ch6_current, 12) \ +X(a, STATIC, OPTIONAL, FLOAT, ch7_voltage, 13) \ +X(a, STATIC, OPTIONAL, FLOAT, ch7_current, 14) \ +X(a, STATIC, OPTIONAL, FLOAT, ch8_voltage, 15) \ +X(a, STATIC, OPTIONAL, FLOAT, ch8_current, 16) #define meshtastic_PowerMetrics_CALLBACK NULL #define meshtastic_PowerMetrics_DEFAULT NULL @@ -535,7 +595,9 @@ X(a, STATIC, OPTIONAL, UINT32, particles_10um, 9) \ X(a, STATIC, OPTIONAL, UINT32, particles_25um, 10) \ X(a, STATIC, OPTIONAL, UINT32, particles_50um, 11) \ X(a, STATIC, OPTIONAL, UINT32, particles_100um, 12) \ -X(a, STATIC, OPTIONAL, UINT32, co2, 13) +X(a, STATIC, OPTIONAL, UINT32, co2, 13) \ +X(a, STATIC, OPTIONAL, FLOAT, co2_temperature, 14) \ +X(a, STATIC, OPTIONAL, FLOAT, co2_humidity, 15) #define meshtastic_AirQualityMetrics_CALLBACK NULL #define meshtastic_AirQualityMetrics_DEFAULT NULL @@ -624,14 +686,14 @@ extern const pb_msgdesc_t meshtastic_Nau7802Config_msg; /* Maximum encoded size of messages (where known) */ #define MESHTASTIC_MESHTASTIC_TELEMETRY_PB_H_MAX_SIZE meshtastic_Telemetry_size -#define meshtastic_AirQualityMetrics_size 78 +#define meshtastic_AirQualityMetrics_size 88 #define meshtastic_DeviceMetrics_size 27 #define meshtastic_EnvironmentMetrics_size 113 #define meshtastic_HealthMetrics_size 11 #define meshtastic_HostMetrics_size 264 #define meshtastic_LocalStats_size 72 #define meshtastic_Nau7802Config_size 16 -#define meshtastic_PowerMetrics_size 30 +#define meshtastic_PowerMetrics_size 81 #define meshtastic_Telemetry_size 272 #ifdef __cplusplus diff --git a/src/mesh/udp/UdpMulticastHandler.h b/src/mesh/udp/UdpMulticastHandler.h index 39bd61021..d1cc1065c 100644 --- a/src/mesh/udp/UdpMulticastHandler.h +++ b/src/mesh/udp/UdpMulticastHandler.h @@ -44,7 +44,10 @@ class UdpMulticastHandler final meshtastic_MeshPacket mp; LOG_DEBUG("Decoding MeshPacket from UDP len=%u", packetLength); bool isPacketDecoded = pb_decode_from_bytes(packet.data(), packetLength, &meshtastic_MeshPacket_msg, &mp); - if (isPacketDecoded && router) { + if (isPacketDecoded && router && mp.which_payload_variant == meshtastic_MeshPacket_encrypted_tag) { + mp.pki_encrypted = false; + mp.public_key.size = 0; + memset(mp.public_key.bytes, 0, sizeof(mp.public_key.bytes)); UniquePacketPoolPacket p = packetPool.allocUniqueCopy(mp); // Unset received SNR/RSSI p->rx_snr = 0; diff --git a/src/mesh/wifi/WiFiAPClient.cpp b/src/mesh/wifi/WiFiAPClient.cpp index 24be97ad7..7a56c258b 100644 --- a/src/mesh/wifi/WiFiAPClient.cpp +++ b/src/mesh/wifi/WiFiAPClient.cpp @@ -87,16 +87,18 @@ static void onNetworkConnected() // start mdns if (!MDNS.begin("Meshtastic")) { - LOG_ERROR("Error setting up MDNS responder!"); + LOG_ERROR("Error setting up mDNS responder!"); } else { LOG_INFO("mDNS Host: Meshtastic.local"); MDNS.addService("meshtastic", "tcp", SERVER_API_DEFAULT_PORT); +// ESPmDNS (ESP32) and SimpleMDNS (RP2040) have slightly different APIs for adding TXT records #ifdef ARCH_ESP32 - MDNS.addService("http", "tcp", 80); - MDNS.addService("https", "tcp", 443); + MDNS.addServiceTxt("meshtastic", "tcp", "shortname", String(owner.short_name)); + MDNS.addServiceTxt("meshtastic", "tcp", "id", String(owner.id)); // ESP32 prints obtained IP address in WiFiEvent #elif defined(ARCH_RP2040) - // ARCH_RP2040 does not support HTTPS + MDNS.addServiceTxt("meshtastic", "shortname", owner.short_name); + MDNS.addServiceTxt("meshtastic", "id", owner.id); LOG_INFO("Obtained IP address: %s", WiFi.localIP().toString().c_str()); #endif } diff --git a/src/meshUtils.h b/src/meshUtils.h index 35b88e8b2..9fcf6f8a8 100644 --- a/src/meshUtils.h +++ b/src/meshUtils.h @@ -13,8 +13,9 @@ template constexpr const T &clamp(const T &v, const T &lo, const T &hi #if HAS_SCREEN #define IF_SCREEN(X) \ - if (screen) \ - X; + if (screen) { \ + X; \ + } #else #define IF_SCREEN(...) #endif diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp index a7966f4be..93cdb719b 100644 --- a/src/modules/AdminModule.cpp +++ b/src/modules/AdminModule.cpp @@ -630,6 +630,7 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c) #if USERPREFS_EVENT_MODE // If we're in event mode, nobody is a Router or Repeater if (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER || + config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER_LATE || config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER) { config.device.role = meshtastic_Config_DeviceConfig_Role_CLIENT; } @@ -1198,7 +1199,7 @@ void AdminModule::reboot(int32_t seconds) { LOG_INFO("Reboot in %d seconds", seconds); if (screen) - screen->showOverlayBanner("Rebooting...", 0); // stays on screen + screen->showSimpleBanner("Rebooting...", 0); // stays on screen rebootAtMsec = (seconds < 0) ? 0 : (millis() + seconds * 1000); } @@ -1334,12 +1335,6 @@ void AdminModule::handleSendInputEvent(const meshtastic_AdminMessage_InputEvent LOG_DEBUG("Processing input event: event_code=%u, kb_char=%u, touch_x=%u, touch_y=%u", inputEvent.event_code, inputEvent.kb_char, inputEvent.touch_x, inputEvent.touch_y); - // Validate input parameters - if (inputEvent.event_code > INPUT_BROKER_ANYKEY) { - LOG_WARN("Invalid input event code: %u", inputEvent.event_code); - return; - } - // Create InputEvent for injection InputEvent event = {.inputEvent = (input_broker_event)inputEvent.event_code, .kbchar = (unsigned char)inputEvent.kb_char, diff --git a/src/modules/CannedMessageModule.cpp b/src/modules/CannedMessageModule.cpp index b24f3ca00..a1b89e0f8 100644 --- a/src/modules/CannedMessageModule.cpp +++ b/src/modules/CannedMessageModule.cpp @@ -154,7 +154,7 @@ int CannedMessageModule::splitConfiguredMessages() } void CannedMessageModule::drawHeader(OLEDDisplay *display, int16_t x, int16_t y, char *buffer) { - if (display->getWidth() > 128) { + if (graphics::isHighResolution) { if (this->dest == NODENUM_BROADCAST) { display->drawStringf(x, y, buffer, "To: Broadcast@%s", channels.getName(this->channel)); } else { @@ -245,12 +245,15 @@ void CannedMessageModule::updateDestinationSelectionList() } } + /* As the nodeDB is sorted, can skip this step // Sort by favorite, then last heard std::sort(this->filteredNodes.begin(), this->filteredNodes.end(), [](const NodeEntry &a, const NodeEntry &b) { if (a.node->is_favorite != b.node->is_favorite) return a.node->is_favorite > b.node->is_favorite; return a.lastHeard < b.lastHeard; }); + */ + scrollIndex = 0; // Show first result at the top destIndex = 0; // Highlight the first entry if (nodesChanged && runState == CANNED_MESSAGE_RUN_STATE_DESTINATION_SELECTION) { @@ -387,6 +390,7 @@ bool CannedMessageModule::handleTabSwitch(const InputEvent *event) // RESTORE THIS! if (runState == CANNED_MESSAGE_RUN_STATE_DESTINATION_SELECTION) updateDestinationSelectionList(); + requestFocus(); UIFrameEvent e; e.action = UIFrameEvent::Action::REGENERATE_FRAMESET; @@ -438,25 +442,34 @@ int CannedMessageModule::handleDestinationSelectionInput(const InputEvent *event return 1; } - // UP - if (isUp && destIndex > 0) { - destIndex--; + if (isUp) { + if (destIndex > 0) { + destIndex--; + } else if (totalEntries > 0) { + destIndex = totalEntries - 1; + } + if ((destIndex / columns) < scrollIndex) scrollIndex = destIndex / columns; else if ((destIndex / columns) >= (scrollIndex + visibleRows)) scrollIndex = (destIndex / columns) - visibleRows + 1; - screen->forceDisplay(); + screen->forceDisplay(true); return 1; } - // DOWN - if (isDown && destIndex + 1 < totalEntries) { - destIndex++; + if (isDown) { + if (destIndex + 1 < totalEntries) { + destIndex++; + } else if (totalEntries > 0) { + destIndex = 0; + scrollIndex = 0; + } + if ((destIndex / columns) >= (scrollIndex + visibleRows)) scrollIndex = (destIndex / columns) - visibleRows + 1; - screen->forceDisplay(); + screen->forceDisplay(true); return 1; } @@ -478,7 +491,7 @@ int CannedMessageModule::handleDestinationSelectionInput(const InputEvent *event runState = returnToCannedList ? CANNED_MESSAGE_RUN_STATE_ACTIVE : CANNED_MESSAGE_RUN_STATE_FREETEXT; returnToCannedList = false; - screen->forceDisplay(); + screen->forceDisplay(true); return 1; } @@ -491,7 +504,7 @@ int CannedMessageModule::handleDestinationSelectionInput(const InputEvent *event // UIFrameEvent e; // e.action = UIFrameEvent::Action::REGENERATE_FRAMESET; // notifyObservers(&e); - screen->forceDisplay(); + screen->forceDisplay(true); return 1; } @@ -703,7 +716,7 @@ bool CannedMessageModule::handleFreeTextInput(const InputEvent *event) } // Backspace - if (event->inputEvent == INPUT_BROKER_BACK) { + if (event->inputEvent == INPUT_BROKER_BACK && this->freetext.length() > 0) { payload = 0x08; lastTouchMillis = millis(); runOnce(); @@ -726,7 +739,8 @@ bool CannedMessageModule::handleFreeTextInput(const InputEvent *event) } // Cancel (dismiss freetext screen) - if (event->inputEvent == INPUT_BROKER_CANCEL || event->inputEvent == INPUT_BROKER_ALT_LONG) { + if (event->inputEvent == INPUT_BROKER_CANCEL || event->inputEvent == INPUT_BROKER_ALT_LONG || + (event->inputEvent == INPUT_BROKER_BACK && this->freetext.length() == 0)) { runState = CANNED_MESSAGE_RUN_STATE_INACTIVE; freetext = ""; cursor = 0; @@ -976,6 +990,7 @@ int32_t CannedMessageModule::runOnce() } this->cursor--; } + } else { } break; case INPUT_BROKER_MSG_TAB: // Tab key: handled by input handler @@ -986,6 +1001,7 @@ int32_t CannedMessageModule::runOnce() default: // Only insert ASCII printable characters (32–126) if (this->payload >= 32 && this->payload <= 126) { + requestFocus(); if (this->cursor == this->freetext.length()) { this->freetext += (char)this->payload; } else { @@ -2061,4 +2077,4 @@ String CannedMessageModule::drawWithCursor(String text, int cursor) return result; } -#endif \ No newline at end of file +#endif diff --git a/src/modules/ExternalNotificationModule.cpp b/src/modules/ExternalNotificationModule.cpp index 956508ce5..5d7233279 100644 --- a/src/modules/ExternalNotificationModule.cpp +++ b/src/modules/ExternalNotificationModule.cpp @@ -362,9 +362,8 @@ ExternalNotificationModule::ExternalNotificationModule() if (nodeDB->loadProto(rtttlConfigFile, meshtastic_RTTTLConfig_size, sizeof(meshtastic_RTTTLConfig), &meshtastic_RTTTLConfig_msg, &rtttlConfig) != LoadFileResult::LOAD_SUCCESS) { memset(rtttlConfig.ringtone, 0, sizeof(rtttlConfig.ringtone)); - strncpy(rtttlConfig.ringtone, - "24:d=32,o=5,b=565:f6,p,f6,4p,p,f6,p,f6,2p,p,b6,p,b6,p,b6,p,b6,p,b,p,b,p,b,p,b,p,b,p,b,p,b,p,b,1p.,2p.,p", - sizeof(rtttlConfig.ringtone)); + // The default ringtone is always loaded from userPrefs.jsonc + strncpy(rtttlConfig.ringtone, USERPREFS_RINGTONE_RTTTL, sizeof(rtttlConfig.ringtone)); } LOG_INFO("Init External Notification Module"); diff --git a/src/modules/KeyVerificationModule.cpp b/src/modules/KeyVerificationModule.cpp index f5a9f2359..3b8225763 100644 --- a/src/modules/KeyVerificationModule.cpp +++ b/src/modules/KeyVerificationModule.cpp @@ -2,7 +2,9 @@ #include "KeyVerificationModule.h" #include "MeshService.h" #include "RTC.h" +#include "graphics/draw/MenuHandler.h" #include "main.h" +#include "meshUtils.h" #include "modules/AdminModule.h" #include @@ -48,18 +50,22 @@ AdminMessageHandleResult KeyVerificationModule::handleAdminMessageForModule(cons bool KeyVerificationModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_KeyVerification *r) { updateState(); - if (mp.pki_encrypted == false) + if (mp.pki_encrypted == false) { return false; - if (mp.from != currentRemoteNode) // because the inital connection request is handled in allocReply() + } + if (mp.from != currentRemoteNode) { // because the inital connection request is handled in allocReply() return false; + } if (currentState == KEY_VERIFICATION_IDLE) { return false; // if we're idle, the only acceptable message is an init, which should be handled by allocReply() + } - } else if (currentState == KEY_VERIFICATION_SENDER_HAS_INITIATED && r->nonce == currentNonce && r->hash2.size == 32 && - r->hash1.size == 0) { + if (currentState == KEY_VERIFICATION_SENDER_HAS_INITIATED && r->nonce == currentNonce && r->hash2.size == 32 && + r->hash1.size == 0) { memcpy(hash2, r->hash2.bytes, 32); - if (screen) - screen->showOverlayBanner("Enter Security Number", 30000); + IF_SCREEN(screen->showNumberPicker("Enter Security Number", 60000, 6, [](int number_picked) -> void { + keyVerificationModule->processSecurityNumber(number_picked); + });) meshtastic_ClientNotification *cn = clientNotificationPool.allocZeroed(); cn->level = meshtastic_LogRecord_Level_WARNING; @@ -79,16 +85,20 @@ bool KeyVerificationModule::handleReceivedProtobuf(const meshtastic_MeshPacket & memset(message, 0, sizeof(message)); sprintf(message, "Verification: \n"); generateVerificationCode(message + 15); - sprintf(message + 24, "\nACCEPT\nREJECT"); LOG_INFO("Hash1 matches!"); - if (screen) { - screen->showOverlayBanner(message, 30000, 2, [=](int selected) { - if (selected == 0) { - auto remoteNodePtr = nodeDB->getMeshNode(currentRemoteNode); - remoteNodePtr->bitfield |= NODEINFO_BITFIELD_IS_KEY_MANUALLY_VERIFIED_MASK; - } - }); - } + static const char *optionsArray[] = {"Reject", "Accept"}; + // Don't try to put the array definition in the macro. Does not work with curly braces. + IF_SCREEN(graphics::BannerOverlayOptions options; options.message = message; options.durationMs = 30000; + options.optionsArrayPtr = optionsArray; options.optionsCount = 2; + options.notificationType = graphics::notificationTypeEnum::selection_picker; + options.bannerCallback = + [=](int selected) { + if (selected == 1) { + auto remoteNodePtr = nodeDB->getMeshNode(currentRemoteNode); + remoteNodePtr->bitfield |= NODEINFO_BITFIELD_IS_KEY_MANUALLY_VERIFIED_MASK; + } + }; + screen->showOverlayBanner(options);) meshtastic_ClientNotification *cn = clientNotificationPool.allocZeroed(); cn->level = meshtastic_LogRecord_Level_WARNING; sprintf(cn->message, "Final confirmation for incoming manual key verification %s", message); @@ -113,6 +123,7 @@ bool KeyVerificationModule::sendInitialRequest(NodeNum remoteNode) // generate nonce updateState(); if (currentState != KEY_VERIFICATION_IDLE) { + IF_SCREEN(graphics::menuHandler::menuQueue = graphics::menuHandler::throttle_message;) return false; } currentNonce = random(); @@ -183,11 +194,8 @@ meshtastic_MeshPacket *KeyVerificationModule::allocReply() responsePacket = allocDataProtobuf(response); responsePacket->pki_encrypted = true; - if (screen) { - snprintf(message, 25, "Security Number \n%03u %03u", currentSecurityNumber / 1000, currentSecurityNumber % 1000); - screen->showOverlayBanner(message, 30000); - LOG_WARN("%s", message); - } + IF_SCREEN(snprintf(message, 25, "Security Number \n%03u %03u", currentSecurityNumber / 1000, currentSecurityNumber % 1000); + screen->showSimpleBanner(message, 30000); LOG_WARN("%s", message);) meshtastic_ClientNotification *cn = clientNotificationPool.allocZeroed(); cn->level = meshtastic_LogRecord_Level_WARNING; sprintf(cn->message, "Incoming Key Verification.\nSecurity Number\n%03u %03u", currentSecurityNumber / 1000, @@ -251,12 +259,7 @@ void KeyVerificationModule::processSecurityNumber(uint32_t incomingNumber) p->priority = meshtastic_MeshPacket_Priority_HIGH; service->sendToMesh(p, RX_SRC_LOCAL, true); currentState = KEY_VERIFICATION_SENDER_AWAITING_USER; - memset(message, 0, sizeof(message)); - sprintf(message, "Verification: \n"); - generateVerificationCode(message + 15); // send the toPhone packet - if (screen) { - screen->showOverlayBanner(message, 30000); - } + IF_SCREEN(screen->requestMenu(graphics::menuHandler::key_verification_final_prompt);) meshtastic_ClientNotification *cn = clientNotificationPool.allocZeroed(); cn->level = meshtastic_LogRecord_Level_WARNING; sprintf(cn->message, "Final confirmation for outgoing manual key verification %s", message); @@ -275,7 +278,7 @@ void KeyVerificationModule::processSecurityNumber(uint32_t incomingNumber) void KeyVerificationModule::updateState() { if (currentState != KEY_VERIFICATION_IDLE) { - // check for the 30 second timeout + // check for the 60 second timeout if (currentNonceTimestamp < getTime() - 60) { resetToIdle(); } else { diff --git a/src/modules/KeyVerificationModule.h b/src/modules/KeyVerificationModule.h index f659e961a..d5dba01d7 100644 --- a/src/modules/KeyVerificationModule.h +++ b/src/modules/KeyVerificationModule.h @@ -27,6 +27,8 @@ class KeyVerificationModule : public ProtobufModule }*/ virtual bool wantUIFrame() { return false; }; bool sendInitialRequest(NodeNum remoteNode); + void generateVerificationCode(char *); // fills char with the user readable verification code + uint32_t getCurrentRemoteNode() { return currentRemoteNode; } protected: /* Called to handle a particular incoming message @@ -56,9 +58,8 @@ class KeyVerificationModule : public ProtobufModule char message[40] = {0}; void processSecurityNumber(uint32_t); - void updateState(); // check the timeouts and maybe reset the state to idle - void resetToIdle(); // Zero out module state - void generateVerificationCode(char *); // fills char with the user readable verification code + void updateState(); // check the timeouts and maybe reset the state to idle + void resetToIdle(); // Zero out module state }; extern KeyVerificationModule *keyVerificationModule; \ No newline at end of file diff --git a/src/modules/Modules.cpp b/src/modules/Modules.cpp index 783c08b9f..3528f57f5 100644 --- a/src/modules/Modules.cpp +++ b/src/modules/Modules.cpp @@ -53,6 +53,7 @@ #endif #if ARCH_PORTDUINO #include "input/LinuxInputImpl.h" +#include "input/SeesawRotary.h" #include "modules/Telemetry/HostMetrics.h" #if !MESHTASTIC_EXCLUDE_STOREFORWARD #include "modules/StoreForwardModule.h" @@ -163,7 +164,6 @@ void setupModules() // Example: Put your module here // new ReplyModule(); #if (HAS_BUTTON || ARCH_PORTDUINO) && !MESHTASTIC_EXCLUDE_INPUTBROKER - if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) { rotaryEncoderInterruptImpl1 = new RotaryEncoderInterruptImpl1(); if (!rotaryEncoderInterruptImpl1->init()) { @@ -189,6 +189,11 @@ void setupModules() #endif // HAS_BUTTON #if ARCH_PORTDUINO if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) { + seesawRotary = new SeesawRotary("SeesawRotary"); + if (!seesawRotary->init()) { + delete seesawRotary; + seesawRotary = nullptr; + } aLinuxInputImpl = new LinuxInputImpl(); aLinuxInputImpl->init(); } @@ -213,11 +218,14 @@ void setupModules() #if HAS_TELEMETRY new DeviceTelemetryModule(); #endif +// TODO: How to improve this? #if HAS_SENSOR && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR new EnvironmentTelemetryModule(); +#if __has_include("Adafruit_PM25AQI.h") if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_PMSA003I].first > 0) { new AirQualityTelemetryModule(); } +#endif #if !MESHTASTIC_EXCLUDE_HEALTH_TELEMETRY if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_MAX30102].first > 0 || nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_MLX90614].first > 0) { diff --git a/src/modules/SystemCommandsModule.cpp b/src/modules/SystemCommandsModule.cpp index a6b01d68a..ab9439b39 100644 --- a/src/modules/SystemCommandsModule.cpp +++ b/src/modules/SystemCommandsModule.cpp @@ -47,7 +47,7 @@ int SystemCommandsModule::handleInputEvent(const InputEvent *event) bool isMuted = externalNotificationModule->getMute(); externalNotificationModule->setMute(!isMuted); IF_SCREEN(graphics::isMuted = !isMuted; if (!isMuted) externalNotificationModule->stopNow(); - screen->showOverlayBanner(isMuted ? "Notifications\nEnabled" : "Notifications\nDisabled", 3000);) + screen->showSimpleBanner(isMuted ? "Notifications\nEnabled" : "Notifications\nDisabled", 3000);) } return 0; // Bluetooth @@ -58,24 +58,24 @@ int SystemCommandsModule::handleInputEvent(const InputEvent *event) #if defined(ARDUINO_ARCH_NRF52) if (!config.bluetooth.enabled) { disableBluetooth(); - IF_SCREEN(screen->showOverlayBanner("Bluetooth OFF\nRebooting", 3000)); + IF_SCREEN(screen->showSimpleBanner("Bluetooth OFF\nRebooting", 3000)); rebootAtMsec = millis() + DEFAULT_REBOOT_SECONDS * 2000; } else { - IF_SCREEN(screen->showOverlayBanner("Bluetooth ON\nRebooting", 3000)); + IF_SCREEN(screen->showSimpleBanner("Bluetooth ON\nRebooting", 3000)); rebootAtMsec = millis() + DEFAULT_REBOOT_SECONDS * 1000; } #else if (!config.bluetooth.enabled) { disableBluetooth(); - IF_SCREEN(screen->showOverlayBanner("Bluetooth OFF", 3000)); + IF_SCREEN(screen->showSimpleBanner("Bluetooth OFF", 3000)); } else { - IF_SCREEN(screen->showOverlayBanner("Bluetooth ON\nRebooting", 3000)); + IF_SCREEN(screen->showSimpleBanner("Bluetooth ON\nRebooting", 3000)); rebootAtMsec = millis() + DEFAULT_REBOOT_SECONDS * 1000; } #endif return 0; case INPUT_BROKER_MSG_REBOOT: - IF_SCREEN(screen->showOverlayBanner("Rebooting...", 0)); + IF_SCREEN(screen->showSimpleBanner("Rebooting...", 0)); nodeDB->saveToDisk(); rebootAtMsec = millis() + DEFAULT_REBOOT_SECONDS * 1000; // runState = CANNED_MESSAGE_RUN_STATE_INACTIVE; @@ -92,7 +92,7 @@ int SystemCommandsModule::handleInputEvent(const InputEvent *event) gps->toggleGpsMode(); const char *msg = (config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_ENABLED) ? "GPS Enabled" : "GPS Disabled"; - IF_SCREEN(screen->forceDisplay(); screen->showOverlayBanner(msg, 3000);) + IF_SCREEN(screen->forceDisplay(); screen->showSimpleBanner(msg, 3000);) } #endif return true; @@ -100,19 +100,23 @@ int SystemCommandsModule::handleInputEvent(const InputEvent *event) case INPUT_BROKER_SEND_PING: service->refreshLocalMeshNode(); if (service->trySendPosition(NODENUM_BROADCAST, true)) { - IF_SCREEN(screen->showOverlayBanner("Position\nUpdate Sent", 3000)); + IF_SCREEN(screen->showSimpleBanner("Position\nSent", 3000)); } else { - IF_SCREEN(screen->showOverlayBanner("Node Info\nUpdate Sent", 3000)); + IF_SCREEN(screen->showSimpleBanner("Node Info\nSent", 3000)); } return true; // Power control case INPUT_BROKER_SHUTDOWN: - LOG_ERROR("Shutting down"); - IF_SCREEN(screen->showOverlayBanner("Shutting down...")); + LOG_ERROR("Shutting Down"); + IF_SCREEN(screen->showSimpleBanner("Shutting Down...")); nodeDB->saveToDisk(); shutdownAtMsec = millis() + DEFAULT_SHUTDOWN_SECONDS * 1000; // runState = CANNED_MESSAGE_RUN_STATE_INACTIVE; return true; + + default: + // No other input events handled here + break; } return false; -} \ No newline at end of file +} diff --git a/src/modules/Telemetry/EnvironmentTelemetry.cpp b/src/modules/Telemetry/EnvironmentTelemetry.cpp index 375d1e596..d1b10fa82 100644 --- a/src/modules/Telemetry/EnvironmentTelemetry.cpp +++ b/src/modules/Telemetry/EnvironmentTelemetry.cpp @@ -30,7 +30,7 @@ namespace graphics { -extern void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *titleStr); +extern void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *titleStr, bool battery_only); } #if __has_include() #include "Sensor/AHT10.h" @@ -358,7 +358,7 @@ void EnvironmentTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiSt int line = 1; // === Set Title - const char *titleStr = (SCREEN_WIDTH > 128) ? "Environment" : "Env."; + const char *titleStr = (graphics::isHighResolution) ? "Environment" : "Env."; // === Header === graphics::drawCommonHeader(display, x, y, titleStr); @@ -450,7 +450,7 @@ void EnvironmentTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiSt if (isOwnTelemetry && bannerMsg && isCooldownOver) { LOG_INFO("drawFrame: IAQ %d (own) — showing banner: %s", m.iaq, bannerMsg); - screen->showOverlayBanner(bannerMsg, 3000); + screen->showSimpleBanner(bannerMsg, 3000); // Only buzz if IAQ is over 200 if (m.iaq > 200 && moduleConfig.external_notification.enabled && !externalNotificationModule->getMute()) { diff --git a/src/modules/Telemetry/PowerTelemetry.cpp b/src/modules/Telemetry/PowerTelemetry.cpp index df1505226..a92013d01 100644 --- a/src/modules/Telemetry/PowerTelemetry.cpp +++ b/src/modules/Telemetry/PowerTelemetry.cpp @@ -24,7 +24,7 @@ namespace graphics { -extern void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *titleStr); +extern void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *titleStr, bool battery_only); } int32_t PowerTelemetryModule::runOnce() @@ -115,7 +115,7 @@ void PowerTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *s int line = 1; // === Set Title - const char *titleStr = (SCREEN_WIDTH > 128) ? "Power Telem." : "Power"; + const char *titleStr = (graphics::isHighResolution) ? "Power Telem." : "Power"; // === Header === graphics::drawCommonHeader(display, x, y, titleStr); diff --git a/src/modules/Telemetry/Sensor/MAX17048Sensor.cpp b/src/modules/Telemetry/Sensor/MAX17048Sensor.cpp index 6ab96aa57..1a6792d3a 100644 --- a/src/modules/Telemetry/Sensor/MAX17048Sensor.cpp +++ b/src/modules/Telemetry/Sensor/MAX17048Sensor.cpp @@ -1,6 +1,6 @@ #include "MAX17048Sensor.h" -#if !MESHTASTIC_EXCLUDE_I2C && !defined(ARCH_STM32WL) && __has_include() +#if !MESHTASTIC_EXCLUDE_I2C && __has_include() MAX17048Singleton *MAX17048Singleton::GetInstance() { diff --git a/src/modules/Telemetry/Sensor/MAX17048Sensor.h b/src/modules/Telemetry/Sensor/MAX17048Sensor.h index 6f61421dc..d27169406 100644 --- a/src/modules/Telemetry/Sensor/MAX17048Sensor.h +++ b/src/modules/Telemetry/Sensor/MAX17048Sensor.h @@ -5,7 +5,7 @@ #include "configuration.h" -#if !MESHTASTIC_EXCLUDE_I2C && !defined(ARCH_STM32WL) && __has_include() +#if !MESHTASTIC_EXCLUDE_I2C && __has_include() // Samples to store in a buffer to determine if the battery is charging or discharging #define MAX17048_CHARGING_SAMPLES 3 diff --git a/src/modules/Telemetry/Sensor/nullSensor.cpp b/src/modules/Telemetry/Sensor/nullSensor.cpp index 9522c7fcc..c84b9d27f 100644 --- a/src/modules/Telemetry/Sensor/nullSensor.cpp +++ b/src/modules/Telemetry/Sensor/nullSensor.cpp @@ -20,4 +20,15 @@ bool NullSensor::getMetrics(meshtastic_Telemetry *measurement) { return false; } + +uint16_t NullSensor::getBusVoltageMv() +{ + return 0; +} + +int16_t NullSensor::getCurrentMa() +{ + return 0; +} + #endif \ No newline at end of file diff --git a/src/modules/Telemetry/Sensor/nullSensor.h b/src/modules/Telemetry/Sensor/nullSensor.h index 94dbcc7f8..a400acf97 100644 --- a/src/modules/Telemetry/Sensor/nullSensor.h +++ b/src/modules/Telemetry/Sensor/nullSensor.h @@ -4,9 +4,12 @@ #pragma once #include "../mesh/generated/meshtastic/telemetry.pb.h" -#include "TelemetrySensor.h" -class NullSensor : public TelemetrySensor +#include "CurrentSensor.h" +#include "TelemetrySensor.h" +#include "VoltageSensor.h" + +class NullSensor : public TelemetrySensor, VoltageSensor, CurrentSensor { protected: @@ -17,6 +20,9 @@ class NullSensor : public TelemetrySensor virtual int32_t runOnce() override; virtual bool getMetrics(meshtastic_Telemetry *measurement) override; int32_t runTrigger() { return 0; } + + virtual uint16_t getBusVoltageMv() override; + virtual int16_t getCurrentMa() override; }; #endif \ No newline at end of file diff --git a/src/modules/TextMessageModule.cpp b/src/modules/TextMessageModule.cpp index f1d01ad16..970f4429c 100644 --- a/src/modules/TextMessageModule.cpp +++ b/src/modules/TextMessageModule.cpp @@ -4,6 +4,7 @@ #include "PowerFSM.h" #include "buzz.h" #include "configuration.h" +#include "graphics/Screen.h" TextMessageModule *textMessageModule; ProcessMessage TextMessageModule::handleReceived(const meshtastic_MeshPacket &mp) @@ -17,7 +18,10 @@ ProcessMessage TextMessageModule::handleReceived(const meshtastic_MeshPacket &mp devicestate.rx_text_message = mp; devicestate.has_rx_text_message = true; - powerFSM.trigger(EVENT_RECEIVED_MSG); + // Only trigger screen wake if configuration allows it + if (shouldWakeOnReceivedMessage()) { + powerFSM.trigger(EVENT_RECEIVED_MSG); + } notifyObservers(&mp); return ProcessMessage::CONTINUE; // Let others look at this message also if they want diff --git a/src/modules/WaypointModule.cpp b/src/modules/WaypointModule.cpp index 578e7183a..aab3ed6bc 100644 --- a/src/modules/WaypointModule.cpp +++ b/src/modules/WaypointModule.cpp @@ -137,10 +137,14 @@ void WaypointModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, if (ourNode && (nodeDB->hasValidPosition(ourNode) || screen->hasHeading())) { const meshtastic_PositionLite &op = ourNode->position; float myHeading; - if (screen->hasHeading()) - myHeading = (screen->getHeading()) * PI / 180; // gotta convert compass degrees to Radians - else - myHeading = screen->estimatedHeading(DegD(op.latitude_i), DegD(op.longitude_i)); + if (uiconfig.compass_mode == meshtastic_CompassMode_FREEZE_HEADING) { + myHeading = 0; + } else { + if (screen->hasHeading()) + myHeading = (screen->getHeading()) * PI / 180; // gotta convert compass degrees to Radians + else + myHeading = screen->estimatedHeading(DegD(op.latitude_i), DegD(op.longitude_i)); + } graphics::CompassRenderer::drawCompassNorth(display, compassX, compassY, myHeading, (compassDiam / 2)); // Compass bearing to waypoint @@ -148,7 +152,7 @@ void WaypointModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, GeoCoord::bearing(DegD(op.latitude_i), DegD(op.longitude_i), DegD(wp.latitude_i), DegD(wp.longitude_i)); // If the top of the compass is a static north then bearingToOther can be drawn on the compass directly // If the top of the compass is not a static north we need adjust bearingToOther based on heading - if (!config.display.compass_north_top) + if (uiconfig.compass_mode != meshtastic_CompassMode_FREEZE_HEADING) bearingToOther -= myHeading; graphics::CompassRenderer::drawNodeHeading(display, compassX, compassY, compassDiam, bearingToOther); diff --git a/src/nimble/NimbleBluetooth.cpp b/src/nimble/NimbleBluetooth.cpp index 3ab06695b..834184292 100644 --- a/src/nimble/NimbleBluetooth.cpp +++ b/src/nimble/NimbleBluetooth.cpp @@ -9,6 +9,7 @@ #include "mesh/mesh-pb-constants.h" #include "sleep.h" #include +#include NimBLECharacteristic *fromNumCharacteristic; NimBLECharacteristic *BatteryCharacteristic; @@ -17,8 +18,37 @@ NimBLEServer *bleServer; static bool passkeyShowing; -class BluetoothPhoneAPI : public PhoneAPI +class BluetoothPhoneAPI : public PhoneAPI, public concurrency::OSThread { + public: + BluetoothPhoneAPI() : concurrency::OSThread("NimbleBluetooth") { nimble_queue.resize(3); } + std::vector nimble_queue; + std::mutex nimble_mutex; + uint8_t queue_size = 0; + bool has_fromRadio = false; + uint8_t fromRadioBytes[meshtastic_FromRadio_size] = {0}; + size_t numBytes = 0; + bool hasChecked = false; + bool phoneWants = false; + + protected: + virtual int32_t runOnce() override + { + std::lock_guard guard(nimble_mutex); + if (queue_size > 0) { + for (uint8_t i = 0; i < queue_size; i++) { + handleToRadio(nimble_queue.at(i).data(), nimble_queue.at(i).length()); + } + LOG_DEBUG("Queue_size %u", queue_size); + queue_size = 0; + } + if (hasChecked == false && phoneWants == true) { + numBytes = getFromRadio(fromRadioBytes); + hasChecked = true; + } + + return 100; + } /** * Subclasses can use this as a hook to provide custom notifications for their transport (i.e. bluetooth notifies) */ @@ -51,15 +81,16 @@ class NimbleBluetoothToRadioCallback : public NimBLECharacteristicCallbacks { virtual void onWrite(NimBLECharacteristic *pCharacteristic) { - LOG_DEBUG("To Radio onwrite"); auto val = pCharacteristic->getValue(); if (memcmp(lastToRadio, val.data(), val.length()) != 0) { - LOG_DEBUG("New ToRadio packet"); - memcpy(lastToRadio, val.data(), val.length()); - bluetoothPhoneAPI->handleToRadio(val.data(), val.length()); - } else { - LOG_DEBUG("Drop dup ToRadio packet we just saw"); + if (bluetoothPhoneAPI->queue_size < 3) { + memcpy(lastToRadio, val.data(), val.length()); + std::lock_guard guard(bluetoothPhoneAPI->nimble_mutex); + bluetoothPhoneAPI->nimble_queue.at(bluetoothPhoneAPI->queue_size) = val; + bluetoothPhoneAPI->queue_size++; + bluetoothPhoneAPI->setIntervalFromNow(0); + } } } }; @@ -68,12 +99,23 @@ class NimbleBluetoothFromRadioCallback : public NimBLECharacteristicCallbacks { virtual void onRead(NimBLECharacteristic *pCharacteristic) { - uint8_t fromRadioBytes[meshtastic_FromRadio_size]; - size_t numBytes = bluetoothPhoneAPI->getFromRadio(fromRadioBytes); - - std::string fromRadioByteString(fromRadioBytes, fromRadioBytes + numBytes); - + int tries = 0; + bluetoothPhoneAPI->phoneWants = true; + while (!bluetoothPhoneAPI->hasChecked && tries < 100) { + bluetoothPhoneAPI->setIntervalFromNow(0); + delay(20); + tries++; + } + std::lock_guard guard(bluetoothPhoneAPI->nimble_mutex); + std::string fromRadioByteString(bluetoothPhoneAPI->fromRadioBytes, + bluetoothPhoneAPI->fromRadioBytes + bluetoothPhoneAPI->numBytes); pCharacteristic->setValue(fromRadioByteString); + + if (bluetoothPhoneAPI->numBytes != 0) // if we did send something, queue it up right away to reload + bluetoothPhoneAPI->setIntervalFromNow(0); + bluetoothPhoneAPI->numBytes = 0; + bluetoothPhoneAPI->hasChecked = false; + bluetoothPhoneAPI->phoneWants = false; } }; @@ -149,7 +191,12 @@ class NimbleBluetoothServerCallback : public NimBLEServerCallbacks new meshtastic::BluetoothStatus(meshtastic::BluetoothStatus::ConnectionState::DISCONNECTED)); if (bluetoothPhoneAPI) { + std::lock_guard guard(bluetoothPhoneAPI->nimble_mutex); bluetoothPhoneAPI->close(); + bluetoothPhoneAPI->hasChecked = false; + bluetoothPhoneAPI->phoneWants = false; + bluetoothPhoneAPI->numBytes = 0; + bluetoothPhoneAPI->queue_size = 0; } } }; diff --git a/src/platform/esp32/architecture.h b/src/platform/esp32/architecture.h index 3763bce1e..baefbc4eb 100644 --- a/src/platform/esp32/architecture.h +++ b/src/platform/esp32/architecture.h @@ -184,6 +184,8 @@ #define HW_VENDOR meshtastic_HardwareModel_HELTEC_SENSOR_HUB #elif defined(ELECROW_PANEL) #define HW_VENDOR meshtastic_HardwareModel_CROWPANEL +#elif defined(RAK3312) +#define HW_VENDOR meshtastic_HardwareModel_RAK3312 #elif defined(LINK_32) #define HW_VENDOR meshtastic_HardwareModel_LINK_32 #endif diff --git a/src/platform/nrf52/NRF52Bluetooth.cpp b/src/platform/nrf52/NRF52Bluetooth.cpp index 89e92afc6..6f0e7250f 100644 --- a/src/platform/nrf52/NRF52Bluetooth.cpp +++ b/src/platform/nrf52/NRF52Bluetooth.cpp @@ -314,7 +314,9 @@ void NRF52Bluetooth::onConnectionSecured(uint16_t conn_handle) } bool NRF52Bluetooth::onPairingPasskey(uint16_t conn_handle, uint8_t const passkey[6], bool match_request) { - LOG_INFO("BLE pair process started with passkey %.3s %.3s", passkey, passkey + 3); + char passkey1[4] = {passkey[0], passkey[1], passkey[2], '\0'}; + char passkey2[4] = {passkey[3], passkey[4], passkey[5], '\0'}; + LOG_INFO("BLE pair process started with passkey %s %s", passkey1, passkey2); powerFSM.trigger(EVENT_BLUETOOTH_PAIR); // Get passkey as string @@ -327,31 +329,33 @@ bool NRF52Bluetooth::onPairingPasskey(uint16_t conn_handle, uint8_t const passke bluetoothStatus->updateStatus(new meshtastic::BluetoothStatus(textkey)); #if !defined(MESHTASTIC_EXCLUDE_SCREEN) // Todo: migrate this display code back into Screen class, and observe bluetoothStatus - screen->startAlert([](OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -> void { - char btPIN[16] = "888888"; - snprintf(btPIN, sizeof(btPIN), "%06u", configuredPasskey); - int x_offset = display->width() / 2; - int y_offset = display->height() <= 80 ? 0 : 12; - display->setTextAlignment(TEXT_ALIGN_CENTER); - display->setFont(FONT_MEDIUM); - display->drawString(x_offset + x, y_offset + y, "Bluetooth"); + if (screen) { + screen->startAlert([](OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -> void { + char btPIN[16] = "888888"; + snprintf(btPIN, sizeof(btPIN), "%06u", configuredPasskey); + int x_offset = display->width() / 2; + int y_offset = display->height() <= 80 ? 0 : 12; + display->setTextAlignment(TEXT_ALIGN_CENTER); + display->setFont(FONT_MEDIUM); + display->drawString(x_offset + x, y_offset + y, "Bluetooth"); - display->setFont(FONT_SMALL); - y_offset = display->height() == 64 ? y_offset + FONT_HEIGHT_MEDIUM - 4 : y_offset + FONT_HEIGHT_MEDIUM + 5; - display->drawString(x_offset + x, y_offset + y, "Enter this code"); + display->setFont(FONT_SMALL); + y_offset = display->height() == 64 ? y_offset + FONT_HEIGHT_MEDIUM - 4 : y_offset + FONT_HEIGHT_MEDIUM + 5; + display->drawString(x_offset + x, y_offset + y, "Enter this code"); - display->setFont(FONT_LARGE); - String displayPin(btPIN); - String pin = displayPin.substring(0, 3) + " " + displayPin.substring(3, 6); - y_offset = display->height() == 64 ? y_offset + FONT_HEIGHT_SMALL - 5 : y_offset + FONT_HEIGHT_SMALL + 5; - display->drawString(x_offset + x, y_offset + y, pin); + display->setFont(FONT_LARGE); + String displayPin(btPIN); + String pin = displayPin.substring(0, 3) + " " + displayPin.substring(3, 6); + y_offset = display->height() == 64 ? y_offset + FONT_HEIGHT_SMALL - 5 : y_offset + FONT_HEIGHT_SMALL + 5; + display->drawString(x_offset + x, y_offset + y, pin); - display->setFont(FONT_SMALL); - String deviceName = "Name: "; - deviceName.concat(getDeviceName()); - y_offset = display->height() == 64 ? y_offset + FONT_HEIGHT_LARGE - 6 : y_offset + FONT_HEIGHT_LARGE + 5; - display->drawString(x_offset + x, y_offset + y, deviceName); - }); + display->setFont(FONT_SMALL); + String deviceName = "Name: "; + deviceName.concat(getDeviceName()); + y_offset = display->height() == 64 ? y_offset + FONT_HEIGHT_LARGE - 6 : y_offset + FONT_HEIGHT_LARGE + 5; + display->drawString(x_offset + x, y_offset + y, deviceName); + }); + } #endif if (match_request) { uint32_t start_time = millis(); @@ -394,8 +398,7 @@ void NRF52Bluetooth::onPairingCompleted(uint16_t conn_handle, uint8_t auth_statu { if (auth_status == BLE_GAP_SEC_STATUS_SUCCESS) { LOG_INFO("BLE pair success"); - bluetoothStatus->updateStatus( - new meshtastic::BluetoothStatus(meshtastic::BluetoothStatus::ConnectionState::DISCONNECTED)); + bluetoothStatus->updateStatus(new meshtastic::BluetoothStatus(meshtastic::BluetoothStatus::ConnectionState::CONNECTED)); } else { LOG_INFO("BLE pair failed"); // Notify UI (or any other interested firmware components) @@ -404,7 +407,9 @@ void NRF52Bluetooth::onPairingCompleted(uint16_t conn_handle, uint8_t auth_statu } // Todo: migrate this display code back into Screen class, and observe bluetoothStatus - screen->endAlert(); + if (screen) { + screen->endAlert(); + } } void NRF52Bluetooth::sendLog(const uint8_t *logMessage, size_t length) diff --git a/src/platform/portduino/PortduinoGlue.cpp b/src/platform/portduino/PortduinoGlue.cpp index f582a116d..685f0d077 100644 --- a/src/platform/portduino/PortduinoGlue.cpp +++ b/src/platform/portduino/PortduinoGlue.cpp @@ -35,6 +35,8 @@ char *configPath = nullptr; char *optionMac = nullptr; bool forceSimulated = false; +const char *argp_program_version = optstr(APP_VERSION); + // FIXME - move setBluetoothEnable into a HALPlatform class void setBluetoothEnable(bool enable) { @@ -642,6 +644,11 @@ bool loadConfig(const char *configPath) settingsMap[tbLeftPin] = yamlConfig["Input"]["TrackballLeft"].as(RADIOLIB_NC); settingsMap[tbRightPin] = yamlConfig["Input"]["TrackballRight"].as(RADIOLIB_NC); settingsMap[tbPressPin] = yamlConfig["Input"]["TrackballPress"].as(RADIOLIB_NC); + if (yamlConfig["Input"]["TrackballDirection"].as("RISING") == "RISING") { + settingsMap[tbDirection] = 4; + } else if (yamlConfig["Input"]["TrackballDirection"].as("RISING") == "FALLING") { + settingsMap[tbDirection] = 3; + } } if (yamlConfig["Webserver"]) { @@ -660,6 +667,21 @@ bool loadConfig(const char *configPath) settingsStrings[hostMetrics_user_command] = (yamlConfig["HostMetrics"]["UserStringCommand"]).as(""); } + if (yamlConfig["Config"]) { + if (yamlConfig["Config"]["DisplayMode"]) { + settingsMap[has_configDisplayMode] = true; + if ((yamlConfig["Config"]["DisplayMode"]).as("") == "TWOCOLOR") { + settingsMap[configDisplayMode] = meshtastic_Config_DisplayConfig_DisplayMode_TWOCOLOR; + } else if ((yamlConfig["Config"]["DisplayMode"]).as("") == "INVERTED") { + settingsMap[configDisplayMode] = meshtastic_Config_DisplayConfig_DisplayMode_INVERTED; + } else if ((yamlConfig["Config"]["DisplayMode"]).as("") == "COLOR") { + settingsMap[configDisplayMode] = meshtastic_Config_DisplayConfig_DisplayMode_COLOR; + } else { + settingsMap[configDisplayMode] = meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT; + } + } + } + if (yamlConfig["General"]) { settingsMap[maxnodes] = (yamlConfig["General"]["MaxNodes"]).as(200); settingsMap[maxtophone] = (yamlConfig["General"]["MaxMessageQueue"]).as(100); diff --git a/src/platform/portduino/PortduinoGlue.h b/src/platform/portduino/PortduinoGlue.h index 43aea4218..288870eef 100644 --- a/src/platform/portduino/PortduinoGlue.h +++ b/src/platform/portduino/PortduinoGlue.h @@ -11,7 +11,7 @@ inline const std::unordered_map configProducts = {{"MESHTOAD", "lora-usb-meshtoad-e22.yaml"}, {"MESHSTICK", "lora-meshstick-1262.yaml"}, {"MESHADV-PI", "lora-MeshAdv-900M30S.yaml"}, - {"MESHADV-MINI", "lora-MeshAdv-Mini-900M22S.yaml"}, + {"MeshAdv Mini", "lora-MeshAdv-Mini-900M22S.yaml"}, {"POWERPI", "lora-MeshAdv-900M30S.yaml"}}; enum configNames { @@ -63,6 +63,7 @@ enum configNames { tbLeftPin, tbRightPin, tbPressPin, + tbDirection, spidev, spiSpeed, i2cdev, @@ -108,7 +109,9 @@ enum configNames { mac_address, hostMetrics_interval, hostMetrics_channel, - hostMetrics_user_command + hostMetrics_user_command, + configDisplayMode, + has_configDisplayMode }; enum { no_screen, x11, fb, st7789, st7735, st7735s, st7796, ili9341, ili9342, ili9486, ili9488, hx8357d }; enum { no_touchscreen, xpt2046, stmpe610, gt911, ft5x06 }; diff --git a/src/platform/stm32wl/architecture.h b/src/platform/stm32wl/architecture.h index 325a192a4..ac2bbe5d1 100644 --- a/src/platform/stm32wl/architecture.h +++ b/src/platform/stm32wl/architecture.h @@ -12,6 +12,9 @@ #ifndef HAS_TELEMETRY #define HAS_TELEMETRY 1 #endif +#ifndef HAS_WIRE +#define HAS_WIRE 1 +#endif // // set HW_VENDOR @@ -28,4 +31,4 @@ #define SX126X_CS 1000 #define SX126X_DIO1 1001 #define SX126X_RESET 1003 -#define SX126X_BUSY 1004 \ No newline at end of file +#define SX126X_BUSY 1004 diff --git a/src/power.h b/src/power.h index 33a356d92..c71f96c10 100644 --- a/src/power.h +++ b/src/power.h @@ -25,11 +25,15 @@ #elif defined(CELL_TYPE_LTO) #define OCV_ARRAY 2700, 2560, 2540, 2520, 2500, 2460, 2420, 2400, 2380, 2320, 1500 #elif defined(TRACKER_T1000_E) -#define OCV_ARRAY 4190, 4078, 4017, 3969, 3887, 3818, 3798, 3791, 3766, 3712, 3100 +#define OCV_ARRAY 4190, 4042, 3957, 3885, 3820, 3776, 3746, 3725, 3696, 3644, 3100 #elif defined(HELTEC_MESH_POCKET_BATTERY_5000) #define OCV_ARRAY 4300, 4240, 4120, 4000, 3888, 3800, 3740, 3698, 3655, 3580, 3400 #elif defined(HELTEC_MESH_POCKET_BATTERY_10000) #define OCV_ARRAY 4100, 4060, 3960, 3840, 3729, 3625, 3550, 3500, 3420, 3345, 3100 +#elif defined(SEEED_WIO_TRACKER_L1) +#define OCV_ARRAY 4200, 3876, 3826, 3763, 3713, 3660, 3573, 3485, 3422, 3359, 3300 +#elif defined(SEEED_SOLAR_NODE) +#define OCV_ARRAY 4200, 3986, 3922, 3812, 3734, 3645, 3527, 3420, 3281, 3087, 2786 #else // LiIon #define OCV_ARRAY 4190, 4050, 3990, 3890, 3800, 3720, 3630, 3530, 3420, 3300, 3100 #endif @@ -77,7 +81,7 @@ extern NullSensor ina3221Sensor; #endif -#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && !defined(ARCH_STM32WL) +#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR #if __has_include() #include "modules/Telemetry/Sensor/MAX17048Sensor.h" extern MAX17048Sensor max17048Sensor; diff --git a/src/serialization/MeshPacketSerializer.cpp b/src/serialization/MeshPacketSerializer.cpp index fc8531298..29a9b6840 100644 --- a/src/serialization/MeshPacketSerializer.cpp +++ b/src/serialization/MeshPacketSerializer.cpp @@ -79,7 +79,8 @@ std::string MeshPacketSerializer::JsonSerialize(const meshtastic_MeshPacket *mp, msgPayload["relative_humidity"] = new JSONValue(decoded->variant.environment_metrics.relative_humidity); } if (decoded->variant.environment_metrics.has_barometric_pressure) { - msgPayload["barometric_pressure"] = new JSONValue(decoded->variant.environment_metrics.barometric_pressure); + msgPayload["barometric_pressure"] = + new JSONValue(decoded->variant.environment_metrics.barometric_pressure); } if (decoded->variant.environment_metrics.has_gas_resistance) { msgPayload["gas_resistance"] = new JSONValue(decoded->variant.environment_metrics.gas_resistance); @@ -125,13 +126,16 @@ std::string MeshPacketSerializer::JsonSerialize(const meshtastic_MeshPacket *mp, msgPayload["pm100"] = new JSONValue((unsigned int)decoded->variant.air_quality_metrics.pm100_standard); } if (decoded->variant.air_quality_metrics.has_pm10_environmental) { - msgPayload["pm10_e"] = new JSONValue((unsigned int)decoded->variant.air_quality_metrics.pm10_environmental); + msgPayload["pm10_e"] = + new JSONValue((unsigned int)decoded->variant.air_quality_metrics.pm10_environmental); } if (decoded->variant.air_quality_metrics.has_pm25_environmental) { - msgPayload["pm25_e"] = new JSONValue((unsigned int)decoded->variant.air_quality_metrics.pm25_environmental); + msgPayload["pm25_e"] = + new JSONValue((unsigned int)decoded->variant.air_quality_metrics.pm25_environmental); } if (decoded->variant.air_quality_metrics.has_pm100_environmental) { - msgPayload["pm100_e"] = new JSONValue((unsigned int)decoded->variant.air_quality_metrics.pm100_environmental); + msgPayload["pm100_e"] = + new JSONValue((unsigned int)decoded->variant.air_quality_metrics.pm100_environmental); } } else if (decoded->which_variant == meshtastic_Telemetry_power_metrics_tag) { if (decoded->variant.power_metrics.has_ch1_voltage) { diff --git a/src/shutdown.h b/src/shutdown.h index 998944677..7e2120149 100644 --- a/src/shutdown.h +++ b/src/shutdown.h @@ -42,7 +42,7 @@ void powerCommandsCheck() #if defined(ARCH_ESP32) || defined(ARCH_NRF52) if (shutdownAtMsec && screen) { - screen->showOverlayBanner("Shutting Down...", 0); // stays on screen + screen->showSimpleBanner("Shutting Down...", 0); // stays on screen } #endif diff --git a/userPrefs.jsonc b/userPrefs.jsonc index 497327478..3da8e7ba6 100644 --- a/userPrefs.jsonc +++ b/userPrefs.jsonc @@ -31,6 +31,7 @@ // "USERPREFS_CONFIG_SMART_POSITION_ENABLED": "false", // "USERPREFS_CONFIG_GPS_UPDATE_INTERVAL": "600", // "USERPREFS_CONFIG_POSITION_BROADCAST_INTERVAL": "1800", + // "USERPREFS_CONFIG_DEVICE_TELEM_UPDATE_INTERVAL": "900", // Device telemetry update interval in seconds // "USERPREFS_LORACONFIG_CHANNEL_NUM": "31", // "USERPREFS_LORACONFIG_MODEM_PRESET": "meshtastic_Config_LoRaConfig_ModemPreset_SHORT_FAST", // "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 }", @@ -52,5 +53,7 @@ // "USERPREFS_MQTT_ENCRYPTION_ENABLED": "true", // "USERPREFS_MQTT_TLS_ENABLED": "false", // "USERPREFS_MQTT_ROOT_TOPIC": "event/REPLACEME", + // "USERPREFS_RINGTONE_NAG_SECS": "60", + "USERPREFS_RINGTONE_RTTTL": "24:d=32,o=5,b=565:f6,p,f6,4p,p,f6,p,f6,2p,p,b6,p,b6,p,b6,p,b6,p,b,p,b,p,b,p,b,p,b,p,b,p,b,p,b,1p.,2p.,p", "USERPREFS_TZ_STRING": "tzplaceholder " } diff --git a/variants/ELECROW-ThinkNode-M1/nicheGraphics.h b/variants/ELECROW-ThinkNode-M1/nicheGraphics.h index f3b709261..f64de9d07 100644 --- a/variants/ELECROW-ThinkNode-M1/nicheGraphics.h +++ b/variants/ELECROW-ThinkNode-M1/nicheGraphics.h @@ -56,7 +56,8 @@ void setupNicheGraphics() inkhud->setDisplayResilience(10, 1.5); // Select fonts - InkHUD::Applet::fontLarge = FREESANS_9PT_WIN1252; + InkHUD::Applet::fontLarge = FREESANS_12PT_WIN1252; + InkHUD::Applet::fontMedium = FREESANS_9PT_WIN1252; InkHUD::Applet::fontSmall = FREESANS_6PT_WIN1252; // Customize default settings @@ -103,11 +104,11 @@ void setupNicheGraphics() buttons->setHandlerDown(1, [backlight]() { backlight->peek(); }); buttons->setHandlerLongPress(1, [backlight]() { backlight->latch(); - playBeep(); + playBoop(); }); buttons->setHandlerShortPress(1, [backlight]() { backlight->off(); - playBoop(); + playChirp(); }); // Begin handling button events diff --git a/variants/diy/esp32c3_super_mini/pins_arduino.h b/variants/diy/esp32c3_super_mini/pins_arduino.h new file mode 100644 index 000000000..a325b81eb --- /dev/null +++ b/variants/diy/esp32c3_super_mini/pins_arduino.h @@ -0,0 +1,24 @@ +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include + +static const uint8_t TX = 21; +static const uint8_t RX = 20; + +static const uint8_t SDA = 1; +static const uint8_t SCL = 0; + +static const uint8_t SS = 8; +static const uint8_t MOSI = 7; +static const uint8_t MISO = 6; +static const uint8_t SCK = 10; + +static const uint8_t A0 = 0; +static const uint8_t A1 = 1; +static const uint8_t A2 = 2; +static const uint8_t A3 = 3; +static const uint8_t A4 = 4; +static const uint8_t A5 = 5; + +#endif /* Pins_Arduino_h */ diff --git a/variants/diy/esp32c3_super_mini/variant.h b/variants/diy/esp32c3_super_mini/variant.h new file mode 100644 index 000000000..48c275912 --- /dev/null +++ b/variants/diy/esp32c3_super_mini/variant.h @@ -0,0 +1,61 @@ +#ifndef _VARIANT_ESP32C3_SUPER_MINI_ +#define _VARIANT_ESP32C3_SUPER_MINI_ + +/*---------------------------------------------------------------------------- + * Headers + *----------------------------------------------------------------------------*/ + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +// I2C (Wire) & OLED +#define WIRE_INTERFACES_COUNT (1) +#define I2C_SDA (1) +#define I2C_SCL (0) + +#define USE_SSD1306 + +// GPS +#undef GPS_RX_PIN +#undef GPS_TX_PIN +#define GPS_RX_PIN (20) +#define GPS_TX_PIN (21) + +// Button +#define BUTTON_PIN (9) // BOOT button + +// LoRa +#define USE_LLCC68 +#define USE_SX1262 +// #define USE_RF95 +#define USE_SX1268 + +#define LORA_DIO0 RADIOLIB_NC +#define LORA_RESET (5) +#define LORA_DIO1 (3) +#define LORA_RXEN (2) +#define LORA_BUSY (4) +#define LORA_SCK (10) +#define LORA_MISO (6) +#define LORA_MOSI (7) +#define LORA_CS (8) + +#define SX126X_CS LORA_CS +#define SX126X_DIO1 LORA_DIO1 +#define SX126X_BUSY LORA_BUSY +#define SX126X_RESET LORA_RESET +#define SX126X_RXEN LORA_RXEN + +#define SX126X_DIO3_TCXO_VOLTAGE (1.8) +#define TCXO_OPTIONAL // make it so that the firmware can try both TCXO and XTAL + +#ifdef __cplusplus +} +#endif + +/*---------------------------------------------------------------------------- + * Arduino objects - C++ only + *----------------------------------------------------------------------------*/ + +#endif diff --git a/variants/diy/hydra/variant.h b/variants/diy/hydra/variant.h index 4c809502e..0d64c1b5e 100644 --- a/variants/diy/hydra/variant.h +++ b/variants/diy/hydra/variant.h @@ -36,8 +36,12 @@ #define SX126X_TXEN 13 // Schematic connects EBYTE module's TXEN pin to MCU #define SX126X_RXEN 14 // Schematic connects EBYTE module's RXEN pin to MCU -#define LORA_CS SX126X_CS // Compatibility with variant file configuration structure -#define LORA_SCK SX126X_SCK // Compatibility with variant file configuration structure -#define LORA_MOSI SX126X_MOSI // Compatibility with variant file configuration structure -#define LORA_MISO SX126X_MISO // Compatibility with variant file configuration structure -#define LORA_DIO1 SX126X_DIO1 // Compatibility with variant file configuration structure +#define LORA_CS SX126X_CS // Compatibility with variant file configuration structure +#define LORA_SCK SX126X_SCK // Compatibility with variant file configuration structure +#define LORA_MOSI SX126X_MOSI // Compatibility with variant file configuration structure +#define LORA_MISO SX126X_MISO // Compatibility with variant file configuration structure +#define LORA_DIO1 SX126X_DIO1 // Compatibility with variant file configuration structure +#define LORA_TXEN SX126X_TXEN // Compatibility with variant file configuration structure +#define LORA_RXEN SX126X_RXEN // Compatibility with variant file configuration structure +#define LORA_RESET SX126X_RESET // Compatibility with variant file configuration structure +#define LORA_DIO2 SX126X_BUSY // Compatibility with variant file configuration structure \ No newline at end of file diff --git a/variants/diy/nrf52_promicro_diy_tcxo/nicheGraphics.h b/variants/diy/nrf52_promicro_diy_tcxo/nicheGraphics.h index bbd530595..8f30a244f 100644 --- a/variants/diy/nrf52_promicro_diy_tcxo/nicheGraphics.h +++ b/variants/diy/nrf52_promicro_diy_tcxo/nicheGraphics.h @@ -55,8 +55,9 @@ void setupNicheGraphics() // Set how many FAST updates per FULL update. inkhud->setDisplayResilience(INKHUD_BUILDCONF_DISPLAYRESILIENCE); // Suggest roughly ten - // Prepare fonts - InkHUD::Applet::fontLarge = FREESANS_9PT_WIN1252; + // Select fonts + InkHUD::Applet::fontLarge = FREESANS_12PT_WIN1252; + InkHUD::Applet::fontMedium = FREESANS_9PT_WIN1252; InkHUD::Applet::fontSmall = FREESANS_6PT_WIN1252; // Init settings, and customize defaults diff --git a/variants/diy/platformio.ini b/variants/diy/platformio.ini index 153796daf..1f0f6d126 100644 --- a/variants/diy/platformio.ini +++ b/variants/diy/platformio.ini @@ -96,6 +96,20 @@ board_level = extra build_flags = ${env:seeed_xiao_nrf52840_kit.build_flags} -D PRIVATE_HW -DXIAO_BLE_LEGACY_PINOUT -DEBYTE_E22 -DEBYTE_E22_900M30S build_unflags = -DGPS_L76K +; Seeed XIAO nRF52840 + EBYTE E22-900M30S - Pinout matching Wio-SX1262 (SKU 113010003) +[env:seeed_xiao_nrf52840_e22_900m30s] +extends = env:seeed_xiao_nrf52840_kit +board_level = extra +build_flags = ${env:seeed_xiao_nrf52840_kit.build_flags} -D PRIVATE_HW -DEBYTE_E22 -DEBYTE_E22_900M30S +build_unflags = -DGPS_L76K + +; Seeed XIAO nRF52840 + EBYTE E22-900M33S - Pinout matching Wio-SX1262 (SKU 113010003) +[env:seeed_xiao_nrf52840_e22_900m33s] +extends = env:seeed_xiao_nrf52840_kit +board_level = extra +build_flags = ${env:seeed_xiao_nrf52840_kit.build_flags} -D PRIVATE_HW -DEBYTE_E22 -DEBYTE_E22_900M33S +build_unflags = -DGPS_L76K + ; Seeed XIAO nRF52840 + XIAO Wio SX1262 DIY [env:seeed-xiao-nrf52840-wio-sx1262] board = xiao_ble_sense @@ -127,3 +141,16 @@ build_flags = -D ARDUINO_USB_MODE=0 -D ARDUINO_USB_CDC_ON_BOOT=1 -I variants/diy/t-energy-s3_e22 + +; ESP32 C3 Super Mini Development Board +; https://www.espboards.dev/esp32/esp32-c3-super-mini/ +[env:esp32c3_super_mini] +extends = esp32c3_base +board = esp32-c3-devkitm-1 +build_flags = + ${esp32_base.build_flags} + -D PRIVATE_HW + -I variants/diy/esp32c3_super_mini + -D ARDUINO_USB_MODE=1 + -D ARDUINO_USB_CDC_ON_BOOT=1 +board_level = extra diff --git a/variants/diy/xiao_ble/README.md b/variants/diy/xiao_ble/README.md index 2a08138ba..fe6dcba2d 100644 --- a/variants/diy/xiao_ble/README.md +++ b/variants/diy/xiao_ble/README.md @@ -1,264 +1,168 @@ -# +# XIAO nrf52840/nrf52840 Sense + Ebyte E22-900M30S -

- Xiao BLE/BLE Sense + Ebyte E22-900M30S -

- -

- A step-by-step guide for macOS and Linux -

+_A step-by-step guide for macOS and Linux._ ## Introduction -This guide will walk you through everything needed to get the Xiao BLE (or BLE Sense) running Meshtastic using an Ebyte E22-900M30S LoRa module. The combination of the E22 with an nRF52840 MCU is desirable because it allows for both very low idle (Rx) power draw and high transmit power. The Xiao BLE is a small but surprisingly well-appointed nRF52840 board, with enough GPIO for most Meshtastic applications and a built-in LiPo charger. The E22, on the other hand, is a famously inscrutable and mysterious beast. It is one of the more readily available LoRa modules capable of transmitting at 30 dBm, and includes an LNA to boost its Rx sensitivity a few dB beyond that of the SX1262. However, its documentation is relatively sparse overall, and seems to merely hint at (or completely omit) several key details regarding its functionality. Thus, much of what follows is a synthesis of my observations and inferences over the course of many hours of trial and error. +This guide will walk you through everything needed to get the XIAO nrf52840 (or XIAO nrf52840 Sense) running Meshtastic using an Ebyte E22-900M30S LoRa module. The combination of the E22 with an nRF52840 MCU is desirable because it allows for both very low idle (Rx) power draw _and_ high transmit power. -

Acknowledgement and friendly disclaimer

+The XIAO nrf52840 is a small but surprisingly well-appointed nRF52840 board, with enough GPIO for most Meshtastic applications and a built-in LiPo charger. + +The E22, on the other hand, is a famously inscrutable and mysterious beast. It is one of the more readily available LoRa modules capable of transmitting at 30 dBm, and includes an LNA to boost its Rx sensitivity a few dB beyond that of the SX1262. + +However, its documentation is relatively sparse overall, and seems to merely hint at (or completely omit) several key details regarding its functionality. Thus, much of what follows is a synthesis of my observations and inferences over the course of many hours of trial and error. + +### Acknowledgement and Friendly Disclaimer Huge thanks to those in the community who have forged the way with the E22, without whose hard work none of this would have been possible! (thebentern, riddick, rainer_vie, beegee-tokyo, geeksville, caveman99, Der_Bear, PlumRugOfDoom, BigCorvus, and many others.) -
- Please take the conclusions here as a tentative work in progress, representing my current (and fairly limited) understanding of the E22 when paired with this particular MCU. It is my hope that this guide will be helpful to others who are interested in trying a DIY Meshtastic build, and also be subject to revision by folks with more experience and better test equipment. -### Obligatory liability disclaimer +### Obligatory Liability Disclaimer This guide and all associated content is for informational purposes only. The information presented is intended for consumption only by persons having appropriate technical skill and judgement, to be used entirely at their own discretion and risk. The authors of this guide in no way provide any warranty, express or implied, toward the content herein, nor its correctness, safety, or suitability to any particular purpose. By following the instructions in this guide in part or in full, you assume all responsibility for all potential risks, including but not limited to fire, property damage, bodily injury, and death. -### Note +## 1. Wire the board -These instructions assume you are running macOS or Linux, but it should be relatively easy to translate each command for Windows. (In this case, in step 2 below, each line of `xiao_ble.sh` would also need to be converted to the equivalent Windows CLI command and run individually.) +Connecting the E22 to the XIAO nrf52840 is straightforward, but there are a few gotchas to be mindful of. -## 1. Update Bootloader +### On the XIAO nrf52840 -The first thing you will need to do is update the Xiao BLE's bootloader. The stock bootloader is functionally very similar to the Adafruit nRF52 UF2 bootloader, but apparently not quite enough so to work with Meshtastic out of the box. +- Pins D4 and D5 are currently mapped to `PIN_WIRE_SDA` and `PIN_WIRE_SCL`, respectively. If you are not using I²C and would like to free up pins D4 and D5 for use as GPIO, `PIN_WIRE_SDA` and `PIN_WIRE_SCL` can be reassigned to any two other unused pin numbers. +- Pins D6 and D7 were originally mapped to the TX and RX pins for serial interface 1 (`PIN_SERIAL1_RX` and `PIN_SERIAL1_TX`) but are currently set to -1 in `variant.h`. If you need to expose a serial interface, you can restore these pins and move e.g. `SX126X_RXEN` to pin 4 or 5 (the opposite should work too). -1. Connect the Xiao BLE to your computer via USB-C. +### On the E22 -2. Install `adafruit-nrfutil` by following the instructions here. +- There are two options for the E22's `TXEN` pin: + 1. It can be connected to the MCU on the pin defined as `SX126X_TXEN` in `variant.h`. In this configuration, the MCU will control Tx/Rx switching "manually". As long as `SX126X_TXEN` and `SX126X_RXEN` are both defined in `variant.h` (and neither is set to `RADIOLIB_NC`), `SX126xInterface.cpp` will initialize the E22 correctly for this mode. + 2. Alternately, it can be connected to the E22's `DIO2` pin only, with neither `TXEN` nor `DIO2` being connected to the MCU. In this configuration, the E22 will control Tx/Rx switching automatically. In `variant.h`, as long as `SX126X_TXEN` is defined as `RADIOLIB_NC`, and `SX126X_RXEN` is defined and connected to the E22's `RXEN` pin, and `E22_TXEN_CONNECTED_TO_DIO2` is defined, `SX126xInterface.cpp` will initialize the E22 correctly for this mode. This configuration frees up a GPIO, and presents no drawbacks that I have found. +- Note that any combination other than the two described above will likely result in unexpected behavior. In my testing, some of these other configurations appeared to "work" at first glance, but every one I tried had at least one of the following flaws: weak Tx power, extremely poor Rx sensitivity, or the E22 overheating because TXEN was never pulled low, causing its PA to stay on indefinitely. +- Along the same lines, it is a good idea to check the E22's temperature frequently by lightly touching the shield. If you feel the shield getting hot (i.e. approaching uncomfortable to touch) near pins 1, 2, and 3, something is probably misconfigured; disconnect both the XIAO nrf52840 and E22 from power and double check wiring and pin mapping. +- Whether you opt to let the E22 control Rx and Tx or handle this manually, **the E22's `RXEN` pin must always be connected to the MCU** on the pin defined as `SX126X_RXEN` in `variant.h`. -3. Open a terminal window and navigate to `firmware/variants/xiao_ble` (where `firmware` is the directory into which you have cloned the Meshtastic firmware repo). +#### Note -4. Run the following command, replacing `/dev/cu.usbmodem2101` with the serial port your Xiao BLE is connected to: +The default pin mapping in `variant.h` uses "Automatic Tx/Rx switching" mode. - ```bash - adafruit-nrfutil --verbose dfu serial --package xiao_nrf52840_ble_bootloader-0.7.0-22-g277a0c8_s140_7.3.0.zip --port /dev/cu.usbmodem2101 -b 115200 --singlebank --touch 1200 - ``` +If you wire your board for Manual Tx/Rx Switching Mode, `SX126X_TXEN` must be defined (`#define #define SX126X_TXEN D6`) in `variants/seeed_xiao_nrf52840_kit/variant.h` in the code block following: -5. If all goes well, the Xiao BLE's red LED should start to pulse slowly, and you should see a new USB storage device called `XIAO-BOOT` appear under `Locations` in Finder. +```c +#ifdef XIAO_BLE_LEGACY_PINOUT +// Legacy xiao_ble variant pinout for third-party SX126x modules e.g. EBYTE E22 +``` -  +### Example Wiring for Automatic Tx/Rx Switching Mode -## 2. PlatformIO Environment Preparation +#### MCU -> E22 Connections -Before building Meshtastic for the Xiao BLE + E22, it is necessary to pull in SoftDevice 7.3.0 and its associated linker script (nrf52840_s140_v7.ld) from Seeed Studio's Arduino core. The `xiao_ble.sh` script does this. +| XIAO nrf52840 pin | variant.h definition | E22 pin | Notes | +| :---------------- | :------------------- | :-------- | :------------------------------------------------------------------------------------------------------------------- | +| D0 | SX126X_CS | 19 (NSS) | | +| D1 | SX126X_DIO1 | 13 (DIO1) | | +| D2 | SX126X_BUSY | 14 (BUSY) | | +| D3 | SX126X_RESET | 15 (NRST) | | +| D7 | SX126X_RXEN | 6 (RXEN) | These pins must still be connected, and `SX126X_RXEN` defined in `variant.h`, otherwise Rx sensitivity will be poor. | +| D8 | PIN_SPI_SCK | 18 (SCK) | | +| D9 | PIN_SPI_MISO | 16 (MISO) | | +| D10 | PIN_SPI_MOSI | 17 (MOSI) | | -1. In your terminal window, run the following command: - - ```bash - sudo ./xiao_ble.sh - ``` - -  - -## 3. Build Meshtastic - -At this point, you should be able to build the firmware successfully. - -1. In VS Code, press `Command Shift P` to bring up the command palette. - -2. Search for and run the `Developer: Reload Window` command. - -3. Bring up the command palette again with `Command Shift P`. Search for and run the `PlatformIO: Pick Project Environment` command. - -4. In the list of environments, select `env:xiao_ble`. PlatformIO may update itself for a minute or two, and should let you know once done. - -5. Return to the command palette once again (`Command Shift P`). Search for and run the `PlatformIO: Build` command. - -6. PlatformIO will build the project. After a few minutes you should see a green `SUCCESS` message. - -  - -## 4. Wire the board - -Connecting the E22 to the Xiao BLE is straightforward, but there are a few gotchas to be mindful of. - -- On the Xiao BLE: - - - Pins D4 and D5 are currently mapped to `PIN_WIRE_SDA` and `PIN_WIRE_SCL`, respectively. If you are not using I²C and would like to free up pins D4 and D5 for use as GPIO, `PIN_WIRE_SDA` and `PIN_WIRE_SCL` can be reassigned to any two other unused pin numbers. - - - Pins D6 and D7 were originally mapped to the TX and RX pins for serial interface 1 (`PIN_SERIAL1_RX` and `PIN_SERIAL1_TX`) but are currently set to -1 in `variant.h`. If you need to expose a serial interface, you can restore these pins and move e.g. `SX126X_RXEN` to pin 4 or 5 (the opposite should work too). - -- On the E22: - - - There are two options for the E22's `TXEN` pin: - - 1. It can be connected to the MCU on the pin defined as `SX126X_TXEN` in `variant.h`. In this configuration, the MCU will control Tx/Rx switching "manually". As long as `SX126X_TXEN` and `SX126X_RXEN` are both defined in `variant.h` (and neither is set to `RADIOLIB_NC`), `SX126xInterface.cpp` will initialize the E22 correctly for this mode. - - 2. Alternately, it can be connected to the E22's `DIO2` pin only, with neither `TXEN` nor `DIO2` being connected to the MCU. In this configuration, the E22 will control Tx/Rx switching automatically. In `variant.h`, as long as `SX126X_TXEN` is defined as `RADIOLIB_NC`, and `SX126X_RXEN` is defined and connected to the E22's `RXEN` pin, and `E22_TXEN_CONNECTED_TO_DIO2` is defined, `SX126xInterface.cpp` will initialize the E22 correctly for this mode. This configuration frees up a GPIO, and presents no drawbacks that I have found. - - - Note that any combination other than the two described above will likely result in unexpected behavior. In my testing, some of these other configurations appeared to "work" at first glance, but every one I tried had at least one of the following flaws: weak Tx power, extremely poor Rx sensitivity, or the E22 overheating because TXEN was never pulled low, causing its PA to stay on indefinitely. - - - Along the same lines, it is a good idea to check the E22's temperature frequently by lightly touching the shield. If you feel the shield getting hot (i.e. approaching uncomfortable to touch) near pins 1, 2, and 3, something is probably misconfigured; disconnect both the Xiao BLE and E22 from power and double check wiring and pin mapping. - - - Whether you opt to let the E22 control Rx and Tx or handle this manually, the E22's `RXEN` pin must always be connected to the MCU on the pin defined as `SX126X_RXEN` in `variant.h`. - -

Note

- -The default pin mapping in `variant.h` uses 'automatic Tx/Rx switching' mode. If you wire your board for manual Rx/Tx switching, make sure to update `variant.h` accordingly by commenting/uncommenting the necessary lines in the 'E22 Tx/Rx control options' section. - -  - ---- - -  - -

Example wiring for "E22 automatic Tx/Rx switching" mode:

-  - -MCU -> E22 connections - -| Xiao BLE pin | variant.h definition | E22 pin | Notes | -| :----------- | :------------------- | :-------- | :------------------------------------------------------------------------------------------------------------------- | -| D0 | SX126X_CS | 19 (NSS) | | -| D1 | SX126X_DIO1 | 13 (DIO1) | | -| D2 | SX126X_BUSY | 14 (BUSY) | | -| D3 | SX126X_RESET | 15 (NRST) | | -| D7 | SX126X_RXEN | 6 (RXEN) | These pins must still be connected, and `SX126X_RXEN` defined in `variant.h`, otherwise Rx sensitivity will be poor. | -| D8 | PIN_SPI_SCK | 18 (SCK) | | -| D9 | PIN_SPI_MISO | 16 (MISO) | | -| D10 | PIN_SPI_MOSI | 17 (MOSI) | | - -  -  - -E22 -> E22 connections: +#### E22 -> E22 Connections | E22 pin | E22 pin | Notes | | :------ | :------ | :------------------------------------------------------------------------ | | TXEN | DIO2 | These must be physically connected for automatic Tx/Rx switching to work. | -

Note

+#### Note The schematic (`xiao-ble-e22-schematic.png`) in the `eagle-project` directory uses this wiring. -  +### Example Wiring for Manual Tx/Rx Switching Mode ---- +#### MCU -> E22 Connections -  +| XIAO nrf52840 pin | variant.h definition | E22 pin | Notes | +| :---------------- | :------------------- | :-------- | :---- | +| D0 | SX126X_CS | 19 (NSS) | | +| D1 | SX126X_DIO1 | 13 (DIO1) | | +| D2 | SX126X_BUSY | 14 (BUSY) | | +| D3 | SX126X_RESET | 15 (NRST) | | +| D6 | SX126X_TXEN | 7 (TXEN) | | +| D7 | SX126X_RXEN | 6 (RXEN) | | +| D8 | PIN_SPI_SCK | 18 (SCK) | | +| D9 | PIN_SPI_MISO | 16 (MISO) | | +| D10 | PIN_SPI_MOSI | 17 (MOSI) | | -

Example wiring for "Manual Tx/Rx switching" mode:

+#### E22 -> E22 connections -MCU -> E22 connections +_(none)_ -| Xiao BLE pin | variant.h definition | E22 pin | Notes | -| :----------- | :------------------- | :-------- | :---- | -| D0 | SX126X_CS | 19 (NSS) | | -| D1 | SX126X_DIO1 | 13 (DIO1) | | -| D2 | SX126X_BUSY | 14 (BUSY) | | -| D3 | SX126X_RESET | 15 (NRST) | | -| D6 | SX126X_TXEN | 7 (TXEN) | | -| D7 | SX126X_RXEN | 6 (RXEN) | | -| D8 | PIN_SPI_SCK | 18 (SCK) | | -| D9 | PIN_SPI_MISO | 16 (MISO) | | -| D10 | PIN_SPI_MOSI | 17 (MOSI) | | +## 2. Build Meshtastic -E22 -> E22 connections: (none) +1. Follow the [Building Meshtastic Firmware](https://meshtastic.org/docs/development/firmware/build/) documentation, stop after **Build** → **Step 2** +2. For **Build** → **Step 3**, select `xiao_ble` as your target +3. Adjust source code if you: + - Wired your board for Manual Tx/Rx Switching Mode: see [Wire the Board](#1-wire-the-board) + - Used an E22-900M33S module + (this step is important to avoid **damaging the power amplifier** in the M33S module and **transmitting power above legal limits**!): + 1. Open `variants/diy/platformio.ini` + 2. Search for `[env:xiao_ble]` + 3. In the line starting with `build_flags` within this section, change `-DEBYTE_E22_900M30S` to `-DEBYTE_E22_900M33S` +4. Follow **Build** → **Step 4** to build the firmware +5. Stop here, because the **PlatformIO: Upload** step does not work for factory-fresh XIAO nrf52840 (the automatic reset to bootloader only works if Meshtastic firmware is already running) +6. The built `firmware.uf2` binary can be found in the folder `.pio/build/xiao_ble/firmware.uf2` (relative to where you cloned the Git repository to), we will need it for [flashing the firmware](#3-flash-the-firmware-to-the-xiao-nrf52840) (manually) -  +## 3. Flash the Firmware to the XIAO nrf52840 -## 5. Flash the firmware to the Xiao BLE +1. Double press the XIAO nrf52840's `reset` button to put it in bootloader mode, and a USB volume named `XIAO SENSE` will appear +2. Copy the `firmware.uf2` file to the `XIAO SENSE` volume (refer to the last step of [Build Meshtastic](#2-build-meshtastic)) +3. The XIAO nrf52840's red LED will flash for several seconds as the firmware is copied +4. Once Meshtastic firmware succesfully boots, the: + 1. Green LED will turn on + 2. Red LED will flash several times to indicate flash memory writes during initial settings file creation + 3. Green LED will blink every second once the firmware is running normally +5. If you do not see the above LED patters, proceed to [Troubleshooting](#4-troubleshooting) -1. Double press the Xiao's `reset` button to put it in bootloader mode. -2. In a terminal window, navigate to the Meshtastic firmware repo's root directory, and from there to `.pio/build/xiao_ble`. -3. Convert the generated `.hex` file into a `.uf2` file: - - ```bash - ../../../bin/uf2conv.py firmware.hex -c -o firmware.uf2 -f 0xADA52840 - ``` - -4. Copy the new `.uf2` file to the Xiao's mass storage volume: - - ```bash - cp firmware.uf2 /Volumes/XIAO-BOOT - ``` - -5. The Xiao's red LED will flash for several seconds as the firmware is copied. -6. Once the firmware is copied, to verify it is running, run the following command: - - ```bash - meshtastic --noproto - ``` - -7. Then, press the Xiao's `reset` button again. You should see a lot of debug output logged in the terminal window. - -  - -## 6. Troubleshooting - -- If after flashing Meshtastic, the Xiao is bootlooped, look at the serial output (you can see this by running `meshtastic --noproto` with the device connected to your computer via USB). +## 4. Troubleshooting +- If after flashing Meshtastic, the XIAO is bootlooped, look at the serial output (you can see this by running `meshtastic --noproto` with the device connected to your computer via USB). - If you see that the SX1262 init result was -2, this likely indicates a wiring problem; double check your wiring and pin mapping in `variant.h`. - - - If you see an error mentioning tinyFS, this may mean you need to reformat the Xiao's storage: - - 1. Double press the `reset` button to put the Xiao in bootloader mode. - - 2. In a terminal window, navigate to the Meshtastic firmware repo's root directory, and from there to `variants/xiao_ble`. - - 3. Run the following command:  `cp xiao-ble-internal-format.uf2 /Volumes/XIAO-BOOT` - - 4. The Xiao's red LED will flash briefly as the filesystem format firmware is copied. - - 5. Run the following command:  `meshtastic --noproto` - - 6. In the output of the above command, you should see a message saying "Formatting...done". - - 7. To flash Meshtastic again, repeat the steps in section 5 above. - + - If you see an error mentioning tinyFS, this may mean you need to reformat the XIAO's storage: + 1. Open the [Meshtastic web flasher](https://flasher.meshtastic.org/) + 2. Select the **_Seeed XIAO NRF52840 Kit_** + 3. Click the **_trash can icon_** to the right of **_Flash_** + 4. Follow the instructions on the screen + **Do not flash the Seeed XIAO NRF52840 Kit firmware** if you have wired the LoRa module according to this variant, as the Seeed XIAO NRF52840 Kit uses different wiring for the SX1262 LoRa chip - If you don't see any specific error message, but the boot process is stuck or not proceeding as expected, this might also mean there is a conflict in `variant.h`. If you have made any changes to the pin mapping, ensure they do not result in a conflict. If all else fails, try reverting your changes and using the known-good configuration included here. - - The above might also mean something is wired incorrectly. Try reverting to one of the known-good example wirings in section 4. - - If the E22 gets hot to the touch: - - The power amplifier is likely running continually. Disconnect it and the Xiao from power immediately, and double check wiring and pin mapping. In my experimentation this occurred in cases where TXEN was inadvertenly high (usually due to a pin mapping conflict). + - The power amplifier is likely running continually. Disconnect it and the XIAO from power immediately, and double check wiring and pin mapping. In my experimentation this occurred in cases where TXEN was inadvertenly high (usually due to a pin mapping conflict). -  +## 5. Notes -## 7. Notes +- **Transmit Power** + - There is a power amplifier after the SX1262's Tx, so the actual Tx power is just over 7 dB greater than the SX1262's set Tx power (the E22-900M30S actually tops out just over 29dB at 5V according to the datasheet) + - Meshtastic firmware is aware of the gain of the E22-900M30S module, so the Meshtastic clients' Tx power setting reflects the actual output power, i.e. setting 30 dBm in the Meshtastic app programs the E22 module to correctly output 30 dBm, setting 24 dBm will output 24 dBm, etc. +- **Adequate 5V Power Supply to the E22 Module** + - Have a bypass capacitor from its 5V supply to ground; 100 µF works well + - Voltage must be between 5V–5.5V, lower supply voltage results in less output power; for example, with a fully charged LiPo at 4.2V, Tx power appears to max out around 26-27 dBm -- There are several anecdotal recommendations regarding the Tx power the E22's internal SX1262 should be set to in order to achieve the advertised output of 30 dBm, ranging from 4 (per this article in the RadioLib github repo) to 22 (per this conversation from the Meshtastic Discord). When paired with the Xiao BLE in the configurations described above, I observed that the output is at its maximum when Tx power is set to 22. +### Additional Reading -- To achieve its full output, the E22 should have a bypass capacitor from its 5V supply to ground. 100 µF works well. +- [S5NC/CDEBYTE_Modules](https://github.com/S5NC/CDEBYTE_Modules) has additional information about EBYTE E22 modules' internal workings, including photographs +- [RadioLib High power Radio Modules Guide](https://github.com/jgromes/RadioLib/wiki/High-power-Radio-Modules-Guide) -- The E22 will happily run on voltages lower than 5V, but the full output power will not be realized. For example, with a fully charged LiPo at 4.2V, Tx power appears to max out around 26-27 dBm. - -  - -## 8. Testing Methodology +## 6. Testing Methodology During what became a fairly long trial-and-error process, I did a lot of careful testing of Tx power and Rx sensitivity. My methodology in these tests was as follows: - All tests were conducted between two nodes: - - 1. The Xiao BLE + E22 coupled with an Abracon ARRKP4065-S915A ceramic patch antenna - - 2. A RAK 5005/4631 coupled with a Laird MA9-5N antenna via a 4" U.FL to Type N pigtail. - + 1. The XIAO nrf52840 + E22 coupled with an [Abracon ARRKP4065-S915A](https://www.digikey.com/en/products/detail/abracon-llc/ARRKP4065-S915A/8593263") ceramic patch antenna + 2. A RAK 5005/4631 coupled with a [Laird MA9-5N](https://www.streakwave.com/laird-technologies-ma9-5n-55dbi-900mhz-mobile-omni-select-mount) antenna via a 4" U.FL to Type N pigtail. - No other nodes were powered up onsite or nearby. - -
- - Each node and its antenna was kept in exactly the same position and orientation throughout testing. - - Other environmental factors (e.g. the location and resting position of my body in the room while testing) were controlled as carefully as possible. - - Each test comprised at least five (and often ten) runs, after which the results were averaged. - - All testing was done by sending single-character messages between nodes and observing the received RSSI reported in the message acknowledgement. Messages were sent one by one, waiting for each to be acknowledged or time out before sending the next. - -- The E22's Tx power was observed by sending messages from the RAK to the Xiao BLE + E22 and recording the received RSSI. - -- The opposite was done to observe the E22's Rx sensitivity: messages were sent from the Xiao BLE + E22 to the RAK, and the received RSSI was recorded. - -While this cannot match the level of accuracy achievable with actual test equipment in a lab setting, it was nonetheless sufficient to demonstrate the (sometimes very large) differences in Tx power and Rx sensitivity between various configurations. +- The E22's Tx power was observed by sending messages from the RAK to the XIAO nrf52840 + E22 and recording the received RSSI. +- The opposite was done to observe the E22's Rx sensitivity: messages were sent from the XIAO nrf52840 + E22 to the RAK, and the received RSSI was recorded. + While this cannot match the level of accuracy achievable with actual test equipment in a lab setting, it was nonetheless sufficient to demonstrate the (sometimes very large) differences in Tx power and Rx sensitivity between various configurations. diff --git a/variants/elecrow_panel/platformio.ini b/variants/elecrow_panel/platformio.ini index 5bce58208..de7f28a83 100644 --- a/variants/elecrow_panel/platformio.ini +++ b/variants/elecrow_panel/platformio.ini @@ -79,6 +79,7 @@ build_flags = -D SPI_FREQUENCY=80000000 -D LGFX_SCREEN_WIDTH=240 -D LGFX_SCREEN_HEIGHT=320 + -D DISPLAY_SIZE=320x240 ; landscape mode -D LGFX_PANEL=ST7789 -D LGFX_ROTATION=1 -D LGFX_CFG_HOST=SPI2_HOST @@ -103,6 +104,7 @@ build_flags = -D SPI_FREQUENCY=60000000 -D LGFX_SCREEN_WIDTH=320 -D LGFX_SCREEN_HEIGHT=480 + -D DISPLAY_SIZE=320x480 ; portrait mode -D LGFX_PANEL=ILI9488 -D LGFX_ROTATION=0 -D LGFX_CFG_HOST=SPI2_HOST @@ -126,3 +128,4 @@ extends = crowpanel_large_esp32s3_base build_flags = ${crowpanel_large_esp32s3_base.build_flags} -D VIEW_320x240 + -D DISPLAY_SIZE=800x480 ; landscape mode diff --git a/variants/heltec_mesh_node_t114-inkhud/nicheGraphics.h b/variants/heltec_mesh_node_t114-inkhud/nicheGraphics.h index fe1c281bf..b6be70ff4 100644 --- a/variants/heltec_mesh_node_t114-inkhud/nicheGraphics.h +++ b/variants/heltec_mesh_node_t114-inkhud/nicheGraphics.h @@ -56,8 +56,9 @@ void setupNicheGraphics() // Set how many FAST updates per FULL update. inkhud->setDisplayResilience(INKHUD_BUILDCONF_DISPLAYRESILIENCE); // Suggest roughly ten - // Prepare fonts - InkHUD::Applet::fontLarge = FREESANS_9PT_WIN1252; + // Select fonts + InkHUD::Applet::fontLarge = FREESANS_12PT_WIN1252; + InkHUD::Applet::fontMedium = FREESANS_9PT_WIN1252; InkHUD::Applet::fontSmall = FREESANS_6PT_WIN1252; // Init settings, and customize defaults diff --git a/variants/heltec_mesh_node_t114/variant.h b/variants/heltec_mesh_node_t114/variant.h index 798c3538a..f4f0baf13 100644 --- a/variants/heltec_mesh_node_t114/variant.h +++ b/variants/heltec_mesh_node_t114/variant.h @@ -57,6 +57,9 @@ extern "C" { #define TFT_OFFSET_X 0 #define TFT_OFFSET_Y 0 +// T114 gets a muted yellow on black display +#define TFT_MESH_OVERRIDE COLOR565(255, 255, 128) + // #define TFT_OFFSET_ROTATION 0 // #define SCREEN_ROTATE // #define SCREEN_TRANSITION_FRAMERATE 5 diff --git a/variants/heltec_mesh_pocket/nicheGraphics.h b/variants/heltec_mesh_pocket/nicheGraphics.h index 271a35d6d..f8202debb 100644 --- a/variants/heltec_mesh_pocket/nicheGraphics.h +++ b/variants/heltec_mesh_pocket/nicheGraphics.h @@ -50,7 +50,8 @@ void setupNicheGraphics() inkhud->setDisplayResilience(10, 1.5); // Select fonts - InkHUD::Applet::fontLarge = FREESANS_9PT_WIN1252; + InkHUD::Applet::fontLarge = FREESANS_12PT_WIN1252; + InkHUD::Applet::fontMedium = FREESANS_9PT_WIN1252; InkHUD::Applet::fontSmall = FREESANS_6PT_WIN1252; // Customize default settings diff --git a/variants/heltec_vision_master_e213/einkDetect.h b/variants/heltec_vision_master_e213/einkDetect.h new file mode 100644 index 000000000..35140db60 --- /dev/null +++ b/variants/heltec_vision_master_e213/einkDetect.h @@ -0,0 +1,35 @@ +#pragma once + +#include "configuration.h" + +enum class EInkDetectionResult : uint8_t { + LCMEN213EFC1 = 0, // Initial version + E0213A367 = 1, // E213 PCB marked V1.1 (Mid 2025) +}; + +EInkDetectionResult detectEInk() +{ + // Test 1: Logic of BUSY pin + + // Determines controller IC manufacturer + // Fitipower: busy when LOW + // Solomon Systech: busy when HIGH + + // Force display BUSY by holding reset pin active + pinMode(PIN_EINK_RES, OUTPUT); + digitalWrite(PIN_EINK_RES, LOW); + + delay(10); + + // Read whether pin is HIGH or LOW while busy + pinMode(PIN_EINK_BUSY, INPUT); + bool busyLogic = digitalRead(PIN_EINK_BUSY); + + // Test complete. Release pin + pinMode(PIN_EINK_RES, INPUT); + + if (busyLogic == LOW) + return EInkDetectionResult::LCMEN213EFC1; + else // busy HIGH + return EInkDetectionResult::E0213A367; +} \ No newline at end of file diff --git a/variants/heltec_vision_master_e213/nicheGraphics.h b/variants/heltec_vision_master_e213/nicheGraphics.h index 26f393f6c..1b1291424 100644 --- a/variants/heltec_vision_master_e213/nicheGraphics.h +++ b/variants/heltec_vision_master_e213/nicheGraphics.h @@ -18,16 +18,22 @@ // Shared NicheGraphics components // -------------------------------- +#include "graphics/niche/Drivers/EInk/E0213A367.h" #include "graphics/niche/Drivers/EInk/LCMEN2R13EFC1.h" #include "graphics/niche/Inputs/TwoButton.h" -// Button feedback -#include "buzz.h" +#include "buzz.h" // Button feedback +#include "einkDetect.h" // Detect display model at runtime void setupNicheGraphics() { using namespace NicheGraphics; + // Detect E-Ink Model + // ------------------- + + EInkDetectionResult displayModel = detectEInk(); + // SPI // ----------------------------- @@ -38,7 +44,13 @@ void setupNicheGraphics() // E-Ink Driver // ----------------------------- - Drivers::EInk *driver = new Drivers::LCMEN213EFC1; + Drivers::EInk *driver; + + if (displayModel == EInkDetectionResult::LCMEN213EFC1) // V1 (unmarked) + driver = new Drivers::LCMEN213EFC1; + else if (displayModel == EInkDetectionResult::E0213A367) // V1.1 + driver = new Drivers::E0213A367; + driver->begin(hspi, PIN_EINK_DC, PIN_EINK_CS, PIN_EINK_BUSY, PIN_EINK_RES); // InkHUD @@ -51,10 +63,15 @@ void setupNicheGraphics() // Set how many FAST updates per FULL update // Set how unhealthy additional FAST updates beyond this number are - inkhud->setDisplayResilience(10, 1.5); + + if (displayModel == EInkDetectionResult::LCMEN213EFC1) // V1 (unmarked) + inkhud->setDisplayResilience(10, 1.5); + else if (displayModel == EInkDetectionResult::E0213A367) // V1.1 + inkhud->setDisplayResilience(15, 3); // Select fonts - InkHUD::Applet::fontLarge = FREESANS_9PT_WIN1252; + InkHUD::Applet::fontLarge = FREESANS_12PT_WIN1252; + InkHUD::Applet::fontMedium = FREESANS_9PT_WIN1252; InkHUD::Applet::fontSmall = FREESANS_6PT_WIN1252; // Customize default settings @@ -90,7 +107,7 @@ void setupNicheGraphics() buttons->setWiring(1, PIN_BUTTON2); buttons->setHandlerShortPress(1, [inkhud]() { inkhud->nextTile(); - playBoop(); + playChirp(); }); // Begin handling button events diff --git a/variants/heltec_vision_master_e213/platformio.ini b/variants/heltec_vision_master_e213/platformio.ini index 34cebb6e3..028caaeff 100644 --- a/variants/heltec_vision_master_e213/platformio.ini +++ b/variants/heltec_vision_master_e213/platformio.ini @@ -7,7 +7,8 @@ build_flags = -Ivariants/heltec_vision_master_e213 -DHELTEC_VISION_MASTER_E213 -DUSE_EINK - -DEINK_DISPLAY_MODEL=GxEPD2_213_FC1 + -DGXEPD2_DRIVER_0=GxEPD2_213_FC1 + -DGXEPD2_DRIVER_1=GxEPD2_213_E0213A367 -DEINK_WIDTH=250 -DEINK_HEIGHT=122 -DUSE_EINK_DYNAMICDISPLAY ; Enable Dynamic EInk @@ -16,7 +17,7 @@ build_flags = -DEINK_HASQUIRK_GHOSTING ; Display model is identified as "prone to ghosting" lib_deps = ${esp32s3_base.lib_deps} - https://github.com/meshtastic/GxEPD2/archive/b202ebfec6a4821e098cf7a625ba0f6f2400292d.zip + https://github.com/meshtastic/GxEPD2/archive/1655054ba298e0e29fc2044741940f927f9c2a43.zip lewisxhe/PCF8563_Library@^1.0.1 upload_speed = 115200 diff --git a/variants/heltec_vision_master_e290/nicheGraphics.h b/variants/heltec_vision_master_e290/nicheGraphics.h index f3cf6355e..61b08c740 100644 --- a/variants/heltec_vision_master_e290/nicheGraphics.h +++ b/variants/heltec_vision_master_e290/nicheGraphics.h @@ -67,7 +67,8 @@ void setupNicheGraphics() inkhud->setDisplayResilience(7, 1.5); // Select fonts - InkHUD::Applet::fontLarge = FREESANS_9PT_WIN1252; + InkHUD::Applet::fontLarge = FREESANS_12PT_WIN1252; + InkHUD::Applet::fontMedium = FREESANS_9PT_WIN1252; InkHUD::Applet::fontSmall = FREESANS_6PT_WIN1252; // Customize default settings @@ -103,7 +104,7 @@ void setupNicheGraphics() buttons->setWiring(1, PIN_BUTTON2); buttons->setHandlerShortPress(1, [inkhud]() { inkhud->nextTile(); - playBoop(); + playChirp(); }); // Begin handling button events diff --git a/variants/heltec_wireless_paper/einkDetect.h b/variants/heltec_wireless_paper/einkDetect.h new file mode 100644 index 000000000..93b3f86e3 --- /dev/null +++ b/variants/heltec_wireless_paper/einkDetect.h @@ -0,0 +1,35 @@ +#pragma once + +#include "configuration.h" + +enum class EInkDetectionResult : uint8_t { + LCMEN213EFC1 = 0, // V1.1 + E0213A367 = 1, // V1.1.1, V1.2 +}; + +EInkDetectionResult detectEInk() +{ + // Test 1: Logic of BUSY pin + + // Determines controller IC manufacturer + // Fitipower: busy when LOW + // Solomon Systech: busy when HIGH + + // Force display BUSY by holding reset pin active + pinMode(PIN_EINK_RES, OUTPUT); + digitalWrite(PIN_EINK_RES, LOW); + + delay(10); + + // Read whether pin is HIGH or LOW while busy + pinMode(PIN_EINK_BUSY, INPUT); + bool busyLogic = digitalRead(PIN_EINK_BUSY); + + // Test complete. Release pin + pinMode(PIN_EINK_RES, INPUT); + + if (busyLogic == LOW) + return EInkDetectionResult::LCMEN213EFC1; + else // busy HIGH + return EInkDetectionResult::E0213A367; +} \ No newline at end of file diff --git a/variants/heltec_wireless_paper/nicheGraphics.h b/variants/heltec_wireless_paper/nicheGraphics.h index c8994b7f1..445b57714 100644 --- a/variants/heltec_wireless_paper/nicheGraphics.h +++ b/variants/heltec_wireless_paper/nicheGraphics.h @@ -18,13 +18,21 @@ // Shared NicheGraphics components // -------------------------------- +#include "graphics/niche/Drivers/EInk/E0213A367.h" #include "graphics/niche/Drivers/EInk/LCMEN2R13EFC1.h" #include "graphics/niche/Inputs/TwoButton.h" +#include "einkDetect.h" // Detect display model at runtime + void setupNicheGraphics() { using namespace NicheGraphics; + // Detect E-Ink Model + // ------------------- + + EInkDetectionResult displayModel = detectEInk(); + // SPI // ----------------------------- @@ -35,7 +43,13 @@ void setupNicheGraphics() // E-Ink Driver // ----------------------------- - Drivers::EInk *driver = new Drivers::LCMEN213EFC1; + Drivers::EInk *driver; + + if (displayModel == EInkDetectionResult::LCMEN213EFC1) // V1.1 + driver = new Drivers::LCMEN213EFC1; + else if (displayModel == EInkDetectionResult::E0213A367) // V1.1.1, V1.2 + driver = new Drivers::E0213A367; + driver->begin(hspi, PIN_EINK_DC, PIN_EINK_CS, PIN_EINK_BUSY, PIN_EINK_RES); // InkHUD @@ -48,10 +62,15 @@ void setupNicheGraphics() // Set how many FAST updates per FULL update // Set how unhealthy additional FAST updates beyond this number are - inkhud->setDisplayResilience(10, 1.5); + + if (displayModel == EInkDetectionResult::LCMEN213EFC1) // V1.1 (unmarked) + inkhud->setDisplayResilience(10, 1.5); + else if (displayModel == EInkDetectionResult::E0213A367) // V1.1.1, V1.2 + inkhud->setDisplayResilience(15, 3); // Select fonts - InkHUD::Applet::fontLarge = FREESANS_9PT_WIN1252; + InkHUD::Applet::fontLarge = FREESANS_12PT_WIN1252; + InkHUD::Applet::fontMedium = FREESANS_9PT_WIN1252; InkHUD::Applet::fontSmall = FREESANS_6PT_WIN1252; // Customize default settings diff --git a/variants/heltec_wireless_paper/platformio.ini b/variants/heltec_wireless_paper/platformio.ini index ce5b5e533..790646056 100644 --- a/variants/heltec_wireless_paper/platformio.ini +++ b/variants/heltec_wireless_paper/platformio.ini @@ -7,7 +7,8 @@ build_flags = ${esp32s3_base.build_flags} -I variants/heltec_wireless_paper -D HELTEC_WIRELESS_PAPER - -D EINK_DISPLAY_MODEL=GxEPD2_213_FC1 + -D GXEPD2_DRIVER_0=GxEPD2_213_FC1 + -D GXEPD2_DRIVER_1=GxEPD2_213_E0213A367 -D EINK_WIDTH=250 -D EINK_HEIGHT=122 -D USE_EINK @@ -17,7 +18,7 @@ build_flags = -D EINK_HASQUIRK_GHOSTING ; Display model is identified as "prone to ghosting" lib_deps = ${esp32s3_base.lib_deps} - https://github.com/meshtastic/GxEPD2/archive/b202ebfec6a4821e098cf7a625ba0f6f2400292d.zip + https://github.com/meshtastic/GxEPD2/archive/1655054ba298e0e29fc2044741940f927f9c2a43.zip lewisxhe/PCF8563_Library@^1.0.1 upload_speed = 115200 diff --git a/variants/mesh-tab/platformio.ini b/variants/mesh-tab/platformio.ini index beeb58a48..52f9fc13c 100644 --- a/variants/mesh-tab/platformio.ini +++ b/variants/mesh-tab/platformio.ini @@ -85,6 +85,7 @@ build_flags = ${mesh_tab_xpt2046.build_flags} -D SPI_FREQUENCY=60000000 -D LGFX_SCREEN_WIDTH=240 -D LGFX_SCREEN_HEIGHT=320 + -D DISPLAY_SIZE=320x240 ; landscape mode -D LGFX_PANEL=ST7789 -D LGFX_INVERT_COLOR=false -D LGFX_ROTATION=3 @@ -97,6 +98,7 @@ build_flags = ${mesh_tab_xpt2046.build_flags} -D SPI_FREQUENCY=60000000 ; if image is distorted then lower to 40 MHz -D LGFX_SCREEN_WIDTH=240 -D LGFX_SCREEN_HEIGHT=320 + -D DISPLAY_SIZE=320x240 ; landscape mode -D LGFX_PANEL=ILI9341 -D LGFX_ROTATION=1 -D LGFX_TOUCH_ROTATION=4 @@ -109,6 +111,7 @@ build_flags = ${mesh_tab_xpt2046.build_flags} -D DISPLAY_SET_RESOLUTION -D LGFX_SCREEN_WIDTH=320 -D LGFX_SCREEN_HEIGHT=480 + -D DISPLAY_SIZE=320x480 ; portrait mode -D LGFX_PANEL=ILI9488 -D LGFX_ROTATION=0 -D LGFX_TOUCH_ROTATION=0 @@ -121,6 +124,7 @@ build_flags = ${mesh_tab_xpt2046.build_flags} -D DISPLAY_SET_RESOLUTION -D LGFX_SCREEN_WIDTH=320 -D LGFX_SCREEN_HEIGHT=480 + -D DISPLAY_SIZE=320x480 ; portrait mode -D LGFX_PANEL=HX8357B -D LGFX_INVERT_COLOR=false -D LGFX_ROTATION=4 @@ -133,6 +137,7 @@ build_flags = ${mesh_tab_ft5x06.build_flags} -D SPI_FREQUENCY=75000000 ; may go higher upto 60/80 MHz -D LGFX_SCREEN_WIDTH=240 -D LGFX_SCREEN_HEIGHT=320 + -D DISPLAY_SIZE=320x240 ; landscape mode -D LGFX_PANEL=ILI9341 -D LGFX_ROTATION=1 -D LGFX_TOUCH_X_MIN=0 @@ -149,6 +154,7 @@ build_flags = ${mesh_tab_ft5x06.build_flags} -D DISPLAY_SET_RESOLUTION -D LGFX_SCREEN_WIDTH=320 -D LGFX_SCREEN_HEIGHT=480 + -D DISPLAY_SIZE=320x480 ; portrait mode -D LGFX_PANEL=ILI9488 -D LGFX_ROTATION=2 -D LGFX_TOUCH_X_MIN=0 @@ -165,6 +171,7 @@ build_flags = ${mesh_tab_ft5x06.build_flags} -D DISPLAY_SET_RESOLUTION -D LGFX_SCREEN_WIDTH=320 -D LGFX_SCREEN_HEIGHT=480 + -D DISPLAY_SIZE=320x480 ; portrait mode -D LGFX_PANEL=HX8357B -D LGFX_ROTATION=4 -D LGFX_TOUCH_X_MIN=0 diff --git a/variants/picomputer-s3/platformio.ini b/variants/picomputer-s3/platformio.ini index b861b5496..cb5e829b4 100644 --- a/variants/picomputer-s3/platformio.ini +++ b/variants/picomputer-s3/platformio.ini @@ -42,6 +42,9 @@ build_flags = -D LV_USE_LOG=0 -D USE_LOG_DEBUG -D LOG_DEBUG_INC=\"DebugConfiguration.h\" + -D LGFX_SCREEN_WIDTH=240 + -D LGFX_SCREEN_HEIGHT=320 + -D DISPLAY_SIZE=320x240 ; landscape mode -D LGFX_DRIVER=LGFX_PICOMPUTER_S3 -D GFX_DRIVER_INC=\"graphics/LGFX/LGFX_PICOMPUTER_S3.h\" -D VIEW_320x240 diff --git a/variants/picomputer-s3/variant.h b/variants/picomputer-s3/variant.h index ff8faa6f4..8252e841c 100644 --- a/variants/picomputer-s3/variant.h +++ b/variants/picomputer-s3/variant.h @@ -49,7 +49,7 @@ #define SCREEN_TRANSITION_FRAMERATE 5 // Picomputer gets a white on black display -#define TFT_MESH COLOR565(0xFF, 0xFF, 0xFF) +#define TFT_MESH_OVERRIDE COLOR565(255, 255, 255) #define CANNED_MESSAGE_MODULE_ENABLE 1 diff --git a/variants/portduino/platformio.ini b/variants/portduino/platformio.ini index 6da827508..5293b12b9 100644 --- a/variants/portduino/platformio.ini +++ b/variants/portduino/platformio.ini @@ -22,7 +22,6 @@ lib_deps = ${native_base.lib_deps} ${device-ui_base.lib_deps} build_flags = ${native_base.build_flags} -Os -lX11 -linput -lxkbcommon -ffunction-sections -fdata-sections -Wl,--gc-sections - -D MESHTASTIC_EXCLUDE_CANNEDMESSAGES=1 -D RAM_SIZE=16384 -D USE_X11=1 -D HAS_TFT=1 @@ -51,7 +50,6 @@ lib_deps = ${device-ui_base.lib_deps} board_level = extra build_flags = ${native_base.build_flags} -Os -ffunction-sections -fdata-sections -Wl,--gc-sections - -D MESHTASTIC_EXCLUDE_CANNEDMESSAGES=1 -D RAM_SIZE=8192 -D USE_FRAMEBUFFER=1 -D LV_COLOR_DEPTH=32 @@ -81,7 +79,6 @@ lib_deps = ${device-ui_base.lib_deps} board_level = extra build_flags = ${native_base.build_flags} -O0 -fsanitize=address -lX11 -linput -lxkbcommon - -D MESHTASTIC_EXCLUDE_CANNEDMESSAGES=1 -D DEBUG_HEAP -D RAM_SIZE=16384 -D USE_X11=1 diff --git a/variants/rak3172/platformio.ini b/variants/rak3172/platformio.ini index 456697aef..99610b17c 100644 --- a/variants/rak3172/platformio.ini +++ b/variants/rak3172/platformio.ini @@ -5,6 +5,8 @@ board_upload.maximum_size = 233472 ; reserve the last 28KB for filesystem build_flags = ${stm32_base.build_flags} -Ivariants/rak3172 + -DPIN_WIRE_SDA=PA11 + -DPIN_WIRE_SCL=PA12 -DHAL_DAC_MODULE_ONLY -DHAL_RNG_MODULE_ENABLED -DRADIOLIB_EXCLUDE_SX128X=1 @@ -18,6 +20,5 @@ build_flags = -DMESHTASTIC_EXCLUDE_SCREEN=1 -DMESHTASTIC_EXCLUDE_MQTT=1 -DMESHTASTIC_EXCLUDE_POWERMON=1 - ;-DPIO_FRAMEWORK_ARDUINO_NANOLIB_FLOAT_PRINTF ;-DCFG_DEBUG upload_port = stlink diff --git a/variants/rak3312/pins_arduino.h b/variants/rak3312/pins_arduino.h new file mode 100644 index 000000000..15a26e991 --- /dev/null +++ b/variants/rak3312/pins_arduino.h @@ -0,0 +1,28 @@ +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include "variant.h" +#include + +#define USB_VID 0x303a +#define USB_PID 0x1001 + +// The default Wire will be mapped to PMU and RTC +static const uint8_t SDA = 9; +static const uint8_t SCL = 40; + +// Default SPI will be mapped to Radio +static const uint8_t SS = 12; +static const uint8_t MOSI = 11; +static const uint8_t MISO = 10; +static const uint8_t SCK = 13; + +#define SPI_MOSI (11) +#define SPI_SCK (13) +#define SPI_MISO (10) +#define SPI_CS (12) + +// LEDs +#define LED_BUILTIN LED_GREEN + +#endif /* Pins_Arduino_h */ diff --git a/variants/rak3312/platformio.ini b/variants/rak3312/platformio.ini new file mode 100644 index 000000000..d2877b3f7 --- /dev/null +++ b/variants/rak3312/platformio.ini @@ -0,0 +1,8 @@ +[env:rak3312] +extends = esp32s3_base +board = wiscore_rak3312 +board_check = true +upload_protocol = esptool + +build_flags = + ${esp32_base.build_flags} -D RAK3312 -I variants/rak3312 diff --git a/variants/rak3312/variant.h b/variants/rak3312/variant.h new file mode 100644 index 000000000..dfdf4de71 --- /dev/null +++ b/variants/rak3312/variant.h @@ -0,0 +1,44 @@ +#define I2C_SDA 9 +#define I2C_SCL 40 + +#define USE_SX1262 + +#define LORA_SCK 5 +#define LORA_MISO 3 +#define LORA_MOSI 6 +#define LORA_CS 7 +#define LORA_RESET 8 + +#ifdef USE_SX1262 +#define SX126X_CS LORA_CS +#define SX126X_DIO1 47 +#define SX126X_BUSY 48 +#define SX126X_RESET LORA_RESET +#define SX126X_DIO2_AS_RF_SWITCH +#define SX126X_DIO3_TCXO_VOLTAGE 1.8 +#endif + +#define SX126X_POWER_EN (4) + +#define PIN_POWER_EN PIN_3V3_EN +#define PIN_3V3_EN (14) + +#define LED_GREEN 46 +#define LED_BLUE 45 + +#define PIN_LED1 LED_GREEN +#define PIN_LED2 LED_BLUE + +#define LED_CONN LED_BLUE +#define LED_PIN LED_GREEN +#define ledOff(pin) pinMode(pin, INPUT) + +#define LED_STATE_ON 1 // State when LED is litted + +#define HAS_GPS 1 +#define GPS_TX_PIN 43 +#define GPS_RX_PIN 44 + +#define BATTERY_PIN 1 +#define ADC_CHANNEL ADC1_GPIO1_CHANNEL +#define ADC_MULTIPLIER 1.667 \ No newline at end of file diff --git a/variants/rak4631/variant.h b/variants/rak4631/variant.h index cd8f46153..f5ec11ef2 100644 --- a/variants/rak4631/variant.h +++ b/variants/rak4631/variant.h @@ -88,8 +88,8 @@ static const uint8_t A7 = PIN_A7; #define ADC_RESOLUTION 14 // Other pins - #define WB_I2C1_SDA (13) // SENSOR_SLOT IO_SLOT - #define WB_I2C1_SCL (14) // SENSOR_SLOT IO_SLOT +#define WB_I2C1_SDA (13) // SENSOR_SLOT IO_SLOT +#define WB_I2C1_SCL (14) // SENSOR_SLOT IO_SLOT #define PIN_AREF (2) #define PIN_NFC1 (9) diff --git a/variants/seeed-sensecap-indicator/platformio.ini b/variants/seeed-sensecap-indicator/platformio.ini index 2187ebd8a..63f814b57 100644 --- a/variants/seeed-sensecap-indicator/platformio.ini +++ b/variants/seeed-sensecap-indicator/platformio.ini @@ -53,6 +53,9 @@ build_flags = -D USE_LOG_DEBUG -D LOG_DEBUG_INC=\"DebugConfiguration.h\" -D CUSTOM_TOUCH_DRIVER + -D LGFX_SCREEN_WIDTH=480 + -D LGFX_SCREEN_HEIGHT=480 + -D DISPLAY_SIZE=480x480 -D LGFX_DRIVER=LGFX_INDICATOR -D GFX_DRIVER_INC=\"graphics/LGFX/LGFX_INDICATOR.h\" -D VIEW_320x240 diff --git a/variants/seeed_wio_tracker_L1_eink/nicheGraphics.h b/variants/seeed_wio_tracker_L1_eink/nicheGraphics.h new file mode 100644 index 000000000..a32753343 --- /dev/null +++ b/variants/seeed_wio_tracker_L1_eink/nicheGraphics.h @@ -0,0 +1,106 @@ +#pragma once + +#include "configuration.h" + +#ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS + +// InkHUD-specific components +// --------------------------- +#include "graphics/niche/InkHUD/InkHUD.h" + +// Applets +#include "graphics/niche/InkHUD/Applets/User/AllMessage/AllMessageApplet.h" +#include "graphics/niche/InkHUD/Applets/User/DM/DMApplet.h" +#include "graphics/niche/InkHUD/Applets/User/Heard/HeardApplet.h" +#include "graphics/niche/InkHUD/Applets/User/Positions/PositionsApplet.h" +#include "graphics/niche/InkHUD/Applets/User/RecentsList/RecentsListApplet.h" +#include "graphics/niche/InkHUD/Applets/User/ThreadedMessage/ThreadedMessageApplet.h" + +// Shared NicheGraphics components +// -------------------------------- +#include "graphics/niche/Drivers/Backlight/LatchingBacklight.h" +#include "graphics/niche/Drivers/EInk/GDEY0213B74.h" +#include "graphics/niche/Inputs/TwoButton.h" + +// Special case - fix T-Echo's touch button +// ---------------------------------------- +// On a handful of T-Echos, LoRa TX triggers the capacitive touch +// To avoid this, we lockout the button during TX +#include "mesh/RadioLibInterface.h" + +void setupNicheGraphics() +{ + using namespace NicheGraphics; + + // SPI + // ----------------------------- + + // For NRF52 platforms, SPI pins are defined in variant.h + SPI1.begin(); + + // E-Ink Driver + // ----------------------------- + + Drivers::EInk *driver = new Drivers::GDEY0213B74; + driver->begin(&SPI1, PIN_EINK_DC, PIN_EINK_CS, PIN_EINK_BUSY, PIN_EINK_RES); + + // InkHUD + // ---------------------------- + + InkHUD::InkHUD *inkhud = InkHUD::InkHUD::getInstance(); + + // Set the E-Ink driver + inkhud->setDriver(driver); + + // Set how many FAST updates per FULL update + // Set how unhealthy additional FAST updates beyond this number are + inkhud->setDisplayResilience(7, 1.5); + + // Select fonts + InkHUD::Applet::fontLarge = FREESANS_12PT_WIN1252; + InkHUD::Applet::fontMedium = FREESANS_9PT_WIN1252; + InkHUD::Applet::fontSmall = FREESANS_6PT_WIN1252; + + // Customize default settings + inkhud->persistence->settings.userTiles.maxCount = 2; // Two applets side-by-side + // 270 degrees clockwise + inkhud->persistence->settings.optionalFeatures.batteryIcon = true; // Device definitely has a battery + inkhud->persistence->settings.optionalMenuItems.backlight = true; // Until proves capacitive button works by touching it + inkhud->persistence->settings.userTiles.count = 1; // One tile only by default, keep things simple for new users + + // Setup backlight controller + // Note: AUX button attached further down + Drivers::LatchingBacklight *backlight = Drivers::LatchingBacklight::getInstance(); + backlight->setPin(PIN_EINK_EN); + + // Pick applets + // Note: order of applets determines priority of "auto-show" feature + inkhud->addApplet("All Messages", new InkHUD::AllMessageApplet, true, true); // Activated, autoshown + inkhud->addApplet("DMs", new InkHUD::DMApplet); // - + inkhud->addApplet("Channel 0", new InkHUD::ThreadedMessageApplet(0)); // - + inkhud->addApplet("Channel 1", new InkHUD::ThreadedMessageApplet(1)); // - + inkhud->addApplet("Positions", new InkHUD::PositionsApplet, true); // Activated + inkhud->addApplet("Recents List", new InkHUD::RecentsListApplet); // - + inkhud->addApplet("Heard", new InkHUD::HeardApplet, true, false, 0); // Activated, no autoshow, default on tile 0 + + inkhud->persistence->settings.rotation = 1; + // inkhud->persistence->printSettings(&inkhud->persistence->settings); + // Start running InkHUD + inkhud->begin(); + // inkhud->persistence->printSettings(&inkhud->persistence->settings); + // Buttons + // -------------------------- + + Inputs::TwoButton *buttons = Inputs::TwoButton::getInstance(); // Shared NicheGraphics component + + // #0: Main User Button + buttons->setWiring(0, Inputs::TwoButton::getUserButtonPin()); + buttons->setTiming(0, 75, 500); + buttons->setHandlerShortPress(0, [inkhud]() { inkhud->shortpress(); }); + buttons->setHandlerLongPress(0, [inkhud]() { inkhud->longpress(); }); + + // Begin handling button events + buttons->start(); +} + +#endif \ No newline at end of file diff --git a/variants/seeed_wio_tracker_L1_eink/platformio.ini b/variants/seeed_wio_tracker_L1_eink/platformio.ini new file mode 100644 index 000000000..b84757b9d --- /dev/null +++ b/variants/seeed_wio_tracker_L1_eink/platformio.ini @@ -0,0 +1,14 @@ +[env:seeed_wio_tracker_L1_eink] +board = seeed_wio_tracker_L1 +extends = nrf52840_base, inkhud +;board_level = extra +build_flags = ${nrf52840_base.build_flags} ${inkhud.build_flags} + -I $PROJECT_DIR/variants/seeed_wio_tracker_L1_eink + -D SEEED_WIO_TRACKER_L1 + -Isrc/platform/nrf52/softdevice -Isrc/platform/nrf52/softdevice/nrf52 +board_build.ldscript = src/platform/nrf52/nrf52840_s140_v7.ld +build_src_filter = ${nrf52_base.build_src_filter} +<../variants/seeed_wio_tracker_L1_eink> ${inkhud.build_src_filter} +lib_deps = + ${inkhud.lib_deps} + ${nrf52840_base.lib_deps} +debug_tool = jlink diff --git a/variants/seeed_wio_tracker_L1_eink/variant.cpp b/variants/seeed_wio_tracker_L1_eink/variant.cpp new file mode 100644 index 000000000..bcbe20ea5 --- /dev/null +++ b/variants/seeed_wio_tracker_L1_eink/variant.cpp @@ -0,0 +1,103 @@ +/* + * variant.cpp - Digital pin mapping for TRACKER L1 + * + * This file defines the pin mapping array that maps logical digital pins (D0-D17) + * to physical GPIO ports/pins on the Nordic nRF52 series microcontroller. + * + * Board: [Seeed Studio WIO TRACKER L1] + * Hardware Features: + * - LoRa module (CS/SCK/MISO/MOSI control pins) + * - GNSS module (TX/RX/Reset/Wakeup) + * - User LEDs (D11-D12) + * - User button (D13) + * - Grove/NFC interface (D14-D15) + * - Battery voltage monitoring (D16) + * + * Created [20250521] + * By [Dylan] + */ + +#include "variant.h" +#include "nrf.h" +#include "wiring_constants.h" +#include "wiring_digital.h" + +/** + * @brief Digital pin to GPIO port/pin mapping table + * + * Format: Logical Pin (Dx) -> nRF Port.Pin (Px.xx) + * + */ + +extern "C" { +const uint32_t g_ADigitalPinMap[] = { + // D0 .. D10 - Peripheral control pins + 41, // D0 P1.09 GNSS_WAKEUP + 7, // D1 P0.07 LORA_DIO1 + 39, // D2 P1.07 LORA_RESET + 42, // D3 P1.10 LORA_BUSY + 46, // D4 P1.14 (A4/SDA) LORA_CS + 40, // D5 P1.08 (A5/SCL) LORA_SW + 27, // D6 P0.27 (UART_TX) GNSS_TX + 26, // D7 P0.26 (UART_RX) GNSS_RX + 30, // D8 P0.30 (SPI_SCK) LORA_SCK + 3, // D9 P0.3 (SPI_MISO) LORA_MISO + 28, // D10 P0.28 (SPI_MOSI) LORA_MOSI + + // D11-D12 - LED outputs + 33, // D11 P1.1 User LED + // Buzzer + 32, // D12 P1.0 Buzzer + + // D13 - User input + 8, // D13 P0.08 User Button + + // D14-D15 - Grove interface + 6, // D14 P0.06 OLED SDA + 5, // D15 P0.05 OLED SCL + + // D16 - Battery voltage ADC input + 31, // D16 P0.31 VBAT_ADC + // GROVE + 43, // D17 P0.00 GROVESDA + 44, // D18 P0.01 GROVESCL + + // FLASH + 21, // D19 P0.21 (QSPI_SCK) + 25, // D20 P0.25 (QSPI_CSN) + 20, // D21 P0.20 (QSPI_SIO_0 DI) + 24, // D22 P0.24 (QSPI_SIO_1 DO) + 22, // D23 P0.22 (QSPI_SIO_2 WP) + 23, // D24 P0.23 (QSPI_SIO_3 HOLD) + + 36, // D25 TB_UP + 12, // D26 TB_DOWN + 11, // D27 TB_LEFT + 35, // D28 TB_RIGHT + 37, // D29 TB_PRESS + 4, // D30 BAT_CTL + + 13, // D31 EINK_SCK + 14, // D32 EINK_RST + 15, // D33 EINK_MOSI + 16, // D34 EINK_DC + 17, // D35 EINK_BUSY + 19, // D36 EINK_CS + +}; +} + +void initVariant() +{ + pinMode(PIN_QSPI_CS, OUTPUT); + digitalWrite(PIN_QSPI_CS, HIGH); + // This setup is crucial for ensuring low power consumption and proper initialization of the hardware components. + // VBAT_ENABLE + pinMode(BAT_READ, OUTPUT); + digitalWrite(BAT_READ, HIGH); + + pinMode(PIN_LED1, OUTPUT); + digitalWrite(PIN_LED1, LOW); + pinMode(PIN_LED2, OUTPUT); + digitalWrite(PIN_LED2, LOW); +} \ No newline at end of file diff --git a/variants/seeed_wio_tracker_L1_eink/variant.h b/variants/seeed_wio_tracker_L1_eink/variant.h new file mode 100644 index 000000000..98a7b2c39 --- /dev/null +++ b/variants/seeed_wio_tracker_L1_eink/variant.h @@ -0,0 +1,194 @@ +#ifndef _SEEED_TRACKER_L1_H_ +#define _SEEED_TRACKER_L1_H_ +#include "WVariant.h" +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +// Clock Configuration +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +#define VARIANT_MCK (64000000ul) // Master clock frequency +#define USE_LFXO // 32.768kHz crystal for LFCLK + +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +// Pin Capacity Definitions +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +#define PINS_COUNT (38u) // Total GPIO pins +#define NUM_DIGITAL_PINS (38u) // Digital I/O pins +#define NUM_ANALOG_INPUTS (8u) // Analog inputs (A0-A5 + VBAT + AREF) +#define NUM_ANALOG_OUTPUTS (0u) + +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +// LED Configuration +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +// LEDs +// LEDs +#define PIN_LED1 (11) // LED P1.15 +#define PIN_LED2 (12) // + +#define LED_BUILTIN PIN_LED1 +#define LED_CONN PIN_LED2 + +#define LED_GREEN PIN_LED1 +#define LED_BLUE PIN_LED2 +// #define LED_PIN PIN_LED2 +#define LED_STATE_ON 1 // State when LED is litted +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +// Button Configuration +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +#ifdef BUTTON_PIN +#undef BUTTON_PIN +#endif + +#define BUTTON_PIN D13 // This is the Program Button +// #define BUTTON_NEED_PULLUP 1 +#define BUTTON_ACTIVE_LOW true +#define BUTTON_ACTIVE_PULLUP false + +#define BUTTON_PIN_TOUCH 13 // Touch button +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +// Digital Pin Mapping (D0-D10) +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +#define D0 0 // P1.06 GNSS_WAKEUP/IO0 +#define D1 1 // P0.07 LORA_DIO1 +#define D2 2 // P1.07 LORA_RESET +#define D3 3 // P1.10 LORA_BUSY +#define D4 4 // P1.14 LORA_CS +#define D5 5 // P1.08 LORA_SW +#define D6 6 // P0.27 GNSS_TX +#define D7 7 // P0.26 GNSS_RX +#define D8 8 // P0.30 SPI_SCK +#define D9 9 // P0.03 SPI_MISO +#define D10 10 // P0.28 SPI_MOSI +#define D12 12 // P1.00 Buzzer +#define D13 13 // P0.08 User Button +#define D14 14 // P0.05 OLED SCL +#define D15 15 // P0.06 OLED SDA +#define D16 16 // P0.31 VBAT_ADC +#define D17 17 // P0.00 GROVE SDA +#define D18 18 // P0.01 GROVE_SCL +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +// Analog Pin Definitions +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +#define PIN_A0 0 // P0.02 Analog Input 0 +#define PIN_A1 1 // P0.03 Analog Input 1 +#define PIN_A2 2 // P0.28 Analog Input 2 +#define PIN_A3 3 // P0.29 Analog Input 3 +#define PIN_A4 4 // P0.04 Analog Input 4 +#define PIN_A5 5 // P0.05 Analog Input 5 +#define PIN_VBAT D16 // P0.31 Battery voltage sense +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +// Communication Interfaces +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +// I2C Configuration +#define HAS_WIRE 1 +#define PIN_WIRE_SDA D18 // P0.09 +#define PIN_WIRE_SCL D17 // P0.10 +#define WIRE_INTERFACES_COUNT 1 + +static const uint8_t SDA = PIN_WIRE_SDA; +static const uint8_t SCL = PIN_WIRE_SCL; + +// SPI Configuration (SX1262) + +// #define SPI_INTERFACES_COUNT 1 +#define PIN_SPI_MISO 9 // P0.03 (D9) +#define PIN_SPI_MOSI 10 // P0.28 (D10) +#define PIN_SPI_SCK 8 // P0.30 (D8) + +// SX1262 LoRa Module Pins +#define USE_SX1262 +#define SX126X_CS D4 // Chip select +#define SX126X_DIO1 D1 // Digital IO 1 (Interrupt) +#define SX126X_BUSY D3 // Busy status +#define SX126X_RESET D2 // Reset control +#define SX126X_DIO3_TCXO_VOLTAGE 1.8 // TCXO supply voltage +#define SX126X_RXEN D5 // RX enable control +#define SX126X_TXEN RADIOLIB_NC +#define SX126X_DIO2_AS_RF_SWITCH // This Line is really necessary for SX1262 to work with RF switch or will loss TX power + +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +// EINK +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +#define SPI_INTERFACES_COUNT 2 +#define PIN_EINK_CS 36 +#define PIN_EINK_BUSY 35 +#define PIN_EINK_DC 34 +#define PIN_EINK_RES 32 +#define PIN_EINK_SCLK 31 +#define PIN_EINK_MOSI 33 +#define PIN_EINK_EN 14 // unused +#define PIN_SPI1_MISO 15 // unused +#define PIN_SPI1_MOSI PIN_EINK_MOSI +#define PIN_SPI1_SCK PIN_EINK_SCLK + +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +// Power Management +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +#define BAT_READ 30 // D30 = P0.04 Reads battery voltage from divider on signal board. +#define BATTERY_SENSE_RESOLUTION_BITS 12 +#define ADC_MULTIPLIER 2.0 +#define BATTERY_PIN PIN_VBAT // PIN_A7 +#define AREF_VOLTAGE 3.6 +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +// GPS L76KB +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +#define GPS_L76K +#ifdef GPS_L76K +#define PIN_GPS_RX D6 // P0.26 +#define PIN_GPS_TX D7 +#define HAS_GPS 1 +#define GPS_BAUDRATE 9600 +#define GPS_THREAD_INTERVAL 50 +#define PIN_SERIAL1_RX PIN_GPS_TX +#define PIN_SERIAL1_TX PIN_GPS_RX + +#define GPS_RX_PIN PIN_GPS_TX +#define GPS_TX_PIN PIN_GPS_RX +#define PIN_GPS_STANDBY D0 + +// #define GPS_DEBUG +// #define GPS_EN D18 // P1.05 +#endif + +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +// On-board QSPI Flash +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +// On-board QSPI Flash +#define PIN_QSPI_SCK (21) +#define PIN_QSPI_CS (22) +#define PIN_QSPI_IO0 (23) +#define PIN_QSPI_IO1 (24) +#define PIN_QSPI_IO2 (25) +#define PIN_QSPI_IO3 (26) + +#define EXTERNAL_FLASH_DEVICES P25Q16H +#define EXTERNAL_FLASH_USE_QSPI + +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +// Buzzer +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +// Buzzer + +#define PIN_BUZZER D12 // P1.00, pwm output + +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +// joystick +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +#define CANNED_MESSAGE_MODULE_ENABLE 1 + +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +// Compatibility Definitions +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +#ifdef __cplusplus +extern "C" { +#endif +// Serial port placeholders + +#define PIN_SERIAL2_RX (-1) +#define PIN_SERIAL2_TX (-1) +#ifdef __cplusplus +} +#endif + +#endif // _SEEED_TRACKER_L1_H_ \ No newline at end of file diff --git a/variants/seeed_xiao_nrf52840_kit/platformio.ini b/variants/seeed_xiao_nrf52840_kit/platformio.ini index 8c4c5a57b..0e1e94cd5 100644 --- a/variants/seeed_xiao_nrf52840_kit/platformio.ini +++ b/variants/seeed_xiao_nrf52840_kit/platformio.ini @@ -1,4 +1,4 @@ -; Seeed Xiao BLE: https://www.digikey.com/en/products/detail/seeed-technology-co-ltd/102010448/16652893 +; Seeed Xiao BLE: https://wiki.seeedstudio.com/XIAO_BLE/ [env:seeed_xiao_nrf52840_kit] extends = nrf52840_base board = xiao_ble_sense diff --git a/variants/seeed_xiao_nrf52840_kit/variant.h b/variants/seeed_xiao_nrf52840_kit/variant.h index d2bbfdda9..a65500612 100644 --- a/variants/seeed_xiao_nrf52840_kit/variant.h +++ b/variants/seeed_xiao_nrf52840_kit/variant.h @@ -179,7 +179,11 @@ static const uint8_t SCK = PIN_SPI_SCK; #define I2C_NO_RESCAN // I2C is a bit finicky, don't scan too much #define WIRE_INTERFACES_COUNT 1 -#if !defined(XIAO_BLE_LEGACY_PINOUT) && !defined(GPS_L76K) +#if defined(XIAO_BLE_LEGACY_PINOUT) +// Used for I2C by DIY xiao_ble variant +#define PIN_WIRE_SDA D4 +#define PIN_WIRE_SCL D5 +#elif !defined(GPS_L76K) // If D6 and D7 are free, I2C is probably the most versatile assignment #define PIN_WIRE_SDA D6 #define PIN_WIRE_SCL D7 diff --git a/variants/t-deck/platformio.ini b/variants/t-deck/platformio.ini index 04e305abb..c9bd64bc3 100644 --- a/variants/t-deck/platformio.ini +++ b/variants/t-deck/platformio.ini @@ -51,7 +51,10 @@ build_flags = -D RADIOLIB_DEBUG_SPI=0 -D RADIOLIB_DEBUG_PROTOCOL=0 -D RADIOLIB_SPI_PARANOID=0 - -D CALIBRATE_TOUCH=0 +; -D CALIBRATE_TOUCH=0 + -D LGFX_SCREEN_WIDTH=240 + -D LGFX_SCREEN_HEIGHT=320 + -D DISPLAY_SIZE=320x240 ; landscape mode -D LGFX_DRIVER=LGFX_TDECK -D GFX_DRIVER_INC=\"graphics/LGFX/LGFX_T_DECK.h\" ; -D LVGL_DRIVER=LVGL_TDECK diff --git a/variants/t-deck/variant.h b/variants/t-deck/variant.h index 9fa0018ec..9b0de631a 100644 --- a/variants/t-deck/variant.h +++ b/variants/t-deck/variant.h @@ -68,6 +68,7 @@ #define TB_LEFT 1 #define TB_RIGHT 2 #define TB_PRESS 0 // BUTTON_PIN +#define TB_DIRECTION FALLING // microphone #define ES7210_SCK 47 diff --git a/variants/t-echo/nicheGraphics.h b/variants/t-echo/nicheGraphics.h index 03185cf5b..c89d816b9 100644 --- a/variants/t-echo/nicheGraphics.h +++ b/variants/t-echo/nicheGraphics.h @@ -57,7 +57,8 @@ void setupNicheGraphics() inkhud->setDisplayResilience(20, 1.5); // Select fonts - InkHUD::Applet::fontLarge = FREESANS_9PT_WIN1252; + InkHUD::Applet::fontLarge = FREESANS_12PT_WIN1252; + InkHUD::Applet::fontMedium = FREESANS_9PT_WIN1252; InkHUD::Applet::fontSmall = FREESANS_6PT_WIN1252; // Customize default settings diff --git a/variants/tlora_t3s3_epaper/nicheGraphics.h b/variants/tlora_t3s3_epaper/nicheGraphics.h index 5184037e8..8f5e63653 100644 --- a/variants/tlora_t3s3_epaper/nicheGraphics.h +++ b/variants/tlora_t3s3_epaper/nicheGraphics.h @@ -51,7 +51,8 @@ void setupNicheGraphics() inkhud->setDisplayResilience(15, 1.5); // Select fonts - InkHUD::Applet::fontLarge = FREESANS_9PT_WIN1252; + InkHUD::Applet::fontLarge = FREESANS_12PT_WIN1252; + InkHUD::Applet::fontMedium = FREESANS_9PT_WIN1252; InkHUD::Applet::fontSmall = FREESANS_6PT_WIN1252; // Customize default settings diff --git a/variants/tracksenger/internal/variant.h b/variants/tracksenger/internal/variant.h index 57ead848d..6f75ad0e2 100644 --- a/variants/tracksenger/internal/variant.h +++ b/variants/tracksenger/internal/variant.h @@ -72,7 +72,7 @@ #define SX126X_DIO3_TCXO_VOLTAGE 1.8 // Picomputer gets a white on black display -#define TFT_MESH COLOR565(0xFF, 0xFF, 0xFF) +#define TFT_MESH_OVERRIDE COLOR565(255, 255, 255) // keyboard changes diff --git a/variants/tracksenger/lcd/variant.h b/variants/tracksenger/lcd/variant.h index ecf4e854e..843bf3924 100644 --- a/variants/tracksenger/lcd/variant.h +++ b/variants/tracksenger/lcd/variant.h @@ -96,7 +96,7 @@ #define SX126X_DIO3_TCXO_VOLTAGE 1.8 // Picomputer gets a white on black display -#define TFT_MESH COLOR565(0xFF, 0xFF, 0xFF) +#define TFT_MESH_OVERRIDE COLOR565(255, 255, 255) // keyboard changes diff --git a/variants/tracksenger/oled/variant.h b/variants/tracksenger/oled/variant.h index 70f0f3209..85cc019c4 100644 --- a/variants/tracksenger/oled/variant.h +++ b/variants/tracksenger/oled/variant.h @@ -74,7 +74,7 @@ #define SX126X_DIO3_TCXO_VOLTAGE 1.8 // Picomputer gets a white on black display -#define TFT_MESH COLOR565(0xFF, 0xFF, 0xFF) +#define TFT_MESH_OVERRIDE COLOR565(255, 255, 255) // keyboard changes diff --git a/variants/unphone/platformio.ini b/variants/unphone/platformio.ini index ef0f62b60..b9da6d0e5 100644 --- a/variants/unphone/platformio.ini +++ b/variants/unphone/platformio.ini @@ -54,6 +54,9 @@ build_flags = -D LV_USE_LOG=0 -D USE_LOG_DEBUG -D LOG_DEBUG_INC=\"DebugConfiguration.h\" + -D LGFX_SCREEN_WIDTH=320 + -D LGFX_SCREEN_HEIGHT=480 + -D DISPLAY_SIZE=320x480 ; portrait mode -D LGFX_DRIVER=LGFX_UNPHONE_V9 -D GFX_DRIVER_INC=\"graphics/LGFX/LGFX_UNPHONE.h\" -D VIEW_320x240 diff --git a/variants/wio-e5/platformio.ini b/variants/wio-e5/platformio.ini index e746ae2f0..1ef7abd78 100644 --- a/variants/wio-e5/platformio.ini +++ b/variants/wio-e5/platformio.ini @@ -8,20 +8,17 @@ build_flags = -DSERIAL_UART_INSTANCE=1 -DPIN_SERIAL_RX=PB7 -DPIN_SERIAL_TX=PB6 + -DPIN_WIRE_SDA=PA15 + -DPIN_WIRE_SCL=PB15 -DHAL_DAC_MODULE_ONLY -DHAL_RNG_MODULE_ENABLED -DRADIOLIB_EXCLUDE_SX128X=1 -DRADIOLIB_EXCLUDE_SX127X=1 -DRADIOLIB_EXCLUDE_LR11X0=1 - -DMESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR=1 - -DMESHTASTIC_EXCLUDE_I2C=1 - -DMESHTASTIC_EXCLUDE_WIFI=1 - -DMESHTASTIC_EXCLUDE_BLUETOOTH=1 - -DMESHTASTIC_EXCLUDE_GPS=1 - -DMESHTASTIC_EXCLUDE_SCREEN=1 - -DMESHTASTIC_EXCLUDE_MQTT=1 - -DMESHTASTIC_EXCLUDE_POWERMON=1 - ;-DPIO_FRAMEWORK_ARDUINO_NANOLIB_FLOAT_PRINTF - ;-DCFG_DEBUG + -DHAS_SENSOR -upload_port = stlink \ No newline at end of file +upload_port = stlink + +lib_deps = + ${stm32_base.lib_deps} + # Add your custom sensor here! \ No newline at end of file diff --git a/version.properties b/version.properties index 3fe1aa385..5de810523 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 2 minor = 7 -build = 1 +build = 3