diff --git a/.clang-format b/.clang-format index 9c4d3050d..d6343bd61 100644 --- a/.clang-format +++ b/.clang-format @@ -1,25 +1,42 @@ ---- -Language: Cpp -BasedOnStyle: WebKit -AllowShortFunctionsOnASingleLine: false -BinPackArguments: false -BinPackParameters: false -BraceWrapping: - AfterClass: false - AfterControlStatement: false - AfterEnum: false - AfterFunction: true - AfterNamespace: false - AfterObjCDeclaration: false - AfterStruct: false - AfterUnion: false - BeforeCatch: false - BeforeElse: false - IndentBraces: false -BreakBeforeBraces: Custom -Cpp11BracedListStyle: true +Language: Cpp +BasedOnStyle: Microsoft +ColumnLimit: 100 +IndentWidth: 4 +IndentPPDirectives: BeforeHash +PPIndentWidth: 4 +ContinuationIndentWidth: 4 + +ReflowComments: false + PointerAlignment: Right -ReflowComments: false -SortIncludes: false -TabWidth: 4 -... +DerivePointerAlignment: false + +BreakBeforeBraces: Custom +BraceWrapping: + AfterClass: false + AfterStruct: false + AfterUnion: false + AfterEnum: false + AfterFunction: true + AfterNamespace: false + AfterExternBlock: false + AfterCaseLabel: false + AfterControlStatement: Never + BeforeElse: false + BeforeCatch: false + BeforeLambdaBody: false + SplitEmptyFunction: false + SplitEmptyRecord: false + SplitEmptyNamespace: false +AlignAfterOpenBracket: DontAlign + +# c++ specific +ConstructorInitializerIndentWidth: 4 +IndentRequiresClause: true +IndentExternBlock: NoIndent +PackConstructorInitializers: NextLine +AlwaysBreakTemplateDeclarations: Yes +AllowShortFunctionsOnASingleLine: Inline +AllowShortLambdasOnASingleLine: Inline +ShortNamespaceLines: 1 +FixNamespaceComments: true diff --git a/.drone.yml b/.drone.yml index 72093f0d3..267a91f02 100644 --- a/.drone.yml +++ b/.drone.yml @@ -12,11 +12,11 @@ steps: - git submodule init - git submodule update --recursive -- name: Generate versions.h +- name: Generate versions.c image: node:16 commands: - npm install --prefix scripts - - scripts/generate-versions-h.js + - scripts/generate-versions.mjs - name: Build (Ubuntu Linux) image: abcminiuser/docker-ci-arm-toolchain:latest diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000..bb5c82ff7 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,72 @@ +name: CI + +on: + push: + branches: + - master* + pull_request: + branches: + - master* + +jobs: + release: + runs-on: ubuntu-22.04 + timeout-minutes: 25 + + steps: + - uses: actions/checkout@v4 + with: + path: firmware-uhk80 + submodules: recursive + + - name: Install build dependencies + run: sudo apt-get install -y gcc-arm-none-eabi + + - name: Install west + run: pip3 install --user -U west + + - name: Install python dependencies of scripts + run: | + cd firmware-uhk80/scripts + pip install -r requirements.txt + + - name: Setup Zephyr project + uses: zephyrproject-rtos/action-zephyr-setup@v1 + with: + app-path: firmware-uhk80 + toolchains: arm-zephyr-eabi + sdk-version: 0.16.8 + + - name: Git user setup + run: | + git config --global user.email "git-patch@uhk.com" + git config --global user.name "Git Patch" + + - name: West patch + run: west patch + + - name: West config + run: west config --local build.cmake-args -- "-Wno-dev" + + - name: Use Node.js (.nvmrc) + uses: actions/setup-node@v4 + with: + node-version-file: firmware-uhk80/scripts/.nvmrc + + - name: Install node dependencies in scripts folder + run: | + cd firmware-uhk80/scripts + npm install + + - name: Create firmware tarball + run: | + cd firmware-uhk80 + scripts/make-release.mjs --allowSha + + - name: Upload firmware artifacts + uses: actions/upload-artifact@v4 + with: + name: firmware + path: firmware-uhk80/scripts/uhk-firmware-*.tar.gz + compression-level: 0 + retention-days: 10 diff --git a/.gitignore b/.gitignore index 9ca3fd609..d6e32790f 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,9 @@ package-lock.json node_modules build_make .cache +samples +build +CMakeCache.txt +build.ninja .vscode/settings.json +scripts/__pycache__ diff --git a/.gitmodules b/.gitmodules index 0e7eb87be..c98df3f4d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -13,3 +13,6 @@ [submodule "lib/SDK_2.8.0_MKL17Z32xxx4"] path = lib/SDK_2.8.0_MKL17Z32xxx4 url = https://github.com/UltimateHackingKeyboard/SDK_2.8.0_MKL17Z32xxx4.git +[submodule "lib/c2usb"] + path = lib/c2usb + url = https://github.com/IntergatedCircuits/c2usb.git diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index f89e6e8d1..0b3f6b9e6 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -1,17 +1,30 @@ { - "version": 4, "configurations": [ { "name": "UHK 60 v1", "defines": [ "DEVICE_ID=DEVICE_ID_UHK60V1" - ] + ], + "configurationProvider": "nordic-semiconductor.nrf-connect" }, { "name": "UHK 60 v2", "defines": [ "DEVICE_ID=DEVICE_ID_UHK60V2" ] + }, + { + "name": "Linux", + "includePath": [ + "${workspaceFolder}/**" + ], + "defines": [], + "compilerPath": "/usr/bin/gcc", + "cStandard": "c17", + "cppStandard": "gnu++20", + "intelliSenseMode": "linux-gcc-x64", + "configurationProvider": "nordic-semiconductor.nrf-connect" } - ] -} + ], + "version": 4 +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..311ccca9e --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,21 @@ +{ + "nrf-connect.toolchain.path": "${nrf-connect.toolchain:2.6.1}", + "nrf-connect.topdir": "${nrf-connect.sdk:2.4.1}", + "nrf-connect.applications": [ + "${workspaceFolder}/device" + ], + "nrf-connect.boardRoots": [ + "${workspaceFolder}/" + ], + "files.associations": { + "*.h": "c", + "*.c": "c", + "bitset": "cpp", + "span": "cpp", + "array": "cpp", + "string": "cpp", + "string_view": "cpp", + "compare": "c", + "system_error": "c" + } +} \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5d9635bbc..0edfc5c88 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -119,31 +119,31 @@ Header files are composed of sections. The order of sections is fixed. Every hea // Includes: - #include "fsl_gpio.h" - ... +#include "fsl_gpio.h" +... // Macros: - #define LED_DRIVER_SDB_PORT PORTA - ... +#define LED_DRIVER_SDB_PORT PORTA +... // Typedefs: - typedef enum { - KeystrokeType_Basic, - KeystrokeType_Media, - KeystrokeType_System, - } keystroke_type_t; +typedef enum { + KeystrokeType_Basic, + KeystrokeType_Media, + KeystrokeType_System, +} keystroke_type_t; // Variables: - extern led_driver_state_t LedDriverState; - ... +extern led_driver_state_t LedDriverState; +... // Functions: - void LedDriver_WriteBuffer(uint8_t i2cAddress, uint8_t buffer[], uint8_t size); - ... +void LedDriver_WriteBuffer(uint8_t i2cAddress, uint8_t buffer[], uint8_t size); +... #endif ``` @@ -154,4 +154,5 @@ The build process must not yield any warnings, and the build must pass [on on th ## Clang format -There is a `.clang-format` present, which allows you to format your `.c` files simply by `clang-format -i `. (It does **not** ensure the required header file structure though!) +There is a `.clang-format` present, which allows you to format your source files simply by `clang-format -i `. +(It does **not** ensure the required header file structure though!) diff --git a/README.md b/README.md index c5c890891..0403e1d31 100644 --- a/README.md +++ b/README.md @@ -16,13 +16,79 @@ If you want to use the latest firmware version for your UHK, then instead of goi If you're one of the brave few who wants to hack the firmware then read on. -1. Make sure to clone this repo with: +### Fetching the codebase -`git clone --recursive git@github.com:UltimateHackingKeyboard/firmware.git` +Note that these commands will create a [west workspace](https://docs.zephyrproject.org/latest/develop/west/workspaces.html#t2-star-topology-application-is-the-manifest-repository) in your current directory. -Then, depending whether you want a full IDE experience or just minimal tools for building and flashing firmware, read *IDE setup* or *Minimal development setup* (if you prefer a text editor + command line). +```bash +git clone --recurse-submodules git@github.com:UltimateHackingKeyboard/firmware-uhk80.git +west init -l firmware-uhk80 +west update +west patch +west config --local build.cmake-args -- "-Wno-dev" +cd firmware-uhk80/scripts +npm i +./generate-versions.mjs +``` -### IDE setup +Then, depending whether you want a full IDE experience or just minimal tools for building and flashing firmware, read *VS Code setup* or *Minimal development setup* (if you prefer a text editor + command line). + +### VS Code setup + +- Install [nRF Connect SDK](https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrf/installation/install_ncs.html) including VS Code extensions. +- In VS Code, click nRF connect icon in the left pane, then `Applications -> Create new build configuration` and select the relevant CMake preset. Now hit Build. This executes cmake steps. +- Now you can rebuild or flash using the Build and Flash actions. + +### Minimal development setup + +- Install commandline stuff from [nRF Connect SDK](https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrf/installation/install_ncs.html) +- You can use `./build.sh` script that basically just packs the following snippets, but should be more up to date: + + - e.g. `./build.sh uhk-80-left build make flash`, which will perform the three actions below + +- If the `build.sh` doesn't suit you, then launch the nrfutil shell: + ``` + nrfutil toolchain-manager launch --shell --ncs-version v2.6.1 + ``` +- In the shell, you can build (e.g.) uhk-80-left as follows: + + - full build including cmake steps, as extracted from VS Code: + ``` + export DEVICE=uhk-80-left + export PWD=`pwd` + west build --build-dir $PWD/device/build/$DEVICE $PWD/device --pristine --board $DEVICE --no-sysbuild -- -DNCS_TOOLCHAIN_VERSION=NONE -DCONF_FILE=$PWD/device/prj.conf -DOVERLAY_CONFIG=$PWD/device/prj.conf.overlays/$DEVICE.prj.conf -DBOARD_ROOT=$PWD + ``` + + - quick rebuild: + ``` + export DEVICE=uhk-80-left + export PWD=`pwd` + west build --build-dir $PWD/device/build/$DEVICE $PWD/device + ``` + + - flash: + ``` + export DEVICE=uhk-80-left + export PWD=`pwd` + west flash -d $PWD/device/build/$DEVICE + ``` + +In case of problems, please refer to scripts/make-release.mjs + +### Recommended tweaks + +You may find this `.git/hooks/post-checkout` git hook useful: + +```bash +#!/bin/bash + +# Update the submodule in lib/c2usb to the commit recorded in the checked-out commit +git submodule update --init --recursive lib/c2usb +# Refresh versions.c, so that Agent always shows what commit you are on (although it doesn't indicate unstaged changes) +scripts/generate-versions.mjs +``` + +### Old IDE setup 2. Download and install MCUXpresso IDE for [Linux](https://ultimatehackingkeyboard.com/mcuxpressoide/mcuxpressoide-11.2.0_4120.x86_64.deb.bin), [Mac](https://ultimatehackingkeyboard.com/mcuxpressoide/MCUXpressoIDE_11.2.0_4120.pkg), or [Windows](https://ultimatehackingkeyboard.com/mcuxpressoide/MCUXpressoIDE_11.2.0_4120.exe). @@ -39,7 +105,7 @@ Then, depending whether you want a full IDE experience or just minimal tools for Going forward, it's easier to flash the firmware of your choice by using the downwards toolbar icon which is located rightwards of the *green play + toolbox icon*. -### Minimal development setup +### Old Minimal development setup 1. Install the ARM cross-compiler, cross-assembler and stdlib implementation. Eg. on Arch Linux the packages `arm-none-eabi-binutils`, `arm-none-eabi-gcc`, `arm-none-eabi-newlib`. @@ -55,10 +121,18 @@ Going forward, it's easier to flash the firmware of your choice by using the dow ### Releasing -6. To build a full firmware tarball: - 1. Run `npm install` in `scripts`. - 2. Run `scripts/make-release.js`. (Or `scripts/make-release.js --allowSha` for development purposes.) - 3. Now, the created tarball `scripts/uhk-firmware-VERSION.tar.gz` can be flashed with UHK Agent. +To build a full firmware tarball: + +1. Run `npm install` in `scripts`. +2. Run `scripts/make-release.mjs`. (Or `scripts/make-release.mjs --allowSha` for development purposes.) +3. Now, the created tarball `scripts/uhk-firmware-VERSION.tar.gz` can be flashed with UHK Agent. + +If `make-release.mjs` fails with a build error, it'll probably succeed in Nordic's shell environment. + +1. Install [nRF Util](https://www.nordicsemi.com/Products/Development-tools/nRF-Util). +2. Install the nRF Connect Toolchain Manager with `nrfutil install toolchain-manager` +3. Enter the Toolchain Manager shell with `nrfutil toolchain-manager launch --shell` +4. Within the shell, run `make-release.mjs` according to the above. ## Contributing diff --git a/boards/arm/shared.dtsi b/boards/arm/shared.dtsi new file mode 100644 index 000000000..f08214fcd --- /dev/null +++ b/boards/arm/shared.dtsi @@ -0,0 +1,96 @@ +&uicr { + gpio-as-nreset; +}; + +&gpiote { + status = "okay"; +}; + +&gpio0 { + status = "okay"; + sense-edge-mask = <0xffffffff>; +}; + +&uart0 { + compatible = "nordic,nrf-uarte"; + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart0_default>; + pinctrl-1 = <&uart0_sleep>; + pinctrl-names = "default", "sleep"; +}; + +zephyr_udc0: &usbd { + compatible = "nordic,nrf-usbd"; + status = "okay"; +}; + +/ { + chosen { + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; + }; +}; + +/ { + sram@2003FFFF { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x2003FFFF 0x1>; + zephyr,memory-region = "RetainedMem"; + status = "okay"; + + retainedmem { + compatible = "zephyr,retained-ram"; + status = "okay"; + #address-cells = <1>; + #size-cells = <1>; + + retention0: retention@0 { + compatible = "zephyr,retention"; + status = "okay"; + reg = <0x0 0x1>; + }; + }; + }; + + chosen { + zephyr,boot-mode = &retention0; + }; +}; + +/* Reduce SRAM0 usage by 1 byte to account for non-init area */ +&sram0 { + reg = <0x20000000 0x3FFFF>; +}; + +&flash0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x0 0x10000>; + }; + slot0_partition: partition@10000 { + label = "image-0"; + reg = <0x10000 0xdc000>; + }; + hardware_config_partition: partition@ec000 { + label = "hardware-config"; + reg = <0xec000 0x1000>; + }; + user_config_partition: partition@ed000 { + label = "user-config"; + reg = <0xed000 0x10000>; + }; + storage_partition: partition@fd000 { + label = "storage"; + reg = <0xfd000 0x3000>; + }; + }; +}; diff --git a/boards/arm/uhk-60-right/Kconfig.board b/boards/arm/uhk-60-right/Kconfig.board new file mode 100644 index 000000000..2cd56c676 --- /dev/null +++ b/boards/arm/uhk-60-right/Kconfig.board @@ -0,0 +1,7 @@ +# Copyright (c) 2018, Prevas A/S +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_UHK_60_RIGHT + bool "UHK 60 right" + depends on SOC_SERIES_KINETIS_K2X + select SOC_PART_NUMBER_MK22FN512VLH12 diff --git a/boards/arm/uhk-60-right/Kconfig.defconfig b/boards/arm/uhk-60-right/Kconfig.defconfig new file mode 100644 index 000000000..48937804b --- /dev/null +++ b/boards/arm/uhk-60-right/Kconfig.defconfig @@ -0,0 +1,21 @@ +# Copyright (c) 2018 Prevas A/S +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_UHK_60_RIGHT + +config BOARD + default "uhk-60-right" + +config OSC_XTAL0_FREQ + default 8000000 + +config MCG_PRDIV0 + default 0x3 + +config MCG_VDIV0 + default 0xc + +config MCG_FCRDIV + default 0 + +endif diff --git a/boards/arm/uhk-60-right/board.cmake b/boards/arm/uhk-60-right/board.cmake new file mode 100644 index 000000000..debe44fba --- /dev/null +++ b/boards/arm/uhk-60-right/board.cmake @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 + +board_runner_args(jlink "--device=MK22FN512xxx12") +board_runner_args(pyocd "--target=k22f") + +include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) diff --git a/boards/arm/uhk-60-right/uhk-60-right.dts b/boards/arm/uhk-60-right/uhk-60-right.dts new file mode 100644 index 000000000..0c890301f --- /dev/null +++ b/boards/arm/uhk-60-right/uhk-60-right.dts @@ -0,0 +1,262 @@ +/dts-v1/; + +#include +#include +#include + +&pinctrl { + ftm0_default: ftm0_default { + group0 { + pinmux = , + ; + drive-strength = "low"; + bias-pull-up; + slew-rate = "fast"; + }; + group1 { + pinmux = ; + drive-strength = "low"; + slew-rate = "fast"; + }; + }; + + i2c0_default: i2c0_default { + group0 { + pinmux = , + ; + drive-strength = "low"; + drive-open-drain; + slew-rate = "fast"; + }; + }; + + spi0_default: spi0_default { + group0 { + pinmux = , + , + , + ; + drive-strength = "low"; + slew-rate = "fast"; + }; + }; + + uart1_default: uart1_default { + group0 { + pinmux = , + ; + drive-strength = "low"; + slew-rate = "fast"; + }; + }; + + uart2_default: uart2_default { + group0 { + pinmux = , + ; + drive-strength = "low"; + slew-rate = "fast"; + }; + }; + +}; + +/ { + model = "NXP Freedom MK22F board"; + compatible = "nxp,mk22f12", "nxp,k22f", "nxp,k2x"; + + gpios { + compatible = "gpio-keys"; + + row1: row1 { + gpios = <&gpioa 12 (GPIO_ACTIVE_HIGH)>; + label = "row1"; + }; + row2: row2 { + gpios = <&gpioa 13 (GPIO_ACTIVE_HIGH)>; + label = "row2"; + }; + row3: row3 { + gpios = <&gpioc 1 (GPIO_ACTIVE_HIGH)>; + label = "row3"; + }; + row4: row4 { + gpios = <&gpioc 0 (GPIO_ACTIVE_HIGH)>; + label = "row4"; + }; + row5: row5 { + gpios = <&gpiod 5 (GPIO_ACTIVE_HIGH)>; + label = "row5"; + }; + + col1: col1 { + gpios = <&gpioa 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; + label = "col1"; + }; + col2: col2 { + gpios = <&gpiob 16 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; + label = "col2"; + }; + col3: col3 { + gpios = <&gpiob 17 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; + label = "col3"; + }; + col4: col4 { + gpios = <&gpiob 18 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; + label = "col4"; + }; + col5: col5 { + gpios = <&gpiob 19 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; + label = "col5"; + }; + col6: col6 { + gpios = <&gpioa 1 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; + label = "col6"; + }; + col7: col7 { + gpios = <&gpiob 1 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; + label = "col7"; + }; + + test_led: test_led { + gpios = <&gpiod 7 GPIO_ACTIVE_HIGH>; + label = "test_led"; + }; + }; + + aliases { + row1 = &row1; + row2 = &row2; + row3 = &row3; + row4 = &row4; + row5 = &row5; + + col1 = &col1; + col2 = &col2; + col3 = &col3; + col4 = &col4; + col5 = &col5; + col6 = &col6; + col7 = &col7; + + test-led = &test_led; + }; + + chosen { + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; + zephyr,console = &uart1; + zephyr,shell-uart = &uart1; + zephyr,uart-pipe = &uart1; + }; +}; + +&sim { + pllfll-select = ; + er32k-select = ; +}; + +&adc0 { + status = "okay"; +}; + +&dac0 { + status = "okay"; + voltage-reference = <2>; +}; +arduino_i2c: &i2c0 { + status = "okay"; + pinctrl-0 = <&i2c0_default>; + pinctrl-names = "default"; +}; + + +arduino_spi: &spi0 { + status = "okay"; + pinctrl-0 = <&spi0_default>; + pinctrl-names = "default"; +}; + +&ftm0 { + status = "okay"; + compatible = "nxp,kinetis-ftm-pwm"; + #pwm-cells = <3>; + pinctrl-0 = <&ftm0_default>; + pinctrl-names = "default"; +}; + +&uart1 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart1_default>; + pinctrl-names = "default"; +}; + +&uart2 { + pinctrl-0 = <&uart2_default>; + pinctrl-names = "default"; +}; + +zephyr_udc0: &usbotg { + compatible = "nxp,kinetis-usbd"; + status = "okay"; + num-bidir-endpoints = <8>; +}; + +&gpioa { + status = "okay"; +}; + +&gpiob { + status = "okay"; +}; + +&gpioc { + status = "okay"; +}; + +&gpiod { + status = "okay"; +}; + +&gpioe { + status = "okay"; +}; + +&flash0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 0x00010000>; + read-only; + }; + slot0_partition: partition@10000 { + label = "image-0"; + reg = <0x00010000 0x00020000>; + }; + slot1_partition: partition@30000 { + label = "image-1"; + reg = <0x00030000 0x00020000>; + }; + scratch_partition: partition@50000 { + label = "image-scratch"; + reg = <0x00050000 0x00010000>; + }; + + /* + * The flash starting at 0x00060000 and ending at + * 0x0007ffff (sectors 16-31) is reserved for use + * by the application. + */ + storage_partition: partition@60000 { + label = "storage"; + reg = <0x00060000 0x00020000>; + }; + + }; +}; diff --git a/boards/arm/uhk-60-right/uhk-60-right.yaml b/boards/arm/uhk-60-right/uhk-60-right.yaml new file mode 100644 index 000000000..0417e11e3 --- /dev/null +++ b/boards/arm/uhk-60-right/uhk-60-right.yaml @@ -0,0 +1,21 @@ +identifier: uhk-60-right +name: UHK 60 right +type: mcu +arch: arm +ram: 64 +toolchain: + - zephyr + - gnuarmemb +supported: + - adc + - arduino_gpio + - arduino_i2c + - arduino_spi + - dac + - gpio + - i2c + - nvs + - pwm + - spi + - usb_device + - watchdog diff --git a/boards/arm/uhk-60-right/uhk-60-right_defconfig b/boards/arm/uhk-60-right/uhk-60-right_defconfig new file mode 100644 index 000000000..391e5c33b --- /dev/null +++ b/boards/arm/uhk-60-right/uhk-60-right_defconfig @@ -0,0 +1,13 @@ +# Copyright (c) 2018 Prevas A/S +# Copyright (c) 2019 Thomas Burdick +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_MK22F51212=y +CONFIG_SOC_SERIES_KINETIS_K2X=y +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_GPIO=y +CONFIG_PINCTRL=y +CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=72000000 +CONFIG_OSC_LOW_POWER=y diff --git a/boards/arm/uhk-80-left/Kconfig.board b/boards/arm/uhk-80-left/Kconfig.board new file mode 100644 index 000000000..ab0a2c5ba --- /dev/null +++ b/boards/arm/uhk-80-left/Kconfig.board @@ -0,0 +1,6 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_UHK_80_LEFT + bool "UHK 80 left" + depends on SOC_NRF52840_QIAA diff --git a/boards/arm/uhk-80-left/Kconfig.defconfig b/boards/arm/uhk-80-left/Kconfig.defconfig new file mode 100644 index 000000000..95c641e03 --- /dev/null +++ b/boards/arm/uhk-80-left/Kconfig.defconfig @@ -0,0 +1,12 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_UHK_80_LEFT + +config BOARD + default "uhk-80-left" + +config BT_CTLR + default BT + +endif diff --git a/boards/arm/uhk-80-left/board.cmake b/boards/arm/uhk-80-left/board.cmake new file mode 100644 index 000000000..da4efd187 --- /dev/null +++ b/boards/arm/uhk-80-left/board.cmake @@ -0,0 +1,9 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +board_runner_args(jlink "--device=nrf52" "--speed=4000") +board_runner_args(pyocd "--target=nrf52840" "--frequency=4000000") +board_runner_args(nrfjprog "--softreset") +include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) +include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) diff --git a/boards/arm/uhk-80-left/pre_dt_board.cmake b/boards/arm/uhk-80-left/pre_dt_board.cmake new file mode 100644 index 000000000..3369c21d3 --- /dev/null +++ b/boards/arm/uhk-80-left/pre_dt_board.cmake @@ -0,0 +1,7 @@ +# Copyright (c) 2022 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +# Suppress "unique_unit_address_if_enabled" to handle the following overlaps: +# - power@40000000 & clock@40000000 & bprot@40000000 +# - acl@4001e000 & flash-controller@4001e000 +list(APPEND EXTRA_DTC_FLAGS "-Wno-unique_unit_address_if_enabled") diff --git a/boards/arm/uhk-80-left/uhk-80-left.dts b/boards/arm/uhk-80-left/uhk-80-left.dts new file mode 100644 index 000000000..0d0d4ab0c --- /dev/null +++ b/boards/arm/uhk-80-left/uhk-80-left.dts @@ -0,0 +1,231 @@ +/dts-v1/; +#include +#include "../shared.dtsi" + +&gpio1 { + status = "okay"; +}; + +&adc { + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + channel@1 { + reg = <1>; + zephyr,gain = "ADC_GAIN_1_4"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,input-positive = ; // VBAT_ADC + zephyr,resolution = <12>; + }; +}; + +&uart1 { + compatible = "nordic,nrf-uarte"; + status = "okay"; + current-speed = <1000000>; + pinctrl-0 = <&uart1_default>; + pinctrl-1 = <&uart1_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&i2c0 { + compatible = "nordic,nrf-twim"; + status = "okay"; + pinctrl-0 = <&i2c2_default>; + pinctrl-1 = <&i2c2_sleep>; + pinctrl-names = "default", "sleep"; + clock-frequency = <100000>; +}; + +&pinctrl { + uart0_default: uart0_default { + group1 { + psels = ; + bias-pull-up; + }; + group2 { + psels = ; + }; + }; + + uart0_sleep: uart0_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; + + uart1_default: uart1_default { + group1 { + psels = ; + bias-pull-up; + }; + group2 { + psels = ; + }; + }; + + uart1_sleep: uart1_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; + + spi1_default: spi1_default { + group1 { + psels = , + ; + }; + }; + + spi1_sleep: spi1_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; + + i2c2_default: i2c2_default { + group1 { + psels = , + ; + bias-pull-up; + }; + }; + i2c2_sleep: i2c2_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; +}; + +&spi1 { + compatible = "nordic,nrf-spi"; + status = "okay"; + pinctrl-0 = <&spi1_default>; + pinctrl-1 = <&spi1_sleep>; + pinctrl-names = "default", "sleep"; +}; + +/ { + model = "UHK 80 left"; + compatible = "uhk-80-left"; + + gpios { + compatible = "gpio-keys"; + + merge_sense: merge_sense { + gpios = <&gpio1 15 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + label = "merge_sense"; + }; + + charger_en: charger_en { + gpios = <&gpio1 10 GPIO_ACTIVE_LOW>; + label = "charger_en"; + }; + charger_stat: charger_stat { + gpios = <&gpio1 11 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + label = "charger_stat"; + }; + + leds_sdb: leds_sdb { + gpios = <&gpio1 13 GPIO_ACTIVE_HIGH>; + label = "leds_sdb"; + }; + leds_cs: leds_cs { + gpios = <&gpio1 9 GPIO_ACTIVE_LOW>; + label = "leds_cs"; + }; + + row1: row1 { + gpios = <&gpio0 16 (GPIO_ACTIVE_HIGH)>; + label = "row1"; + }; + row2: row2 { + gpios = <&gpio0 12 (GPIO_ACTIVE_HIGH)>; + label = "row2"; + }; + row3: row3 { + gpios = <&gpio0 17 (GPIO_ACTIVE_HIGH)>; + label = "row3"; + }; + row4: row4 { + gpios = <&gpio0 11 (GPIO_ACTIVE_HIGH)>; + label = "row4"; + }; + row5: row5 { + gpios = <&gpio0 21 (GPIO_ACTIVE_HIGH)>; + label = "row5"; + }; + row6: row6 { + gpios = <&gpio0 20 (GPIO_ACTIVE_HIGH)>; + label = "row6"; + }; + + col1: col1 { + gpios = <&gpio0 19 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; + label = "col1"; + }; + col2: col2 { + gpios = <&gpio0 15 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; + label = "col2"; + }; + col3: col3 { + gpios = <&gpio0 14 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; + label = "col3"; + }; + col4: col4 { + gpios = <&gpio1 12 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; + label = "col4"; + }; + col5: col5 { + gpios = <&gpio0 30 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; + label = "col5"; + }; + col6: col6 { + gpios = <&gpio0 31 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; + label = "col6"; + }; + col7: col7 { + gpios = <&gpio0 29 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; + label = "col7"; + }; + }; + + zephyr,user { + io-channels = <&adc 1>; + }; + + aliases { + merge-sense = &merge_sense; + + charger-en = &charger_en; + charger-stat = &charger_stat; + + leds-sdb = &leds_sdb; + leds-cs = &leds_cs; + + row1 = &row1; + row2 = &row2; + row3 = &row3; + row4 = &row4; + row5 = &row5; + row6 = &row6; + + col1 = &col1; + col2 = &col2; + col3 = &col3; + col4 = &col4; + col5 = &col5; + col6 = &col6; + col7 = &col7; + }; +}; diff --git a/boards/arm/uhk-80-left/uhk-80-left.yaml b/boards/arm/uhk-80-left/uhk-80-left.yaml new file mode 100644 index 000000000..b7cb42d4a --- /dev/null +++ b/boards/arm/uhk-80-left/uhk-80-left.yaml @@ -0,0 +1,13 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +identifier: uhk-80-left +name: UHK 80 left +type: mcu +arch: arm +ram: 256 +flash: 1024 +toolchain: + - zephyr + - gnuarmemb + - xtools diff --git a/boards/arm/uhk-80-left/uhk-80-left_defconfig b/boards/arm/uhk-80-left/uhk-80-left_defconfig new file mode 100644 index 000000000..3170f72a9 --- /dev/null +++ b/boards/arm/uhk-80-left/uhk-80-left_defconfig @@ -0,0 +1,12 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_NRF52X=y +CONFIG_SOC_NRF52840_QIAA=y +CONFIG_BOARD_UHK_80_LEFT=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable hardware stack protection +CONFIG_HW_STACK_PROTECTION=y diff --git a/boards/arm/uhk-80-right/Kconfig.board b/boards/arm/uhk-80-right/Kconfig.board new file mode 100644 index 000000000..e29fdbeb0 --- /dev/null +++ b/boards/arm/uhk-80-right/Kconfig.board @@ -0,0 +1,6 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_UHK_80_RIGHT + bool "UHK 80 right" + depends on SOC_NRF52840_QIAA diff --git a/boards/arm/uhk-80-right/Kconfig.defconfig b/boards/arm/uhk-80-right/Kconfig.defconfig new file mode 100644 index 000000000..4868033f7 --- /dev/null +++ b/boards/arm/uhk-80-right/Kconfig.defconfig @@ -0,0 +1,12 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_UHK_80_RIGHT + +config BOARD + default "uhk-80-right" + +config BT_CTLR + default BT + +endif diff --git a/boards/arm/uhk-80-right/board.cmake b/boards/arm/uhk-80-right/board.cmake new file mode 100644 index 000000000..da4efd187 --- /dev/null +++ b/boards/arm/uhk-80-right/board.cmake @@ -0,0 +1,9 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +board_runner_args(jlink "--device=nrf52" "--speed=4000") +board_runner_args(pyocd "--target=nrf52840" "--frequency=4000000") +board_runner_args(nrfjprog "--softreset") +include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) +include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) diff --git a/boards/arm/uhk-80-right/pre_dt_board.cmake b/boards/arm/uhk-80-right/pre_dt_board.cmake new file mode 100644 index 000000000..3369c21d3 --- /dev/null +++ b/boards/arm/uhk-80-right/pre_dt_board.cmake @@ -0,0 +1,7 @@ +# Copyright (c) 2022 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +# Suppress "unique_unit_address_if_enabled" to handle the following overlaps: +# - power@40000000 & clock@40000000 & bprot@40000000 +# - acl@4001e000 & flash-controller@4001e000 +list(APPEND EXTRA_DTC_FLAGS "-Wno-unique_unit_address_if_enabled") diff --git a/boards/arm/uhk-80-right/uhk-80-right.dts b/boards/arm/uhk-80-right/uhk-80-right.dts new file mode 100644 index 000000000..2b871039d --- /dev/null +++ b/boards/arm/uhk-80-right/uhk-80-right.dts @@ -0,0 +1,261 @@ +/dts-v1/; +#include +#include "../shared.dtsi" + +&gpio1 { + status = "okay"; +}; + +&adc { + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + channel@1 { + reg = <1>; + zephyr,gain = "ADC_GAIN_1_4"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,input-positive = ; // VBAT_ADC + zephyr,resolution = <12>; + }; +}; + +&uart1 { + compatible = "nordic,nrf-uarte"; + status = "okay"; + current-speed = <1000000>; + pinctrl-0 = <&uart1_default>; + pinctrl-1 = <&uart1_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&i2c0 { + compatible = "nordic,nrf-twim"; + status = "okay"; + pinctrl-0 = <&i2c2_default>; + pinctrl-1 = <&i2c2_sleep>; + pinctrl-names = "default", "sleep"; + clock-frequency = <100000>; +}; + +&pinctrl { + uart0_default: uart0_default { + group1 { + psels = ; + bias-pull-up; + }; + group2 { + psels = ; + }; + }; + + uart0_sleep: uart0_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; + + uart1_default: uart1_default { + group1 { + psels = ; + bias-pull-up; + }; + group2 { + psels = ; + }; + }; + + uart1_sleep: uart1_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; + + spi1_default: spi1_default { + group1 { + psels = , + ; + }; + }; + + spi1_sleep: spi1_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; + i2c2_default: i2c2_default { + group1 { + psels = , + ; + bias-pull-up; + }; + }; + i2c2_sleep: i2c2_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; +}; + +&spi1 { + compatible = "nordic,nrf-spi"; + status = "okay"; + pinctrl-0 = <&spi1_default>; + pinctrl-1 = <&spi1_sleep>; + pinctrl-names = "default", "sleep"; +}; + +/ { + model = "UHK 80 right"; + compatible = "uhk-80-right"; + + gpios { + compatible = "gpio-keys"; + + charger_en: charger_en { + gpios = <&gpio0 27 GPIO_ACTIVE_LOW>; + label = "charger_en"; + }; + charger_stat: charger_stat { + gpios = <&gpio0 22 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + label = "charger_stat"; + }; + + leds_sdb: leds_sdb { + gpios = <&gpio0 30 GPIO_ACTIVE_HIGH>; + label = "leds_sdb"; + }; + + oled_en: oled_en { + gpios = <&gpio1 3 GPIO_ACTIVE_HIGH>; + label = "oled_en"; + }; + oled_reset: oled_reset { + gpios = <&gpio1 2 GPIO_ACTIVE_HIGH>; + label = "oled_reset"; + }; + oled_a0: oled_a0 { + gpios = <&gpio0 16 GPIO_ACTIVE_HIGH>; + label = "oled_a0"; + }; + oled_cs: oled_cs { + gpios = <&gpio1 0 GPIO_ACTIVE_LOW>; + label = "oled_cs"; + }; + leds_cs: leds_cs { + gpios = <&gpio0 7 GPIO_ACTIVE_LOW>; + label = "leds_cs"; + }; + + row1: row1 { + gpios = <&gpio0 31 (GPIO_ACTIVE_HIGH)>; + label = "row1"; + }; + row2: row2 { + gpios = <&gpio0 17 (GPIO_ACTIVE_HIGH)>; + label = "row2"; + }; + row3: row3 { + gpios = <&gpio1 6 (GPIO_ACTIVE_HIGH)>; + label = "row3"; + }; + row4: row4 { + gpios = <&gpio0 26 (GPIO_ACTIVE_HIGH)>; + label = "row4"; + }; + row5: row5 { + gpios = <&gpio0 2 (GPIO_ACTIVE_HIGH)>; + label = "row5"; + }; + row6: row6 { + gpios = <&gpio0 28 (GPIO_ACTIVE_HIGH)>; + label = "row6"; + }; + + col1: col1 { + gpios = <&gpio1 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; + label = "col1"; + }; + col2: col2 { + gpios = <&gpio0 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; + label = "col2"; + }; + col3: col3 { + gpios = <&gpio1 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; + label = "col3"; + }; + col4: col4 { + gpios = <&gpio1 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; + label = "col4"; + }; + col5: col5 { + gpios = <&gpio0 13 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; + label = "col5"; + }; + col6: col6 { + gpios = <&gpio0 15 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; + label = "col6"; + }; + col7: col7 { + gpios = <&gpio0 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; + label = "col7"; + }; + col8: col8 { + gpios = <&gpio0 19 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; + label = "col8"; + }; + col9: col9 { + gpios = <&gpio0 29 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; + label = "col9"; + }; + col10: col10 { + gpios = <&gpio0 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; + label = "col10"; + }; + }; + + zephyr,user { + io-channels = <&adc 1>; + }; + + aliases { + charger-en = &charger_en; + charger-stat = &charger_stat; + + leds-sdb = &leds_sdb; + + oled-en = &oled_en; + oled-reset = &oled_reset; + oled-a0 = &oled_a0; + oled-cs = &oled_cs; + + leds-cs = &leds_cs; + + row1 = &row1; + row2 = &row2; + row3 = &row3; + row4 = &row4; + row5 = &row5; + row6 = &row6; + + col1 = &col1; + col2 = &col2; + col3 = &col3; + col4 = &col4; + col5 = &col5; + col6 = &col6; + col7 = &col7; + col8 = &col8; + col9 = &col9; + col10 = &col10; + }; +}; diff --git a/boards/arm/uhk-80-right/uhk-80-right.yaml b/boards/arm/uhk-80-right/uhk-80-right.yaml new file mode 100644 index 000000000..82a54f1e5 --- /dev/null +++ b/boards/arm/uhk-80-right/uhk-80-right.yaml @@ -0,0 +1,13 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +identifier: uhk-80-right +name: UHK 80 right +type: mcu +arch: arm +ram: 256 +flash: 1024 +toolchain: + - zephyr + - gnuarmemb + - xtools diff --git a/boards/arm/uhk-80-right/uhk-80-right_defconfig b/boards/arm/uhk-80-right/uhk-80-right_defconfig new file mode 100644 index 000000000..63d485bf2 --- /dev/null +++ b/boards/arm/uhk-80-right/uhk-80-right_defconfig @@ -0,0 +1,12 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_NRF52X=y +CONFIG_SOC_NRF52840_QIAA=y +CONFIG_BOARD_UHK_80_RIGHT=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable hardware stack protection +CONFIG_HW_STACK_PROTECTION=y diff --git a/boards/arm/uhk-dongle/Kconfig.board b/boards/arm/uhk-dongle/Kconfig.board new file mode 100644 index 000000000..165551096 --- /dev/null +++ b/boards/arm/uhk-dongle/Kconfig.board @@ -0,0 +1,6 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_UHK_DONGLE + bool "UHK dongle" + depends on SOC_NRF52840_QIAA diff --git a/boards/arm/uhk-dongle/Kconfig.defconfig b/boards/arm/uhk-dongle/Kconfig.defconfig new file mode 100644 index 000000000..2bf872a39 --- /dev/null +++ b/boards/arm/uhk-dongle/Kconfig.defconfig @@ -0,0 +1,12 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_UHK_DONGLE + +config BOARD + default "uhk-dongle" + +config BT_CTLR + default BT + +endif diff --git a/boards/arm/uhk-dongle/board.cmake b/boards/arm/uhk-dongle/board.cmake new file mode 100644 index 000000000..da4efd187 --- /dev/null +++ b/boards/arm/uhk-dongle/board.cmake @@ -0,0 +1,9 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +board_runner_args(jlink "--device=nrf52" "--speed=4000") +board_runner_args(pyocd "--target=nrf52840" "--frequency=4000000") +board_runner_args(nrfjprog "--softreset") +include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) +include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) diff --git a/boards/arm/uhk-dongle/pre_dt_board.cmake b/boards/arm/uhk-dongle/pre_dt_board.cmake new file mode 100644 index 000000000..3369c21d3 --- /dev/null +++ b/boards/arm/uhk-dongle/pre_dt_board.cmake @@ -0,0 +1,7 @@ +# Copyright (c) 2022 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +# Suppress "unique_unit_address_if_enabled" to handle the following overlaps: +# - power@40000000 & clock@40000000 & bprot@40000000 +# - acl@4001e000 & flash-controller@4001e000 +list(APPEND EXTRA_DTC_FLAGS "-Wno-unique_unit_address_if_enabled") diff --git a/boards/arm/uhk-dongle/uhk-dongle.dts b/boards/arm/uhk-dongle/uhk-dongle.dts new file mode 100644 index 000000000..9a0da29e3 --- /dev/null +++ b/boards/arm/uhk-dongle/uhk-dongle.dts @@ -0,0 +1,93 @@ +/dts-v1/; +#include +#include "../shared.dtsi" + +&pwm0 { + status = "okay"; + pinctrl-0 = <&pwm0_default>; + pinctrl-1 = <&pwm0_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&pinctrl { + uart0_default: uart0_default { + group1 { + psels = ; + bias-pull-up; + }; + group2 { + psels = ; + }; + }; + + uart0_sleep: uart0_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; + + pwm0_default: pwm0_default { + group1 { + psels = , + , + ; + nordic,invert; + }; + }; + + pwm0_sleep: pwm0_sleep { + group1 { + psels = , + , + ; + low-power-enable; + }; + }; +}; + +/ { + model = "UHK dongle"; + compatible = "uhk-dongle"; + + leds { + compatible = "gpio-leds"; + led0_green: led_0 { + gpios = <&gpio0 6 GPIO_ACTIVE_LOW>; + label = "Green LED 0"; + }; + led1_red: led_1 { + gpios = <&gpio0 8 GPIO_ACTIVE_LOW>; + label = "Red LED 1"; + }; + led1_green: led_2 { + gpios = <&gpio1 9 GPIO_ACTIVE_LOW>; + label = "Green LED 1"; + }; + led1_blue: led_3 { + gpios = <&gpio0 12 GPIO_ACTIVE_LOW>; + label = "Blue LED 1"; + }; + }; + + pwmleds { + compatible = "pwm-leds"; + red_pwm_led: red_pwm_led { + pwms = <&pwm0 0 PWM_MSEC(20) PWM_POLARITY_INVERTED>; + }; + green_pwm_led: green_pwm_led { + pwms = <&pwm0 1 PWM_MSEC(20) PWM_POLARITY_INVERTED>; + }; + blue_pwm_led: blue_pwm_led { + pwms = <&pwm0 2 PWM_MSEC(20) PWM_POLARITY_INVERTED>; + }; + }; + + aliases { + led0-green = &led0_green; + red-pwm-led = &red_pwm_led; + green-pwm-led = &green_pwm_led; + blue-pwm-led = &blue_pwm_led; + }; +}; diff --git a/boards/arm/uhk-dongle/uhk-dongle.yaml b/boards/arm/uhk-dongle/uhk-dongle.yaml new file mode 100644 index 000000000..a9470e937 --- /dev/null +++ b/boards/arm/uhk-dongle/uhk-dongle.yaml @@ -0,0 +1,13 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +identifier: uhk-dongle +name: UHK dongle +type: mcu +arch: arm +ram: 256 +flash: 1024 +toolchain: + - zephyr + - gnuarmemb + - xtools diff --git a/boards/arm/uhk-dongle/uhk-dongle_defconfig b/boards/arm/uhk-dongle/uhk-dongle_defconfig new file mode 100644 index 000000000..4d9381c91 --- /dev/null +++ b/boards/arm/uhk-dongle/uhk-dongle_defconfig @@ -0,0 +1,12 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_NRF52X=y +CONFIG_SOC_NRF52840_QIAA=y +CONFIG_BOARD_UHK_DONGLE=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable hardware stack protection +CONFIG_HW_STACK_PROTECTION=y diff --git a/build.sh b/build.sh new file mode 100755 index 000000000..7899a322a --- /dev/null +++ b/build.sh @@ -0,0 +1,368 @@ +#!/bin/bash + +NCS_VERSION=v2.6.1 + +BUILD_SESSION_NAME="buildsession" +UART_SESSION_NAME="uartsession" + +function help() { + cat << END +usage: ./build DEVICE1 DEVICE2 ... ACTION1 ACTION2 ... + + DEVICE is in { uhk-80-left | uhk-80-right | uhk-60-right | uhk-dongle } + there are also these aliases: { left | right | dongle | all } + ACTION is in { clean | setup | update | build | make | flash | flashUsb | shell | uart | addrline
} + + setup initialize submodules and set up zephyr environment + clean removes zephyr libraries + update check out submodules after a git checkout + build full clean build with cmake execution + make just recompile / relink the binary + flash make and then flash + flashUsb just flash via USB + shell open build shell + uart open uhk shell + + Optionally run with "--dev-id 123" to select device for flashing. + + Or you can also specify dev ids in a .devices file, e.g.: + + DEVICEID_UHK80_LEFT=69660648 + DEVICEID_UHK80_RIGHT=69660578 + DEVICEID_UHK_DONGLE=683150769 + + You can also set a command that will be executed after the builds are finished, + and a command that will be executed whenever this script is invoked: + + POSTBUILD=mplayer ring.mp3 + PREBUILD=./fixStuff.sh + + Examples: + ./build uhk-80-right flash --dev-id 123 + ./build all build flash +END +} + +function processArguments() { + DEVICES="" + OTHER_ARGS="" + + while [ -n "$1" ] + do + case $1 in + uhk-80-left|uhk-80-right|uhk-60-right|uhk-dongle) + DEVICES="$DEVICES $1" + shift + ;; + left) + DEVICES="$DEVICES uhk-80-left" + shift + ;; + right) + DEVICES="$DEVICES uhk-80-right" + shift + ;; + dongle) + DEVICES="$DEVICES uhk-dongle" + shift + ;; + all) + DEVICES="$DEVICES uhk-80-left uhk-80-right uhk-dongle" + shift + ;; + clean|setup|update|build|make|flash|flashUsb|shell|release) + ACTIONS="$ACTIONS $1" + TARGET_TMUX_SESSION=$BUILD_SESSION_NAME + shift + ;; + addrline) + shift + ADDR=$1 + shift + for device in $DEVICES + do + echo "addrline for $ADDR:" + printf " " + # addr2line -e device/build/$device/zephyr/zephyr.elf $ADDR + arm-none-eabi-addr2line -e device/build/$device/zephyr/zephyr.elf $ADDR + done + exit 0 + ;; + uart) + ACTIONS="$ACTIONS $1" + TARGET_TMUX_SESSION=$UART_SESSION_NAME + shift + ;; + *) + OTHER_ARGS="$OTHER_ARGS $1" + shift + ;; + esac + done + + if [ "$ACTIONS" == "" ] + then + help + fi +} + +mutex() { + local lockfile="/tmp/uhk_build_lockfile" + if [ "$1" == "lock" ]; then + exec 200>"$lockfile" # Open file descriptor 200 for the lockfile + flock 200 # Block until lock is acquired + elif [ "$1" == "unlock" ]; then + flock -u 200 # Unlock the file descriptor + rm -f "$lockfile" # Remove lockfile + fi +} + +function determineUsbDeviceArg() { + DEVICE=$1 + DEVICEUSBID="" + + case $DEVICE in + uhk-80-left) + DEVICEUSBID="--vid=0x37a8 --pid=7 --usb-interface=2" + ;; + uhk-80-right) + DEVICEUSBID="--vid=0x37a8 --pid=9 --usb-interface=2" + ;; + uhk-dongle) + DEVICEUSBID="--vid=0x37a8 --pid=5 --usb-interface=2" + ;; + uhk-60) + ;; + esac + + echo $DEVICEUSBID +} + +function determineDevIdArg() { + DEVICE=$1 + DEVICEID="" + + case $DEVICE in + uhk-80-left) + DEVICEID="$DEVICEID_UHK80_LEFT" + ;; + uhk-80-right) + DEVICEID="$DEVICEID_UHK80_RIGHT" + ;; + uhk-dongle) + DEVICEID="$DEVICEID_UHK_DONGLE" + ;; + uhk-60) + DEVICEID="$DEVICEID_UHK60" + ;; + esac + + + if [ "$DEVICEID" == "" ] + then + cat > /dev/tty << END + "In order to make your life comfortable, you can define your device + ids in file .devices. Example content: + + DEVICEID_UHK80_LEFT=69660648 + DEVICEID_UHK80_RIGHT=69660578 + DEVICEID_UHK_DONGLE=683150769 +END + echo "" + else + echo "--dev-id $DEVICEID" + fi +} + +function establishSession() { + SESSION_NAME=$1 + NUM_PANES=$2 + + tmux has-session -t $SESSION_NAME 2>/dev/null + if [ $? != 0 ]; then + tmux new-session -d -s $SESSION_NAME + pane_count=1 + is_new_session=true + else + pane_count=$(tmux list-panes -t $SESSION_NAME | wc -l) + is_new_session=false + fi + + for ((i = $pane_count; i < $NUM_PANES; i++)) + do + tmux split-window -t $SESSION_NAME + tmux select-layout -t $SESSION_NAME tiled + done + + tmux if-shell '[ "$(tmux display-message -p "#{pane_index}")" -gt '"$NUM_PANES"' ]' 'select-pane -t 1' +} + +function setupUartMonitor() { + SESSION_NAME=$TARGET_TMUX_SESSION + establishSession $SESSION_NAME `ls /dev/ttyUSB* | wc -l` + + i=0 + for TTY in `ls /dev/ttyUSB*` + do + tmux send-keys -t $SESSION_NAME.$i "screen $TTY 115200" C-m + i=$(( $i + 1 )) + done + + if [ "$is_new_session" == "true" ] + then + tmux attach -t $SESSION_NAME + fi +} + +function createCentralCompileCommands() { + TEMP_COMMANDS=`mktemp` + + echo creating central compile_commands.json + + jq -s 'add' $ROOT/device/build/*/compile_commands.json $ROOT/right/uhk60v2/compile_commands.json $ROOT/*/compile_commands.json > $TEMP_COMMANDS + + mv $TEMP_COMMANDS $ROOT/compile_commands.json +} + +function performAction() { + DEVICE=$1 + ACTION=$2 + ROOT=`realpath .` + + case $ACTION in + update) + git submodule update --init --recursive + west update + west patch + west config --local build.cmake-args -- "-Wno-dev" + cd "$ROOT/scripts" + npm ci + ./generate-versions.mjs + ;; + clean) + rm -rf device/build .west bootloader modules nrf nrfxlib test tools zephyr + ;; + setup) + # update this according to README + git submodule init + git submodule update --init --recursive + cd "$ROOT/.." + west init -l "$ROOT" + west update + west patch + west config --local build.cmake-args -- "-Wno-dev" + cd "$ROOT/scripts" + npm i + ./generate-versions.mjs + ;; + build) + # reference version of the build process is to be found in scripts/make-release.mjs + nrfutil toolchain-manager launch --shell --ncs-version $NCS_VERSION << END + unset PYTHONPATH + unset PYTHONHOME + ZEPHYR_TOOLCHAIN_VARIANT=zephyr west build --build-dir "$ROOT/device/build/$DEVICE" "$ROOT/device" --pristine --board "$DEVICE" --no-sysbuild -- -DNCS_TOOLCHAIN_VERSION=NONE -DEXTRA_CONF_FILE=prj.conf.overlays/$DEVICE.prj.conf -DBOARD_ROOT="$ROOT" -Dmcuboot_OVERLAY_CONFIG="$ROOT/device/child_image/mcuboot.conf;$ROOT/device/child_image/$DEVICE.mcuboot.conf" + +END + createCentralCompileCommands + ;; + make) + nrfutil toolchain-manager launch --shell --ncs-version $NCS_VERSION << END + west build --build-dir $ROOT/device/build/$DEVICE device +END + ;; + flash) + DEVICEARG=`determineDevIdArg $DEVICE` + nrfutil toolchain-manager launch --shell --ncs-version $NCS_VERSION << END + west flash -d $ROOT/device/build/$DEVICE $DEVICEARG $OTHER_ARGS < /dev/tty +END + ;; + flashUsb) + USBDEVICEARG=`determineUsbDeviceArg $DEVICE` + USB_SCRIPT_DIR=$ROOT/lib/agent/packages/usb/ + cd $USB_SCRIPT_DIR + echo "running $USB_SCRIPT_DIR$ ./update-device-firmware.ts $USBDEVICEARG $ROOT/device/build/$DEVICE/zephyr/app_update.bin $OTHER_ARGS" + mutex lock + ./update-device-firmware.ts $USBDEVICEARG $ROOT/device/build/$DEVICE/zephyr/app_update.bin $OTHER_ARGS + mutex unlock + cd $ROOT + ;; + release) + nrfutil toolchain-manager launch --shell --ncs-version $NCS_VERSION << END + scripts/make-release.mjs --allowSha +END + ;; + shell) + nrfutil toolchain-manager launch --shell --ncs-version $NCS_VERSION + ;; + uart) + setupUartMonitor + ;; + addrline) + ;; + *) + help + ;; + esac +} + +function performActions() { + DEVICE=$1 + for ACTION in $ACTIONS + do + performAction "$DEVICE" $ACTION + done + eval $POSTBUILD +} + +function runPerDevice() { + SESSION_NAME=$TARGET_TMUX_SESSION + establishSession $SESSION_NAME `echo $DEVICES | wc -w` + + i=0 + for DEVICE in $DEVICES + do + tmux send-keys -t $SESSION_NAME.$i "$0 $DEVICE $ACTIONS" C-m + i=$(( $i + 1 )) + done + + if [ "$is_new_session" == "true" ] + then + tmux attach -t $SESSION_NAME + fi +} + +function run() { + if [ -f .devices ] + then + source .devices + eval $PREBUILD + fi + + processArguments $@ + + echo "DEVICES = $DEVICES" + echo "ACTIONS = $ACTIONS" + + if [ `echo $DEVICES | wc -w` -gt 1 ] + then + runPerDevice + elif [ `echo $DEVICES | wc -w` -eq 0 ] + then + performActions $DEVICES + else + tmux has-session -t $TARGET_TMUX_SESSION 2>/dev/null + SESSION_EXISTS=$? + if [ $SESSION_EXISTS == 0 -a "$TMUX" == "" ] + then + runPerDevice + else + performActions $DEVICES + fi + fi + +} + +run $@ + + + diff --git a/device/.gitignore b/device/.gitignore new file mode 100644 index 000000000..0ec9e7f98 --- /dev/null +++ b/device/.gitignore @@ -0,0 +1 @@ +/build* diff --git a/device/CMakeLists.txt b/device/CMakeLists.txt new file mode 100644 index 000000000..7168199ae --- /dev/null +++ b/device/CMakeLists.txt @@ -0,0 +1,48 @@ +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(uhk) + +target_include_directories(app PUBLIC + src + src/legacy + src/legacy/config_parser + src/shared +) + +file(GLOB usb_sources src/usb/*.c) +file(GLOB usb_cpp_sources src/usb/*.cpp) +file(GLOB_RECURSE keyboard_sources src/keyboard/*.c) +file(GLOB app_sources src/*.c) +file(GLOB app_cpp_sources src/*.cpp) +file(GLOB lvgl_dummy src/lvgl/*.c) +file(GLOB_RECURSE legacy_sources src/legacy/*.c) +file(GLOB_RECURSE shared_sources src/shared/*.c) + +# add the versions.c source file conditionally +if(NOT NOVERSIONS) + target_sources(app PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../shared/versions.c) + set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/../shared/versions.c PROPERTIES GENERATED TRUE) +endif() + +if(BOARD STREQUAL "uhk-60-right") + file(GLOB main src/uhk60/main.c) + target_sources(app PRIVATE ${main}) +elseif ((BOARD STREQUAL "uhk-dongle")) + target_sources(app PRIVATE ${app_sources} ${app_cpp_sources} ${usb_sources} ${usb_cpp_sources} ${legacy_sources} ${shared_sources}) +else() + target_sources(app PRIVATE ${app_sources} ${app_cpp_sources} ${usb_sources} ${usb_cpp_sources} ${legacy_sources} ${shared_sources} ${keyboard_sources} ${lvgl_dummy}) +endif() + +if(NOT BOARD STREQUAL "uhk-60-right") + # C headers compiled with C++ give pointer conversion errors, turn them to warnings + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive") + + set(C2USB_PATH "c2usb") + + add_subdirectory(${C2USB_PATH}) + + # Link app to c2usb + target_link_libraries(app PRIVATE + c2usb + ) +endif() diff --git a/device/CMakePresets.json b/device/CMakePresets.json new file mode 100644 index 000000000..517bd40c2 --- /dev/null +++ b/device/CMakePresets.json @@ -0,0 +1,89 @@ +{ + "version": 2, + "cmakeMinimumRequired": { + "major": 3, + "minor": 20 + }, + "configurePresets": [ + { + "name": "build-uhk-60-v1-right", + "displayName": "UHK 60 v1 right", + "generator": "Ninja", + "binaryDir": "${sourceDir}/build/uhk-60-right-v1", + "cacheVariables": { + "NCS_TOOLCHAIN_VERSION": "NONE", + "BOARD": "uhk-60-right", + "BOARD_ROOT": "${sourceParentDir}/", + "CONF_FILE": "${sourceDir}/prj.conf", + "OVERLAY_CONFIG": "${sourceDir}/prj.conf.overlays/uhk-60-v1-right.prj.conf" + }, + "warnings": { + "dev": false + } + }, + { + "name": "build-uhk-60-v2-right", + "displayName": "UHK 60 v2 right", + "generator": "Ninja", + "binaryDir": "${sourceDir}/build/uhk-60-right-v2", + "cacheVariables": { + "NCS_TOOLCHAIN_VERSION": "NONE", + "BOARD": "uhk-60-right", + "BOARD_ROOT": "${sourceParentDir}/", + "CONF_FILE": "${sourceDir}/prj.conf", + "OVERLAY_CONFIG": "${sourceDir}/prj.conf.overlays/uhk-60-v2-right.prj.conf" + }, + "warnings": { + "dev": false + } + }, + { + "name": "build/uhk-80-right", + "displayName": "Build for UHK 80 right", + "generator": "Ninja", + "binaryDir": "${sourceDir}/build/uhk-80-right", + "cacheVariables": { + "NCS_TOOLCHAIN_VERSION": "NONE", + "BOARD": "uhk-80-right", + "BOARD_ROOT": "${sourceParentDir}/", + "mcuboot_OVERLAY_CONFIG": "${sourceDir}/child_image/mcuboot.conf;${sourceDir}/child_image/uhk-80-right.mcuboot.conf", + "EXTRA_CONF_FILE": "${sourceDir}/prj.conf.overlays/uhk-80-right.prj.conf" + }, + "warnings": { + "dev": false + } + }, + { + "name": "build/uhk-80-left", + "displayName": "Build for UHK 80 left", + "generator": "Ninja", + "binaryDir": "${sourceDir}/build/uhk-80-left", + "cacheVariables": { + "NCS_TOOLCHAIN_VERSION": "NONE", + "BOARD": "uhk-80-left", + "BOARD_ROOT": "${sourceParentDir}/", + "mcuboot_OVERLAY_CONFIG": "${sourceDir}/child_image/mcuboot.conf;${sourceDir}/child_image/uhk-80-left.mcuboot.conf", + "EXTRA_CONF_FILE": "${sourceDir}/prj.conf.overlays/uhk-80-left.prj.conf" + }, + "warnings": { + "dev": false + } + }, + { + "name": "build/uhk-dongle", + "displayName": "Build for UHK dongle", + "generator": "Ninja", + "binaryDir": "${sourceDir}/build/uhk-dongle", + "cacheVariables": { + "NCS_TOOLCHAIN_VERSION": "NONE", + "BOARD": "uhk-dongle", + "BOARD_ROOT": "${sourceParentDir}/", + "mcuboot_OVERLAY_CONFIG": "${sourceDir}/child_image/mcuboot.conf;${sourceDir}/child_image/uhk-dongle.mcuboot.conf", + "EXTRA_CONF_FILE": "${sourceDir}/prj.conf.overlays/uhk-dongle.prj.conf" + }, + "warnings": { + "dev": false + } + } + ] +} \ No newline at end of file diff --git a/device/Kconfig b/device/Kconfig new file mode 100644 index 000000000..d42383526 --- /dev/null +++ b/device/Kconfig @@ -0,0 +1,25 @@ +source "Kconfig.zephyr" + +rsource "c2usb/c2usb/port/zephyr/Kconfig" + +config DEVICE_ID + int "UHK device id" + default 0 + help + The device id that identifies the specific UHK half or dongle. + +config KEYBOARD_MAX_SCANCODE + hex "highest keyboard scancode" + default 0x86 + range 0x66 0xDD + help + The highest keyboard scancode value influences the overall length of the HID record sent to the host. + The default is set so Android devices (which don't exchange the MTU from the default 23) + still receive the "NKRO" report layout. If a higher scancode is used, the report size will exceed this size, + causing a fallback to 6KRO report layout on Android. + +config USB_PID + hex "USB product ID" + range 0x0000 0xFFFF + help + The USB product ID is used to identify the specific UHK device. diff --git a/device/c2usb b/device/c2usb new file mode 120000 index 000000000..060933c71 --- /dev/null +++ b/device/c2usb @@ -0,0 +1 @@ +../lib/c2usb \ No newline at end of file diff --git a/device/child_image/mcuboot.conf b/device/child_image/mcuboot.conf new file mode 100644 index 000000000..f91fe5581 --- /dev/null +++ b/device/child_image/mcuboot.conf @@ -0,0 +1,24 @@ +CONFIG_PINCTRL=y +CONFIG_PM_PARTITION_SIZE_MCUBOOT=0x10000 +CONFIG_LOG=y +CONFIG_SIZE_OPTIMIZATIONS=y +CONFIG_SERIAL=y +CONFIG_UART_LINE_CTRL=y +CONFIG_MCUBOOT_SERIAL=y +CONFIG_BOOT_SERIAL_CDC_ACM=y +CONFIG_BOOT_SERIAL_PIN_RESET=y +CONFIG_BOOT_SERIAL_WAIT_FOR_DFU=y +CONFIG_BOOT_SERIAL_WAIT_FOR_DFU_ALWAYS=n +CONFIG_BOOT_SERIAL_WAIT_FOR_DFU_TIMEOUT=3000 +CONFIG_BOOT_SERIAL_NO_APPLICATION=y +CONFIG_USB_DEVICE_VID=0x37A8 +CONFIG_USB_DEVICE_MANUFACTURER="Ultimate Gadget Laboratories" +CONFIG_DISABLE_FLASH_PATCH=y +CONFIG_LOG_BACKEND_RTT=n +CONFIG_SINGLE_APPLICATION_SLOT=y +CONFIG_BOOT_MAX_LINE_INPUT_LEN=8192 +CONFIG_BOOT_SERIAL_MAX_RECEIVE_SIZE=4096 +CONFIG_RETAINED_MEM=y +CONFIG_RETENTION=y +CONFIG_RETENTION_BOOT_MODE=y +CONFIG_BOOT_SERIAL_BOOT_MODE=y diff --git a/device/child_image/uhk-80-left.mcuboot.conf b/device/child_image/uhk-80-left.mcuboot.conf new file mode 100644 index 000000000..b8c9af3ce --- /dev/null +++ b/device/child_image/uhk-80-left.mcuboot.conf @@ -0,0 +1,2 @@ +CONFIG_USB_DEVICE_PRODUCT="UHK 80 left half bootloader" +CONFIG_USB_DEVICE_PID=0x0006 diff --git a/device/child_image/uhk-80-right.mcuboot.conf b/device/child_image/uhk-80-right.mcuboot.conf new file mode 100755 index 000000000..95fa80db4 --- /dev/null +++ b/device/child_image/uhk-80-right.mcuboot.conf @@ -0,0 +1,2 @@ +CONFIG_USB_DEVICE_PRODUCT="UHK 80 right half bootloader" +CONFIG_USB_DEVICE_PID=0x0008 diff --git a/device/child_image/uhk-dongle.mcuboot.conf b/device/child_image/uhk-dongle.mcuboot.conf new file mode 100644 index 000000000..21e1583e5 --- /dev/null +++ b/device/child_image/uhk-dongle.mcuboot.conf @@ -0,0 +1,2 @@ +CONFIG_USB_DEVICE_PRODUCT="UHK dongle bootloader" +CONFIG_USB_DEVICE_PID=0x0004 diff --git a/device/pm_static.yml b/device/pm_static.yml new file mode 100644 index 000000000..a4314f18c --- /dev/null +++ b/device/pm_static.yml @@ -0,0 +1,63 @@ +app: + address: 0x10200 + end_address: 0xfd000 + region: flash_primary + size: 0xece00 +mcuboot: + address: 0x0 + end_address: 0x10000 + placement: + before: + - mcuboot_primary + region: flash_primary + size: 0x10000 +mcuboot_pad: + address: 0x10000 + end_address: 0x10200 + placement: + align: + start: 0x1000 + before: + - mcuboot_primary_app + region: flash_primary + size: 0x200 +mcuboot_primary: + address: 0x10000 + end_address: 0xfd000 + orig_span: &id001 + - app + - mcuboot_pad + region: flash_primary + size: 0xed000 + span: *id001 +mcuboot_primary_app: + address: 0x10200 + end_address: 0xfd000 + orig_span: &id002 + - app + region: flash_primary + size: 0xece00 + span: *id002 +hardware_config_partition: + address: 0xec000 + end_address: 0xed000 + size: 0x1000 +user_config_partition: + address: 0xed000 + end_address: 0xfd000 + size: 0x10000 +settings_storage: + address: 0xfd000 + end_address: 0x100000 + placement: + align: + start: 0x1000 + before: + - end + region: flash_primary + size: 0x3000 +sram_primary: + address: 0x20000000 + end_address: 0x20040000 + region: sram_primary + size: 0x40000 diff --git a/device/prj.conf b/device/prj.conf new file mode 100644 index 000000000..cfc45635b --- /dev/null +++ b/device/prj.conf @@ -0,0 +1,97 @@ +CONFIG_PINCTRL=y +CONFIG_RETAINED_MEM=y +CONFIG_RETENTION=y +CONFIG_RETENTION_BOOT_MODE=y + +CONFIG_EXTRA_EXCEPTION_INFO=y +CONFIG_INIT_STACKS=y + +CONFIG_CPP=y +CONFIG_STD_CPP20=y +CONFIG_NEWLIB_LIBC=y +CONFIG_GLIBCXX_LIBCPP=y + +CONFIG_UDC_DRIVER=y + +CONFIG_NCS_SAMPLES_DEFAULTS=y + +CONFIG_BT=y +# CONFIG_BT_DEBUG_LOG=y +CONFIG_BT_MAX_CONN=4 +CONFIG_BT_MAX_PAIRED=20 +CONFIG_BT_SMP=y +CONFIG_BT_L2CAP_TX_BUF_COUNT=5 +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_DEVICE_NAME="UHK 80" +CONFIG_BT_DEVICE_APPEARANCE=961 + +CONFIG_BT_BAS=y + +CONFIG_BT_DIS=y +CONFIG_BT_DIS_PNP=y +CONFIG_BT_DIS_PNP_VID_SRC=2 +CONFIG_BT_DIS_PNP_VID=0x37A8 +CONFIG_BT_DIS_MANUF="Ultimate Gadget Laboratories" + +CONFIG_BT_SETTINGS=y +CONFIG_FLASH=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_FLASH_MAP=y +CONFIG_NVS=y +CONFIG_SETTINGS=y + +CONFIG_SERIAL=y + +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y +CONFIG_UART_LINE_CTRL=y +CONFIG_UART_ASYNC_API=y + +CONFIG_SHELL=y +CONFIG_SHELL_VT100_COMMANDS=y +CONFIG_SHELL_VT100_COLORS=y +CONFIG_BT_SHELL=y +CONFIG_SHELL_BT_NUS=y +CONFIG_HWINFO=y +CONFIG_HWINFO_SHELL=y +CONFIG_I2C=y +CONFIG_I2C_SHELL=y +CONFIG_STREAM_FLASH=y +CONFIG_SETTINGS_SHELL=y +CONFIG_SHELL_BACKENDS=y + +CONFIG_USE_SEGGER_RTT=y +CONFIG_RTT_CONSOLE=y +CONFIG_SHELL_BACKEND_SERIAL=y +CONFIG_SHELL_BACKEND_RTT=y +# CONFIG_LOG_BACKEND_RTT=y +CONFIG_BUILD_OUTPUT_HEX=y + +CONFIG_BT_CENTRAL=y +CONFIG_BT_GATT_CLIENT=y +CONFIG_BT_OBSERVER=y +CONFIG_BT_NUS=y +CONFIG_BT_NUS_CLIENT=y +CONFIG_BT_SCAN=y +CONFIG_BT_SCAN_FILTER_ENABLE=y +CONFIG_BT_SCAN_UUID_CNT=1 +CONFIG_BT_GATT_DM=y +CONFIG_HEAP_MEM_POOL_SIZE=2048 +CONFIG_BT_SCAN_ADDRESS_CNT=2 +CONFIG_WARN_EXPERIMENTAL=n + +CONFIG_BT_GAP_AUTO_UPDATE_CONN_PARAMS=n + +CONFIG_BT_USER_DATA_LEN_UPDATE=y +CONFIG_BT_BUF_ACL_RX_SIZE=251 +CONFIG_BT_BUF_ACL_TX_SIZE=251 +CONFIG_BT_L2CAP_TX_MTU=247 + +CONFIG_BT_ATT_PREPARE_COUNT=4 + +CONFIG_UDC_DRIVER_LOG_LEVEL_WRN=y + +# Apply config requires deep stack, and since Agent expects response code, +# we can't just do it from the main thread +CONFIG_C2USB_UDC_MAC_THREAD_STACK_SIZE=2048 + diff --git a/device/prj.conf.overlays/uhk-60-v1-right.prj.conf b/device/prj.conf.overlays/uhk-60-v1-right.prj.conf new file mode 100644 index 000000000..fd4365e77 --- /dev/null +++ b/device/prj.conf.overlays/uhk-60-v1-right.prj.conf @@ -0,0 +1,13 @@ +# DEVICE_ID_UHK60V1 +CONFIG_UDC_KINETIS=y +CONFIG_BOOTLOADER_MCUBOOT=n +CONFIG_DEVICE_ID=1 +CONFIG_BT=n +CONFIG_SHELL_PROMPT_UART="uhk60v1:right$ " +CONFIG_SHELL_PROMPT_RTT="uhk60v1:right$ " + +CONFIG_BT_DIS_MODEL="UHK 60 v1" +CONFIG_BT_DIS_PNP_VID_SRC=2 +CONFIG_BT_DIS_PNP_VID=0x1D50 +CONFIG_BT_DIS_PNP_PID=0x6122 +CONFIG_BT_DIS_PNP_VER=0x0001 diff --git a/device/prj.conf.overlays/uhk-60-v2-right.prj.conf b/device/prj.conf.overlays/uhk-60-v2-right.prj.conf new file mode 100644 index 000000000..5200e2e55 --- /dev/null +++ b/device/prj.conf.overlays/uhk-60-v2-right.prj.conf @@ -0,0 +1,13 @@ +# DEVICE_ID_UHK60V2 +CONFIG_UDC_KINETIS=y +CONFIG_BOOTLOADER_MCUBOOT=n +CONFIG_DEVICE_ID=2 +CONFIG_BT=n +CONFIG_SHELL_PROMPT_UART="uhk60v2:right$ " +CONFIG_SHELL_PROMPT_RTT="uhk60v2:right$ " + +CONFIG_BT_DIS_MODEL="UHK 60 v2" +CONFIG_BT_DIS_PNP_VID_SRC=2 +CONFIG_BT_DIS_PNP_VID=0x1D50 +CONFIG_BT_DIS_PNP_PID=0x6124 +CONFIG_BT_DIS_PNP_VER=0x0002 diff --git a/device/prj.conf.overlays/uhk-80-left.prj.conf b/device/prj.conf.overlays/uhk-80-left.prj.conf new file mode 100644 index 000000000..3fd36bc24 --- /dev/null +++ b/device/prj.conf.overlays/uhk-80-left.prj.conf @@ -0,0 +1,15 @@ +# DEVICE_ID_UHK80_LEFT +CONFIG_SPI=y +CONFIG_UART_1_ASYNC=y +CONFIG_UART_1_NRF_HW_ASYNC=y +CONFIG_UART_1_NRF_HW_ASYNC_TIMER=1 +CONFIG_ADC=y +CONFIG_UDC_NRF=y +CONFIG_BOOTLOADER_MCUBOOT=y +CONFIG_DEVICE_ID=3 +CONFIG_SHELL_PROMPT_UART="uhk80:left$ " +CONFIG_SHELL_PROMPT_RTT="uhk80:left$ " + +CONFIG_BT_DIS_MODEL="UHK 80 left half" +CONFIG_BT_DIS_PNP_PID=0x8007 +CONFIG_USB_PID=0x0007 diff --git a/device/prj.conf.overlays/uhk-80-right.prj.conf b/device/prj.conf.overlays/uhk-80-right.prj.conf new file mode 100644 index 000000000..e848bdd57 --- /dev/null +++ b/device/prj.conf.overlays/uhk-80-right.prj.conf @@ -0,0 +1,19 @@ +# DEVICE_ID_UHK80_RIGHT +CONFIG_C2USB_BLUETOOTH=y +CONFIG_BT_KEYS_OVERWRITE_OLDEST=y +CONFIG_BT_KEYS_SAVE_AGING_COUNTER_ON_PAIRING=y + +CONFIG_SPI=y +CONFIG_UART_1_ASYNC=y +CONFIG_UART_1_NRF_HW_ASYNC=y +CONFIG_UART_1_NRF_HW_ASYNC_TIMER=1 +CONFIG_ADC=y +CONFIG_UDC_NRF=y +CONFIG_BOOTLOADER_MCUBOOT=y +CONFIG_DEVICE_ID=4 +CONFIG_SHELL_PROMPT_UART="uhk80:right$ " +CONFIG_SHELL_PROMPT_RTT="uhk80:right$ " + +CONFIG_BT_DIS_MODEL="UHK 80 right half" +CONFIG_BT_DIS_PNP_PID=0x8009 +CONFIG_USB_PID=0x0009 diff --git a/device/prj.conf.overlays/uhk-dongle.prj.conf b/device/prj.conf.overlays/uhk-dongle.prj.conf new file mode 100644 index 000000000..264ac82df --- /dev/null +++ b/device/prj.conf.overlays/uhk-dongle.prj.conf @@ -0,0 +1,12 @@ +# DEVICE_ID_UHK_DONGLE +CONFIG_ADC=n +CONFIG_PWM=y +CONFIG_UDC_NRF=y +CONFIG_BOOTLOADER_MCUBOOT=y +CONFIG_DEVICE_ID=5 +CONFIG_SHELL_PROMPT_UART="uhk-dongle$ " +CONFIG_SHELL_PROMPT_RTT="uhk-dongle$ " + +CONFIG_BT_DIS_MODEL="UHK dongle" +CONFIG_BT_DIS_PNP_PID=0x8005 +CONFIG_USB_PID=0x0005 diff --git a/device/src/bt_advertise.c b/device/src/bt_advertise.c new file mode 100644 index 000000000..728caf86d --- /dev/null +++ b/device/src/bt_advertise.c @@ -0,0 +1,90 @@ +#include "bt_advertise.h" +#include +#include +#include "device.h" + +#undef DEVICE_NAME +#define DEVICE_NAME CONFIG_BT_DEVICE_NAME +#define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1) + +// Advertisement packets + +#define AD_NUS_DATA \ + BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), \ + BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN), + +#define AD_HID_DATA \ + BT_DATA_BYTES(BT_DATA_GAP_APPEARANCE, (CONFIG_BT_DEVICE_APPEARANCE >> 0) & 0xff, \ + (CONFIG_BT_DEVICE_APPEARANCE >> 8) & 0xff), \ + BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), \ + BT_DATA_BYTES(BT_DATA_UUID16_ALL, BT_UUID_16_ENCODE(BT_UUID_HIDS_VAL), \ + BT_UUID_16_ENCODE(BT_UUID_BAS_VAL)), + +static const struct bt_data adNus[] = {AD_NUS_DATA}; + +static const struct bt_data adHid[] = {AD_HID_DATA}; + +static const struct bt_data adNusHid[] = {AD_NUS_DATA AD_HID_DATA}; + +// Scan response packets + +#define SD_NUS_DATA BT_DATA_BYTES(BT_DATA_UUID128_ALL, BT_UUID_NUS_VAL), + +#define SD_HID_DATA BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN), + +static const struct bt_data sdNus[] = {SD_NUS_DATA}; + +static const struct bt_data sdHid[] = {SD_HID_DATA}; + +static const struct bt_data sdNusHid[] = {SD_NUS_DATA SD_HID_DATA}; + +void BtAdvertise_Start(uint8_t adv_type) +{ + int err; + const char *adv_type_string; + if (adv_type == (ADVERTISE_NUS | ADVERTISE_HID)) { + adv_type_string = "NUS and HID"; + err = bt_le_adv_start( + BT_LE_ADV_CONN, adNusHid, ARRAY_SIZE(adNusHid), sdNusHid, ARRAY_SIZE(sdNusHid)); + } else if (adv_type == ADVERTISE_NUS) { + adv_type_string = "NUS"; + err = bt_le_adv_start(BT_LE_ADV_CONN, adNus, ARRAY_SIZE(adNus), sdNus, ARRAY_SIZE(sdNus)); + } else if (adv_type == ADVERTISE_HID) { + adv_type_string = "HID"; + err = bt_le_adv_start(BT_LE_ADV_CONN, adHid, ARRAY_SIZE(adHid), sdHid, ARRAY_SIZE(sdHid)); + } else { + printk("Attempted to start advertising without any type! Ignoring.\n"); + return; + } + + if (err == 0) { + printk("%s advertising successfully started\n", adv_type_string); + } else if (err == -EALREADY) { + printk("%s advertising continued\n", adv_type_string); + } else { + printk("%s advertising failed to start (err %d)\n", adv_type_string, err); + } +} + +void BtAdvertise_Stop() { + int err = bt_le_adv_stop(); + if (err) { + printk("Advertising failed to stop (err %d)\n", err); + } else { + printk("Advertising successfully stopped\n"); + } +} + +uint8_t BtAdvertise_Type() { + switch (DEVICE_ID) { + case DeviceId_Uhk80_Left: + return ADVERTISE_NUS; + case DeviceId_Uhk80_Right: + return ADVERTISE_NUS | ADVERTISE_HID; + case DeviceId_Uhk_Dongle: + return 0; + default: + printk("unknown device!\n"); + return 0; + } +} diff --git a/device/src/bt_advertise.h b/device/src/bt_advertise.h new file mode 100644 index 000000000..f43a39c30 --- /dev/null +++ b/device/src/bt_advertise.h @@ -0,0 +1,19 @@ +#ifndef __BT_ADVERTISE_H__ +#define __BT_ADVERTISE_H__ + +// Includes: + + #include + +// Macros: + + #define ADVERTISE_NUS (1 << 0) + #define ADVERTISE_HID (1 << 1) + +// Functions: + + void BtAdvertise_Start(uint8_t adv_type); + void BtAdvertise_Stop(); + uint8_t BtAdvertise_Type(); + +#endif // __BT_ADVERTISE_H__ diff --git a/device/src/bt_conn.c b/device/src/bt_conn.c new file mode 100644 index 000000000..ff468361c --- /dev/null +++ b/device/src/bt_conn.c @@ -0,0 +1,458 @@ +#include +#include +#include +#include +#include "bt_advertise.h" +#include "bt_conn.h" +#include "bt_scan.h" +#include "device_state.h" +#include "keyboard/oled/screens/screen_manager.h" +#include "keyboard/oled/widgets/widget.h" +#include "legacy/host_connection.h" +#include "nus_client.h" +#include "nus_server.h" +#include "device.h" +#include "keyboard/oled/screens/pairing_screen.h" +#include "usb/usb.h" +#include "keyboard/oled/widgets/widgets.h" +#include +#include "bt_pair.h" +#include "bt_manager.h" +#include + +bool Bt_NewPairedDevice = false; + +#define BLE_KEY_LEN 16 +#define BLE_ADDR_LEN 6 + +peer_t Peers[PeerCount] = { + { + .id = PeerIdLeft, + .name = "left", + }, + { + .id = PeerIdRight, + .name = "right", + }, + { + .id = PeerIdDongle, + .name = "dongle", + }, + { + .id = PeerIdHid, + .name = "bthid", + }, +}; + + +peer_t *getPeerByAddr(const bt_addr_le_t *addr) { + for (uint8_t i = 0; i < PeerCount; i++) { + if (bt_addr_le_eq(addr, &Peers[i].addr)) { + return &Peers[i]; + } + } + + for (uint8_t hostConnectionId = 0; hostConnectionId < HOST_CONNECTION_COUNT_MAX; hostConnectionId++) { + host_connection_t* hostConnection = &HostConnections[hostConnectionId]; + + if (hostConnection->type == HostConnectionType_Dongle && bt_addr_le_eq(addr, &hostConnection->bleAddress)) { + return &Peers[PeerIdDongle]; + } + if (hostConnection->type == HostConnectionType_Ble && bt_addr_le_eq(addr, &hostConnection->bleAddress)) { + return &Peers[PeerIdHid]; + } + } + + return NULL; +} + +int8_t getPeerIdByConn(const struct bt_conn *conn) { + const bt_addr_le_t *addr = bt_conn_get_dst(conn); + peer_t *peer = getPeerByAddr(addr); + int8_t peerId = peer ? peer->id : PeerIdUnknown; + return peerId; +} + +char *GetPeerStringByAddr(const bt_addr_le_t *addr) { + char addrStr[BT_ADDR_STR_LEN]; + for (uint8_t i=0; ia.val[BT_ADDR_SIZE-1-i]); + } + addrStr[BT_ADDR_STR_LEN-1] = '\0'; + + peer_t *peer = getPeerByAddr(addr); + char peerName[PeerNameMaxLength]; + + if (peer) { + strcpy(peerName, peer->name); + } else { + strcpy(peerName, "unknown"); + } + + static char peerString[PeerNameMaxLength + BT_ADDR_LE_STR_LEN + 3]; + sprintf(peerString, "%s (%s)", peerName, addrStr); + + return peerString; +} + +char *GetPeerStringByConn(const struct bt_conn *conn) { + const bt_addr_le_t *addr = bt_conn_get_dst(conn); + return GetPeerStringByAddr(addr); +} + +static struct bt_conn_le_data_len_param *data_len; + +static void enableDataLengthExtension(struct bt_conn *conn) { + data_len = BT_LE_DATA_LEN_PARAM_MAX; + + int err = bt_conn_le_data_len_update(conn, data_len); + if (err) { + printk("LE data length update failed: %d", err); + } +} + +static void configureLatency(struct bt_conn *conn) { + // https://developer.apple.com/library/archive/qa/qa1931/_index.html + // https://punchthrough.com/manage-ble-connection/ + // https://devzone.nordicsemi.com/f/nordic-q-a/28058/what-is-connection-parameters + static const struct bt_le_conn_param conn_params = BT_LE_CONN_PARAM_INIT( + 6, 9, // keep it low, lowest allowed is 6 (7.5ms), lowest supported widely is 9 (11.25ms) + 0, // keeping it higher allows power saving on peripheral when there's nothing to send (keep it under 30 though) + 100 // connection timeout (*10ms) + ); + int err = bt_conn_le_param_update(conn, &conn_params); + if (err) { + printk("LE latencies update failed: %d\n", err); + } +} + +static void assignPeer(const bt_addr_le_t *addr, int8_t peerId) { + if (Peers[peerId].isConnected) { + char addrString[32]; + bt_addr_le_to_str(addr, addrString, sizeof(addrString)); + printk("Peer slot %s already occupied. Overwriting with address %s\n", Peers[peerId].name, addrString); + } + Peers[peerId].addr = *addr; + Peers[peerId].isConnected = true; +} + +static void connected(struct bt_conn *conn, uint8_t err) { + int8_t peerId = getPeerIdByConn(conn); + + if (err) { + printk("Failed to connect to %s, err %u\n", GetPeerStringByConn(conn), err); + + if (DEVICE_IS_UHK80_RIGHT) { + err = bt_scan_start(BT_SCAN_TYPE_SCAN_ACTIVE); + if (err) { + printk("Scanning failed to start (err %d)\n", err); + } + } + + return; + } + + printk("Bt connected to %s\n", GetPeerStringByConn(conn)); + + if (peerId == PeerIdUnknown || peerId == PeerIdHid) { + static const struct bt_le_conn_param conn_params = BT_LE_CONN_PARAM_INIT( + 6, 9, // keep it low, lowest allowed is 6 (7.5ms), lowest supported widely is 9 (11.25ms) + 10, // keeping it higher allows power saving on peripheral when there's nothing to send (keep it under 30 though) + 100 // connection timeout (*10ms) + ); + bt_conn_le_param_update(conn, &conn_params); + } + + if (peerId == PeerIdUnknown) { + return; + } + + assignPeer(bt_conn_get_dst(conn), peerId); + + if (peerId == PeerIdHid) { + // USB_DisableHid(); + } else { + bt_conn_set_security(conn, BT_SECURITY_L4); + // continue connection process in in `connectionSecured()` + } + + if (DEVICE_IS_UHK80_RIGHT && (peerId == PeerIdHid || peerId == PeerIdUnknown || peerId == PeerIdDongle)) { + BtAdvertise_Start(BtAdvertise_Type()); + } +} + +static void disconnected(struct bt_conn *conn, uint8_t reason) { + int8_t peerId = getPeerIdByConn(conn); + ARG_UNUSED(peerId); + + printk("Bt disconnected from %s, reason %u\n", GetPeerStringByConn(conn), reason); + + if (!BtPair_OobPairingInProgress && !BtManager_Restarting) { + if (DEVICE_IS_UHK80_RIGHT) { + if (peerId == PeerIdHid || peerId == PeerIdUnknown) { + BtAdvertise_Start(BtAdvertise_Type()); + // USB_EnableHid(); + } + if (peerId == PeerIdDongle) { + BtAdvertise_Start(BtAdvertise_Type()); + } + if (peerId == PeerIdLeft) { + BtScan_Start(); + } + } + + if (DEVICE_IS_UHK_DONGLE && peerId == PeerIdRight) { + BtScan_Start(); + } + + if (DEVICE_IS_UHK80_LEFT && peerId == PeerIdRight) { + BtAdvertise_Start(BtAdvertise_Type()); + } + } + + if (DEVICE_IS_UHK80_LEFT && peerId == PeerIdRight) { + NusServer_Disconnected(); + } + if (DEVICE_IS_UHK80_RIGHT && peerId == PeerIdDongle) { + NusServer_Disconnected(); + } + if (DEVICE_IS_UHK80_RIGHT && peerId == PeerIdLeft) { + NusClient_Disconnected(); + } + if (DEVICE_IS_UHK_DONGLE && peerId == PeerIdRight) { + NusClient_Disconnected(); + } + + if (peerId != PeerIdUnknown) { + Peers[peerId].isConnected = false; + Peers[peerId].isConnectedAndConfigured = false; + DeviceState_TriggerUpdate(); + } +} + +bool Bt_DeviceIsConnected(device_id_t deviceId) { + switch (deviceId) { + case DeviceId_Uhk80_Left: + return Peers[PeerIdLeft].isConnectedAndConfigured; + case DeviceId_Uhk80_Right: + return Peers[PeerIdRight].isConnectedAndConfigured; + case DeviceId_Uhk_Dongle: + return Peers[PeerIdDongle].isConnectedAndConfigured; + default: + return false; + } +} + +void Bt_SetDeviceConnected(device_id_t deviceId) { + switch (deviceId) { + case DeviceId_Uhk80_Left: + Peers[PeerIdLeft].isConnectedAndConfigured = true; + break; + case DeviceId_Uhk80_Right: + Peers[PeerIdRight].isConnectedAndConfigured = true; + break; + case DeviceId_Uhk_Dongle: + Peers[PeerIdDongle].isConnectedAndConfigured = true; + break; + default: + break; + } + DeviceState_TriggerUpdate(); +} + +static void securityChanged(struct bt_conn *conn, bt_security_t level, enum bt_security_err err) { + int8_t peerId = getPeerIdByConn(conn); + + bool isUhkPeer = peerId == PeerIdLeft || peerId == PeerIdRight || peerId == PeerIdDongle; + if (err || (isUhkPeer && level < BT_SECURITY_L4)) { + printk("Bt security failed: %s, level %u, err %d, disconnecting\n", GetPeerStringByConn(conn), level, err); + bt_conn_auth_cancel(conn); + return; + } + + printk("Bt connection secured: %s, level %u, peerId %d\n", GetPeerStringByConn(conn), level, peerId); + + if (isUhkPeer) { + configureLatency(conn); + enableDataLengthExtension(conn); + + if ( + (DEVICE_IS_UHK80_RIGHT && peerId == PeerIdLeft) + || (DEVICE_IS_UHK_DONGLE && peerId == PeerIdRight) + ) { + printk("Initiating NUS connection with %s\n", GetPeerStringByConn(conn)); + NusClient_Connect(conn); + } + } + +#if DEVICE_IS_UHK80_LEFT + // gatt_discover(conn); // Taken from bt_central_uart.c +#endif +} + +__attribute__((unused)) static void infoLatencyParamsUpdated(struct bt_conn* conn, uint16_t interval, uint16_t latency, uint16_t timeout) +{ + uint8_t peerId = getPeerIdByConn(conn); + if (peerId == PeerIdUnknown || peerId == PeerIdHid) { + printk("BLE HID conn params: interval=%u ms, latency=%u, timeout=%u ms\n", + interval * 5 / 4, latency, timeout * 10); + } +} + +BT_CONN_CB_DEFINE(conn_callbacks) = { + .connected = connected, + .disconnected = disconnected, + .security_changed = securityChanged, + .le_param_updated = infoLatencyParamsUpdated, +}; + +// Auth callbacks + +struct bt_conn *auth_conn; + +static void auth_passkey_display(struct bt_conn *conn, unsigned int passkey) +{ + printk("Passkey for %s: %06u\n", GetPeerStringByConn(conn), passkey); +} + +static void auth_passkey_confirm(struct bt_conn *conn, unsigned int passkey) { + auth_conn = bt_conn_ref(conn); + + printk("Received passkey pairing inquiry.\n"); + + if (!auth_conn) { + printk("Returning: no auth conn\n"); + return; + } + + int8_t peerId = getPeerIdByConn(conn); + bool isUhkPeer = peerId == PeerIdLeft || peerId == PeerIdRight || peerId == PeerIdDongle; + if (isUhkPeer || BtPair_OobPairingInProgress) { + printk("refusing passkey authentification for %s\n", GetPeerStringByConn(conn)); + bt_conn_auth_cancel(conn); + return; + } + +#if DEVICE_HAS_OLED + PairingScreen_AskForPassword(passkey); +#endif + + printk("Passkey for %s: %06u\n", GetPeerStringByConn(conn), passkey); + printk("Type `uhk btacc 1/0` to accept/reject\n"); +} + +static void auth_cancel(struct bt_conn *conn) { + printk("Pairing cancelled: peer %s\n", GetPeerStringByConn(conn)); +} + +static void auth_oob_data_request(struct bt_conn *conn, struct bt_conn_oob_info *oob_info) { + int err; + struct bt_conn_info info; + + err = bt_conn_get_info(conn, &info); + if (err) { + return; + } + + + struct bt_le_oob* oobLocal = BtPair_GetLocalOob(); + struct bt_le_oob* oobRemote = BtPair_GetRemoteOob(); + + if (memcmp(info.le.remote->a.val, oobRemote->addr.a.val, sizeof(info.le.remote->a.val))) { + printk("Addresses not matching! Cancelling authentication\n"); + bt_conn_auth_cancel(conn); + return; + } + + printk("Pairing OOB data requested!\n"); + + bt_le_oob_set_sc_data(conn, &oobLocal->le_sc_data, &oobRemote->le_sc_data); +} + +static struct bt_conn_auth_cb conn_auth_callbacks = { + .passkey_display = auth_passkey_display, + .passkey_confirm = auth_passkey_confirm, + .oob_data_request = auth_oob_data_request, + .cancel = auth_cancel, +}; + +// Auth info callbacks + +static void pairing_complete(struct bt_conn *conn, bool bonded) { + printk("Pairing completed: %s, bonded %d\n", GetPeerStringByConn(conn), bonded); + BtPair_EndPairing(true, "Successfuly bonded!"); + + bt_addr_le_t addr = *bt_conn_get_dst(conn); + uint8_t peerId = getPeerIdByConn(conn); + bool isUhkPeer = peerId == PeerIdLeft || peerId == PeerIdRight || peerId == PeerIdDongle; + if (!HostConnections_IsKnownBleAddress(&addr) && !isUhkPeer) { + Bt_NewPairedDevice = true; + } +} + +static void bt_foreach_conn_cb(struct bt_conn *conn, void *user_data) { + bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + // gpt says you should unref here. Don't believe it! +} + +void BtConn_DisconnectAll() { + bt_conn_foreach(BT_CONN_TYPE_LE, bt_foreach_conn_cb, NULL); +} + +static void pairing_failed(struct bt_conn *conn, enum bt_security_err reason) { + if (!auth_conn) { + return; + } + + if (auth_conn == conn) { + bt_conn_unref(auth_conn); + printk("Pairing of auth conn failed because of %d\n", reason); + auth_conn = NULL; + } + + printk("Pairing failed: %s, reason %d\n", GetPeerStringByConn(conn), reason); +} + +static struct bt_conn_auth_info_cb conn_auth_info_callbacks = { + .pairing_complete = pairing_complete, + .pairing_failed = pairing_failed +}; + +void BtConn_Init(void) { + int err = 0; + + err = bt_conn_auth_cb_register(&conn_auth_callbacks); + if (err) { + printk("Failed to register authorization callbacks.\n"); + } + + err = bt_conn_auth_info_cb_register(&conn_auth_info_callbacks); + if (err) { + printk("Failed to register authorization info callbacks.\n"); + } +} + +void num_comp_reply(uint8_t accept) { + struct bt_conn *conn; + +#if DEVICE_HAS_OLED + ScreenManager_SwitchScreenEvent(); +#endif + + if (!auth_conn) { + return; + } + + conn = auth_conn; + + if (accept) { + bt_conn_auth_passkey_confirm(conn); + printk("Numeric Match, conn %p\n", conn); + } else { + bt_conn_auth_cancel(conn); + printk("Numeric Reject, conn %p\n", conn); + } + + bt_conn_unref(auth_conn); + auth_conn = NULL; +} diff --git a/device/src/bt_conn.h b/device/src/bt_conn.h new file mode 100644 index 000000000..911ddd70b --- /dev/null +++ b/device/src/bt_conn.h @@ -0,0 +1,51 @@ +#ifndef __BT_CONN_H__ +#define __BT_CONN_H__ + +// Includes: + + #include + #include + #include "device.h" + +// Macros: + + #define PeerNameMaxLength 8 + + #define PeerIdUnknown -1 + #define PeerIdLeft 0 + #define PeerIdRight 1 + #define PeerIdDongle 2 + #define PeerIdHid 3 + #define PeerCount 4 + + + #define BLE_ADDR_LEN 6 + #define BLE_KEY_LEN 16 + +// Typedefs: + + typedef struct { + uint8_t id; + char name[PeerNameMaxLength + 1]; + bt_addr_le_t addr; + bool isConnected; + bool isConnectedAndConfigured; + } peer_t; + +// Variables: + + extern peer_t Peers[]; + extern bool Bt_NewPairedDevice; + +// Functions: + + char *GetPeerStringByAddr(const bt_addr_le_t *addr); + char *GetPeerStringByConn(const struct bt_conn *conn); + extern void num_comp_reply(uint8_t accept); + + void Bt_SetDeviceConnected(device_id_t deviceId); + bool Bt_DeviceIsConnected(uint8_t deviceId); + void BtConn_Init(void); + void BtConn_DisconnectAll(); + +#endif // __BT_CONN_H__ diff --git a/device/src/bt_conn_auth.c b/device/src/bt_conn_auth.c new file mode 100644 index 000000000..e69de29bb diff --git a/device/src/bt_manager.c b/device/src/bt_manager.c new file mode 100644 index 000000000..6ef6684c0 --- /dev/null +++ b/device/src/bt_manager.c @@ -0,0 +1,114 @@ +#include "bt_manager.h" +#include "event_scheduler.h" +#include "usb/usb.h" +#include "bt_advertise.h" +#include "nus_client.h" +#include "nus_server.h" +#include "legacy/event_scheduler.h" +#include +#include +#include +#include +#include "bt_conn.h" +#include "bt_scan.h" +#include "settings.h" + +bool BtManager_Restarting = false; + +static void bt_ready(int err) +{ + if (err) { + printk("Bluetooth init failed (err %d)\n", err); + } else { + printk("Bluetooth initialized successfully\n"); + } +} + +void BtManager_InitBt() { + BtConn_Init(); + + if (DEVICE_IS_UHK80_LEFT || DEVICE_IS_UHK80_RIGHT) { + int err = NusServer_Init(); + if (err) { + printk("NusServer_Init failed with error %d\n", err); + } + } + + if (DEVICE_IS_UHK80_RIGHT || DEVICE_IS_UHK_DONGLE) { + BtScan_Init(); + NusClient_Init(); + } +} + +void BtManager_StartBt() { + printk("Starting bluetooth services.\n"); + + if (DEVICE_IS_UHK80_RIGHT) { + HOGP_Enable(); + } + + if (DEVICE_IS_UHK80_LEFT || DEVICE_IS_UHK80_RIGHT) { + BtAdvertise_Start(BtAdvertise_Type()); + } + + if (DEVICE_IS_UHK80_RIGHT || DEVICE_IS_UHK_DONGLE) { + // This scan effectively initiates NUS client connection. + BtScan_Start(); + } +} + +void BtManager_StopBt() { + if (DEVICE_IS_UHK80_RIGHT) { + HOGP_Disable(); + } + + if (DEVICE_IS_UHK80_LEFT || DEVICE_IS_UHK80_RIGHT) { + BtAdvertise_Stop(); + } + + if (DEVICE_IS_UHK80_RIGHT || DEVICE_IS_UHK_DONGLE) { + BtScan_Stop(); + } +} + +void BtManager_RestartBt() { + printk("Going to reset bluetooth stack\n"); + + BtManager_Restarting = true; + int err; + + BtManager_StopBt(); + + BtConn_DisconnectAll(); + + err = bt_disable(); + if (err) { + printk("Bluetooth disable failed (err %d)\n", err); + return; + } + + //wait for them to properly disconnect + k_sleep(K_MSEC(100)); + + err = bt_hci_cmd_send(BT_HCI_OP_RESET, NULL); + if (err) { + printk("HCI Reset failed (err %d)\n", err); + } + + err = bt_enable(bt_ready); + if (err) { + printk("Bluetooth init failed (err %d)\n", err); + } + + Settings_Reload(); + + BtManager_StartBt(); + + BtManager_Restarting = false; + + printk("Bluetooth subsystem restart finished\n"); +} + +void BtManager_RestartBtAsync() { + EventScheduler_Schedule(k_uptime_get()+10, EventSchedulerEvent_RestartBt, "Restart bluetooth"); +} diff --git a/device/src/bt_manager.h b/device/src/bt_manager.h new file mode 100644 index 000000000..76c5b6532 --- /dev/null +++ b/device/src/bt_manager.h @@ -0,0 +1,25 @@ +#ifndef __BT_MANAGER_H__ +#define __BT_MANAGER_H__ + +// Includes: + + #include + #include + #include "device.h" + +// Macros: + +// Typedefs: + +// Variables: + + extern bool BtManager_Restarting; + +// Functions: + + void BtManager_InitBt(); + void BtManager_StartBt(); + void BtManager_StopBt(); + void BtManager_RestartBt(); + +#endif // __BT_MANAGER_H__ diff --git a/device/src/bt_pair.c b/device/src/bt_pair.c new file mode 100644 index 000000000..dbb02ba71 --- /dev/null +++ b/device/src/bt_pair.c @@ -0,0 +1,218 @@ +#include "bt_pair.h" +#include "nus_client.h" +#include +#include +#include +#include +#include +#include "bt_conn.h" +#include "bt_scan.h" +#include "legacy/event_scheduler.h" +#include "zephyr/kernel.h" +#include "bt_manager.h" +#include "bt_advertise.h" +#include "legacy/host_connection.h" +#include "settings.h" + +bool BtPair_LastPairingSucceeded = true; +bool BtPair_OobPairingInProgress = false; + +static bool pairingAsCentral = false; +static bool initialized = false; +static struct bt_le_oob oobRemote; +static struct bt_le_oob oobLocal; + +void BtManager_EnterPairingMode() { + printk("--- Entering pairing mode. Going to stop BT and disconnect all connections. ---\n"); + BtPair_OobPairingInProgress = true; + BtManager_StopBt(); + BtConn_DisconnectAll(); +} + +struct bt_le_oob* BtPair_GetLocalOob() { + if (!initialized) { + int err = bt_le_oob_get_local(BT_ID_DEFAULT, &oobLocal); + if (err) { + printk("Failed to get local OOB data (err %d)\n", err); + return NULL; + } + initialized = true; + } + return &oobLocal; +} + +struct bt_le_oob* BtPair_GetRemoteOob() { + return &oobRemote; +} + +void BtPair_SetRemoteOob(const struct bt_le_oob* oob) { + oobRemote = *oob; +} + +void BtPair_PairCentral() { + pairingAsCentral = true; + Settings_Reload(); + bt_le_oob_set_sc_flag(true); + BtScan_Start(); + printk ("Scanning for pairable device\n"); + EventScheduler_Reschedule(k_uptime_get_32() + PAIRING_TIMEOUT, EventSchedulerEvent_EndBtPairing, "Oob pairing timeout."); +} + +void BtPair_PairPeripheral() { + pairingAsCentral = false; + Settings_Reload(); + bt_le_oob_set_sc_flag(true); + BtAdvertise_Start(ADVERTISE_NUS); + printk ("Waiting for central to pair to me.\n"); + EventScheduler_Reschedule(k_uptime_get_32() + PAIRING_TIMEOUT, EventSchedulerEvent_EndBtPairing, "Oob pairing timeout."); +} + +void BtPair_EndPairing(bool success, const char* msg) { + printk("--- Pairing ended, success = %d: %s ---\n", success, msg); + + initialized = false; + + memset(&oobRemote, 0, sizeof(oobRemote)); + memset(&oobLocal, 0, sizeof(oobLocal)); + + BtPair_OobPairingInProgress = false; + BtPair_LastPairingSucceeded = success; + bt_le_oob_set_sc_flag(false); + EventScheduler_Unschedule(EventSchedulerEvent_EndBtPairing); + + if (pairingAsCentral) { + BtScan_Stop(); + } else { + BtAdvertise_Stop(); + } + + k_sleep(K_MSEC(100)); + + BtManager_StartBt(); +} + +struct delete_args_t { + bool all; + const bt_addr_le_t* addr; +}; + +static void deleteBond(const struct bt_bond_info *info) { + int err; + + struct bt_conn* conn; + + if (bt_addr_le_cmp(&Peers[PeerIdLeft].addr, &info->addr) == 0) { + settings_delete("uhk/addr/left"); + } + if (bt_addr_le_cmp(&Peers[PeerIdRight].addr, &info->addr) == 0) { + settings_delete("uhk/addr/right"); + } + if (bt_addr_le_cmp(&Peers[PeerIdDongle].addr, &info->addr) == 0) { + settings_delete("uhk/addr/dongle"); + } + + // Get the connection object if the device is currently connected + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &info->addr); + + // Unpair the device + err = bt_unpair(BT_ID_DEFAULT, &info->addr); + if (err) { + printk("Failed to unpair (err %d)\n", err); + } else { + char addr[32]; + bt_addr_le_to_str(&info->addr, addr, sizeof(addr)); + printk("Unpaired device %s\n", addr); + } + + // If the device was connected, release the connection object + if (conn) { + bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + bt_conn_unref(conn); + } +} + +static void bt_foreach_bond_cb_delete(const struct bt_bond_info *info, void *user_data) +{ + struct delete_args_t* args = (struct delete_args_t*)user_data; + + if (!args->all && bt_addr_le_cmp(args->addr, &info->addr) != 0) { + char addr[32]; + bt_addr_le_to_str(&info->addr, addr, sizeof(addr)); + printk("Not deleting bond for %s\n", addr); + return; + } + + deleteBond(info); +} + +void BtPair_Unpair(const bt_addr_le_t addr) { + bool deleteAll = true; + + for (uint8_t i = 0; i < BLE_ADDR_LEN; i++) { + if (addr.a.val[i] != 0) { + deleteAll = false; + break; + } + } + + if (deleteAll) { + printk("Deleting all bonds!\n"); + settings_delete("uhk/addr/left"); + settings_delete("uhk/addr/right"); + settings_delete("uhk/addr/dongle"); + } + + struct delete_args_t args = { + .all = deleteAll, + .addr = &addr + }; + + // Iterate through all stored bonds + bt_foreach_bond(BT_ID_DEFAULT, bt_foreach_bond_cb_delete, (void*)&args); + + // Update settings + Settings_Reload(); +} + +struct check_bonded_device_args_t { + const bt_addr_le_t* addr; + bool* bonded; +}; + +void checkBondedDevice(const struct bt_bond_info *info, void *user_data) { + struct check_bonded_device_args_t* args = (struct check_bonded_device_args_t*)user_data; + char addr[32]; + bt_addr_le_to_str(&info->addr, addr, sizeof(addr)); + char ref[32]; + bt_addr_le_to_str(args->addr, ref, sizeof(ref)); + if (bt_addr_le_cmp(&info->addr, args->addr) == 0) { + *args->bonded = true; + printk("Device %s is bonded, ref %s\n", addr, ref); + } +}; + +bool BtPair_IsDeviceBonded(const bt_addr_le_t *addr) +{ + bool bonded = false; + + struct check_bonded_device_args_t args = { + .addr = addr, + .bonded = &bonded + }; + + // Iterate over all bonded devices + bt_foreach_bond(BT_ID_DEFAULT, checkBondedDevice, (void*)&args); + + return bonded; +} + +void deleteBondIfUnknown(const struct bt_bond_info *info, void *user_data) { + if (!HostConnections_IsKnownBleAddress(&info->addr)) { + deleteBond(info); + } +}; + + +void BtPair_ClearUnknownBonds() { + bt_foreach_bond(BT_ID_DEFAULT, deleteBondIfUnknown, NULL); +} diff --git a/device/src/bt_pair.h b/device/src/bt_pair.h new file mode 100644 index 000000000..c4426425b --- /dev/null +++ b/device/src/bt_pair.h @@ -0,0 +1,35 @@ +#ifndef __BT_PAIR_H__ +#define __BT_PAIR_H__ + +// Includes: + + #include + #include + #include "device.h" + #include + +// Macros: + +// Typedefs: + + #define PAIRING_TIMEOUT 20000 + +// Functions: + + struct bt_le_oob* BtPair_GetLocalOob(); + struct bt_le_oob* BtPair_GetRemoteOob(); + void BtPair_SetRemoteOob(const struct bt_le_oob* oob); + void BtPair_PairCentral(); + void BtPair_PairPeripheral(); + void BtPair_EndPairing(bool success, const char* msg); + void BtPair_Unpair(const bt_addr_le_t addr); + bool BtPair_IsDeviceBonded(const bt_addr_le_t *addr); + void BtManager_EnterPairingMode(); + void BtPair_ClearUnknownBonds(); + +// Variables + + extern bool BtPair_OobPairingInProgress; + extern bool BtPair_LastPairingSucceeded; + +#endif // __BT_PAIR_H__ diff --git a/device/src/bt_scan.c b/device/src/bt_scan.c new file mode 100644 index 000000000..a0c04de83 --- /dev/null +++ b/device/src/bt_scan.c @@ -0,0 +1,99 @@ +#include +#include "bt_conn.h" +#include "bt_pair.h" +#include "device.h" +#include "legacy/host_connection.h" + +static void scan_filter_match(struct bt_scan_device_info *device_info, + struct bt_scan_filter_match *filter_match, bool connectable) +{ + printk("Filters matched: %s, connectable:%d\n", + GetPeerStringByAddr(device_info->recv_info->addr), connectable); +} + +static void scan_connecting_error(struct bt_scan_device_info *device_info) { + printk("Connecting failed: %s\n", GetPeerStringByAddr(device_info->recv_info->addr)); +} + +static void scan_connecting(struct bt_scan_device_info *device_info, struct bt_conn *conn) { + printk("Scan connecting: %s\n", GetPeerStringByAddr(device_info->recv_info->addr)); +} + +BT_SCAN_CB_INIT(scan_cb, scan_filter_match, NULL, scan_connecting_error, scan_connecting); + +static void addAddress(int* err, bt_addr_le_t* addr) { + if (*err) { + return; + } + + *err = bt_scan_filter_add(BT_SCAN_FILTER_TYPE_ADDR, addr); +} + +static int scan_fill() { + int err = 0; + + if (DEVICE_IS_UHK80_RIGHT) { + addAddress(&err, &Peers[PeerIdLeft].addr); + } + if (DEVICE_IS_UHK_DONGLE) { + addAddress(&err, &Peers[PeerIdRight].addr); + } + + if (err) { + printk("Scanning filters cannot be set (err %d)\n", err); + return err; + } + return err; +} + +int BtScan_Stop(void) { + int err; + + bt_scan_stop(); + bt_scan_start(BT_SCAN_TYPE_SCAN_ACTIVE); + err = bt_scan_stop(); + if (err) { + printk("Stop LE scan failed (err %d)\n", err); + } else { + printk("Scanning successfully stopped.\n"); + } + + bt_scan_filter_disable(); + + bt_scan_filter_remove_all(); + + return err; +} + +int BtScan_Init(void) { + struct bt_scan_init_param scan_init = { + .connect_if_match = 1, + }; + + bt_scan_init(&scan_init); + bt_scan_cb_register(&scan_cb); + + printk("Scan module initialized\n"); + return 0; +} + +int BtScan_Start(void) { + int err; + + scan_fill(); + + err = bt_scan_filter_enable(BT_SCAN_ADDR_FILTER, false); + if (err) { + printk("Filters cannot be turned on (err %d)\n", err); + return err; + } + + err = bt_scan_start(BT_SCAN_TYPE_SCAN_ACTIVE); + if (err) { + printk("Scanning failed to start (err %d)\n", err); + } else { + printk("Scanning successfully started\n"); + } + + return err; +} diff --git a/device/src/bt_scan.h b/device/src/bt_scan.h new file mode 100644 index 000000000..f09172cc0 --- /dev/null +++ b/device/src/bt_scan.h @@ -0,0 +1,10 @@ +#ifndef __BT_SCAN_H__ +#define __BT_SCAN_H__ + +// Functions: + + int BtScan_Init(void); + int BtScan_Start(void); + int BtScan_Stop(void); + +#endif // __BT_SCAN_H__ diff --git a/device/src/debug_eventloop_timing.c b/device/src/debug_eventloop_timing.c new file mode 100644 index 000000000..e2717611a --- /dev/null +++ b/device/src/debug_eventloop_timing.c @@ -0,0 +1,64 @@ +#include "debug_eventloop_timing.h" +#include "main.h" + +static bool running = false; +static uint64_t startTime = 0; +static uint64_t outherThreadRunningTime = 0; +static uint64_t reportingTime = 0; +static uint64_t lastThreadStartTime = 0; +static uint64_t lastWatchTime = 0; +static uint64_t lastOtherThreadWatchTime = 0; +static k_tid_t lastThreadId; + +void EventloopTiming_Start() { + startTime = k_cyc_to_us_near64(k_cycle_get_32()); + lastThreadId = k_sched_current_thread_query(); + outherThreadRunningTime = 0; + lastOtherThreadWatchTime = 0; + lastWatchTime = startTime; + reportingTime = 0; + running = true; +} + +void EventloopTiming_Switch() { + if (lastThreadId != Main_ThreadId) { + uint64_t thisTime = k_cyc_to_us_near64(k_cycle_get_32()); + outherThreadRunningTime += thisTime - lastThreadStartTime; + } + + lastThreadId = k_sched_current_thread_query(); + lastThreadStartTime = k_cyc_to_us_near64(k_cycle_get_32()); +} + +void EventloopTiming_End() { + uint64_t thisTime = k_cyc_to_us_near64(k_cycle_get_32()); + uint64_t runningTime = thisTime - startTime - outherThreadRunningTime - reportingTime; + printk("User logic took %lld us, interrupted for %lld\n", runningTime, outherThreadRunningTime); + running = false; +} + +void EventloopTiming_WatchReset() { + lastWatchTime = k_cyc_to_us_near64(k_cycle_get_32()); + lastOtherThreadWatchTime = outherThreadRunningTime; +} + +void EventloopTiming_Watch(const char* section) { + uint64_t now = k_cyc_to_us_near64(k_cycle_get_32()); + uint64_t currentInterruptions = outherThreadRunningTime - lastOtherThreadWatchTime; + uint64_t currentRunningTime = now - lastWatchTime - currentInterruptions; + + printk(" %s took %lld\n", section, currentRunningTime); + uint64_t now2 = k_cyc_to_us_near64(k_cycle_get_32()); + + reportingTime += now2 - now; + + lastWatchTime = k_cyc_to_us_near64(k_cycle_get_32()); + lastOtherThreadWatchTime = outherThreadRunningTime; +} + +void sys_trace_thread_switched_in_user(void) { + if (running) { + EventloopTiming_Switch(); + } +} + diff --git a/device/src/debug_eventloop_timing.h b/device/src/debug_eventloop_timing.h new file mode 100644 index 000000000..02d0508e8 --- /dev/null +++ b/device/src/debug_eventloop_timing.h @@ -0,0 +1,26 @@ +#ifndef __DEBUG_EVENTLOOP_TIMING_H__ +#define __DEBUG_EVENTLOOP_TIMING_H__ + +// Includes: + + #include + #include + #include "legacy/debug.h" + +// Macros: + +// Typedefs: + +// Variables: + +// Functions: + +#if DEBUG_EVENTLOOP_TIMING + void EventloopTiming_Start(); + void EventloopTiming_Switch(); + void EventloopTiming_End(); + void EventloopTiming_Watch(const char* section); + void EventloopTiming_WatchReset(); +#endif + +#endif diff --git a/device/src/device.h b/device/src/device.h new file mode 120000 index 000000000..7048efe19 --- /dev/null +++ b/device/src/device.h @@ -0,0 +1 @@ +../../shared/device.h \ No newline at end of file diff --git a/device/src/device_state.c b/device/src/device_state.c new file mode 100644 index 000000000..d4f14d5bc --- /dev/null +++ b/device/src/device_state.c @@ -0,0 +1,130 @@ +#include "device_state.h" +#include "bt_conn.h" +#include "device.h" +#include "keyboard/uart.h" +#include "keyboard/oled/widgets/widgets.h" +#include "legacy/slave_drivers/uhk_module_driver.h" +#include "state_sync.h" +#include "shared/slave_protocol.h" +#include "legacy/event_scheduler.h" +#include "legacy/power_mode.h" +#include "dongle_leds.h" + +static connection_type_t isConnected[ConnectionId_Count] = {}; + +bool DeviceState_IsDeviceConnected(device_id_t deviceId) { + return deviceId == DEVICE_ID || isConnected[deviceId - DEVICE_STATE_FIRST_DEVICE] != ConnectionType_None; +} + +bool DeviceState_IsConnected(connection_id_t connectionId) { + return isConnected[connectionId] != ConnectionType_None; +} + +void handleStateTransition(connection_id_t remoteId, bool connected) { + switch (DEVICE_ID) { + case DeviceId_Uhk80_Left: + if (remoteId == ConnectionId_Right && connected) { + StateSync_ResetRightLeftLink(true); + } + break; + case DeviceId_Uhk80_Right: + switch (remoteId) { + case ConnectionId_Left: + Widget_Refresh(&StatusWidget); + if (connected) { + StateSync_ResetRightLeftLink(true); + ModuleConnectionStates[UhkModuleDriverId_LeftKeyboardHalf].moduleId = ModuleId_LeftKeyboardHalf; + } else { + ModuleConnectionStates[UhkModuleDriverId_LeftKeyboardHalf].moduleId = 0; + ModuleConnectionStates[UhkModuleDriverId_LeftModule].moduleId = 0; + + bool changed = false; + for (uint8_t slotId = SlotId_LeftKeyboardHalf; slotId <= SlotId_LeftModule; slotId++) { + for (uint8_t keyId = 0; keyId < MAX_KEY_COUNT_PER_MODULE; keyId++) { + if (KeyStates[slotId][keyId].hardwareSwitchState) { + KeyStates[slotId][keyId].hardwareSwitchState = false; + changed = true; + } + } + } + + if (changed) { + EventVector_Set(EventVector_StateMatrix); + EventVector_WakeMain(); + } + } + break; + case ConnectionId_Dongle: + if (connected) { + StateSync_ResetRightDongleLink(true); + } + Widget_Refresh(&TargetWidget); + EventScheduler_Reschedule(CurrentTime + POWER_MODE_UPDATE_DELAY, EventSchedulerEvent_PowerMode, "update sleep mode from device state dongle"); + break; + case ConnectionId_UsbHid: + Widget_Refresh(&TargetWidget); + break; + case ConnectionId_BluetoothHid: + Widget_Refresh(&TargetWidget); + EventScheduler_Reschedule(CurrentTime + POWER_MODE_UPDATE_DELAY, EventSchedulerEvent_PowerMode, "update sleep mode from device state bluetooth hid"); + break; + default: + break; + } + break; + case DeviceId_Uhk_Dongle: + if (remoteId == ConnectionId_Right && connected) { + StateSync_ResetRightDongleLink(true); + } + DongleLeds_Update(); + break; + default: + break; + } +} + +void DeviceState_SetConnection(connection_id_t connection, connection_type_t type) { + if (isConnected[connection] != type) { + isConnected[connection] = type; + handleStateTransition(connection, isConnected[connection] != ConnectionType_None); + } +} + +static connection_id_t deviceToConnection(device_id_t deviceId) { + switch (deviceId) { + case DeviceId_Uhk80_Left: + return ConnectionId_Left; + case DeviceId_Uhk80_Right: + return ConnectionId_Right; + case DeviceId_Uhk_Dongle: + return ConnectionId_Dongle; + default: + return ConnectionId_Invalid; + } +} + +void DeviceState_TriggerUpdate() { + for (uint8_t devId = DEVICE_STATE_FIRST_DEVICE; devId <= DEVICE_STATE_LAST_DEVICE; devId++) { + connection_type_t newIsConnected = ConnectionType_None; + + if (Bt_DeviceIsConnected(devId)) { + newIsConnected = ConnectionType_Bt; + } + + if (devId == DeviceId_Uhk80_Left && DEVICE_ID == DeviceId_Uhk80_Right && Uart_IsConnected()) { + newIsConnected = ConnectionType_Uart; + } + + if (devId == DeviceId_Uhk80_Right && DEVICE_ID == DeviceId_Uhk80_Left && Uart_IsConnected()) { + newIsConnected = ConnectionType_Uart; + } + + connection_id_t conId = deviceToConnection(devId); + connection_type_t oldIsConnected = isConnected[conId]; + isConnected[conId] = newIsConnected; + if (newIsConnected != oldIsConnected) { + handleStateTransition(conId, newIsConnected); + } + } +} + diff --git a/device/src/device_state.h b/device/src/device_state.h new file mode 100644 index 000000000..e1b4b6738 --- /dev/null +++ b/device/src/device_state.h @@ -0,0 +1,45 @@ +#ifndef __DEVICE_STATE_H__ +#define __DEVICE_STATE_H__ + +// Includes: + + #include + #include + #include "device.h" + +// Macros: + + #define DEVICE_STATE_FIRST_DEVICE DeviceId_Uhk80_Left + #define DEVICE_STATE_LAST_DEVICE DeviceId_Uhk_Dongle + + + typedef enum { + ConnectionType_None, + ConnectionType_Uart, + ConnectionType_Bt, + ConnectionType_Usb, + ConnectionType_Count, + } connection_type_t; + + typedef enum { + ConnectionId_Left, + ConnectionId_Right, + ConnectionId_Dongle, + ConnectionId_UsbHid, + ConnectionId_BluetoothHid, + ConnectionId_Count, + ConnectionId_Invalid = ConnectionId_Count, + } connection_id_t; + +// Typedefs: + +// Functions: + + bool DeviceState_IsConnected(connection_id_t connection); + bool DeviceState_IsDeviceConnected(device_id_t deviceId); + void DeviceState_SetConnection(connection_id_t connection, connection_type_t type); + void DeviceState_TriggerUpdate(); + +// Variables: + +#endif // __DEVICE_STATE_H__ diff --git a/device/src/dongle_leds.c b/device/src/dongle_leds.c new file mode 100644 index 000000000..10c9fa34b --- /dev/null +++ b/device/src/dongle_leds.c @@ -0,0 +1,42 @@ +#include "device.h" +#if DEVICE_IS_UHK_DONGLE +#include "dongle_leds.h" +#include "device_state.h" +#include "settings.h" + +const struct pwm_dt_spec red_pwm_led = PWM_DT_SPEC_GET(DT_ALIAS(red_pwm_led)); +const struct pwm_dt_spec green_pwm_led = PWM_DT_SPEC_GET(DT_ALIAS(green_pwm_led)); +const struct pwm_dt_spec blue_pwm_led = PWM_DT_SPEC_GET(DT_ALIAS(blue_pwm_led)); + + +// There is also the following zero led. +// const struct gpio_dt_spec led0 = GPIO_DT_SPEC_GET(DT_ALIAS(led0_green), gpios); +// gpio_pin_configure_dt(&led0, GPIO_OUTPUT); +// gpio_pin_set_dt(&led0, true); +// k_sleep(K_MSEC(1000)); +// gpio_pin_set_dt(&led0, false); + +void set_dongle_led(const struct pwm_dt_spec *device, uint8_t percentage) { + pwm_set_pulse_dt(device, percentage * device->period / 100); +} + + +void DongleLeds_Set(bool r, bool g, bool b) { + set_dongle_led(&red_pwm_led, r ? 100 : 0); + set_dongle_led(&green_pwm_led, g ? 100 : 0); + set_dongle_led(&blue_pwm_led, b ? 100 : 0); +} + +void DongleLeds_Update() { + if (DeviceState_IsConnected(ConnectionId_Right)) { + DongleLeds_Set(false, true, false); + return; + } + if (RightAddressIsSet) { + DongleLeds_Set(false, false, true); + return; + } + DongleLeds_Set(true, false, false); +} + +#endif // DEVICE_IS_UHK_DONGLE diff --git a/device/src/dongle_leds.h b/device/src/dongle_leds.h new file mode 100644 index 000000000..a4f158923 --- /dev/null +++ b/device/src/dongle_leds.h @@ -0,0 +1,27 @@ +#include "device.h" +#if !defined __DONGLE_LEDS_H__ && DEVICE_IS_UHK_DONGLE +#define __DONGLE_LEDS_H__ + +// Includes: + + #include + #include + #include + +// Typedefs: + +// Functions: + + extern void DongleLeds_Set(bool r, bool g, bool b); + extern void DongleLeds_Update(); + extern void set_dongle_led(const struct pwm_dt_spec *device, uint8_t percentage); + +// Variables: + + extern const struct pwm_dt_spec red_pwm_led; + extern const struct pwm_dt_spec green_pwm_led; + extern const struct pwm_dt_spec blue_pwm_led; + +#else + #include "stubs.h" +#endif // __DONGLE_LEDS_H__ diff --git a/device/src/flash.c b/device/src/flash.c new file mode 100644 index 000000000..b6ed6295a --- /dev/null +++ b/device/src/flash.c @@ -0,0 +1,118 @@ +#include "flash.h" +#include "legacy/storage.h" +#include + +const struct flash_area *hardwareConfigArea; +const struct flash_area *userConfigArea; + +// Thread definitions + +#define THREAD_STACK_SIZE 1000 +#define THREAD_PRIORITY -1 + +static K_THREAD_STACK_DEFINE(stack_area, THREAD_STACK_SIZE); +static struct k_thread thread_data; +static k_tid_t threadId = 0; + +typedef struct { + bool pending; + storage_operation_t operation; + config_buffer_id_t configBufferId; + void (*successCallback)(void); +} command_t; + +command_t currentCommand = {}; + +struct k_mutex isBusyMutex; + +#define ALIGNMENT 4096 +#define ALIGN_SIZE(S) ((((S)-1)/ALIGNMENT+1)*ALIGNMENT) + +uint8_t Flash_LaunchTransfer(storage_operation_t operation, config_buffer_id_t configBufferId, void (*successCallback)) +{ + if (k_mutex_lock(&isBusyMutex, K_NO_WAIT) == 0) { + currentCommand.operation = operation; + currentCommand.configBufferId = configBufferId; + currentCommand.successCallback = successCallback; + currentCommand.pending = true; + k_wakeup(threadId); + return 0; + } else { + return 1; + } +} + +int Flash_ReadAreaSync(const struct flash_area *fa, off_t off, void *dst, size_t len) { + k_mutex_lock(&isBusyMutex, K_FOREVER); + int res = flash_area_read(fa, off, dst, len); + if (res != 0) { + printk("Flash read error: %d\n", res); + } + k_mutex_unlock(&isBusyMutex); + return res; +} + +bool Flash_IsBusy() { + if (k_mutex_lock(&isBusyMutex, K_NO_WAIT) == 0) { + k_mutex_unlock(&isBusyMutex); + return false; + } else { + return true; + } +} + +static void executeCommand() { + if (!currentCommand.pending) { + return; + } + + const struct flash_area *configArea = currentCommand.configBufferId == ConfigBufferId_HardwareConfig ? hardwareConfigArea : userConfigArea; + size_t configSize = currentCommand.configBufferId == ConfigBufferId_HardwareConfig ? HARDWARE_CONFIG_SIZE : USER_CONFIG_SIZE; + + if (currentCommand.operation == StorageOperation_Read) { + int err = 0; + err = flash_area_read(configArea, 0, ConfigBufferIdToConfigBuffer(currentCommand.configBufferId)->buffer, configSize); + if (err != 0) { + printk("Flash read error: %d\n", err); + } + } else if (currentCommand.operation == StorageOperation_Write) { + int err = 0; + uint32_t alignedLen = ALIGN_SIZE(configSize); + err = flash_area_erase(configArea, 0, alignedLen); + if (err != 0) { + printk("Flash erase error: %d\n", err); + } + err = flash_area_write(configArea, 0, ConfigBufferIdToConfigBuffer(currentCommand.configBufferId)->buffer, configSize); + if (err != 0) { + printk("Flash write error: %d\n", err); + } + } + currentCommand.pending = false; + if (currentCommand.successCallback) { + currentCommand.successCallback(); + } +} + +void flash() { + k_sleep(K_FOREVER); + while (true) { + if (k_mutex_lock(&isBusyMutex, K_NO_WAIT) != 0) { + executeCommand(); + k_mutex_unlock(&isBusyMutex); + } + k_sleep(K_FOREVER); + } +} + +void InitFlash() { + k_mutex_init(&isBusyMutex); + + threadId = k_thread_create( + &thread_data, stack_area, + K_THREAD_STACK_SIZEOF(stack_area), + flash, + NULL, NULL, NULL, + THREAD_PRIORITY, 0, K_NO_WAIT + ); + k_thread_name_set(&thread_data, "flash"); +} diff --git a/device/src/flash.h b/device/src/flash.h new file mode 100644 index 000000000..4424759a3 --- /dev/null +++ b/device/src/flash.h @@ -0,0 +1,30 @@ +#ifndef __FLASH_H__ +#define __FLASH_H__ + +// Includes: + +#include "zephyr/storage/flash_map.h" +#include "config_parser/config_globals.h" +#include "storage.h" + +// Macros: + +#ifdef __ZEPHYR__ + // Don't mix them with UHK60 definitions as USER_CONFIG_SIZE differs + #define HARDWARE_CONFIG_SIZE 64 + #define USER_CONFIG_SIZE (32*1024) +#endif + +// Variables: + + extern const struct flash_area *hardwareConfigArea; + extern const struct flash_area *userConfigArea; + +// Functions: + + uint8_t Flash_LaunchTransfer(storage_operation_t operation, config_buffer_id_t config_buffer_id, void (*successCallback)); + int Flash_ReadAreaSync(const struct flash_area *fa, off_t off, void *dst, size_t len); + bool Flash_IsBusy(); + void InitFlash(); + +#endif // __FLASH_H__ diff --git a/device/src/keyboard/README.md b/device/src/keyboard/README.md new file mode 100644 index 000000000..dbb13546f --- /dev/null +++ b/device/src/keyboard/README.md @@ -0,0 +1 @@ +This directory contains code that the only the keyboard halves use, not the dongle. \ No newline at end of file diff --git a/device/src/keyboard/charger.c b/device/src/keyboard/charger.c new file mode 100644 index 000000000..6bc87c64b --- /dev/null +++ b/device/src/keyboard/charger.c @@ -0,0 +1,183 @@ +#include +#include +#include +#include "charger.h" +#include "keyboard/charger.h" +#include "shell.h" +#include "legacy/timer.h" +#include "attributes.h" +#include "legacy/event_scheduler.h" +#include "state_sync.h" +#include + +const struct gpio_dt_spec chargerEnDt = GPIO_DT_SPEC_GET(DT_ALIAS(charger_en), gpios); +const struct gpio_dt_spec chargerStatDt = GPIO_DT_SPEC_GET(DT_ALIAS(charger_stat), gpios); +struct gpio_callback callbackStruct; +const struct adc_dt_spec adc_channel = ADC_DT_SPEC_GET_BY_IDX(DT_PATH(zephyr_user), 0); + +#define CHARGER_UPDATE_PERIOD 60000 +#define CHARGER_STAT_PERIOD 700 + +static battery_state_t batteryState; + +static uint16_t minCharge = 3000; +static uint16_t maxCharge = 4000; + +static uint32_t lastStatZeroTime = 0; +static uint32_t lastStatOneTime = 0; + +static uint16_t buf; +static struct adc_sequence sequence = { + .buffer = &buf, + .buffer_size = sizeof(buf), +}; + +bool RunningOnBattery = false; +bool RightRunningOnBattery = false; + +static bool setBatteryPresent(bool present) { + if (batteryState.batteryPresent != present) { + batteryState.batteryPresent = present; + if (!present) { + batteryState.batteryCharging = false; + batteryState.batteryVoltage = 0; + batteryState.batteryPercentage = 0; + } + return true; + } + return false; +} + +static bool setCharging(bool charging) { + if (batteryState.batteryCharging != charging) { + batteryState.batteryCharging = charging; + return true; + } + return false; +} + +static bool setPercentage(uint16_t voltage, uint8_t perc) { + batteryState.batteryVoltage = voltage; + + if (batteryState.batteryPercentage != perc) { + batteryState.batteryPercentage = perc; + return true; + } + return false; +} + +static bool updateBatteryPresent() { + uint32_t statPeriod = MIN((uint32_t)(lastStatZeroTime - lastStatOneTime), (uint32_t)(lastStatOneTime-lastStatZeroTime)); + uint32_t lastStat = MAX(lastStatZeroTime, lastStatOneTime); + bool batteryOscilates = statPeriod < CHARGER_STAT_PERIOD; + bool changedRecently = (CurrentTime - lastStat) < CHARGER_STAT_PERIOD; + bool batteryMissing = (changedRecently && batteryOscilates); + bool batteryPresent = !batteryMissing; + return setBatteryPresent(batteryPresent); +} + +static bool updatePowered() { + bool powered = nrfx_power_usbstatus_get() > NRFX_POWER_USB_STATE_DISCONNECTED; + if (batteryState.powered != powered) { + batteryState.powered = powered; + return true; + } + return false; +} + +static uint16_t getVoltage() { + adc_read(adc_channel.dev, &sequence); + int32_t val_mv = (int32_t)buf; + adc_raw_to_millivolts_dt(&adc_channel, &val_mv); + return (uint16_t)(VOLTAGE_DIVIDER_MULTIPLIER*val_mv); +} + +void Charger_PrintState() { + printk("Battery is present: %i, charging: %i, at %imV (%i%%)\n", batteryState.batteryPresent, batteryState.batteryCharging, batteryState.batteryVoltage, batteryState.batteryPercentage); +} + +void Charger_UpdateBatteryState() { + bool stateChanged = false; + stateChanged |= updateBatteryPresent(); + stateChanged |= updatePowered(); + + if (batteryState.batteryPresent) { + bool charging = !gpio_pin_get_dt(&chargerStatDt); + + stateChanged |= setCharging(charging); + + uint16_t voltage = getVoltage(); + + // TODO: add more accurate computation + uint8_t perc = MIN(100, 100*(MAX(voltage, minCharge)-minCharge) / (maxCharge - minCharge)); + stateChanged |= setPercentage(voltage, perc); + + if (voltage == 0) { + EventScheduler_Schedule(CurrentTime + CHARGER_STAT_PERIOD, EventSchedulerEvent_UpdateBattery, "charger - voltage == 0"); + } else { + EventScheduler_Schedule(CurrentTime + CHARGER_UPDATE_PERIOD, EventSchedulerEvent_UpdateBattery, "charger - minute period"); + } + } + + if (stateChanged) { + StateSync_UpdateProperty(StateSyncPropertyId_Battery, &batteryState); + } +} + +static nrfx_power_usb_event_handler_t originalPowerHandler = NULL; + +static void powerCallback(nrfx_power_usb_evt_t event) { + originalPowerHandler(event); + CurrentTime = k_uptime_get_32(); + EventScheduler_Schedule(CurrentTime + CHARGER_STAT_PERIOD, EventSchedulerEvent_UpdateBattery, "charger - power callback"); +} + +void chargerStatCallback(const struct device *port, struct gpio_callback *cb, gpio_port_pins_t pins) { + bool stat = gpio_pin_get_dt(&chargerStatDt); + CurrentTime = k_uptime_get_32(); + if (stat) { + lastStatOneTime = CurrentTime; + } else { + lastStatZeroTime = CurrentTime; + } + bool stateChanged = false; + stateChanged |= updateBatteryPresent(); + stateChanged |= updatePowered(); + if (stateChanged) { + StateSync_UpdateProperty(StateSyncPropertyId_Battery, &batteryState); + } + if (Shell.statLog) { + printk("STAT changed to %i\n", stat ? 1 : 0); + } + EventScheduler_Reschedule(CurrentTime + CHARGER_STAT_PERIOD, EventSchedulerEvent_UpdateBattery, "charger - stat callback"); +} + +// charging battery with CHARGER_EN yields STAT 0 +// fully charged battery with CHARGER_EN yields STAT 1 +// CHARGER_EN 0 yields STAT 1 + +void InitCharger(void) { + gpio_pin_configure_dt(&chargerEnDt, GPIO_OUTPUT); + gpio_pin_set_dt(&chargerEnDt, true); + + gpio_pin_configure_dt(&chargerStatDt, GPIO_INPUT); + gpio_pin_interrupt_configure_dt(&chargerStatDt, GPIO_INT_EDGE_BOTH); + gpio_init_callback(&callbackStruct, chargerStatCallback, BIT(chargerStatDt.pin)); + gpio_add_callback(chargerStatDt.port, &callbackStruct); + + adc_channel_setup_dt(&adc_channel); + + (void)adc_sequence_init_dt(&adc_channel, &sequence); + + const nrfx_power_usbevt_config_t config = { + .handler = &powerCallback + }; + + originalPowerHandler = nrfx_power_usb_handler_get(); + nrfx_power_usbevt_init(&config); + nrfx_power_usbevt_enable(); + + EventScheduler_Reschedule(CurrentTime + CHARGER_STAT_PERIOD, EventSchedulerEvent_UpdateBattery, "charger - init"); + + // TODO: Update battery level. See bas_notify() +} diff --git a/device/src/keyboard/charger.h b/device/src/keyboard/charger.h new file mode 100644 index 000000000..8426f89de --- /dev/null +++ b/device/src/keyboard/charger.h @@ -0,0 +1,41 @@ +#ifndef __CHARGER_H__ +#define __CHARGER_H__ + +// Includes: + + #include "shared/attributes.h" + #include + #include + #include + +// Macros: + + #define VOLTAGE_DIVIDER_MULTIPLIER 2 + +// Typedefs: + + typedef struct { + uint16_t batteryVoltage; + uint8_t batteryPercentage; + bool batteryPresent; + bool batteryCharging; + bool powered; + } ATTR_PACKED battery_state_t; + +// Variables: + + extern const struct gpio_dt_spec chargerEnDt; + extern const struct gpio_dt_spec chargerStatDt; + extern const struct adc_dt_spec adc_channel; + + extern bool UsbPowered; + extern bool RunningOnBattery; + extern bool RightRunningOnBattery; + +// Functions: + + void InitCharger(void); + void Charger_PrintState(); + void Charger_UpdateBatteryState(); + +#endif // __CHARGER_H__ diff --git a/device/src/keyboard/i2c.c b/device/src/keyboard/i2c.c new file mode 100644 index 000000000..30f77cb44 --- /dev/null +++ b/device/src/keyboard/i2c.c @@ -0,0 +1,106 @@ +#include +#include +#include "device.h" +#include "i2c_compatibility.h" +#include "legacy/timer.h" +#include "shared/slave_protocol.h" +#include "legacy/slave_scheduler.h" +#include "legacy/slave_drivers/uhk_module_driver.h" +#include "legacy/i2c.h" +#include "keyboard/i2c.h" + +// Thread definitions + +#define THREAD_STACK_SIZE 1000 +#define THREAD_PRIORITY -1 + +static K_THREAD_STACK_DEFINE(stack_area, THREAD_STACK_SIZE); +static struct k_thread thread_data; + +static bool masterTransferInProgress; +static i2c_master_transfer_t* masterTransfer; + +const struct device *i2c0_dev = DEVICE_DT_GET(DT_NODELABEL(i2c0)); + +status_t ZephyrI2c_MasterTransferNonBlocking(i2c_master_transfer_t *transfer) { + if (masterTransferInProgress) { + return kStatus_I2C_Busy; + } else { + masterTransfer = transfer; + masterTransferInProgress = true; + return kStatus_Success; + } +} + +status_t processMasterTransfer() { + if (masterTransfer->direction == kI2C_Write) { + status_t ret = i2c_write(i2c0_dev, masterTransfer->data, masterTransfer->dataSize, masterTransfer->slaveAddress); + masterTransferInProgress = false; + if (ret != 0) { + return kStatus_Fail; + } + return kStatus_Success; + } + if (masterTransfer->direction == kI2C_Read && masterTransfer->dataSize == I2C_MESSAGE_MAX_TOTAL_LENGTH) { + struct i2c_msg msg; + msg.buf = masterTransfer->data; + msg.len = 1; + msg.flags = I2C_MSG_READ; // Unlike i2c_read(), don't use I2C_MSG_STOP + int ret = i2c_transfer(i2c0_dev, &msg, 1, masterTransfer->slaveAddress); + size_t msgLen = masterTransfer->data[0]; + + if (ret != 0) { + return kStatus_Fail; + } + + ret = i2c_read(i2c0_dev, masterTransfer->data+1, msgLen+2, masterTransfer->slaveAddress); + if (ret != 0) { + return kStatus_Fail; + } + + masterTransferInProgress = false; + return kStatus_Success; + } + if (masterTransfer->direction == kI2C_Read) { + int ret = i2c_read(i2c0_dev, masterTransfer->data, masterTransfer->dataSize, masterTransfer->slaveAddress); + + masterTransferInProgress = false; + + if (ret != 0) { + return kStatus_Fail; + } + return kStatus_Success; + } + masterTransferInProgress = false; + return kStatus_Fail; +} + +void i2cPoller() { + InitSlaveScheduler(); + + while (true) { + static status_t lastStatus = kStatus_Success; + + SlaveSchedulerCallback(lastStatus); + + if (masterTransfer->direction == kI2C_Write) { + k_msleep(1); + } + + if (masterTransferInProgress) { + lastStatus = processMasterTransfer(); + } + } +} + +void InitZephyrI2c(void) { + k_thread_create( + &thread_data, stack_area, + K_THREAD_STACK_SIZEOF(stack_area), + i2cPoller, + NULL, NULL, NULL, + THREAD_PRIORITY, 0, K_NO_WAIT + ); + + k_thread_name_set(&thread_data, "i2c_poller"); +} diff --git a/device/src/keyboard/i2c.h b/device/src/keyboard/i2c.h new file mode 100644 index 000000000..3301c62ae --- /dev/null +++ b/device/src/keyboard/i2c.h @@ -0,0 +1,15 @@ +#ifndef __ZEPHYR_I2C_H__ +#define __ZEPHYR_I2C_H__ + +// Includes: + + #include + #include + #include "keyboard/i2c_compatibility.h" + +// Functions: + + extern void InitZephyrI2c(void); + status_t ZephyrI2c_MasterTransferNonBlocking(i2c_master_transfer_t *transfer); + +#endif // __ZEPHYR_I2C_H__ diff --git a/device/src/keyboard/i2c_compatibility.h b/device/src/keyboard/i2c_compatibility.h new file mode 100644 index 000000000..b23f9571a --- /dev/null +++ b/device/src/keyboard/i2c_compatibility.h @@ -0,0 +1,123 @@ +#ifndef __I2C_COMPATIBILITY_H__ +#define __I2C_COMPATIBILITY_H__ + +// Includes: + + #include + #include + #include + +// Typedefs: + typedef int32_t status_t; + #define MAKE_STATUS(group, code) ((((group)*100) + (code))) + + /*! @brief Direction of master and slave transfers. */ + typedef enum _i2c_direction + { + kI2C_Write = 0x0U, /*!< Master transmit to slave. */ + kI2C_Read = 0x1U, /*!< Master receive from slave. */ + } i2c_direction_t; + + /** I2C - Register Layout Typedef */ + typedef struct { } I2C_Type; + + /*! @brief I2C master handle typedef. */ + typedef struct _i2c_master_handle i2c_master_handle_t; + + /*! @brief I2C master transfer callback typedef. */ + typedef void (*i2c_master_transfer_callback_t)(I2C_Type *base, + i2c_master_handle_t *handle, + status_t status, + void *userData); + + /*! @brief I2C master transfer structure. */ + typedef struct _i2c_master_transfer + { + uint32_t flags; /*!< Transfer flag which controls the transfer. */ + uint8_t slaveAddress; /*!< 7-bit slave address. */ + i2c_direction_t direction; /*!< Transfer direction, read or write. */ + uint32_t subaddress; /*!< Sub address. Transferred MSB first. */ + uint8_t subaddressSize; /*!< Size of command buffer. */ + uint8_t *volatile data; /*!< Transfer buffer. */ + volatile size_t dataSize; /*!< Transfer size. */ + } i2c_master_transfer_t; + + /*! @brief I2C master handle structure. */ + struct _i2c_master_handle + { + i2c_master_transfer_t transfer; /*!< I2C master transfer copy. */ + size_t transferSize; /*!< Total bytes to be transferred. */ + uint8_t state; /*!< Transfer state maintained during transfer. */ + i2c_master_transfer_callback_t completionCallback; /*!< Callback function called when transfer finished. */ + void *userData; /*!< Callback parameter passed to callback function. */ + }; + + + /*! @brief Status group numbers. */ + enum _status_groups + { + kStatusGroup_Generic = 0, /*!< Group number for generic status codes. */ + kStatusGroup_FLASH = 1, /*!< Group number for FLASH status codes. */ + kStatusGroup_LPSPI = 4, /*!< Group number for LPSPI status codes. */ + kStatusGroup_FLEXIO_SPI = 5, /*!< Group number for FLEXIO SPI status codes. */ + kStatusGroup_DSPI = 6, /*!< Group number for DSPI status codes. */ + kStatusGroup_FLEXIO_UART = 7, /*!< Group number for FLEXIO UART status codes. */ + kStatusGroup_FLEXIO_I2C = 8, /*!< Group number for FLEXIO I2C status codes. */ + kStatusGroup_LPI2C = 9, /*!< Group number for LPI2C status codes. */ + kStatusGroup_UART = 10, /*!< Group number for UART status codes. */ + kStatusGroup_I2C = 11, /*!< Group number for UART status codes. */ + kStatusGroup_LPSCI = 12, /*!< Group number for LPSCI status codes. */ + kStatusGroup_LPUART = 13, /*!< Group number for LPUART status codes. */ + kStatusGroup_SPI = 14, /*!< Group number for SPI status code.*/ + kStatusGroup_XRDC = 15, /*!< Group number for XRDC status code.*/ + kStatusGroup_SEMA42 = 16, /*!< Group number for SEMA42 status code.*/ + kStatusGroup_SDHC = 17, /*!< Group number for SDHC status code */ + kStatusGroup_SDMMC = 18, /*!< Group number for SDMMC status code */ + kStatusGroup_SAI = 19, /*!< Group number for SAI status code */ + kStatusGroup_MCG = 20, /*!< Group number for MCG status codes. */ + kStatusGroup_SCG = 21, /*!< Group number for SCG status codes. */ + kStatusGroup_SDSPI = 22, /*!< Group number for SDSPI status codes. */ + kStatusGroup_FLEXIO_I2S = 23, /*!< Group number for FLEXIO I2S status codes */ + kStatusGroup_SDRAMC = 35, /*!< Group number for SDRAMC status codes. */ + kStatusGroup_POWER = 39, /*!< Group number for POWER status codes. */ + kStatusGroup_ENET = 40, /*!< Group number for ENET status codes. */ + kStatusGroup_PHY = 41, /*!< Group number for PHY status codes. */ + kStatusGroup_TRGMUX = 42, /*!< Group number for TRGMUX status codes. */ + kStatusGroup_SMARTCARD = 43, /*!< Group number for SMARTCARD status codes. */ + kStatusGroup_LMEM = 44, /*!< Group number for LMEM status codes. */ + kStatusGroup_QSPI = 45, /*!< Group number for QSPI status codes. */ + kStatusGroup_DMA = 50, /*!< Group number for DMA status codes. */ + kStatusGroup_EDMA = 51, /*!< Group number for EDMA status codes. */ + kStatusGroup_DMAMGR = 52, /*!< Group number for DMAMGR status codes. */ + kStatusGroup_FLEXCAN = 53, /*!< Group number for FlexCAN status codes. */ + kStatusGroup_LTC = 54, /*!< Group number for LTC status codes. */ + kStatusGroup_FLEXIO_CAMERA = 55, /*!< Group number for FLEXIO CAMERA status codes. */ + kStatusGroup_NOTIFIER = 98, /*!< Group number for NOTIFIER status codes. */ + kStatusGroup_DebugConsole = 99, /*!< Group number for debug console status codes. */ + kStatusGroup_ApplicationRangeStart = 100, /*!< Starting number for application groups. */ + }; + + /*! @brief Generic status return codes. */ + enum _generic_status + { + kStatus_Success = MAKE_STATUS(kStatusGroup_Generic, 0), + kStatus_Fail = MAKE_STATUS(kStatusGroup_Generic, 1), + }; + + + /*! @brief I2C status return codes. */ + enum _i2c_status + { + kStatus_I2C_Busy = MAKE_STATUS(kStatusGroup_I2C, 0), /*!< I2C is busy with current transfer. */ + kStatus_I2C_Idle = MAKE_STATUS(kStatusGroup_I2C, 1), /*!< Bus is Idle. */ + kStatus_I2C_Nak = MAKE_STATUS(kStatusGroup_I2C, 2), /*!< NAK received during transfer. */ + kStatus_I2C_ArbitrationLost = MAKE_STATUS(kStatusGroup_I2C, 3), /*!< Arbitration lost during transfer. */ + kStatus_I2C_Timeout = MAKE_STATUS(kStatusGroup_I2C, 4), /*!< Wait event timeout. */ + }; + + + + + + +#endif diff --git a/device/src/keyboard/input_interceptor.c b/device/src/keyboard/input_interceptor.c new file mode 100644 index 000000000..f4ebee8cc --- /dev/null +++ b/device/src/keyboard/input_interceptor.c @@ -0,0 +1,26 @@ +#include "input_interceptor.h" +#include "keyboard/oled/screens/screen_manager.h" +#include "keyboard/oled/screens/pairing_screen.h" + +static void(*recipient)(uint8_t) = NULL; + +static void registerScancode(uint8_t scancode) +{ + usb_basic_keyboard_report_t* inactiveReport = GetInactiveUsbBasicKeyboardReport(); + if (!UsbBasicKeyboard_ContainsScancode(inactiveReport, scancode) && recipient != NULL) + { + recipient(scancode); + } +} + +bool InputInterceptor_RegisterReport(usb_basic_keyboard_report_t* activeReport) +{ + switch (ActiveScreen) { + case ScreenId_Pairing: + recipient = &PairingScreen_RegisterScancode; + UsbBasicKeyboard_ForeachScancode(activeReport, ®isterScancode); + return true; + default: + return false; + } +} diff --git a/device/src/keyboard/input_interceptor.h b/device/src/keyboard/input_interceptor.h new file mode 100644 index 000000000..869d7fee8 --- /dev/null +++ b/device/src/keyboard/input_interceptor.h @@ -0,0 +1,21 @@ +#ifndef __INPUT_INTERCEPTOR_H__ +#define __INPUT_INTERCEPTOR_H__ + +// Includes: + + #include + #include + #include "legacy/usb_interfaces/usb_interface_basic_keyboard.h" + +// Macros: + +// Typedefs: + +// Variables: + + +// Functions: + + bool InputInterceptor_RegisterReport(usb_basic_keyboard_report_t* activeReport); + +#endif diff --git a/device/src/keyboard/key_scanner.c b/device/src/keyboard/key_scanner.c new file mode 100644 index 000000000..5b222d72e --- /dev/null +++ b/device/src/keyboard/key_scanner.c @@ -0,0 +1,180 @@ +#include "device.h" +#include +#include +#include +#include "keyboard/key_scanner.h" +#include "shell.h" +#include "keyboard/uart.h" +#include "nus_client.h" +#include "nus_server.h" +#include "oled/oled_buffer.h" +#include "logger.h" +#include "key_states.h" +#include "bool_array_converter.h" +#include "legacy/module.h" +#include "logger.h" +#include "messenger.h" +#include "device.h" +#include "legacy/event_scheduler.h" +#include "main.h" +#include "legacy/config_manager.h" +#include "legacy/macros/keyid_parser.h" +#include "attributes.h" +#include "legacy/layouts/key_layout.h" +#include "legacy/layouts/key_layout_80_to_universal.h" + +// Thread definitions + +#define THREAD_STACK_SIZE 1000 +#define THREAD_PRIORITY -1 + +static K_THREAD_STACK_DEFINE(stack_area, THREAD_STACK_SIZE); +static struct k_thread thread_data; + +// Keyboard matrix definitions + +static struct gpio_dt_spec rows[KEY_MATRIX_ROWS] = { + GPIO_DT_SPEC_GET(DT_ALIAS(row1), gpios), + GPIO_DT_SPEC_GET(DT_ALIAS(row2), gpios), + GPIO_DT_SPEC_GET(DT_ALIAS(row3), gpios), + GPIO_DT_SPEC_GET(DT_ALIAS(row4), gpios), + GPIO_DT_SPEC_GET(DT_ALIAS(row5), gpios), + GPIO_DT_SPEC_GET(DT_ALIAS(row6), gpios), +}; + +static struct gpio_dt_spec cols[KEY_MATRIX_COLS] = { + GPIO_DT_SPEC_GET(DT_ALIAS(col1), gpios), + GPIO_DT_SPEC_GET(DT_ALIAS(col2), gpios), + GPIO_DT_SPEC_GET(DT_ALIAS(col3), gpios), + GPIO_DT_SPEC_GET(DT_ALIAS(col4), gpios), + GPIO_DT_SPEC_GET(DT_ALIAS(col5), gpios), + GPIO_DT_SPEC_GET(DT_ALIAS(col6), gpios), + GPIO_DT_SPEC_GET(DT_ALIAS(col7), gpios), +#if DEVICE_IS_UHK80_RIGHT + GPIO_DT_SPEC_GET(DT_ALIAS(col8), gpios), + GPIO_DT_SPEC_GET(DT_ALIAS(col9), gpios), + GPIO_DT_SPEC_GET(DT_ALIAS(col10), gpios), +#endif +}; + +#define COLS_COUNT (sizeof(cols) / sizeof(cols[0])) +volatile bool KeyPressed; + +ATTR_UNUSED static void reportChange(uint8_t sourceIndex, bool active) { + uint8_t slotId = DEVICE_IS_UHK80_LEFT ? SlotId_LeftKeyboardHalf : SlotId_RightKeyboardHalf; + uint8_t keyId = KeyLayout_Uhk80_to_Uhk60[slotId][sourceIndex]; + const char* abbrev = MacroKeyIdParser_KeyIdToAbbreviation(slotId*64 + keyId); + if (active) { + Log("%s down\n", abbrev); + } else { + Log(" %s up\n", abbrev); + } +} + +static void scanKeys() { + bool somethingChanged = false; + static bool keyStateBuffer[KEY_MATRIX_ROWS*KEY_MATRIX_COLS]; + bool keyPressed = false; + + CurrentTime = k_uptime_get_32(); + + for (uint8_t rowId=0; rowId= 8) { + targetKeyId = KeyLayout_Uhk80_to_Universal[slotId][sourceIndex]; + } else { + targetKeyId = KeyLayout_Uhk80_to_Uhk60[slotId][sourceIndex]; + } + + if (targetKeyId < MAX_KEY_COUNT_PER_MODULE) { + if (currentBacklightingMode == BacklightingMode_LedTest) { + if ( keyStateBuffer[sourceIndex] ) { + Ledmap_ActivateTestled(slotId, targetKeyId); + EventVector_WakeMain(); + } + KeyStates[CURRENT_SLOT_ID][targetKeyId].hardwareSwitchState = false; + continue; + } + + if (DEVICE_IS_UHK80_RIGHT) { + KeyStates[CURRENT_SLOT_ID][targetKeyId].hardwareSwitchState = keyStateBuffer[sourceIndex]; + } + + if (DEVICE_IS_UHK80_LEFT) { + BoolBitToBytes(keyStateBuffer[sourceIndex], targetKeyId, compressedBuffer); + } + } + } + } + + if (DEVICE_IS_UHK80_RIGHT) { + EventVector_Set(EventVector_StateMatrix); + EventVector_WakeMain(); + } + + if (DEVICE_IS_UHK80_LEFT) { + Messenger_Send2(DeviceId_Uhk80_Right, MessageId_SyncableProperty, SyncablePropertyId_LeftHalfKeyStates, compressedBuffer, compressedLength); + } +} + +void keyScanner() { + while (true) { + scanKeys(); + k_msleep(1); + } +} + +void InitKeyScanner(void) +{ + for (uint8_t rowId=0; rowId<6; rowId++) { + gpio_pin_configure_dt(&rows[rowId], GPIO_OUTPUT); + } + for (uint8_t colId=0; colId +#include +#include "keyboard/leds.h" +#include "keyboard/spi.h" +#include "leds.h" +#include "shell.h" +#include "keyboard/key_scanner.h" +#include "legacy/ledmap.h" +#include "legacy/slave_drivers/is31fl3xxx_driver.h" + +// Thread definitions + +#define THREAD_STACK_SIZE 1000 +#define THREAD_PRIORITY 5 + +static K_THREAD_STACK_DEFINE(stack_area, THREAD_STACK_SIZE); +static struct k_thread thread_data; +static k_tid_t ledUpdaterTid = 0; + +// LED GPIOs + +const struct gpio_dt_spec ledsCsDt = GPIO_DT_SPEC_GET(DT_ALIAS(leds_cs), gpios); +const struct gpio_dt_spec ledsSdbDt = GPIO_DT_SPEC_GET(DT_ALIAS(leds_sdb), gpios); + +uint8_t Uhk80LedDriverValues[UHK80_LED_DRIVER_LED_COUNT_MAX]; + +void setLedsCs(bool state) +{ + gpio_pin_set_dt(&ledsCsDt, state); +} + +#define LedPagePrefix 0b01010000 + +static volatile bool ledsNeedUpdate = false; + +static void setOperationMode(bool on) { + // Set software shutdown control (SSD) register to normal mode + setLedsCs(true); + writeSpi(LedPagePrefix | 2); + writeSpi(0x00); + writeSpi(0b00001000 | (on ? 1 : 0)); + setLedsCs(false); +} + +static void sleepLeds() { + k_mutex_lock(&SpiMutex, K_FOREVER); + setOperationMode(0); + k_mutex_unlock(&SpiMutex); + + while (KeyBacklightBrightness == 0) { + k_sleep(K_FOREVER); + } +} + +void ledUpdater() { + k_sleep(K_MSEC(100)); + while (true) { + k_mutex_lock(&SpiMutex, K_FOREVER); + + setOperationMode(1); + + // Set 180 degree phase delay to reduce audible noise, although it doesn't seem to make a difference + setLedsCs(true); + writeSpi(LedPagePrefix | 2); + writeSpi(0x02); + writeSpi(0b10110011); + setLedsCs(false); + + // Enable spread spectrum with 15% range and 1980us cycle time, which substantially reduces audible noise + setLedsCs(true); + writeSpi(LedPagePrefix | 2); + writeSpi(0x25); + writeSpi(0x14); + setLedsCs(false); + + setLedsCs(true); + writeSpi(LedPagePrefix | 2); + writeSpi(0x01); + writeSpi(0xff); + setLedsCs(false); + + setLedsCs(true); + writeSpi(LedPagePrefix | 0); + writeSpi(0x00); + for (int i=0; i<255; i++) { + writeSpi(Uhk80LedDriverValues[i]); + } + setLedsCs(false); + + setLedsCs(true); + writeSpi(LedPagePrefix | 1); + writeSpi(0x00); + for (int i=0; i<255; i++) { + writeSpi(KeyBacklightBrightness); + } + setLedsCs(false); + + k_mutex_unlock(&SpiMutex); + + if (!ledsNeedUpdate) { + k_sleep(K_FOREVER); + } + + if (KeyBacklightBrightness == 0) { + sleepLeds(); + } + + ledsNeedUpdate = false; + } +} + +void Uhk80_UpdateLeds() { + ledsNeedUpdate = true; + k_wakeup(ledUpdaterTid); +} + +void InitLeds(void) { + gpio_pin_configure_dt(&ledsCsDt, GPIO_OUTPUT); + + gpio_pin_configure_dt(&ledsSdbDt, GPIO_OUTPUT); + gpio_pin_set_dt(&ledsSdbDt, true); + + ledUpdaterTid = k_thread_create( + &thread_data, stack_area, + K_THREAD_STACK_SIZEOF(stack_area), + ledUpdater, + NULL, NULL, NULL, + THREAD_PRIORITY, 0, K_NO_WAIT + ); + k_thread_name_set(&thread_data, "led_updater"); +} diff --git a/device/src/keyboard/leds.h b/device/src/keyboard/leds.h new file mode 100644 index 000000000..147bc5a8f --- /dev/null +++ b/device/src/keyboard/leds.h @@ -0,0 +1,22 @@ +#ifndef __LEDS_H__ +#define __LEDS_H__ + +// Includes + + #include + +// Macros: + + #define UHK80_LED_DRIVER_LED_COUNT_MAX 255 +// Variables: + + extern uint8_t Uhk80LedDriverValues[UHK80_LED_DRIVER_LED_COUNT_MAX]; + extern const struct gpio_dt_spec ledsCsDt; + extern const struct gpio_dt_spec ledsSdbDt; + +// Functions: + + extern void Uhk80_UpdateLeds(); + extern void InitLeds(void); + +#endif // __LEDS_H__ diff --git a/device/src/keyboard/legacy_ports.h b/device/src/keyboard/legacy_ports.h new file mode 100644 index 000000000..466b51f59 --- /dev/null +++ b/device/src/keyboard/legacy_ports.h @@ -0,0 +1,33 @@ +#ifndef __LEGACY_PORTS_H__ +#define __LEGACY_PORTS_H__ + +// Typedefs: + +#ifdef __ZEPHYR__ + typedef enum _usb_status + { + kStatus_USB_Success = 0x00U, /*!< Success */ + kStatus_USB_Error, /*!< Failed */ + + kStatus_USB_Busy, /*!< Busy */ + kStatus_USB_InvalidHandle, /*!< Invalid handle */ + kStatus_USB_InvalidParameter, /*!< Invalid parameter */ + kStatus_USB_InvalidRequest, /*!< Invalid request */ + kStatus_USB_ControllerNotFound, /*!< Controller cannot be found */ + kStatus_USB_InvalidControllerInterface, /*!< Invalid controller interface */ + + kStatus_USB_NotSupported, /*!< Configuration is not supported */ + kStatus_USB_Retry, /*!< Enumeration get configuration retry */ + kStatus_USB_TransferStall, /*!< Transfer stalled */ + kStatus_USB_TransferFailed, /*!< Transfer failed */ + kStatus_USB_AllocFail, /*!< Allocation failed */ + kStatus_USB_LackSwapBuffer, /*!< Insufficient swap buffer for KHCI */ + kStatus_USB_TransferCancel, /*!< The transfer cancelled */ + kStatus_USB_BandwidthFail, /*!< Allocate bandwidth failed */ + kStatus_USB_MSDStatusFail, /*!< For MSD, the CSW status means fail */ + } usb_status_t; + + typedef uint8_t usb_hid_protocol_t; +#endif + +#endif diff --git a/device/src/keyboard/oled/fonts/custom_mono_8.c b/device/src/keyboard/oled/fonts/custom_mono_8.c new file mode 100644 index 000000000..b8d9d3087 --- /dev/null +++ b/device/src/keyboard/oled/fonts/custom_mono_8.c @@ -0,0 +1,490 @@ +/******************************************************************************* + * Size: 8 px + * Bpp: 4 + * Opts: + ******************************************************************************/ + +#ifdef LV_LVGL_H_INCLUDE_SIMPLE +#include "lvgl.h" +#else +#include "lvgl/lvgl.h" +#endif + +#ifndef JETBRAINSMONO8 +#define JETBRAINSMONO8 1 +#endif + +#if JETBRAINSMONO8 + +/*----------------- + * BITMAPS + *----------------*/ + +/*Store the image of the glyphs*/ +static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { + /* U+0020 " " */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+0021 "!" */ +0x00, 0xf0, 0x00, 0x0f, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+0022 "\"" */ +0x0f, 0x0f, 0x00, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..23 "#" */ +0x00, 0x00, 0x00, 0xf0, 0xf0, 0xff, 0xff, 0x0f, 0xff, 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..24 "$" */ +0xff, 0xff, 0xff, 0x0f, 0x00, 0xff, 0xff, 0xf0, 0x0f, 0x0f, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..25 "%" */ +0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..26 "&" */ +0x0f, 0x00, 0x0f, 0x0f, 0x00, 0x0f, 0xf0, 0x0f, 0x00, 0xf0, 0x0f, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..27 "'" */ +0x00, 0xf0, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..28 "(" */ +0x00, 0x0f, 0x00, 0x0f, 0x00, 0x00, 0xf0, 0x00, 0x0f, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..29 ")" */ +0x0f, 0x00, 0x00, 0x0f, 0x00, 0x00, 0xf0, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..2A "*" */ +0x00, 0xf0, 0x00, 0xff, 0xf0, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..2B "+" */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0xff, 0xf0, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..2C "," */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, + + /* U+..2D "-" */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..2E "." */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..2F "/" */ +0x00, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..3. "." */ +0x0f, 0xff, 0x0f, 0x00, 0x0f, 0xf0, 0x00, 0xff, 0x00, 0x0f, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..31 "1" */ +0x00, 0xf0, 0x00, 0xff, 0x00, 0x00, 0xf0, 0x00, 0x0f, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..32 "2" */ +0x0f, 0xff, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..33 "3" */ +0x0f, 0xff, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x0f, 0x00, 0x0f, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..34 "4" */ +0x00, 0xf0, 0x00, 0xf0, 0x00, 0xff, 0xff, 0x00, 0x0f, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..35 "5" */ +0xff, 0xff, 0x0f, 0x00, 0x00, 0xff, 0xf0, 0x00, 0x00, 0xf0, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..36 "6" */ +0x00, 0xf0, 0x00, 0xf0, 0x00, 0xff, 0xf0, 0x0f, 0x00, 0xf0, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..37 "7" */ +0xff, 0xff, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..38 "8" */ +0x0f, 0xff, 0x0f, 0x00, 0x0f, 0x0f, 0xff, 0x0f, 0x00, 0x0f, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..39 "9" */ +0x0f, 0xf0, 0x0f, 0x00, 0xf0, 0x0f, 0xff, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..3A ":" */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..3B ";" */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, + + /* U+..3C "<" */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0xf0, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..3D "=" */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..3E ">" */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0xff, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..3F "?" */ +0xff, 0xf0, 0x00, 0x00, 0xf0, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..4. "@" */ +0x0f, 0xff, 0x0f, 0x00, 0x0f, 0xf0, 0xf0, 0xff, 0xf0, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, + + /* U+..41 "A" */ +0x0f, 0xff, 0x0f, 0x00, 0x0f, 0xff, 0xff, 0xff, 0x00, 0x0f, 0xf0, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..42 "B" */ +0xff, 0xff, 0x0f, 0x00, 0x0f, 0xff, 0xff, 0x0f, 0x00, 0x0f, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..43 "C" */ +0x0f, 0xff, 0x0f, 0x00, 0x0f, 0xf0, 0x00, 0x0f, 0x00, 0x0f, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..44 "D" */ +0xff, 0xff, 0x0f, 0x00, 0x0f, 0xf0, 0x00, 0xff, 0x00, 0x0f, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..45 "E" */ +0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x0f, 0x00, 0x00, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..46 "F" */ +0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xf0, 0x0f, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..47 "G" */ +0x0f, 0xff, 0x0f, 0x00, 0x00, 0xf0, 0x0f, 0xff, 0x00, 0x0f, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..48 "H" */ +0xf0, 0x00, 0xff, 0x00, 0x0f, 0xff, 0xff, 0xff, 0x00, 0x0f, 0xf0, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..49 "I" */ +0x0f, 0xff, 0x00, 0x0f, 0x00, 0x00, 0xf0, 0x00, 0x0f, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..4A "J" */ +0xff, 0xff, 0xf0, 0x00, 0x0f, 0x00, 0x00, 0xff, 0x00, 0x0f, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..4B "K" */ +0xf0, 0x00, 0xff, 0x0f, 0xf0, 0xff, 0x00, 0x0f, 0x0f, 0xf0, 0xf0, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..4C "L" */ +0xf0, 0x00, 0x0f, 0x00, 0x00, 0xf0, 0x00, 0x0f, 0x00, 0x00, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..4D "M" */ +0xf0, 0x00, 0xff, 0xf0, 0xff, 0xf0, 0xf0, 0xff, 0x00, 0x0f, 0xf0, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..4E "N" */ +0xf0, 0x00, 0xff, 0xf0, 0x0f, 0xf0, 0xf0, 0xff, 0x00, 0xff, 0xf0, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..4F "O" */ +0x0f, 0xff, 0x0f, 0x00, 0x0f, 0xf0, 0x00, 0xff, 0x00, 0x0f, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..5. "P" */ +0xff, 0xff, 0x0f, 0x00, 0x0f, 0xff, 0xff, 0x0f, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..51 "Q" */ +0x0f, 0xff, 0x0f, 0x00, 0x0f, 0xf0, 0x00, 0xff, 0x00, 0x0f, 0x0f, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, + + /* U+..52 "R" */ +0xff, 0xff, 0x0f, 0x00, 0x0f, 0xff, 0xff, 0x0f, 0x00, 0x0f, 0xf0, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..53 "S" */ +0x0f, 0xff, 0xff, 0x00, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x0f, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..54 "T" */ +0xff, 0xff, 0xf0, 0x0f, 0x00, 0x00, 0xf0, 0x00, 0x0f, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..55 "U" */ +0xf0, 0x00, 0xff, 0x00, 0x0f, 0xf0, 0x00, 0xff, 0x00, 0x0f, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..56 "V" */ +0xf0, 0x00, 0xff, 0x00, 0x0f, 0xf0, 0x00, 0xf0, 0xf0, 0xf0, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..57 "W" */ +0xf0, 0x00, 0xff, 0x00, 0x0f, 0xf0, 0x00, 0xff, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..58 "X" */ +0xf0, 0x00, 0xf0, 0xf0, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0xf0, 0xf0, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..59 "Y" */ +0xf0, 0x00, 0xf0, 0xf0, 0xf0, 0x00, 0xf0, 0x00, 0x0f, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..5A "Z" */ +0xff, 0xff, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..5B "[" */ +0x0f, 0xff, 0x00, 0xf0, 0x00, 0x0f, 0x00, 0x00, 0xf0, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..5C "\\" */ +0xf0, 0x00, 0x00, 0xf0, 0x00, 0x00, 0xf0, 0x00, 0x00, 0xf0, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..5D "]" */ +0x0f, 0xff, 0x00, 0x00, 0xf0, 0x00, 0x0f, 0x00, 0x00, 0xf0, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..5E "^" */ +0x00, 0xf0, 0x00, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..5F "_" */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..6. "`" */ +0x0f, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..61 "a" */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x0f, 0x00, 0xf0, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..62 "b" */ +0xf0, 0x00, 0x0f, 0x00, 0x00, 0xff, 0xf0, 0x0f, 0x00, 0xf0, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..63 "c" */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x0f, 0x00, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..64 "d" */ +0x00, 0x0f, 0x00, 0x00, 0xf0, 0x0f, 0xff, 0x0f, 0x00, 0xf0, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..65 "e" */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xf0, 0x0f, 0xff, 0xf0, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..66 "f" */ +0x00, 0x0f, 0x00, 0x0f, 0x00, 0x00, 0xff, 0x00, 0x0f, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..67 "g" */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x0f, 0x00, 0xf0, 0x0f, 0xff, 0x00, 0x00, 0xf0, 0x0f, 0xf0, 0x00, + + /* U+..68 "h" */ +0xf0, 0x00, 0x0f, 0x00, 0x00, 0xff, 0xf0, 0x0f, 0x00, 0xf0, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..69 "i" */ +0x00, 0xf0, 0x00, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x0f, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..6A "j" */ +0x00, 0xf0, 0x00, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x0f, 0x00, 0x00, 0xf0, 0x00, 0x0f, 0x00, 0x0f, 0xf0, 0x00, + + /* U+..6B "k" */ +0xf0, 0x00, 0x0f, 0x00, 0x00, 0xf0, 0xff, 0x0f, 0xf0, 0x00, 0xf0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..6C "l" */ +0x0f, 0xf0, 0x00, 0x0f, 0x00, 0x00, 0xf0, 0x00, 0x0f, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..6D "m" */ +0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x0f, 0x0f, 0x0f, 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..6E "n" */ +0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xf0, 0x0f, 0x00, 0xf0, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..6F "o" */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xf0, 0x0f, 0x00, 0xf0, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..7. "p" */ +0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xf0, 0x0f, 0x00, 0xf0, 0xff, 0xf0, 0x0f, 0x00, 0x00, 0xf0, 0x00, 0x00, + + /* U+..71 "q" */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x0f, 0x00, 0xf0, 0x0f, 0xff, 0x00, 0x00, 0xf0, 0x00, 0x0f, 0x00, + + /* U+..72 "r" */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x00, 0xf0, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..73 "s" */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..74 "t" */ +0x00, 0x00, 0x00, 0x0f, 0x00, 0x0f, 0xff, 0x00, 0x0f, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..75 "u" */ +0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x0f, 0x00, 0xf0, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..76 "v" */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x00, 0xf0, 0xf0, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..77 "w" */ +0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0xff, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..78 "x" */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..79 "y" */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x00, 0xf0, 0xf0, 0x00, 0xf0, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x00, + + /* U+..7A "z" */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x00, 0x0f, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..7B "{" */ +0x00, 0xff, 0x00, 0x0f, 0x00, 0x0f, 0xf0, 0x00, 0x0f, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..7C "|" */ +0x00, 0xf0, 0x00, 0x0f, 0x00, 0x00, 0xf0, 0x00, 0x0f, 0x00, 0x00, 0xf0, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, + + /* U+..7D "}" */ +0x0f, 0xf0, 0x00, 0x0f, 0x00, 0x00, 0xff, 0x00, 0x0f, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* U+..7E "~" */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + + +/*--------------------- + * GLYPH DESCRIPTION + *--------------------*/ + +static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = { + {.bitmap_index = 0, .adv_w = 0, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0} /* id = 0 reserved */, + {.bitmap_index = 0, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 18, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 36, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 54, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 72, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 90, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 108, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 126, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 144, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 162, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 180, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 198, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 216, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 234, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 252, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 270, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 288, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 306, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 324, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 342, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 360, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 378, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 396, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 414, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 432, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 450, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 468, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 486, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 504, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 522, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 540, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 558, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 576, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 594, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 612, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 630, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 648, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 666, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 684, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 702, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 720, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 738, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 756, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 774, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 792, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 810, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 828, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 846, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 864, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 882, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 900, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 918, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 936, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 954, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 972, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 990, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 1008, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 1026, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 1044, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 1062, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 1080, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 1098, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 1116, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 1134, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 1152, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 1170, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 1188, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 1206, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 1224, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 1242, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 1260, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 1278, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 1296, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 1314, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 1332, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 1350, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 1368, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 1386, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 1404, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 1422, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 1440, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 1458, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 1476, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 1494, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 1512, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 1530, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 1548, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 1566, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 1584, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 1602, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 1620, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 1638, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 1656, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 1674, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 1692, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 1710, .adv_w = 96, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, +}; +/*--------------------- + * CHARACTER MAPPING + *--------------------*/ + + + +/*Collect the unicode lists and glyph_id offsets*/ +static const lv_font_fmt_txt_cmap_t cmaps[] = +{ + { + .range_start = 32, .range_length = 95, .glyph_id_start = 1, + .unicode_list = NULL, .glyph_id_ofs_list = NULL, .list_length = 0, .type = LV_FONT_FMT_TXT_CMAP_FORMAT0_TINY + } +}; + + + +/*-------------------- + * ALL CUSTOM DATA + *--------------------*/ + +#if LVGL_VERSION_MAJOR == 8 +/*Store all the custom data of the font*/ +static lv_font_fmt_txt_glyph_cache_t cache; +#endif + +#if LVGL_VERSION_MAJOR >= 8 +static const lv_font_fmt_txt_dsc_t font_dsc = { +#else +static lv_font_fmt_txt_dsc_t font_dsc = { +#endif + .glyph_bitmap = glyph_bitmap, + .glyph_dsc = glyph_dsc, + .cmaps = cmaps, + .kern_dsc = NULL, + .kern_scale = 0, + .cmap_num = 1, + .bpp = 4, + .kern_classes = 0, + .bitmap_format = 0, +#if LVGL_VERSION_MAJOR == 8 + .cache = &cache +#endif +}; + + +/*----------------- + * PUBLIC FONT + *----------------*/ + +/*Initialize a public general font descriptor*/ +#if LVGL_VERSION_MAJOR >= 8 +const lv_font_t CustomMono8 = { +#else +lv_font_t JetBrainsMono8 = { +#endif + .get_glyph_dsc = lv_font_get_glyph_dsc_fmt_txt, /*Function pointer to get glyph's data*/ + .get_glyph_bitmap = lv_font_get_bitmap_fmt_txt, /*Function pointer to get glyph's bitmap*/ + .line_height = 7, /*The maximum line height required by the font*/ + .base_line = 2, /*Baseline measured from the bottom of the line*/ +#if !(LVGL_VERSION_MAJOR == 6 && LVGL_VERSION_MINOR == 0) + .subpx = LV_FONT_SUBPX_NONE, +#endif +#if LV_VERSION_CHECK(7, 4, 0) || LVGL_VERSION_MAJOR >= 8 + .underline_position = -1, + .underline_thickness = 0, +#endif + .dsc = &font_dsc, /*The custom font data. Will be accessed by `get_glyph_bitmap/dsc` */ + .fallback = NULL, + .user_data = NULL +}; + + + +#endif /*#if JETBRAINSMONO8*/ + diff --git a/device/src/keyboard/oled/fonts/font_awesome_12.c b/device/src/keyboard/oled/fonts/font_awesome_12.c new file mode 100644 index 000000000..5d9fc2e72 --- /dev/null +++ b/device/src/keyboard/oled/fonts/font_awesome_12.c @@ -0,0 +1,258 @@ +/******************************************************************************* + * Size: 12 px + * Bpp: 4 + * Opts: --lv-font-name FontAwesome12 --format lvgl --bpp 4 -o font_awesome_12.c --size 12 --font /opt/fontawesome/otfs/font_awesome_6_regular.ttf --range 0xf057,0xf8dd,0xf1e6,0xe000,0xf071 --no-compress + ******************************************************************************/ + +#include "font_awesome_12.h" +#ifdef LV_LVGL_H_INCLUDE_SIMPLE +#include "lvgl.h" +#else +#include "lvgl/lvgl.h" +#endif + +#ifndef FONTAWESOME12 +#define FONTAWESOME12 1 +#endif + +#if FONTAWESOME12 + +/*----------------- + * BITMAPS + *----------------*/ + +/*Store the image of the glyphs*/ +static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { + // These have to follow order defined in font_awesome_12_data + /* U+E000 "circle-xmark-large" */ + 0x0, 0x0, 0x13, 0x31, 0x0, 0x0, 0x0, 0x3b, + 0xfe, 0xef, 0xb3, 0x0, 0x5, 0xf8, 0x10, 0x1, + 0x8f, 0x40, 0x2f, 0x53, 0x10, 0x1, 0x35, 0xf2, + 0x99, 0x8, 0xd1, 0x1d, 0x90, 0x99, 0xe4, 0x0, + 0xad, 0xda, 0x0, 0x4e, 0xf2, 0x0, 0x1f, 0xf1, + 0x0, 0x2f, 0xe4, 0x1, 0xda, 0xad, 0x10, 0x4e, + 0x99, 0xa, 0xa0, 0xa, 0xa0, 0x99, 0x2f, 0x40, + 0x0, 0x0, 0x5, 0xf2, 0x5, 0xf8, 0x10, 0x1, + 0x8f, 0x40, 0x0, 0x3b, 0xfe, 0xef, 0xb3, 0x0, + 0x0, 0x0, 0x13, 0x31, 0x0, 0x0, + + /* U+F057 "" */ + 0x0, 0x0, 0x13, 0x31, 0x0, 0x0, 0x0, 0x2, + 0xbf, 0xee, 0xfb, 0x20, 0x0, 0x4, 0xf9, 0x10, + 0x1, 0x8f, 0x50, 0x1, 0xf5, 0x0, 0x0, 0x0, + 0x4f, 0x20, 0x8a, 0x0, 0x30, 0x3, 0x0, 0x99, + 0xd, 0x40, 0xd, 0x98, 0xe0, 0x3, 0xe0, 0xe3, + 0x0, 0x1f, 0xf2, 0x0, 0x2f, 0xd, 0x40, 0x8, + 0xed, 0x90, 0x3, 0xe0, 0x8a, 0x0, 0xa2, 0x1a, + 0x0, 0x99, 0x1, 0xe5, 0x0, 0x0, 0x0, 0x4f, + 0x20, 0x4, 0xf9, 0x10, 0x1, 0x8f, 0x50, 0x0, + 0x2, 0xbf, 0xee, 0xfb, 0x20, 0x0, 0x0, 0x0, + 0x13, 0x31, 0x0, 0x0, 0x0, + + /* U+F071 "" */ + 0x0, 0x0, 0xb, 0xb0, 0x0, 0x0, 0x0, 0x0, + 0x9c, 0xc9, 0x0, 0x0, 0x0, 0x2, 0xf2, 0x2f, + 0x20, 0x0, 0x0, 0xb, 0x89, 0x38, 0xc0, 0x0, + 0x0, 0x5e, 0xc, 0x50, 0xe5, 0x0, 0x0, 0xe6, + 0xc, 0x50, 0x6e, 0x0, 0x8, 0xc0, 0x4, 0x10, + 0xc, 0x80, 0x2f, 0x30, 0x7, 0x20, 0x3, 0xf2, + 0xaa, 0x0, 0xc, 0x50, 0x0, 0xaa, 0xf5, 0x22, + 0x22, 0x22, 0x22, 0x5f, 0x7e, 0xff, 0xff, 0xff, + 0xff, 0xe7, + + /* U+F1E6 "" */ + 0x0, 0x50, 0x0, 0x50, 0x0, 0x1f, 0x0, 0xf, + 0x10, 0x2, 0xf0, 0x0, 0xf2, 0x1, 0x24, 0x22, + 0x24, 0x21, 0xdf, 0xff, 0xff, 0xff, 0xd4, 0xe0, + 0x0, 0x0, 0xe4, 0x3e, 0x0, 0x0, 0xe, 0x31, + 0xf2, 0x0, 0x2, 0xf1, 0x9, 0xc2, 0x2, 0xc9, + 0x0, 0x9, 0xfe, 0xf9, 0x0, 0x0, 0x1, 0xf1, + 0x0, 0x0, 0x0, 0xf, 0x0, 0x0, 0x0, 0x0, + 0x60, 0x0, 0x0, + + /* U+F8DD "signal-stream" */ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa, + 0x60, 0x0, 0x0, 0x0, 0x1d, 0x10, 0x4e, 0x11, + 0x0, 0x0, 0x2, 0xa, 0xa0, 0xa8, 0xc, 0x60, + 0x0, 0xe, 0x42, 0xf0, 0xe3, 0x3f, 0x0, 0x52, + 0x7, 0xb0, 0xd4, 0xf2, 0x5c, 0x1, 0xf9, 0x4, + 0xd0, 0xc5, 0xe3, 0x3f, 0x0, 0x51, 0x7, 0xb0, + 0xd4, 0xa8, 0xc, 0x60, 0x0, 0xe, 0x42, 0xf0, + 0x4e, 0x11, 0x0, 0x0, 0x2, 0xa, 0xa0, 0xa, + 0x60, 0x0, 0x0, 0x0, 0x1d, 0x10, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, + + + /* U+E001 "lock-square-a" */ + 0x0, 0x66, 0x66, 0x66, 0x66, 0x0, + 0x0f, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0xf5, 0x0, 0x3, 0x30, 0x0, 0x5f, + 0xf5, 0x0, 0xd, 0xd0, 0x0, 0x5f, + 0xf5, 0x0, 0x5f, 0xf5, 0x0, 0x5f, + 0xf5, 0x0, 0xca, 0xac, 0x0, 0x5f, + 0xf5, 0x3, 0xf3, 0x3f, 0x30, 0x5f, + 0xf5, 0xa, 0xe6, 0x6e, 0xb0, 0x5f, + 0xf5, 0x1f, 0xee, 0xee, 0xf2, 0x5f, + 0xf5, 0x8e, 0x0, 0x0, 0xda, 0x5f, + 0xf6, 0xa6, 0x0, 0x0, 0x5e, 0x5f, + 0x0f, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0x0, 0x66, 0x66, 0x66, 0x66, 0x0, + + /* U+E002 "lock-square-num" */ + 0x0, 0x66, 0x66, 0x66, 0x66, 0x00, + 0x0f, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0xf6, 0x0, 0x1, 0x80, 0x0, 0x5f, + 0xf6, 0x0, 0xc, 0xf3, 0x0, 0x5f, + 0xf6, 0x2, 0xef, 0xf3, 0x0, 0x5f, + 0xf6, 0x2, 0x83, 0xf3, 0x0, 0x5f, + 0xf6, 0x0, 0x2, 0xf3, 0x0, 0x5f, + 0xf6, 0x0, 0x2, 0xf3, 0x0, 0x5f, + 0xf6, 0x0, 0x2, 0xf3, 0x0, 0x5f, + 0xf6, 0x0, 0x2, 0xf3, 0x0, 0x5f, + 0xf6, 0x0, 0x0, 0x80, 0x0, 0x5f, + 0x0f, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0x0, 0x66, 0x66, 0x66, 0x66, 0x00, + + /* U+E003 "plugs-connected" */ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, + 0x0, 0x2, 0x0, 0xcb, 0x0, 0x0, 0x4, 0xef, + 0xfd, 0xc1, 0x0, 0x0, 0x5f, 0xff, 0xff, 0x40, + 0x0, 0x1, 0x3f, 0xff, 0xff, 0x90, 0x0, 0x4f, + 0x43, 0xff, 0xff, 0x90, 0x1, 0xff, 0xf4, 0x3f, + 0xff, 0x20, 0x7, 0xff, 0xff, 0x44, 0xf6, 0x0, + 0x8, 0xff, 0xff, 0xf4, 0x10, 0x0, 0x3, 0xff, + 0xff, 0xf7, 0x0, 0x0, 0xb, 0xee, 0xff, 0x60, + 0x0, 0x0, 0x9d, 0x10, 0x20, 0x0, 0x0, 0x0, + 0x11, 0x0, 0x0, 0x0, 0x0, 0x0, + + /* U+F06B "gift" */ + 0x0, 0x3, 0x0, 0x2, 0x30, 0x0, 0x1, 0xee, + 0xe2, 0x5f, 0xec, 0x0, 0x7, 0xa0, 0x9b, 0xf4, + 0xd, 0x40, 0x18, 0xd4, 0x5f, 0xd4, 0x5f, 0x61, + 0xed, 0xdd, 0xdf, 0xed, 0xdd, 0xec, 0xf2, 0x0, + 0xe, 0x90, 0x0, 0x4d, 0xdf, 0xff, 0xff, 0xff, + 0xff, 0xfa, 0x4d, 0x22, 0x2e, 0xa2, 0x22, 0xf1, + 0x4d, 0x0, 0xe, 0x90, 0x0, 0xf1, 0x4d, 0x0, + 0xe, 0x90, 0x0, 0xf1, 0x3d, 0x0, 0xe, 0x90, + 0x0, 0xf1, 0x1e, 0xdd, 0xdf, 0xed, 0xde, 0xd0, + 0x1, 0x44, 0x44, 0x44, 0x44, 0x0, + + /* U+E422 "lock-a" */ + 0x0, 0x0, 0x57, 0x30, 0x0, 0x0, 0x2, 0xef, + 0xff, 0x80, 0x0, 0x0, 0xce, 0x30, 0x8f, 0x40, + 0x0, 0xf, 0x70, 0x0, 0xf8, 0x0, 0x2, 0xf6, + 0x0, 0xe, 0xa0, 0x8, 0xff, 0xff, 0xff, 0xff, + 0xd2, 0xff, 0xff, 0xfb, 0xff, 0xff, 0x7f, 0xff, + 0xf8, 0x1f, 0xff, 0xf8, 0xff, 0xff, 0x39, 0x8f, + 0xff, 0x8f, 0xff, 0x81, 0x21, 0xff, 0xf8, 0xff, + 0xf4, 0xff, 0x99, 0xff, 0x8e, 0xff, 0xff, 0xff, + 0xff, 0xf6, 0x28, 0x99, 0x99, 0x99, 0x96, 0x0, + + /* U+E423 "lock-hashtag" */ + 0x0, 0x1, 0x56, 0x30, 0x0, 0x0, 0x2, 0xef, + 0xff, 0x80, 0x0, 0x0, 0xce, 0x31, 0x9f, 0x30, + 0x0, 0xf, 0x70, 0x0, 0xf8, 0x0, 0x1, 0xf5, + 0x0, 0xe, 0x90, 0x8, 0xff, 0xff, 0xff, 0xff, + 0xd1, 0xff, 0xfd, 0x9f, 0x6f, 0xff, 0x6f, 0xfc, + 0x21, 0x30, 0x7f, 0xf7, 0xff, 0xfb, 0x7f, 0x3f, + 0xff, 0x7f, 0xfd, 0x53, 0x71, 0xaf, 0xf7, 0xff, + 0xfb, 0x7f, 0x4f, 0xff, 0x7c, 0xff, 0xff, 0xff, + 0xff, 0xf3, 0x4, 0x44, 0x44, 0x44, 0x42, 0x0 +}; + +/*--------------------- + * GLYPH DESCRIPTION + *--------------------*/ + +#define COMPUTE_GLYPH_LEN(BOXW, BOXH) (((BOXW)*(BOXH)+1)/2) +const uint8_t GlyphOffset_0 = 0; +#define GLYPH_DATA(INDEX0, INDEX1, NAME, ADVW, BOXW, BOXH, OFSX, OFSY) const uint16_t GlyphOffset_##INDEX1 = GlyphOffset_##INDEX0 + COMPUTE_GLYPH_LEN(BOXW, BOXH); +#include "font_awesome_12_data.h" +#undef GLYPH_DATA + +static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = { + {.bitmap_index = 0, .adv_w = 0, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0} /* id = 0 reserved */, + + #define GLYPH_DATA(INDEX0, INDEX1, NAME, ADVW, BOXW, BOXH, OFSX, OFSY) {.bitmap_index = GlyphOffset_##INDEX0, .adv_w = ADVW, .box_w = BOXW, .box_h = BOXH, .ofs_x = OFSX, .ofs_y = OFSY}, + #include "font_awesome_12_data.h" + #undef GLYPH_DATA +}; + + +/*--------------------- + * CHARACTER MAPPING + *--------------------*/ + +// unused I believe +static const uint16_t unicode_list_0[] = { + 0x0, 0x1057, 0x1071, 0x11e6, 0x18dd +}; + +/*Collect the unicode lists and glyph_id offsets*/ +static const lv_font_fmt_txt_cmap_t cmaps[] = +{ + { + .range_start = 57344, .range_length = 6366, .glyph_id_start = 1, + .unicode_list = unicode_list_0, .glyph_id_ofs_list = NULL, .list_length = 5, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY + } +}; + +/*-------------------- + * ALL CUSTOM DATA + *--------------------*/ + +#if LVGL_VERSION_MAJOR == 8 +/*Store all the custom data of the font*/ +static lv_font_fmt_txt_glyph_cache_t cache; +#endif + +#if LVGL_VERSION_MAJOR >= 8 +static const lv_font_fmt_txt_dsc_t font_dsc = { +#else +static lv_font_fmt_txt_dsc_t font_dsc = { +#endif + .glyph_bitmap = glyph_bitmap, + .glyph_dsc = glyph_dsc, + .cmaps = cmaps, + .kern_dsc = NULL, + .kern_scale = 0, + .cmap_num = 1, + .bpp = 4, + .kern_classes = 0, + .bitmap_format = 0, +#if LVGL_VERSION_MAJOR == 8 + .cache = &cache +#endif +}; + + +/*----------------- + * PUBLIC FONT + *----------------*/ + +/*Initialize a public general font descriptor*/ +#if LVGL_VERSION_MAJOR >= 8 +const lv_font_t FontAwesome12 = { +#else +lv_font_t FontAwesome12 = { +#endif + .get_glyph_dsc = lv_font_get_glyph_dsc_fmt_txt, /*Function pointer to get glyph's data*/ + .get_glyph_bitmap = lv_font_get_bitmap_fmt_txt, /*Function pointer to get glyph's bitmap*/ + .line_height = 13, /*The maximum line height required by the font*/ + .base_line = 2, /*Baseline measured from the bottom of the line*/ +#if !(LVGL_VERSION_MAJOR == 6 && LVGL_VERSION_MINOR == 0) + .subpx = LV_FONT_SUBPX_NONE, +#endif +#if LV_VERSION_CHECK(7, 4, 0) || LVGL_VERSION_MAJOR >= 8 + .underline_position = 0, + .underline_thickness = 0, +#endif + .dsc = &font_dsc, /*The custom font data. Will be accessed by `get_glyph_bitmap/dsc` */ + .fallback = NULL, + .user_data = NULL +}; + + + +#endif /*#if FONTAWESOME12*/ + diff --git a/device/src/keyboard/oled/fonts/font_awesome_12.h b/device/src/keyboard/oled/fonts/font_awesome_12.h new file mode 100644 index 000000000..5c170f872 --- /dev/null +++ b/device/src/keyboard/oled/fonts/font_awesome_12.h @@ -0,0 +1,22 @@ +#ifndef __FONT_AWESOME_12_H__ +#define __FONT_AWESOME_12_H__ + + +// Typedefs: + +/** + * Instructions to add a new glyph: + * - Generate a .c lv font file using instructions in fonts.h" + * - Add the glyph's data into the glyph_bitmap array in font_awesome_12.c + * - Add the metadata into font_awesome_12_data.h + * */ + + typedef enum { + #define GLYPH_DATA(INDEX0, INDEX1, NAME, ADVW, BOXW, BOXH, OFSX, OFSY) FontIcon_##NAME = 32+INDEX0, + #include "font_awesome_12_data.h" + #undef GLYPH_DATA + FontIcon_AfterLast, + FontIcon_Count = FontIcon_AfterLast - 32, + } font_icons_t; + +#endif diff --git a/device/src/keyboard/oled/fonts/font_awesome_12_data.h b/device/src/keyboard/oled/fonts/font_awesome_12_data.h new file mode 100644 index 000000000..605245451 --- /dev/null +++ b/device/src/keyboard/oled/fonts/font_awesome_12_data.h @@ -0,0 +1,14 @@ +// Indexes have to go in order one by one! + +GLYPH_DATA(0, 1, CircleXmarkLarge, 192, 12, 13, 0, -2) +GLYPH_DATA(1, 2, CircleXmark, 192, 13, 13, 0, -2) +GLYPH_DATA(2, 3, TriangleExclamation, 192, 12, 11, 0, -1) +GLYPH_DATA(3, 4, Plug, 144, 9, 13, 0, -2) +GLYPH_DATA(4, 5, SignalStream, 216, 14, 11, 0, -1) +GLYPH_DATA(5, 6, LockSquareA, 192, 12, 13, 0, -2) +GLYPH_DATA(6, 7, LockSquareOne, 192, 12, 13, 0, -2) +GLYPH_DATA(7, 8, PlugsConnected, 192, 12, 13, 0, -2) +GLYPH_DATA(8, 9, Gift, 224, 12, 13, 1, -5) +GLYPH_DATA(9, 10, LockA, 168, 11, 13, 0, -2) +GLYPH_DATA(10, 11, LockHashtag, 168, 11, 13, 0, -2) + diff --git a/device/src/keyboard/oled/fonts/fonts.h b/device/src/keyboard/oled/fonts/fonts.h new file mode 100644 index 000000000..361f3360b --- /dev/null +++ b/device/src/keyboard/oled/fonts/fonts.h @@ -0,0 +1,58 @@ +#ifndef __FONTS_H__ +#define __FONTS_H__ + +// Includes: + + #include "lvgl/lvgl.h" + +// Variables: + +/* Instructions to add new font: + * + * We use the lvgl font converter from https://lvgl.io/tools/fontconverter. Unfortunately, from some version the font converter stopped generating fonts compatible with our rendering code, so we need to use an older version. + * + * ``` + * git clone git@github.com:lvgl/lv_font_conv.git + * cd lv_font_conv + * git checkout 968adde4d1d6e01af18774ce83e51da119cf5d91 + * npm ci + * npx lv_font_conv --lv-font-name JetBrainsMono10 --format lvgl --bpp 4 -o jet_brains_mono_10.c --size 10 --font ~/Downloads/fonts/ttf/JetBrainsMono-Regular.ttf --range 0x20-0x7F --no-compress + * ``` + * + * - f057 - circle-xmark + * - f8dd - signal-stream + * - f1e6 - plug + * - f071 - triangle-exclamation + * - f06b - gift + * + * customs: + * - e000 - circle-xmark-large (custom) + * - e001,e002 - caps lock, numlock + * - e003 - connected plug + * + * Script to create icon fonts, to be run from the root of a decompressed fontawesome folder: +``` +#!/bin/bash +mkdir ttfs + +fontforge -lang=ff -c 'Open($1); Generate($2);' otfs/Font\ Awesome\ 6\ Pro-Regular-400.otf ttfs/font_awesome_6_regular.ttf +fontforge -lang=ff -c 'Open($1); Generate($2);' otfs/Font\ Awesome\ 6\ Pro-Solid-900.otf ttfs/font_awesome_6_solid.ttf +fontforge -lang=ff -c 'Open($1); Generate($2);' otfs/Font\ Awesome\ Kit\ 4711ad2078-Regular-400.otf ttfs/font_awesome_custom.ttf + +npx lv_font_conv --lv-font-name CustomIcons --format lvgl --bpp 4 -o icons_custom.c --size 12 --font ttfs/font_awesome_custom.ttf --range 0xe000-0xe003 --no-compress +npx lv_font_conv --lv-font-name RegularIcons --format lvgl --bpp 4 -o icons_regular.c --size 12 --font ttfs/font_awesome_6_regular.ttf --range 0xf057,0xf8dd,0xf1e6,0xf071,0xf06b --no-compress +npx lv_font_conv --lv-font-name SolidIcons --format lvgl --bpp 4 -o icons_solid.c --size 12 --font ttfs/font_awesome_6_solid.ttf --range 0xe423,0xe422 --no-compress +``` + + * */ + + extern const lv_font_t JetBrainsMono8; + extern const lv_font_t JetBrainsMono10; + extern const lv_font_t JetBrainsMono12; + extern const lv_font_t JetBrainsMono16; + extern const lv_font_t JetBrainsMono24; + extern const lv_font_t JetBrainsMono32; + extern const lv_font_t CustomMono8; + extern const lv_font_t FontAwesome12; + +#endif diff --git a/device/src/keyboard/oled/fonts/jet_brains_mono_10.c b/device/src/keyboard/oled/fonts/jet_brains_mono_10.c new file mode 100644 index 000000000..03b771623 --- /dev/null +++ b/device/src/keyboard/oled/fonts/jet_brains_mono_10.c @@ -0,0 +1,658 @@ +/******************************************************************************* + * Size: 10 px + * Bpp: 4 + * Opts: --lv-font-name JetBrainsMono10 --format lvgl --bpp 4 -o jet_brains_mono_10.c --size 10 --font /home/me/Downloads/fonts/ttf/JetBrainsMono-Regular.ttf --range 0x20-0x7F --no-compress + ******************************************************************************/ + +#ifdef LV_LVGL_H_INCLUDE_SIMPLE +#include "lvgl.h" +#else +#include "lvgl/lvgl.h" +#endif + +#ifndef JETBRAINSMONO10 +#define JETBRAINSMONO10 1 +#endif + +#if JETBRAINSMONO10 + +/*----------------- + * BITMAPS + *----------------*/ + +/*Store the image of the glyphs*/ +static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { + /* U+0020 " " */ + + /* U+0021 "!" */ + 0x88, 0x87, 0x77, 0x77, 0x66, 0x33, 0x12, 0x99, + + /* U+0022 "\"" */ + 0x87, 0x78, 0x86, 0x68, 0x86, 0x68, 0x11, 0x11, + + /* U+0023 "#" */ + 0x0, 0xb0, 0x91, 0x1, 0x90, 0xb0, 0x3c, 0xdb, + 0xe7, 0x6, 0x42, 0x90, 0x9, 0x24, 0x60, 0x7e, + 0xbd, 0xc3, 0xb, 0x9, 0x10, 0x19, 0xb, 0x0, + + /* U+0024 "$" */ + 0x0, 0x45, 0x0, 0x1, 0x9a, 0x20, 0xc, 0x9a, + 0xd0, 0xe, 0x45, 0x61, 0xd, 0x95, 0x0, 0x2, + 0xce, 0x50, 0x0, 0x48, 0xe1, 0x15, 0x45, 0xa3, + 0x1d, 0x9a, 0xd0, 0x2, 0xaa, 0x20, 0x0, 0x45, + 0x0, + + /* U+0025 "%" */ + 0x7c, 0x80, 0x38, 0xc0, 0xc0, 0xa0, 0xc0, 0xc6, + 0x40, 0x5c, 0x89, 0x0, 0x0, 0xa8, 0xc5, 0x4, + 0x6c, 0xc, 0xa, 0xc, 0xb, 0x83, 0x8, 0xc7, + + /* U+0026 "&" */ + 0x6, 0xdc, 0x20, 0x0, 0xd1, 0x47, 0x0, 0x8, + 0x50, 0x0, 0x2, 0xcd, 0x20, 0x0, 0xa4, 0x2c, + 0x5b, 0xb, 0x20, 0x8e, 0x0, 0xa4, 0xc, 0xd3, + 0x2, 0xdd, 0x52, 0xc0, + + /* U+0027 "'" */ + 0x88, 0x77, 0x77, 0x11, + + /* U+0028 "(" */ + 0x0, 0x0, 0x0, 0x5b, 0x5, 0xc1, 0xd, 0x20, + 0x1d, 0x0, 0x2c, 0x0, 0x2c, 0x0, 0x1d, 0x0, + 0xe, 0x0, 0x8, 0x90, 0x0, 0xaa, 0x0, 0x1, + + /* U+0029 ")" */ + 0x0, 0x0, 0xb5, 0x0, 0x1c, 0x50, 0x2, 0xd0, + 0x0, 0xd1, 0x0, 0xc2, 0x0, 0xc2, 0x0, 0xc1, + 0x0, 0xe0, 0x9, 0x80, 0xa9, 0x0, 0x10, 0x0, + + /* U+002A "*" */ + 0x0, 0x66, 0x0, 0x32, 0x66, 0x23, 0x4c, 0xdd, + 0xc4, 0x0, 0xbc, 0x0, 0x9, 0x67, 0x90, 0x4, + 0x0, 0x40, + + /* U+002B "+" */ + 0x0, 0x77, 0x0, 0x0, 0x77, 0x0, 0x4d, 0xee, + 0xd4, 0x0, 0x77, 0x0, 0x0, 0x77, 0x0, 0x0, + 0x0, 0x0, + + /* U+002C "," */ + 0x13, 0x79, 0xa5, 0xd2, + + /* U+002D "-" */ + 0x8d, 0xd8, + + /* U+002E "." */ + 0x66, 0x99, + + /* U+002F "/" */ + 0x0, 0x0, 0xd1, 0x0, 0x3, 0xb0, 0x0, 0x9, + 0x50, 0x0, 0xe, 0x0, 0x0, 0x4a, 0x0, 0x0, + 0xa4, 0x0, 0x0, 0xe0, 0x0, 0x5, 0x90, 0x0, + 0xb, 0x30, 0x0, 0x1d, 0x0, 0x0, + + /* U+0030 "0" */ + 0x6, 0xdd, 0x60, 0x1d, 0x0, 0xd1, 0x3a, 0x0, + 0xa3, 0x3a, 0x77, 0xa3, 0x3a, 0x0, 0xa3, 0x3a, + 0x0, 0xa3, 0x1d, 0x0, 0xd1, 0x6, 0xdd, 0x50, + + /* U+0031 "1" */ + 0x2, 0xdc, 0x0, 0x1d, 0x5c, 0x0, 0x1, 0x2c, + 0x0, 0x0, 0x2c, 0x0, 0x0, 0x2c, 0x0, 0x0, + 0x2c, 0x0, 0x0, 0x2c, 0x0, 0x1e, 0xef, 0xe5, + + /* U+0032 "2" */ + 0x6, 0xdd, 0x50, 0x1d, 0x1, 0xe0, 0x13, 0x0, + 0xc2, 0x0, 0x2, 0xd0, 0x0, 0xc, 0x30, 0x0, + 0xb6, 0x0, 0x9, 0x80, 0x0, 0x2f, 0xee, 0xe3, + + /* U+0033 "3" */ + 0x1e, 0xee, 0xe0, 0x0, 0xa, 0x60, 0x0, 0x88, + 0x0, 0x0, 0xbe, 0x60, 0x0, 0x1, 0xe0, 0x12, + 0x0, 0xc1, 0x2c, 0x1, 0xe0, 0x7, 0xdd, 0x50, + + /* U+0034 "4" */ + 0x0, 0xd, 0x10, 0x8, 0x70, 0x2, 0xd0, 0x0, + 0xb4, 0x7, 0x3b, 0x0, 0xe4, 0xee, 0xee, 0x0, + 0x0, 0xe0, 0x0, 0xe, + + /* U+0035 "5" */ + 0xf, 0xee, 0xc0, 0xd, 0x0, 0x0, 0xd, 0x0, + 0x0, 0xe, 0xed, 0x50, 0x0, 0x1, 0xe0, 0x2, + 0x0, 0xc2, 0x1d, 0x1, 0xe0, 0x7, 0xdd, 0x50, + + /* U+0036 "6" */ + 0x0, 0x4b, 0x0, 0x0, 0xc3, 0x0, 0x4, 0xb0, + 0x0, 0xc, 0xcc, 0x50, 0x2d, 0x0, 0xd2, 0x59, + 0x0, 0x95, 0x2d, 0x0, 0xd2, 0x6, 0xde, 0x70, + + /* U+0037 "7" */ + 0x3f, 0xee, 0xf7, 0x3b, 0x0, 0xb3, 0x1, 0x1, + 0xd0, 0x0, 0x7, 0x80, 0x0, 0xd, 0x20, 0x0, + 0x2c, 0x0, 0x0, 0x86, 0x0, 0x0, 0xe1, 0x0, + + /* U+0038 "8" */ + 0x6, 0xdd, 0x60, 0x1e, 0x0, 0xe1, 0xd, 0x11, + 0xd0, 0x6, 0xff, 0x60, 0x1d, 0x11, 0xd1, 0x59, + 0x0, 0x94, 0x2d, 0x0, 0xd2, 0x6, 0xee, 0x60, + + /* U+0039 "9" */ + 0x7, 0xed, 0x60, 0x2d, 0x0, 0xd2, 0x59, 0x0, + 0x95, 0x2d, 0x0, 0xd2, 0x5, 0xcc, 0xc0, 0x0, + 0xc, 0x40, 0x0, 0x4c, 0x0, 0x0, 0xc4, 0x0, + + /* U+003A ":" */ + 0xaa, 0x55, 0x0, 0x0, 0x55, 0xaa, + + /* U+003B ";" */ + 0xaa, 0x55, 0x0, 0x0, 0x12, 0x88, 0xb4, 0xd1, + + /* U+003C "<" */ + 0x0, 0x0, 0x10, 0x0, 0x7, 0xd1, 0x6, 0xd6, + 0x0, 0x2e, 0x20, 0x0, 0x5, 0xd8, 0x10, 0x0, + 0x6, 0xd1, 0x0, 0x0, 0x0, + + /* U+003D "=" */ + 0x2d, 0xdd, 0xd2, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x2d, 0xdd, 0xd2, + + /* U+003E ">" */ + 0x1, 0x0, 0x0, 0x1d, 0x70, 0x0, 0x0, 0x7d, + 0x60, 0x0, 0x2, 0xe2, 0x0, 0x7c, 0x50, 0x1d, + 0x60, 0x0, 0x0, 0x0, 0x0, + + /* U+003F "?" */ + 0xae, 0xc1, 0x0, 0x6a, 0x0, 0x1c, 0x0, 0x6a, + 0xd, 0xc1, 0xc, 0x0, 0x3, 0x0, 0x2f, 0x20, + + /* U+0040 "@" */ + 0x6, 0xcc, 0x80, 0x2b, 0x0, 0x95, 0x75, 0x0, + 0x48, 0x84, 0x2b, 0x99, 0x84, 0x84, 0x49, 0x84, + 0x93, 0x39, 0x84, 0x85, 0x58, 0x75, 0x1b, 0xb1, + 0x2c, 0x0, 0x0, 0x5, 0xdd, 0x40, + + /* U+0041 "A" */ + 0x0, 0xbb, 0x0, 0x0, 0xdd, 0x0, 0x3, 0xaa, + 0x30, 0x6, 0x67, 0x60, 0xa, 0x33, 0xa0, 0xe, + 0xdd, 0xe0, 0x2c, 0x0, 0xc2, 0x68, 0x0, 0x86, + + /* U+0042 "B" */ + 0x1f, 0xdd, 0x70, 0x1d, 0x0, 0xe0, 0x1d, 0x1, + 0xd0, 0x1f, 0xdf, 0x50, 0x1d, 0x1, 0xc1, 0x1d, + 0x0, 0xa3, 0x1d, 0x0, 0xd2, 0x1f, 0xee, 0x70, + + /* U+0043 "C" */ + 0x5, 0xdd, 0x60, 0xe, 0x10, 0xd1, 0x1d, 0x0, + 0x20, 0x1d, 0x0, 0x0, 0x1d, 0x0, 0x0, 0x1d, + 0x0, 0x20, 0xe, 0x10, 0xd1, 0x5, 0xdd, 0x70, + + /* U+0044 "D" */ + 0x1f, 0xdd, 0x40, 0x1d, 0x1, 0xe0, 0x1d, 0x0, + 0xc1, 0x1d, 0x0, 0xc2, 0x1d, 0x0, 0xc2, 0x1d, + 0x0, 0xc1, 0x1d, 0x1, 0xe0, 0x1f, 0xdd, 0x40, + + /* U+0045 "E" */ + 0xfe, 0xee, 0x2e, 0x0, 0x0, 0xe0, 0x0, 0xf, + 0xdd, 0xb0, 0xe0, 0x0, 0xe, 0x0, 0x0, 0xe0, + 0x0, 0xf, 0xee, 0xe2, + + /* U+0046 "F" */ + 0xf, 0xee, 0xe3, 0xd, 0x0, 0x0, 0xd, 0x0, + 0x0, 0xd, 0x0, 0x0, 0xf, 0xee, 0xd0, 0xd, + 0x0, 0x0, 0xd, 0x0, 0x0, 0xd, 0x0, 0x0, + + /* U+0047 "G" */ + 0x5, 0xdd, 0x60, 0xe, 0x10, 0xd0, 0x1c, 0x0, + 0x40, 0x2c, 0x0, 0x0, 0x2c, 0x2e, 0xe2, 0x1c, + 0x0, 0xb2, 0xe, 0x10, 0xd1, 0x5, 0xdd, 0x60, + + /* U+0048 "H" */ + 0x1d, 0x0, 0xd1, 0x1d, 0x0, 0xd1, 0x1d, 0x0, + 0xd1, 0x1f, 0xee, 0xf1, 0x1d, 0x0, 0xd1, 0x1d, + 0x0, 0xd1, 0x1d, 0x0, 0xd1, 0x1d, 0x0, 0xd1, + + /* U+0049 "I" */ + 0xde, 0xed, 0x7, 0x70, 0x7, 0x70, 0x7, 0x70, + 0x7, 0x70, 0x7, 0x70, 0x7, 0x70, 0xde, 0xed, + + /* U+004A "J" */ + 0x0, 0x0, 0xe0, 0x0, 0xe, 0x0, 0x0, 0xe0, + 0x0, 0xe, 0x0, 0x0, 0xe3, 0x20, 0xe, 0x69, + 0x3, 0xc0, 0xad, 0xc3, + + /* U+004B "K" */ + 0x1d, 0x0, 0xb3, 0x1d, 0x4, 0xb0, 0x1d, 0xc, + 0x30, 0x1f, 0xdc, 0x0, 0x1d, 0xd, 0x20, 0x1d, + 0x7, 0x80, 0x1d, 0x1, 0xe0, 0x1d, 0x0, 0xa6, + + /* U+004C "L" */ + 0xb3, 0x0, 0xb, 0x30, 0x0, 0xb3, 0x0, 0xb, + 0x30, 0x0, 0xb3, 0x0, 0xb, 0x30, 0x0, 0xb3, + 0x0, 0xb, 0xee, 0xe7, + + /* U+004D "M" */ + 0x4f, 0x23, 0xf4, 0x4c, 0x77, 0xb4, 0x49, 0xaa, + 0x94, 0x49, 0xa9, 0x94, 0x49, 0x32, 0x94, 0x49, + 0x0, 0x94, 0x49, 0x0, 0x94, 0x49, 0x0, 0x94, + + /* U+004E "N" */ + 0x1f, 0x40, 0xc1, 0x1e, 0x90, 0xc1, 0x1b, 0xc0, + 0xc1, 0x1c, 0x83, 0xc1, 0x1c, 0x38, 0xc1, 0x1c, + 0xc, 0xb1, 0x1c, 0x9, 0xe1, 0x1c, 0x4, 0xf1, + + /* U+004F "O" */ + 0x5, 0xdd, 0x50, 0xe, 0x11, 0xe0, 0x1c, 0x0, + 0xc1, 0x2c, 0x0, 0xc2, 0x2c, 0x0, 0xc2, 0x1c, + 0x0, 0xc1, 0xe, 0x11, 0xe0, 0x5, 0xdd, 0x50, + + /* U+0050 "P" */ + 0x1f, 0xdd, 0x90, 0x1d, 0x0, 0xb4, 0x1d, 0x0, + 0x77, 0x1d, 0x0, 0xc4, 0x1f, 0xed, 0x80, 0x1d, + 0x0, 0x0, 0x1d, 0x0, 0x0, 0x1d, 0x0, 0x0, + + /* U+0051 "Q" */ + 0x6, 0xdd, 0x60, 0x1d, 0x1, 0xd1, 0x3b, 0x0, + 0xb3, 0x3b, 0x0, 0xb3, 0x3b, 0x0, 0xb3, 0x3b, + 0x0, 0xb3, 0x1d, 0x0, 0xe1, 0x6, 0xdf, 0x70, + 0x0, 0x8, 0x70, 0x0, 0x1, 0xe1, + + /* U+0052 "R" */ + 0x1f, 0xde, 0x70, 0x1d, 0x0, 0xd2, 0x1d, 0x0, + 0x95, 0x1d, 0x0, 0xd2, 0x1f, 0xdf, 0x70, 0x1d, + 0xb, 0x40, 0x1d, 0x3, 0xb0, 0x1d, 0x0, 0xc3, + + /* U+0053 "S" */ + 0x5, 0xdd, 0x50, 0xd, 0x1, 0xe0, 0xe, 0x0, + 0x0, 0x8, 0xd8, 0x10, 0x0, 0x28, 0xd0, 0x2, + 0x0, 0xa3, 0x2d, 0x0, 0xc2, 0x7, 0xdd, 0x70, + + /* U+0054 "T" */ + 0x6e, 0xee, 0xe6, 0x0, 0x77, 0x0, 0x0, 0x77, + 0x0, 0x0, 0x77, 0x0, 0x0, 0x77, 0x0, 0x0, + 0x77, 0x0, 0x0, 0x77, 0x0, 0x0, 0x77, 0x0, + + /* U+0055 "U" */ + 0x1c, 0x0, 0xc1, 0x1c, 0x0, 0xc1, 0x1c, 0x0, + 0xc1, 0x1c, 0x0, 0xc1, 0x1c, 0x0, 0xc1, 0x1c, + 0x0, 0xc1, 0xe, 0x11, 0xe0, 0x5, 0xdd, 0x50, + + /* U+0056 "V" */ + 0x68, 0x0, 0x86, 0x2c, 0x0, 0xc2, 0xe, 0x0, + 0xd0, 0xa, 0x33, 0xa0, 0x7, 0x76, 0x60, 0x3, + 0xaa, 0x30, 0x0, 0xdc, 0x0, 0x0, 0xbb, 0x0, + + /* U+0057 "W" */ + 0xb1, 0x88, 0xb, 0xa2, 0x99, 0x2a, 0x84, 0x99, + 0x38, 0x65, 0x99, 0x56, 0x57, 0x99, 0x74, 0x3b, + 0x77, 0xa2, 0x1e, 0x66, 0xd1, 0xf, 0x44, 0xf0, + + /* U+0058 "X" */ + 0x3c, 0x0, 0xb3, 0xb, 0x43, 0xb0, 0x3, 0xbb, + 0x30, 0x0, 0xbb, 0x0, 0x0, 0xcc, 0x0, 0x4, + 0xaa, 0x50, 0xc, 0x22, 0xd0, 0x5a, 0x0, 0xa5, + + /* U+0059 "Y" */ + 0x78, 0x0, 0x86, 0xd, 0x0, 0xd0, 0x8, 0x65, + 0x80, 0x2, 0xcc, 0x20, 0x0, 0xaa, 0x0, 0x0, + 0x77, 0x0, 0x0, 0x77, 0x0, 0x0, 0x77, 0x0, + + /* U+005A "Z" */ + 0x1e, 0xee, 0xf0, 0x0, 0x3, 0xc0, 0x0, 0xb, + 0x30, 0x0, 0x4b, 0x0, 0x0, 0xc2, 0x0, 0x5, + 0xa0, 0x0, 0xd, 0x10, 0x0, 0x2f, 0xee, 0xe2, + + /* U+005B "[" */ + 0xed, 0x6e, 0x0, 0xe0, 0xe, 0x0, 0xe0, 0xe, + 0x0, 0xe0, 0xe, 0x0, 0xe0, 0xe, 0xd6, + + /* U+005C "\\" */ + 0x1d, 0x0, 0x0, 0xb, 0x30, 0x0, 0x5, 0x90, + 0x0, 0x0, 0xe0, 0x0, 0x0, 0xa4, 0x0, 0x0, + 0x4a, 0x0, 0x0, 0xe, 0x0, 0x0, 0x9, 0x50, + 0x0, 0x3, 0xb0, 0x0, 0x0, 0xd1, + + /* U+005D "]" */ + 0x6d, 0xe0, 0xe, 0x0, 0xe0, 0xe, 0x0, 0xe0, + 0xe, 0x0, 0xe0, 0xe, 0x0, 0xe6, 0xde, + + /* U+005E "^" */ + 0x0, 0x9a, 0x0, 0x1, 0xaa, 0x10, 0x8, 0x44, + 0x80, 0xc, 0x0, 0xc0, + + /* U+005F "_" */ + 0x5d, 0xdd, 0xd5, + + /* U+0060 "`" */ + 0x16, 0x0, 0x95, + + /* U+0061 "a" */ + 0x7, 0xdd, 0x60, 0x6, 0x0, 0xd0, 0x8, 0xcc, + 0xf1, 0x3b, 0x0, 0xd1, 0x4b, 0x1, 0xf1, 0xa, + 0xda, 0xd1, + + /* U+0062 "b" */ + 0x1d, 0x0, 0x0, 0x1c, 0x0, 0x0, 0x1d, 0xad, + 0x70, 0x1e, 0x10, 0xe0, 0x1d, 0x0, 0xc1, 0x1d, + 0x0, 0xc1, 0x1e, 0x10, 0xe0, 0x1d, 0xae, 0x70, + + /* U+0063 "c" */ + 0x5, 0xdd, 0x70, 0xe, 0x10, 0xd2, 0x1c, 0x0, + 0x0, 0x1c, 0x0, 0x0, 0xe, 0x10, 0xd1, 0x5, + 0xdd, 0x70, + + /* U+0064 "d" */ + 0x0, 0x0, 0xd1, 0x0, 0x0, 0xd1, 0x7, 0xda, + 0xd1, 0xe, 0x1, 0xe1, 0x1c, 0x0, 0xd1, 0x1c, + 0x0, 0xd1, 0xe, 0x1, 0xe1, 0x7, 0xea, 0xd1, + + /* U+0065 "e" */ + 0x5, 0xcc, 0x60, 0xc, 0x0, 0xd1, 0x2e, 0xcc, + 0xd2, 0x2b, 0x0, 0x0, 0xe, 0x10, 0xa0, 0x5, + 0xde, 0x60, + + /* U+0066 "f" */ + 0x0, 0x6e, 0xe4, 0x0, 0xc1, 0x0, 0x0, 0xd0, + 0x0, 0x6e, 0xfe, 0xe4, 0x0, 0xd0, 0x0, 0x0, + 0xd0, 0x0, 0x0, 0xd0, 0x0, 0x0, 0xd0, 0x0, + + /* U+0067 "g" */ + 0x7, 0xda, 0xd1, 0xe, 0x1, 0xf1, 0x1c, 0x0, + 0xd1, 0x1c, 0x0, 0xd1, 0xe, 0x11, 0xf1, 0x5, + 0xda, 0xd1, 0x0, 0x0, 0xe0, 0x5, 0xee, 0x60, + + /* U+0068 "h" */ + 0x1d, 0x0, 0x0, 0x1d, 0x0, 0x0, 0x1d, 0xad, + 0x70, 0x1e, 0x10, 0xe0, 0x1d, 0x0, 0xc1, 0x1d, + 0x0, 0xc1, 0x1d, 0x0, 0xc1, 0x1d, 0x0, 0xc1, + + /* U+0069 "i" */ + 0x0, 0x24, 0x0, 0x0, 0x59, 0x0, 0x0, 0x0, + 0x0, 0xd, 0xeb, 0x0, 0x0, 0x3b, 0x0, 0x0, + 0x3b, 0x0, 0x0, 0x3b, 0x0, 0x0, 0x3b, 0x0, + 0x2e, 0xef, 0xe7, + + /* U+006A "j" */ + 0x0, 0x5, 0x20, 0x0, 0xa5, 0x0, 0x0, 0x2, + 0xee, 0xf5, 0x0, 0x8, 0x50, 0x0, 0x85, 0x0, + 0x8, 0x50, 0x0, 0x85, 0x0, 0x8, 0x50, 0x0, + 0xc2, 0x1e, 0xe8, 0x0, + + /* U+006B "k" */ + 0xe, 0x0, 0x0, 0xe, 0x0, 0x0, 0xe, 0x0, + 0xd2, 0xe, 0xa, 0x60, 0xf, 0xdd, 0x0, 0xe, + 0xc, 0x40, 0xe, 0x3, 0xc0, 0xe, 0x0, 0xb5, + + /* U+006C "l" */ + 0x9e, 0xf1, 0x0, 0x0, 0xc1, 0x0, 0x0, 0xc1, + 0x0, 0x0, 0xc1, 0x0, 0x0, 0xc1, 0x0, 0x0, + 0xc1, 0x0, 0x0, 0xc2, 0x0, 0x0, 0x5e, 0xe7, + + /* U+006D "m" */ + 0x6a, 0xc8, 0xc2, 0x67, 0x66, 0x76, 0x67, 0x66, + 0x76, 0x67, 0x66, 0x76, 0x67, 0x66, 0x76, 0x67, + 0x66, 0x76, + + /* U+006E "n" */ + 0x1d, 0xac, 0x70, 0x1e, 0x0, 0xe0, 0x1d, 0x0, + 0xc1, 0x1d, 0x0, 0xc1, 0x1d, 0x0, 0xc1, 0x1d, + 0x0, 0xc1, + + /* U+006F "o" */ + 0x6, 0xdd, 0x60, 0xd, 0x0, 0xd0, 0x2b, 0x0, + 0xb2, 0x2b, 0x0, 0xb2, 0xd, 0x0, 0xd0, 0x6, + 0xdd, 0x50, + + /* U+0070 "p" */ + 0x1d, 0xac, 0x70, 0x1e, 0x0, 0xd0, 0x1d, 0x0, + 0xc1, 0x1d, 0x0, 0xc1, 0x1e, 0x10, 0xe0, 0x1d, + 0xae, 0x70, 0x1c, 0x0, 0x0, 0x1d, 0x0, 0x0, + + /* U+0071 "q" */ + 0x7, 0xda, 0xd1, 0xe, 0x1, 0xe1, 0x1c, 0x0, + 0xd1, 0x1c, 0x0, 0xd1, 0xd, 0x1, 0xe1, 0x7, + 0xea, 0xd1, 0x0, 0x0, 0xd1, 0x0, 0x0, 0xd1, + + /* U+0072 "r" */ + 0xe8, 0xca, 0xe, 0x20, 0xb3, 0xe0, 0x5, 0x2e, + 0x0, 0x0, 0xe0, 0x0, 0xe, 0x0, 0x0, + + /* U+0073 "s" */ + 0x8, 0xdd, 0x80, 0xe, 0x0, 0x70, 0xd, 0xa7, + 0x20, 0x0, 0x46, 0xe0, 0x19, 0x0, 0xd1, 0x9, + 0xdd, 0x90, + + /* U+0074 "t" */ + 0x0, 0x70, 0x0, 0x0, 0xe0, 0x0, 0x7e, 0xfe, + 0xe2, 0x0, 0xe0, 0x0, 0x0, 0xe0, 0x0, 0x0, + 0xe0, 0x0, 0x0, 0xe0, 0x0, 0x0, 0x8e, 0xe2, + + /* U+0075 "u" */ + 0x1c, 0x0, 0xc1, 0x1c, 0x0, 0xc1, 0x1c, 0x0, + 0xc1, 0x1c, 0x0, 0xc1, 0xe, 0x11, 0xe0, 0x5, + 0xdd, 0x50, + + /* U+0076 "v" */ + 0x4a, 0x0, 0xa4, 0xe, 0x0, 0xe0, 0xa, 0x43, + 0xa0, 0x5, 0x88, 0x50, 0x1, 0xdc, 0x10, 0x0, + 0xbb, 0x0, + + /* U+0077 "w" */ + 0x92, 0x88, 0x19, 0x74, 0x99, 0x47, 0x56, 0x9a, + 0x64, 0x29, 0x99, 0x82, 0xd, 0x77, 0xc0, 0xd, + 0x45, 0xd0, + + /* U+0078 "x" */ + 0x1d, 0x0, 0xd1, 0x6, 0x88, 0x70, 0x0, 0xcc, + 0x0, 0x0, 0xdd, 0x0, 0x8, 0x77, 0x80, 0x3d, + 0x0, 0xd3, + + /* U+0079 "y" */ + 0x4a, 0x0, 0xa4, 0xd, 0x0, 0xd0, 0x8, 0x64, + 0x90, 0x3, 0xba, 0x40, 0x0, 0xcd, 0x0, 0x0, + 0x89, 0x0, 0x0, 0xb3, 0x0, 0x1, 0xd0, 0x0, + + /* U+007A "z" */ + 0xe, 0xee, 0xf0, 0x0, 0x7, 0x90, 0x0, 0x3c, + 0x0, 0x1, 0xd2, 0x0, 0xb, 0x50, 0x0, 0x1f, + 0xee, 0xe1, + + /* U+007B "{" */ + 0x0, 0xa, 0xd0, 0x0, 0x3b, 0x0, 0x0, 0x2b, + 0x0, 0x0, 0x2b, 0x0, 0x3d, 0xe3, 0x0, 0x0, + 0x3b, 0x0, 0x0, 0x2c, 0x0, 0x0, 0x3b, 0x0, + 0x0, 0x3c, 0x0, 0x0, 0x9, 0xd0, + + /* U+007C "|" */ + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, + + /* U+007D "}" */ + 0xd, 0x90, 0x0, 0x0, 0xb3, 0x0, 0x0, 0xc1, + 0x0, 0x0, 0xd0, 0x0, 0x0, 0x6f, 0xd3, 0x0, + 0xd1, 0x0, 0x0, 0xd0, 0x0, 0x0, 0xb2, 0x0, + 0x0, 0xc3, 0x0, 0xd, 0x80, 0x0, + + /* U+007E "~" */ + 0x1b, 0xc2, 0x84, 0x48, 0x2c, 0xc1 +}; + + +/*--------------------- + * GLYPH DESCRIPTION + *--------------------*/ + +static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = { + {.bitmap_index = 0, .adv_w = 0, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0} /* id = 0 reserved */, + {.bitmap_index = 0, .adv_w = 96, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 0, .adv_w = 96, .box_w = 2, .box_h = 8, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 8, .adv_w = 96, .box_w = 4, .box_h = 4, .ofs_x = 1, .ofs_y = 4}, + {.bitmap_index = 16, .adv_w = 96, .box_w = 6, .box_h = 8, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 40, .adv_w = 96, .box_w = 6, .box_h = 11, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 73, .adv_w = 96, .box_w = 6, .box_h = 8, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 97, .adv_w = 96, .box_w = 7, .box_h = 8, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 125, .adv_w = 96, .box_w = 2, .box_h = 4, .ofs_x = 2, .ofs_y = 4}, + {.bitmap_index = 129, .adv_w = 96, .box_w = 4, .box_h = 12, .ofs_x = 1, .ofs_y = -2}, + {.bitmap_index = 153, .adv_w = 96, .box_w = 4, .box_h = 12, .ofs_x = 1, .ofs_y = -2}, + {.bitmap_index = 177, .adv_w = 96, .box_w = 6, .box_h = 6, .ofs_x = 0, .ofs_y = 1}, + {.bitmap_index = 195, .adv_w = 96, .box_w = 6, .box_h = 6, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 213, .adv_w = 96, .box_w = 2, .box_h = 4, .ofs_x = 2, .ofs_y = -2}, + {.bitmap_index = 217, .adv_w = 96, .box_w = 4, .box_h = 1, .ofs_x = 1, .ofs_y = 3}, + {.bitmap_index = 219, .adv_w = 96, .box_w = 2, .box_h = 2, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 221, .adv_w = 96, .box_w = 6, .box_h = 10, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 251, .adv_w = 96, .box_w = 6, .box_h = 8, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 275, .adv_w = 96, .box_w = 6, .box_h = 8, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 299, .adv_w = 96, .box_w = 6, .box_h = 8, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 323, .adv_w = 96, .box_w = 6, .box_h = 8, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 347, .adv_w = 96, .box_w = 5, .box_h = 8, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 367, .adv_w = 96, .box_w = 6, .box_h = 8, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 391, .adv_w = 96, .box_w = 6, .box_h = 8, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 415, .adv_w = 96, .box_w = 6, .box_h = 8, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 439, .adv_w = 96, .box_w = 6, .box_h = 8, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 463, .adv_w = 96, .box_w = 6, .box_h = 8, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 487, .adv_w = 96, .box_w = 2, .box_h = 6, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 493, .adv_w = 96, .box_w = 2, .box_h = 8, .ofs_x = 2, .ofs_y = -2}, + {.bitmap_index = 501, .adv_w = 96, .box_w = 6, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 522, .adv_w = 96, .box_w = 6, .box_h = 4, .ofs_x = 0, .ofs_y = 2}, + {.bitmap_index = 534, .adv_w = 96, .box_w = 6, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 555, .adv_w = 96, .box_w = 4, .box_h = 8, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 571, .adv_w = 96, .box_w = 6, .box_h = 10, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 601, .adv_w = 96, .box_w = 6, .box_h = 8, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 625, .adv_w = 96, .box_w = 6, .box_h = 8, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 649, .adv_w = 96, .box_w = 6, .box_h = 8, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 673, .adv_w = 96, .box_w = 6, .box_h = 8, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 697, .adv_w = 96, .box_w = 5, .box_h = 8, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 717, .adv_w = 96, .box_w = 6, .box_h = 8, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 741, .adv_w = 96, .box_w = 6, .box_h = 8, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 765, .adv_w = 96, .box_w = 6, .box_h = 8, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 789, .adv_w = 96, .box_w = 4, .box_h = 8, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 805, .adv_w = 96, .box_w = 5, .box_h = 8, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 825, .adv_w = 96, .box_w = 6, .box_h = 8, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 849, .adv_w = 96, .box_w = 5, .box_h = 8, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 869, .adv_w = 96, .box_w = 6, .box_h = 8, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 893, .adv_w = 96, .box_w = 6, .box_h = 8, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 917, .adv_w = 96, .box_w = 6, .box_h = 8, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 941, .adv_w = 96, .box_w = 6, .box_h = 8, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 965, .adv_w = 96, .box_w = 6, .box_h = 10, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 995, .adv_w = 96, .box_w = 6, .box_h = 8, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1019, .adv_w = 96, .box_w = 6, .box_h = 8, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1043, .adv_w = 96, .box_w = 6, .box_h = 8, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1067, .adv_w = 96, .box_w = 6, .box_h = 8, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1091, .adv_w = 96, .box_w = 6, .box_h = 8, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1115, .adv_w = 96, .box_w = 6, .box_h = 8, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1139, .adv_w = 96, .box_w = 6, .box_h = 8, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1163, .adv_w = 96, .box_w = 6, .box_h = 8, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1187, .adv_w = 96, .box_w = 6, .box_h = 8, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1211, .adv_w = 96, .box_w = 3, .box_h = 10, .ofs_x = 2, .ofs_y = -1}, + {.bitmap_index = 1226, .adv_w = 96, .box_w = 6, .box_h = 10, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 1256, .adv_w = 96, .box_w = 3, .box_h = 10, .ofs_x = 1, .ofs_y = -1}, + {.bitmap_index = 1271, .adv_w = 96, .box_w = 6, .box_h = 4, .ofs_x = 0, .ofs_y = 4}, + {.bitmap_index = 1283, .adv_w = 96, .box_w = 6, .box_h = 1, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 1286, .adv_w = 96, .box_w = 3, .box_h = 2, .ofs_x = 1, .ofs_y = 7}, + {.bitmap_index = 1289, .adv_w = 96, .box_w = 6, .box_h = 6, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1307, .adv_w = 96, .box_w = 6, .box_h = 8, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1331, .adv_w = 96, .box_w = 6, .box_h = 6, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1349, .adv_w = 96, .box_w = 6, .box_h = 8, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1373, .adv_w = 96, .box_w = 6, .box_h = 6, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1391, .adv_w = 96, .box_w = 6, .box_h = 8, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1415, .adv_w = 96, .box_w = 6, .box_h = 8, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 1439, .adv_w = 96, .box_w = 6, .box_h = 8, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1463, .adv_w = 96, .box_w = 6, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1490, .adv_w = 96, .box_w = 5, .box_h = 11, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 1518, .adv_w = 96, .box_w = 6, .box_h = 8, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1542, .adv_w = 96, .box_w = 6, .box_h = 8, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1566, .adv_w = 96, .box_w = 6, .box_h = 6, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1584, .adv_w = 96, .box_w = 6, .box_h = 6, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1602, .adv_w = 96, .box_w = 6, .box_h = 6, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1620, .adv_w = 96, .box_w = 6, .box_h = 8, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 1644, .adv_w = 96, .box_w = 6, .box_h = 8, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 1668, .adv_w = 96, .box_w = 5, .box_h = 6, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1683, .adv_w = 96, .box_w = 6, .box_h = 6, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1701, .adv_w = 96, .box_w = 6, .box_h = 8, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1725, .adv_w = 96, .box_w = 6, .box_h = 6, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1743, .adv_w = 96, .box_w = 6, .box_h = 6, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1761, .adv_w = 96, .box_w = 6, .box_h = 6, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1779, .adv_w = 96, .box_w = 6, .box_h = 6, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1797, .adv_w = 96, .box_w = 6, .box_h = 8, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 1821, .adv_w = 96, .box_w = 6, .box_h = 6, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1839, .adv_w = 96, .box_w = 6, .box_h = 10, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 1869, .adv_w = 96, .box_w = 2, .box_h = 10, .ofs_x = 2, .ofs_y = -1}, + {.bitmap_index = 1879, .adv_w = 96, .box_w = 6, .box_h = 10, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 1909, .adv_w = 96, .box_w = 6, .box_h = 2, .ofs_x = 0, .ofs_y = 3} +}; + +/*--------------------- + * CHARACTER MAPPING + *--------------------*/ + + + +/*Collect the unicode lists and glyph_id offsets*/ +static const lv_font_fmt_txt_cmap_t cmaps[] = +{ + { + .range_start = 32, .range_length = 95, .glyph_id_start = 1, + .unicode_list = NULL, .glyph_id_ofs_list = NULL, .list_length = 0, .type = LV_FONT_FMT_TXT_CMAP_FORMAT0_TINY + } +}; + + + +/*-------------------- + * ALL CUSTOM DATA + *--------------------*/ + +#if LVGL_VERSION_MAJOR == 8 +/*Store all the custom data of the font*/ +static lv_font_fmt_txt_glyph_cache_t cache; +#endif + +#if LVGL_VERSION_MAJOR >= 8 +static const lv_font_fmt_txt_dsc_t font_dsc = { +#else +static lv_font_fmt_txt_dsc_t font_dsc = { +#endif + .glyph_bitmap = glyph_bitmap, + .glyph_dsc = glyph_dsc, + .cmaps = cmaps, + .kern_dsc = NULL, + .kern_scale = 0, + .cmap_num = 1, + .bpp = 4, + .kern_classes = 0, + .bitmap_format = 0, +#if LVGL_VERSION_MAJOR == 8 + .cache = &cache +#endif +}; + + +/*----------------- + * PUBLIC FONT + *----------------*/ + +/*Initialize a public general font descriptor*/ +#if LVGL_VERSION_MAJOR >= 8 +const lv_font_t JetBrainsMono10 = { +#else +lv_font_t JetBrainsMono10 = { +#endif + .get_glyph_dsc = lv_font_get_glyph_dsc_fmt_txt, /*Function pointer to get glyph's data*/ + .get_glyph_bitmap = lv_font_get_bitmap_fmt_txt, /*Function pointer to get glyph's bitmap*/ + .line_height = 12, /*The maximum line height required by the font*/ + .base_line = 2, /*Baseline measured from the bottom of the line*/ +#if !(LVGL_VERSION_MAJOR == 6 && LVGL_VERSION_MINOR == 0) + .subpx = LV_FONT_SUBPX_NONE, +#endif +#if LV_VERSION_CHECK(7, 4, 0) || LVGL_VERSION_MAJOR >= 8 + .underline_position = -2, + .underline_thickness = 1, +#endif + .dsc = &font_dsc, /*The custom font data. Will be accessed by `get_glyph_bitmap/dsc` */ + .fallback = NULL, + .user_data = NULL +}; + + + +#endif /*#if JETBRAINSMONO10*/ + diff --git a/device/src/keyboard/oled/fonts/jet_brains_mono_12.c b/device/src/keyboard/oled/fonts/jet_brains_mono_12.c new file mode 100644 index 000000000..6dff149a4 --- /dev/null +++ b/device/src/keyboard/oled/fonts/jet_brains_mono_12.c @@ -0,0 +1,736 @@ +/******************************************************************************* + * Size: 12 px + * Bpp: 4 + * Opts: + ******************************************************************************/ + +#ifdef LV_LVGL_H_INCLUDE_SIMPLE +#include "lvgl.h" +#else +#include "lvgl/lvgl.h" +#endif + +#ifndef JETBRAINSMONO12 +#define JETBRAINSMONO12 1 +#endif + +#if JETBRAINSMONO12 + +/*----------------- + * BITMAPS + *----------------*/ + +/*Store the image of the glyphs*/ +static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { + /* U+0020 " " */ + + /* U+0021 "!" */ + 0xf, 0x30, 0xf3, 0xf, 0x20, 0xf2, 0xe, 0x20, + 0xe1, 0x6, 0x0, 0x72, 0x2f, 0x50, + + /* U+0022 "\"" */ + 0x4e, 0xb, 0x73, 0xe0, 0xb7, 0x3e, 0xa, 0x62, + 0xa0, 0x74, + + /* U+0023 "#" */ + 0x0, 0x85, 0xc, 0x10, 0xb, 0x10, 0xd0, 0x2d, + 0xfd, 0xdf, 0xa0, 0x1b, 0x5, 0x70, 0x4, 0x80, + 0x84, 0x7, 0xee, 0xdf, 0xd4, 0x9, 0x30, 0xd0, + 0x0, 0xc0, 0xc, 0x0, 0xd, 0x2, 0xa0, 0x0, + + /* U+0024 "$" */ + 0x0, 0x5, 0x0, 0x0, 0x0, 0xb0, 0x0, 0x1, + 0x9f, 0xc3, 0x0, 0xaa, 0xc5, 0xe0, 0xd, 0x3b, + 0x7, 0x10, 0xaa, 0xb0, 0x0, 0x2, 0xdf, 0x91, + 0x0, 0x0, 0xbb, 0xd0, 0x0, 0xb, 0xd, 0x40, + 0xf1, 0xb0, 0xd3, 0x8, 0xde, 0xcb, 0x0, 0x3, + 0xd4, 0x0, 0x0, 0xb, 0x0, 0x0, + + /* U+0025 "%" */ + 0x6e, 0xd2, 0x3, 0xa0, 0xc2, 0x77, 0xc, 0x10, + 0xc2, 0x77, 0x85, 0x0, 0x5d, 0xc5, 0xb0, 0x0, + 0x0, 0xc, 0x10, 0x0, 0x0, 0x86, 0xbd, 0x70, + 0x3, 0xb4, 0xa0, 0xe0, 0xc, 0x14, 0xa0, 0xe0, + 0x76, 0x0, 0xcd, 0x80, + + /* U+0026 "&" */ + 0x1, 0xcf, 0xa0, 0x0, 0x9, 0x80, 0xb7, 0x0, + 0x9, 0x80, 0x33, 0x0, 0x2, 0xe3, 0x0, 0x0, + 0x1b, 0xed, 0x0, 0xa1, 0x99, 0x9, 0xa9, 0x80, + 0xb5, 0x0, 0xcd, 0x0, 0x9a, 0x15, 0xdd, 0x40, + 0x1b, 0xfb, 0x13, 0xe1, + + /* U+0027 "'" */ + 0xf, 0x30, 0xf2, 0xf, 0x20, 0xb1, + + /* U+0028 "(" */ + 0x0, 0x4, 0x3, 0xe9, 0x1e, 0x50, 0x7b, 0x0, + 0xa6, 0x0, 0xc4, 0x0, 0xc4, 0x0, 0xc4, 0x0, + 0xa6, 0x0, 0x7b, 0x0, 0x1e, 0x50, 0x3, 0xe9, + 0x0, 0x4, + + /* U+0029 ")" */ + 0x31, 0x0, 0x6e, 0x50, 0x3, 0xf3, 0x0, 0x8a, + 0x0, 0x2d, 0x0, 0x1f, 0x0, 0x1f, 0x0, 0x1f, + 0x0, 0x3d, 0x0, 0x8a, 0x3, 0xf3, 0x7e, 0x50, + 0x31, 0x0, + + /* U+002A "*" */ + 0x0, 0xe, 0x10, 0x1, 0x0, 0xe1, 0x1, 0x6f, + 0x8e, 0x7e, 0x90, 0x28, 0xfa, 0x30, 0x0, 0xc8, + 0xe1, 0x0, 0x7c, 0x8, 0xa0, 0x1, 0x10, 0x2, + 0x0, + + /* U+002B "+" */ + 0x0, 0xe, 0x20, 0x0, 0x0, 0xe2, 0x0, 0x3f, + 0xff, 0xff, 0x60, 0x0, 0xe2, 0x0, 0x0, 0xe, + 0x20, 0x0, 0x0, 0xc1, 0x0, + + /* U+002C "," */ + 0xb, 0x50, 0xf2, 0x3f, 0x6, 0xb0, + + /* U+002D "-" */ + 0x5f, 0xff, 0x80, + + /* U+002E "." */ + 0x0, 0x3, 0xf6, 0x3f, 0x60, + + /* U+002F "/" */ + 0x0, 0x0, 0xf, 0x10, 0x0, 0x6, 0xc0, 0x0, + 0x0, 0xb6, 0x0, 0x0, 0x1f, 0x10, 0x0, 0x7, + 0xb0, 0x0, 0x0, 0xc5, 0x0, 0x0, 0x2f, 0x0, + 0x0, 0x8, 0xa0, 0x0, 0x0, 0xd4, 0x0, 0x0, + 0x3e, 0x0, 0x0, 0x9, 0x90, 0x0, 0x0, 0xe3, + 0x0, 0x0, + + /* U+0030 "0" */ + 0x2, 0xcf, 0xd4, 0x0, 0xc7, 0x4, 0xe0, 0xf, + 0x0, 0xd, 0x30, 0xf0, 0x0, 0xc3, 0xf, 0xf, + 0x3c, 0x30, 0xf0, 0x30, 0xc3, 0xf, 0x0, 0xd, + 0x30, 0xc7, 0x4, 0xf0, 0x2, 0xcf, 0xd4, 0x0, + + /* U+0031 "1" */ + 0x9, 0xf8, 0x0, 0xba, 0x98, 0x0, 0x60, 0x88, + 0x0, 0x0, 0x88, 0x0, 0x0, 0x88, 0x0, 0x0, + 0x88, 0x0, 0x0, 0x88, 0x0, 0x0, 0x88, 0x0, + 0xef, 0xff, 0xf7, + + /* U+0032 "2" */ + 0x2, 0xcf, 0xd4, 0x0, 0xc7, 0x5, 0xe0, 0x9, + 0x0, 0xe, 0x20, 0x0, 0x2, 0xf0, 0x0, 0x0, + 0xc7, 0x0, 0x0, 0xaa, 0x0, 0x0, 0x9b, 0x0, + 0x0, 0x8c, 0x10, 0x0, 0xf, 0xff, 0xff, 0x50, + + /* U+0033 "3" */ + 0xe, 0xff, 0xfe, 0x0, 0x0, 0xb, 0x70, 0x0, + 0xb, 0x80, 0x0, 0x6, 0xf8, 0x0, 0x0, 0x14, + 0xac, 0x0, 0x0, 0x0, 0xf1, 0x18, 0x0, 0xf, + 0x10, 0xe6, 0x6, 0xe0, 0x3, 0xdf, 0xc3, 0x0, + + /* U+0034 "4" */ + 0x0, 0x4, 0xe0, 0x0, 0xd, 0x50, 0x0, 0x7c, + 0x0, 0x1, 0xf2, 0x3, 0xa, 0x80, 0x3e, 0x2f, + 0x0, 0x3e, 0x2f, 0xee, 0xfe, 0x1, 0x11, 0x4e, + 0x0, 0x0, 0x3e, + + /* U+0035 "5" */ + 0xc, 0xff, 0xfe, 0x0, 0xc3, 0x0, 0x0, 0xc, + 0x30, 0x0, 0x0, 0xcf, 0xec, 0x30, 0x1, 0x12, + 0x7e, 0x0, 0x0, 0x0, 0xf2, 0xa, 0x0, 0xf, + 0x20, 0xd7, 0x6, 0xe0, 0x3, 0xcf, 0xd3, 0x0, + + /* U+0036 "6" */ + 0x0, 0xa, 0x70, 0x0, 0x3, 0xd0, 0x0, 0x0, + 0xc3, 0x0, 0x0, 0x5e, 0xdd, 0x40, 0xc, 0x60, + 0x4f, 0x11, 0xe0, 0x0, 0xb6, 0x3e, 0x0, 0xb, + 0x50, 0xe7, 0x5, 0xf1, 0x3, 0xcf, 0xd4, 0x0, + + /* U+0037 "7" */ + 0xf, 0xff, 0xff, 0x80, 0xf1, 0x0, 0xc5, 0x7, + 0x0, 0x2f, 0x0, 0x0, 0x9, 0x90, 0x0, 0x0, + 0xe3, 0x0, 0x0, 0x5d, 0x0, 0x0, 0xb, 0x60, + 0x0, 0x2, 0xf1, 0x0, 0x0, 0x8a, 0x0, 0x0, + + /* U+0038 "8" */ + 0x1, 0xcf, 0xd4, 0x0, 0xc8, 0x5, 0xe0, 0xe, + 0x20, 0xf, 0x20, 0xa8, 0x5, 0xd0, 0x2, 0xdf, + 0xf4, 0x0, 0xd6, 0x4, 0xe2, 0x2e, 0x0, 0xb, + 0x50, 0xf6, 0x4, 0xf2, 0x3, 0xcf, 0xd6, 0x0, + + /* U+0039 "9" */ + 0x2, 0xcf, 0xd4, 0x0, 0xd7, 0x5, 0xf2, 0x2e, + 0x0, 0xb, 0x62, 0xe0, 0x0, 0xb5, 0xe, 0x60, + 0x4e, 0x0, 0x3c, 0xee, 0x80, 0x0, 0x2, 0xe0, + 0x0, 0x0, 0xb6, 0x0, 0x0, 0x5d, 0x0, 0x0, + + /* U+003A ":" */ + 0x3e, 0x62, 0xc4, 0x0, 0x0, 0x0, 0x0, 0x2, + 0xc4, 0x3e, 0x60, + + /* U+003B ";" */ + 0x3f, 0x72, 0xd5, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xc4, 0x1f, 0x24, 0xe0, 0x7b, 0x0, + + /* U+003C "<" */ + 0x0, 0x0, 0x11, 0x0, 0x18, 0xe2, 0x18, 0xe8, + 0x10, 0xe8, 0x10, 0x0, 0xbd, 0x40, 0x0, 0x4, + 0xcc, 0x40, 0x0, 0x5, 0xd2, 0x0, 0x0, 0x0, + + /* U+003D "=" */ + 0xff, 0xff, 0xf3, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xff, 0xff, 0xf3, + + /* U+003E ">" */ + 0x20, 0x0, 0x0, 0xea, 0x20, 0x0, 0x7, 0xe9, + 0x20, 0x0, 0x7, 0xe2, 0x0, 0x2a, 0xd1, 0x2a, + 0xd6, 0x0, 0xe6, 0x0, 0x0, 0x0, 0x0, 0x0, + + /* U+003F "?" */ + 0x7f, 0xfa, 0x0, 0x12, 0xb9, 0x0, 0x5, 0xc0, + 0x0, 0xa9, 0x8, 0xfb, 0x0, 0x88, 0x0, 0x1, + 0x10, 0x0, 0x45, 0x0, 0xb, 0xb0, 0x0, + + /* U+0040 "@" */ + 0x2, 0xbe, 0xd7, 0x0, 0xd4, 0x0, 0xb6, 0x4a, + 0x0, 0x4, 0xa7, 0x80, 0x8c, 0xab, 0x78, 0x1f, + 0x5, 0xb7, 0x82, 0xd0, 0x3b, 0x78, 0xf, 0x16, + 0x97, 0x80, 0x7d, 0xc2, 0x5a, 0x0, 0x0, 0x0, + 0xd6, 0x0, 0x0, 0x2, 0xbf, 0xf3, 0x0, + + /* U+0041 "A" */ + 0x0, 0x4f, 0x70, 0x0, 0x8, 0xcb, 0x0, 0x0, + 0xc6, 0xf0, 0x0, 0xf, 0x1d, 0x30, 0x4, 0xd0, + 0xa7, 0x0, 0x89, 0x6, 0xb0, 0xc, 0xff, 0xff, + 0x0, 0xf2, 0x0, 0xe3, 0x4d, 0x0, 0xa, 0x70, + + /* U+0042 "B" */ + 0xef, 0xfd, 0x40, 0xe2, 0x5, 0xe0, 0xe2, 0x0, + 0xf1, 0xe2, 0x5, 0xd0, 0xef, 0xfe, 0x30, 0xe2, + 0x3, 0xe1, 0xe2, 0x0, 0xb4, 0xe2, 0x3, 0xf2, + 0xef, 0xfe, 0x60, + + /* U+0043 "C" */ + 0x1b, 0xfd, 0x40, 0xa9, 0x4, 0xf1, 0xd3, 0x0, + 0x71, 0xe3, 0x0, 0x0, 0xe3, 0x0, 0x0, 0xe3, + 0x0, 0x0, 0xd3, 0x0, 0x71, 0xa9, 0x4, 0xf1, + 0x1b, 0xfd, 0x50, + + /* U+0044 "D" */ + 0xef, 0xfc, 0x20, 0xe3, 0x7, 0xd0, 0xe3, 0x0, + 0xf1, 0xe3, 0x0, 0xf2, 0xe3, 0x0, 0xf2, 0xe3, + 0x0, 0xf2, 0xe3, 0x0, 0xf1, 0xe3, 0x7, 0xd0, + 0xef, 0xfc, 0x20, + + /* U+0045 "E" */ + 0xcf, 0xff, 0xf3, 0xc4, 0x0, 0x0, 0xc4, 0x0, + 0x0, 0xc4, 0x0, 0x0, 0xcf, 0xff, 0xd0, 0xc4, + 0x0, 0x0, 0xc4, 0x0, 0x0, 0xc4, 0x0, 0x0, + 0xcf, 0xff, 0xf3, + + /* U+0046 "F" */ + 0xdf, 0xff, 0xf4, 0xd3, 0x0, 0x0, 0xd3, 0x0, + 0x0, 0xd3, 0x0, 0x0, 0xdf, 0xee, 0xe0, 0xd4, + 0x11, 0x10, 0xd3, 0x0, 0x0, 0xd3, 0x0, 0x0, + 0xd3, 0x0, 0x0, + + /* U+0047 "G" */ + 0x2b, 0xfd, 0x40, 0xb8, 0x4, 0xf0, 0xe2, 0x0, + 0x61, 0xf2, 0x0, 0x0, 0xf2, 0x9e, 0xe3, 0xf2, + 0x11, 0xd3, 0xe2, 0x0, 0xe2, 0xb8, 0x4, 0xe0, + 0x2b, 0xfd, 0x40, + + /* U+0048 "H" */ + 0xe3, 0x0, 0xf1, 0xe3, 0x0, 0xf1, 0xe3, 0x0, + 0xf1, 0xe3, 0x0, 0xf1, 0xee, 0xee, 0xf1, 0xe4, + 0x11, 0xf1, 0xe3, 0x0, 0xf1, 0xe3, 0x0, 0xf1, + 0xe3, 0x0, 0xf1, + + /* U+0049 "I" */ + 0xbf, 0xff, 0xf0, 0xf, 0x20, 0x0, 0xf2, 0x0, + 0xf, 0x20, 0x0, 0xf2, 0x0, 0xf, 0x20, 0x0, + 0xf2, 0x0, 0xf, 0x20, 0xbf, 0xff, 0xf0, + + /* U+004A "J" */ + 0x0, 0x0, 0x2f, 0x0, 0x0, 0x2f, 0x0, 0x0, + 0x2f, 0x0, 0x0, 0x2f, 0x0, 0x0, 0x2f, 0x0, + 0x0, 0x2f, 0x47, 0x0, 0x2e, 0x3e, 0x30, 0x9a, + 0x6, 0xef, 0xb1, + + /* U+004B "K" */ + 0xe3, 0x0, 0xd5, 0xe3, 0x4, 0xd0, 0xe3, 0xc, + 0x60, 0xe3, 0x4e, 0x0, 0xef, 0xf8, 0x0, 0xe3, + 0x4e, 0x0, 0xe3, 0xc, 0x70, 0xe3, 0x4, 0xe0, + 0xe3, 0x0, 0xc7, + + /* U+004C "L" */ + 0x7a, 0x0, 0x0, 0x7a, 0x0, 0x0, 0x7a, 0x0, + 0x0, 0x7a, 0x0, 0x0, 0x7a, 0x0, 0x0, 0x7a, + 0x0, 0x0, 0x7a, 0x0, 0x0, 0x7a, 0x0, 0x0, + 0x7f, 0xff, 0xf9, + + /* U+004D "M" */ + 0x2f, 0x90, 0x6f, 0x52, 0xdd, 0xb, 0xb5, 0x2d, + 0xa3, 0xca, 0x52, 0xe5, 0xc7, 0xb5, 0x2e, 0x1f, + 0x2b, 0x52, 0xe0, 0x0, 0xb5, 0x2e, 0x0, 0xb, + 0x52, 0xe0, 0x0, 0xb5, 0x2e, 0x0, 0xb, 0x50, + + /* U+004E "N" */ + 0xeb, 0x0, 0xe2, 0xee, 0x10, 0xe2, 0xea, 0x60, + 0xe2, 0xe5, 0xb0, 0xe2, 0xe2, 0xd1, 0xe2, 0xe2, + 0x86, 0xe2, 0xe2, 0x2c, 0xe2, 0xe2, 0xd, 0xf2, + 0xe2, 0x7, 0xf2, + + /* U+004F "O" */ + 0x2c, 0xfd, 0x30, 0xb8, 0x5, 0xe0, 0xe2, 0x0, + 0xf1, 0xf2, 0x0, 0xf2, 0xf2, 0x0, 0xf2, 0xf2, + 0x0, 0xf2, 0xe2, 0x0, 0xf1, 0xb8, 0x5, 0xe0, + 0x2c, 0xfd, 0x30, + + /* U+0050 "P" */ + 0xef, 0xfe, 0x80, 0xe3, 0x2, 0xd5, 0xe3, 0x0, + 0x88, 0xe3, 0x1, 0xd6, 0xee, 0xef, 0x90, 0xe4, + 0x10, 0x0, 0xe3, 0x0, 0x0, 0xe3, 0x0, 0x0, + 0xe3, 0x0, 0x0, + + /* U+0051 "Q" */ + 0x2, 0xcf, 0xd4, 0x0, 0xc8, 0x5, 0xe0, 0xf, + 0x10, 0xd, 0x30, 0xf0, 0x0, 0xd3, 0xf, 0x0, + 0xd, 0x30, 0xf0, 0x0, 0xd3, 0xf, 0x10, 0xd, + 0x30, 0xc8, 0x5, 0xf0, 0x2, 0xcf, 0xf4, 0x0, + 0x0, 0xd, 0x60, 0x0, 0x0, 0x3e, 0x10, + + /* U+0052 "R" */ + 0xef, 0xfe, 0x60, 0xe3, 0x3, 0xf3, 0xe3, 0x0, + 0xb6, 0xe3, 0x2, 0xe3, 0xee, 0xef, 0x80, 0xe4, + 0x3e, 0x0, 0xe3, 0xb, 0x60, 0xe3, 0x4, 0xd0, + 0xe3, 0x0, 0xd5, + + /* U+0053 "S" */ + 0x1, 0xcf, 0xd3, 0x0, 0xc8, 0x6, 0xe0, 0xe, + 0x30, 0x5, 0x0, 0x9c, 0x40, 0x0, 0x0, 0x7c, + 0xe6, 0x0, 0x0, 0x3, 0xe2, 0x8, 0x0, 0xc, + 0x40, 0xe6, 0x4, 0xf2, 0x3, 0xcf, 0xd5, 0x0, + + /* U+0054 "T" */ + 0x5f, 0xff, 0xff, 0x80, 0x0, 0xf2, 0x0, 0x0, + 0xf, 0x20, 0x0, 0x0, 0xf2, 0x0, 0x0, 0xf, + 0x20, 0x0, 0x0, 0xf2, 0x0, 0x0, 0xf, 0x20, + 0x0, 0x0, 0xf2, 0x0, 0x0, 0xf, 0x20, 0x0, + + /* U+0055 "U" */ + 0xe2, 0x0, 0xf2, 0xe2, 0x0, 0xf2, 0xe2, 0x0, + 0xf2, 0xe2, 0x0, 0xf2, 0xe2, 0x0, 0xf2, 0xe2, + 0x0, 0xf2, 0xe2, 0x0, 0xf1, 0xb8, 0x5, 0xe0, + 0x2c, 0xfd, 0x40, + + /* U+0056 "V" */ + 0x4d, 0x0, 0xa, 0x70, 0xf1, 0x0, 0xd3, 0xc, + 0x50, 0x1f, 0x0, 0x88, 0x5, 0xb0, 0x4, 0xc0, + 0x97, 0x0, 0xf, 0xc, 0x30, 0x0, 0xc5, 0xe0, + 0x0, 0x8, 0xcb, 0x0, 0x0, 0x4f, 0x70, 0x0, + + /* U+0057 "W" */ + 0xb4, 0xf, 0x40, 0xe9, 0x62, 0xd6, 0x2c, 0x77, + 0x4a, 0x84, 0xa5, 0x96, 0x6a, 0x58, 0x3b, 0x83, + 0xb7, 0x62, 0xca, 0x1b, 0x94, 0xe, 0xb0, 0xbb, + 0x20, 0xeb, 0xa, 0xd1, 0xc, 0xb0, 0x8f, 0x0, + + /* U+0058 "X" */ + 0x2f, 0x20, 0xd, 0x50, 0x99, 0x6, 0xc0, 0x1, + 0xf2, 0xd3, 0x0, 0x8, 0xea, 0x0, 0x0, 0x2f, + 0x50, 0x0, 0x9, 0xcc, 0x0, 0x2, 0xe1, 0xd5, + 0x0, 0xb7, 0x4, 0xe0, 0x3e, 0x0, 0xc, 0x70, + + /* U+0059 "Y" */ + 0x5c, 0x0, 0x9, 0x80, 0xd4, 0x1, 0xe1, 0x6, + 0xb0, 0x79, 0x0, 0xe, 0x3e, 0x20, 0x0, 0x7e, + 0xa0, 0x0, 0x0, 0xf3, 0x0, 0x0, 0xf, 0x20, + 0x0, 0x0, 0xf2, 0x0, 0x0, 0xf, 0x20, 0x0, + + /* U+005A "Z" */ + 0xef, 0xff, 0xf1, 0x0, 0x5, 0xd0, 0x0, 0xd, + 0x40, 0x0, 0x7a, 0x0, 0x1, 0xe2, 0x0, 0x9, + 0x80, 0x0, 0x3e, 0x0, 0x0, 0xc6, 0x0, 0x0, + 0xff, 0xff, 0xf3, + + /* U+005B "[" */ + 0x8f, 0xf6, 0x88, 0x0, 0x88, 0x0, 0x88, 0x0, + 0x88, 0x0, 0x88, 0x0, 0x88, 0x0, 0x88, 0x0, + 0x88, 0x0, 0x88, 0x0, 0x88, 0x0, 0x8f, 0xf6, + + /* U+005C "\\" */ + 0xe, 0x30, 0x0, 0x0, 0x99, 0x0, 0x0, 0x3, + 0xe0, 0x0, 0x0, 0xd, 0x40, 0x0, 0x0, 0x8a, + 0x0, 0x0, 0x2, 0xf0, 0x0, 0x0, 0xc, 0x50, + 0x0, 0x0, 0x7b, 0x0, 0x0, 0x1, 0xf1, 0x0, + 0x0, 0xb, 0x60, 0x0, 0x0, 0x6c, 0x0, 0x0, + 0x0, 0xf1, + + /* U+005D "]" */ + 0x3f, 0xfb, 0x0, 0x5b, 0x0, 0x5b, 0x0, 0x5b, + 0x0, 0x5b, 0x0, 0x5b, 0x0, 0x5b, 0x0, 0x5b, + 0x0, 0x5b, 0x0, 0x5b, 0x0, 0x5b, 0x3f, 0xfb, + + /* U+005E "^" */ + 0x0, 0x1f, 0x50, 0x0, 0x8, 0x8b, 0x0, 0x0, + 0xd0, 0xb2, 0x0, 0x68, 0x5, 0x90, 0xd, 0x20, + 0xd, 0x10, + + /* U+005F "_" */ + 0x4f, 0xff, 0xff, 0x70, + + /* U+0060 "`" */ + 0xb, 0x70, 0x1, 0xe2, + + /* U+0061 "a" */ + 0x2, 0xcf, 0xd4, 0x0, 0xb7, 0x5, 0xe0, 0x0, + 0x0, 0xf, 0x10, 0x5d, 0xee, 0xf1, 0x1f, 0x20, + 0xf, 0x11, 0xf2, 0x5, 0xf1, 0x7, 0xee, 0x7f, + 0x10, + + /* U+0062 "b" */ + 0xe3, 0x0, 0x0, 0xe2, 0x0, 0x0, 0xe7, 0xee, + 0x50, 0xe8, 0x4, 0xf0, 0xe3, 0x0, 0xf2, 0xe3, + 0x0, 0xe2, 0xe3, 0x0, 0xf2, 0xe8, 0x4, 0xf0, + 0xe8, 0xee, 0x50, + + /* U+0063 "c" */ + 0x1b, 0xfd, 0x50, 0xb9, 0x3, 0xf1, 0xe2, 0x0, + 0x41, 0xf2, 0x0, 0x0, 0xe2, 0x0, 0x41, 0xb9, + 0x3, 0xf1, 0x1b, 0xfd, 0x50, + + /* U+0064 "d" */ + 0x0, 0x0, 0xf1, 0x0, 0x0, 0xf1, 0x3d, 0xf7, + 0xf1, 0xc7, 0x6, 0xf1, 0xe2, 0x0, 0xf1, 0xf2, + 0x0, 0xf1, 0xe2, 0x0, 0xf1, 0xc7, 0x5, 0xf1, + 0x3d, 0xf7, 0xf1, + + /* U+0065 "e" */ + 0x2b, 0xed, 0x30, 0xb7, 0x4, 0xe0, 0xf1, 0x0, + 0xe2, 0xfe, 0xee, 0xe2, 0xf1, 0x0, 0x0, 0xb7, + 0x3, 0xc0, 0x2b, 0xfd, 0x50, + + /* U+0066 "f" */ + 0x0, 0x1c, 0xff, 0x50, 0x6, 0xc0, 0x0, 0x0, + 0x6a, 0x0, 0x5, 0xef, 0xfe, 0xe5, 0x1, 0x7b, + 0x11, 0x0, 0x6, 0xa0, 0x0, 0x0, 0x6a, 0x0, + 0x0, 0x6, 0xa0, 0x0, 0x0, 0x6a, 0x0, 0x0, + + /* U+0067 "g" */ + 0x3d, 0xf8, 0xf1, 0xc7, 0x5, 0xf1, 0xe2, 0x0, + 0xf1, 0xe2, 0x0, 0xf1, 0xc7, 0x5, 0xf1, 0x3d, + 0xe8, 0xf1, 0x0, 0x0, 0xf1, 0x0, 0x5, 0xe0, + 0x1f, 0xfd, 0x40, + + /* U+0068 "h" */ + 0xe3, 0x0, 0x0, 0xe3, 0x0, 0x0, 0xe8, 0xee, + 0x50, 0xe8, 0x5, 0xf0, 0xe3, 0x0, 0xf1, 0xe3, + 0x0, 0xf2, 0xe3, 0x0, 0xf2, 0xe3, 0x0, 0xf2, + 0xe3, 0x0, 0xf2, + + /* U+0069 "i" */ + 0x0, 0x52, 0x0, 0x0, 0xe7, 0x0, 0x0, 0x0, + 0x0, 0xbf, 0xf7, 0x0, 0x0, 0xa7, 0x0, 0x0, + 0xa7, 0x0, 0x0, 0xa7, 0x0, 0x0, 0xa7, 0x0, + 0x0, 0xa7, 0x0, 0xff, 0xff, 0xfa, + + /* U+006A "j" */ + 0x0, 0x6, 0x10, 0x2, 0xf4, 0x0, 0x0, 0xf, + 0xff, 0xf3, 0x0, 0xd, 0x30, 0x0, 0xd3, 0x0, + 0xd, 0x30, 0x0, 0xd3, 0x0, 0xd, 0x30, 0x0, + 0xe2, 0x0, 0x5e, 0xe, 0xfd, 0x40, + + /* U+006B "k" */ + 0xd4, 0x0, 0x0, 0xd4, 0x0, 0x0, 0xd4, 0x0, + 0xe4, 0xd4, 0x9, 0xa0, 0xd4, 0x3e, 0x10, 0xdf, + 0xfa, 0x0, 0xd4, 0x2f, 0x20, 0xd4, 0x8, 0xc0, + 0xd4, 0x0, 0xd6, + + /* U+006C "l" */ + 0xaf, 0xfb, 0x0, 0x0, 0x5, 0xb0, 0x0, 0x0, + 0x5b, 0x0, 0x0, 0x5, 0xb0, 0x0, 0x0, 0x5b, + 0x0, 0x0, 0x5, 0xb0, 0x0, 0x0, 0x5b, 0x0, + 0x0, 0x4, 0xd1, 0x0, 0x0, 0xa, 0xff, 0x90, + + /* U+006D "m" */ + 0x4c, 0xca, 0x9d, 0x14, 0xc0, 0xe1, 0x97, 0x4b, + 0xd, 0x8, 0x74, 0xb0, 0xd0, 0x87, 0x4b, 0xd, + 0x8, 0x74, 0xb0, 0xd0, 0x87, 0x4b, 0xd, 0x8, + 0x70, + + /* U+006E "n" */ + 0xe8, 0xcd, 0x50, 0xe7, 0x3, 0xf0, 0xe3, 0x0, + 0xf1, 0xe3, 0x0, 0xf2, 0xe3, 0x0, 0xf2, 0xe3, + 0x0, 0xf2, 0xe3, 0x0, 0xf2, + + /* U+006F "o" */ + 0x2b, 0xfd, 0x30, 0xb8, 0x5, 0xe0, 0xf1, 0x0, + 0xe2, 0xf1, 0x0, 0xe3, 0xf1, 0x0, 0xe2, 0xb8, + 0x5, 0xe0, 0x2c, 0xfd, 0x30, + + /* U+0070 "p" */ + 0xe8, 0xce, 0x50, 0xe7, 0x3, 0xf0, 0xe3, 0x0, + 0xe2, 0xe3, 0x0, 0xe2, 0xe3, 0x0, 0xf2, 0xe8, + 0x4, 0xf0, 0xe7, 0xee, 0x50, 0xe2, 0x0, 0x0, + 0xe3, 0x0, 0x0, + + /* U+0071 "q" */ + 0x3d, 0xf7, 0xf1, 0xc7, 0x5, 0xf1, 0xe2, 0x0, + 0xf1, 0xf2, 0x0, 0xf1, 0xe2, 0x0, 0xf1, 0xc7, + 0x5, 0xf1, 0x3d, 0xf7, 0xf1, 0x0, 0x0, 0xf1, + 0x0, 0x0, 0xf1, + + /* U+0072 "r" */ + 0xa9, 0xce, 0x80, 0xaa, 0x0, 0xe3, 0xa7, 0x0, + 0xb5, 0xa6, 0x0, 0x0, 0xa6, 0x0, 0x0, 0xa6, + 0x0, 0x0, 0xa6, 0x0, 0x0, + + /* U+0073 "s" */ + 0x4d, 0xfe, 0x50, 0xc5, 0x3, 0xb0, 0xc8, 0x20, + 0x0, 0x3b, 0xef, 0x80, 0x0, 0x1, 0xf1, 0xd4, + 0x2, 0xf1, 0x5d, 0xfe, 0x70, + + /* U+0074 "t" */ + 0x0, 0x88, 0x0, 0x0, 0x8, 0x80, 0x0, 0x7f, + 0xff, 0xff, 0x30, 0x8, 0x80, 0x0, 0x0, 0x88, + 0x0, 0x0, 0x8, 0x80, 0x0, 0x0, 0x88, 0x0, + 0x0, 0x7, 0xb0, 0x0, 0x0, 0x1c, 0xff, 0x30, + + /* U+0075 "u" */ + 0xe2, 0x0, 0xf2, 0xe2, 0x0, 0xf2, 0xe2, 0x0, + 0xf2, 0xe2, 0x0, 0xf2, 0xe2, 0x0, 0xf1, 0xa8, + 0x6, 0xd0, 0x1b, 0xfc, 0x30, + + /* U+0076 "v" */ + 0x3f, 0x0, 0xc, 0x60, 0xe4, 0x1, 0xf1, 0x8, + 0x90, 0x5b, 0x0, 0x3e, 0xa, 0x60, 0x0, 0xe3, + 0xf1, 0x0, 0x9, 0xbc, 0x0, 0x0, 0x4f, 0x70, + 0x0, + + /* U+0077 "w" */ + 0x86, 0xf, 0x32, 0xb6, 0x83, 0xd6, 0x49, 0x3a, + 0x59, 0x86, 0x61, 0xc8, 0x4b, 0x84, 0xd, 0xb0, + 0xcb, 0x10, 0xcc, 0xb, 0xc0, 0xa, 0xb0, 0x9c, + 0x0, + + /* U+0078 "x" */ + 0xe, 0x50, 0x2f, 0x20, 0x4e, 0xb, 0x70, 0x0, + 0xab, 0xd0, 0x0, 0x3, 0xf6, 0x0, 0x0, 0xc9, + 0xe1, 0x0, 0x6c, 0x9, 0x90, 0x2f, 0x30, 0x1e, + 0x40, + + /* U+0079 "y" */ + 0x2f, 0x0, 0xc, 0x50, 0xc5, 0x1, 0xf0, 0x6, + 0xb0, 0x7a, 0x0, 0xf, 0x1c, 0x40, 0x0, 0x99, + 0xe0, 0x0, 0x3, 0xf8, 0x0, 0x0, 0xf, 0x20, + 0x0, 0x5, 0xc0, 0x0, 0x0, 0xa7, 0x0, 0x0, + + /* U+007A "z" */ + 0xdf, 0xff, 0xf0, 0x0, 0x9, 0xb0, 0x0, 0x5d, + 0x10, 0x2, 0xe2, 0x0, 0xd, 0x50, 0x0, 0xa9, + 0x0, 0x0, 0xef, 0xff, 0xf2, + + /* U+007B "{" */ + 0x0, 0x1, 0xcf, 0x10, 0x0, 0x99, 0x0, 0x0, + 0xa, 0x60, 0x0, 0x0, 0x97, 0x0, 0x0, 0x8, + 0x80, 0x0, 0x0, 0xb5, 0x0, 0x1f, 0xfa, 0x0, + 0x0, 0x0, 0xa7, 0x0, 0x0, 0x8, 0x80, 0x0, + 0x0, 0xa6, 0x0, 0x0, 0xa, 0x80, 0x0, 0x0, + 0x2c, 0xf1, + + /* U+007C "|" */ + 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, + 0xf2, 0xf2, 0xf2, 0xf2, + + /* U+007D "}" */ + 0xdd, 0x40, 0x0, 0x6, 0xd0, 0x0, 0x3, 0xd0, + 0x0, 0x5, 0xb0, 0x0, 0x7, 0x90, 0x0, 0x5, + 0xb0, 0x0, 0x0, 0xcf, 0xf4, 0x6, 0xb0, 0x0, + 0x6, 0xa0, 0x0, 0x4, 0xd0, 0x0, 0x6, 0xe0, + 0x0, 0xdd, 0x50, 0x0, + + /* U+007E "~" */ + 0x9, 0xe6, 0xa, 0x51, 0xe1, 0xd2, 0xc4, 0x2d, + 0x3, 0xeb, 0x0 +}; + + +/*--------------------- + * GLYPH DESCRIPTION + *--------------------*/ + +static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = { + {.bitmap_index = 0, .adv_w = 0, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0} /* id = 0 reserved */, + {.bitmap_index = 0, .adv_w = 115, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 0, .adv_w = 115, .box_w = 3, .box_h = 9, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 14, .adv_w = 115, .box_w = 5, .box_h = 4, .ofs_x = 1, .ofs_y = 5}, + {.bitmap_index = 24, .adv_w = 115, .box_w = 7, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 56, .adv_w = 115, .box_w = 7, .box_h = 13, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 102, .adv_w = 115, .box_w = 8, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 138, .adv_w = 115, .box_w = 8, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 174, .adv_w = 115, .box_w = 3, .box_h = 4, .ofs_x = 2, .ofs_y = 5}, + {.bitmap_index = 180, .adv_w = 115, .box_w = 4, .box_h = 13, .ofs_x = 2, .ofs_y = -2}, + {.bitmap_index = 206, .adv_w = 115, .box_w = 4, .box_h = 13, .ofs_x = 1, .ofs_y = -2}, + {.bitmap_index = 232, .adv_w = 115, .box_w = 7, .box_h = 7, .ofs_x = 0, .ofs_y = 1}, + {.bitmap_index = 257, .adv_w = 115, .box_w = 7, .box_h = 6, .ofs_x = 0, .ofs_y = 1}, + {.bitmap_index = 278, .adv_w = 115, .box_w = 3, .box_h = 4, .ofs_x = 2, .ofs_y = -2}, + {.bitmap_index = 284, .adv_w = 115, .box_w = 5, .box_h = 1, .ofs_x = 1, .ofs_y = 4}, + {.bitmap_index = 287, .adv_w = 115, .box_w = 3, .box_h = 3, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 292, .adv_w = 115, .box_w = 7, .box_h = 12, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 334, .adv_w = 115, .box_w = 7, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 366, .adv_w = 115, .box_w = 6, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 393, .adv_w = 115, .box_w = 7, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 425, .adv_w = 115, .box_w = 7, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 457, .adv_w = 115, .box_w = 6, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 484, .adv_w = 115, .box_w = 7, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 516, .adv_w = 115, .box_w = 7, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 548, .adv_w = 115, .box_w = 7, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 580, .adv_w = 115, .box_w = 7, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 612, .adv_w = 115, .box_w = 7, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 644, .adv_w = 115, .box_w = 3, .box_h = 7, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 655, .adv_w = 115, .box_w = 3, .box_h = 9, .ofs_x = 2, .ofs_y = -2}, + {.bitmap_index = 669, .adv_w = 115, .box_w = 6, .box_h = 8, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 693, .adv_w = 115, .box_w = 6, .box_h = 4, .ofs_x = 1, .ofs_y = 2}, + {.bitmap_index = 705, .adv_w = 115, .box_w = 6, .box_h = 8, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 729, .adv_w = 115, .box_w = 5, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 752, .adv_w = 115, .box_w = 7, .box_h = 11, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 791, .adv_w = 115, .box_w = 7, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 823, .adv_w = 115, .box_w = 6, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 850, .adv_w = 115, .box_w = 6, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 877, .adv_w = 115, .box_w = 6, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 904, .adv_w = 115, .box_w = 6, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 931, .adv_w = 115, .box_w = 6, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 958, .adv_w = 115, .box_w = 6, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 985, .adv_w = 115, .box_w = 6, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1012, .adv_w = 115, .box_w = 5, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1035, .adv_w = 115, .box_w = 6, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1062, .adv_w = 115, .box_w = 6, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1089, .adv_w = 115, .box_w = 6, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1116, .adv_w = 115, .box_w = 7, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1148, .adv_w = 115, .box_w = 6, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1175, .adv_w = 115, .box_w = 6, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1202, .adv_w = 115, .box_w = 6, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1229, .adv_w = 115, .box_w = 7, .box_h = 11, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 1268, .adv_w = 115, .box_w = 6, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1295, .adv_w = 115, .box_w = 7, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1327, .adv_w = 115, .box_w = 7, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1359, .adv_w = 115, .box_w = 6, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1386, .adv_w = 115, .box_w = 7, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1418, .adv_w = 115, .box_w = 7, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1450, .adv_w = 115, .box_w = 7, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1482, .adv_w = 115, .box_w = 7, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1514, .adv_w = 115, .box_w = 6, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1541, .adv_w = 115, .box_w = 4, .box_h = 12, .ofs_x = 2, .ofs_y = -1}, + {.bitmap_index = 1565, .adv_w = 115, .box_w = 7, .box_h = 12, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 1607, .adv_w = 115, .box_w = 4, .box_h = 12, .ofs_x = 1, .ofs_y = -1}, + {.bitmap_index = 1631, .adv_w = 115, .box_w = 7, .box_h = 5, .ofs_x = 0, .ofs_y = 4}, + {.bitmap_index = 1649, .adv_w = 115, .box_w = 7, .box_h = 1, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 1653, .adv_w = 115, .box_w = 4, .box_h = 2, .ofs_x = 1, .ofs_y = 8}, + {.bitmap_index = 1657, .adv_w = 115, .box_w = 7, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1682, .adv_w = 115, .box_w = 6, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1709, .adv_w = 115, .box_w = 6, .box_h = 7, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1730, .adv_w = 115, .box_w = 6, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1757, .adv_w = 115, .box_w = 6, .box_h = 7, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1778, .adv_w = 115, .box_w = 7, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1810, .adv_w = 115, .box_w = 6, .box_h = 9, .ofs_x = 1, .ofs_y = -2}, + {.bitmap_index = 1837, .adv_w = 115, .box_w = 6, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1864, .adv_w = 115, .box_w = 6, .box_h = 10, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1894, .adv_w = 115, .box_w = 5, .box_h = 12, .ofs_x = 1, .ofs_y = -2}, + {.bitmap_index = 1924, .adv_w = 115, .box_w = 6, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1951, .adv_w = 115, .box_w = 7, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1983, .adv_w = 115, .box_w = 7, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 2008, .adv_w = 115, .box_w = 6, .box_h = 7, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 2029, .adv_w = 115, .box_w = 6, .box_h = 7, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 2050, .adv_w = 115, .box_w = 6, .box_h = 9, .ofs_x = 1, .ofs_y = -2}, + {.bitmap_index = 2077, .adv_w = 115, .box_w = 6, .box_h = 9, .ofs_x = 1, .ofs_y = -2}, + {.bitmap_index = 2104, .adv_w = 115, .box_w = 6, .box_h = 7, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 2125, .adv_w = 115, .box_w = 6, .box_h = 7, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 2146, .adv_w = 115, .box_w = 7, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 2178, .adv_w = 115, .box_w = 6, .box_h = 7, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 2199, .adv_w = 115, .box_w = 7, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 2224, .adv_w = 115, .box_w = 7, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 2249, .adv_w = 115, .box_w = 7, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 2274, .adv_w = 115, .box_w = 7, .box_h = 9, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 2306, .adv_w = 115, .box_w = 6, .box_h = 7, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 2327, .adv_w = 115, .box_w = 7, .box_h = 12, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 2369, .adv_w = 115, .box_w = 2, .box_h = 12, .ofs_x = 3, .ofs_y = -1}, + {.bitmap_index = 2381, .adv_w = 115, .box_w = 6, .box_h = 12, .ofs_x = 1, .ofs_y = -1}, + {.bitmap_index = 2417, .adv_w = 115, .box_w = 7, .box_h = 3, .ofs_x = 0, .ofs_y = 3} +}; + +/*--------------------- + * CHARACTER MAPPING + *--------------------*/ + + + +/*Collect the unicode lists and glyph_id offsets*/ +static const lv_font_fmt_txt_cmap_t cmaps[] = +{ + { + .range_start = 32, .range_length = 95, .glyph_id_start = 1, + .unicode_list = NULL, .glyph_id_ofs_list = NULL, .list_length = 0, .type = LV_FONT_FMT_TXT_CMAP_FORMAT0_TINY + } +}; + + + +/*-------------------- + * ALL CUSTOM DATA + *--------------------*/ + +#if LVGL_VERSION_MAJOR == 8 +/*Store all the custom data of the font*/ +static lv_font_fmt_txt_glyph_cache_t cache; +#endif + +#if LVGL_VERSION_MAJOR >= 8 +static const lv_font_fmt_txt_dsc_t font_dsc = { +#else +static lv_font_fmt_txt_dsc_t font_dsc = { +#endif + .glyph_bitmap = glyph_bitmap, + .glyph_dsc = glyph_dsc, + .cmaps = cmaps, + .kern_dsc = NULL, + .kern_scale = 0, + .cmap_num = 1, + .bpp = 4, + .kern_classes = 0, + .bitmap_format = 0, +#if LVGL_VERSION_MAJOR == 8 + .cache = &cache +#endif +}; + + +/*----------------- + * PUBLIC FONT + *----------------*/ + +/*Initialize a public general font descriptor*/ +#if LVGL_VERSION_MAJOR >= 8 +const lv_font_t JetBrainsMono12 = { +#else +lv_font_t JetBrainsMono12 = { +#endif + .get_glyph_dsc = lv_font_get_glyph_dsc_fmt_txt, /*Function pointer to get glyph's data*/ + .get_glyph_bitmap = lv_font_get_bitmap_fmt_txt, /*Function pointer to get glyph's bitmap*/ + .line_height = 13, /*The maximum line height required by the font*/ + .base_line = 2, /*Baseline measured from the bottom of the line*/ +#if !(LVGL_VERSION_MAJOR == 6 && LVGL_VERSION_MINOR == 0) + .subpx = LV_FONT_SUBPX_NONE, +#endif +#if LV_VERSION_CHECK(7, 4, 0) || LVGL_VERSION_MAJOR >= 8 + .underline_position = -2, + .underline_thickness = 1, +#endif + .dsc = &font_dsc, /*The custom font data. Will be accessed by `get_glyph_bitmap/dsc` */ + .fallback = NULL, + .user_data = NULL +}; + + + +#endif /*#if JETBRAINSMONO12*/ + diff --git a/device/src/keyboard/oled/fonts/jet_brains_mono_16.c b/device/src/keyboard/oled/fonts/jet_brains_mono_16.c new file mode 100644 index 000000000..059ad36fd --- /dev/null +++ b/device/src/keyboard/oled/fonts/jet_brains_mono_16.c @@ -0,0 +1,930 @@ +/******************************************************************************* + * Size: 16 px + * Bpp: 4 + * Opts: + ******************************************************************************/ + +#ifdef LV_LVGL_H_INCLUDE_SIMPLE +#include "lvgl.h" +#else +#include "lvgl/lvgl.h" +#endif + +#ifndef JETBRAINSMONO16 +#define JETBRAINSMONO16 1 +#endif + +#if JETBRAINSMONO16 + +/*----------------- + * BITMAPS + *----------------*/ + +/*Store the image of the glyphs*/ +static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { + /* U+0020 " " */ + + /* U+0021 "!" */ + 0xf, 0xa0, 0xf9, 0xf, 0x90, 0xf8, 0xf, 0x80, + 0xe8, 0xe, 0x70, 0xe7, 0x3, 0x20, 0x0, 0x3e, + 0xb3, 0xfc, + + /* U+0022 "\"" */ + 0xbe, 0x4, 0xf4, 0xae, 0x4, 0xf4, 0xad, 0x4, + 0xf4, 0x9d, 0x3, 0xf3, 0x7a, 0x2, 0xd2, + + /* U+0023 "#" */ + 0x0, 0x9, 0x80, 0xe, 0x20, 0x0, 0xc, 0x50, + 0x1f, 0x0, 0x0, 0xe, 0x30, 0x3e, 0x0, 0x0, + 0x1f, 0x0, 0x6b, 0x0, 0xc, 0xef, 0xee, 0xff, + 0xe0, 0x1, 0x7b, 0x11, 0xc7, 0x10, 0x0, 0x98, + 0x0, 0xe3, 0x0, 0x0, 0xc5, 0x1, 0xf0, 0x0, + 0x6e, 0xff, 0xee, 0xfe, 0x70, 0x3, 0xf1, 0x18, + 0xb1, 0x0, 0x5, 0xc0, 0xa, 0x70, 0x0, 0x9, + 0x80, 0xe, 0x30, 0x0, + + /* U+0024 "$" */ + 0x0, 0x4, 0x20, 0x0, 0x0, 0x9, 0x50, 0x0, + 0x0, 0xa, 0x70, 0x0, 0x6, 0xff, 0xfe, 0x30, + 0x3f, 0x8a, 0x7c, 0xe0, 0x7f, 0x9, 0x53, 0xf3, + 0x6f, 0x19, 0x50, 0x0, 0x1f, 0xbb, 0x50, 0x0, + 0x4, 0xef, 0xd7, 0x0, 0x0, 0xa, 0xcf, 0xb0, + 0x0, 0x9, 0x55, 0xf3, 0x65, 0x9, 0x50, 0xf6, + 0xad, 0x9, 0x53, 0xf4, 0x2f, 0xdd, 0xcf, 0xc0, + 0x2, 0x9e, 0xd7, 0x0, 0x0, 0x9, 0x50, 0x0, + 0x0, 0x9, 0x50, 0x0, + + /* U+0025 "%" */ + 0x2c, 0xfb, 0x10, 0x2, 0xe1, 0xaa, 0x2b, 0x90, + 0xc, 0x60, 0xc6, 0x8, 0xa0, 0x7b, 0x0, 0xb9, + 0xa, 0x92, 0xe1, 0x0, 0x3e, 0xfe, 0x2c, 0x60, + 0x0, 0x0, 0x10, 0x7b, 0x0, 0x0, 0x0, 0x2, + 0xe1, 0x0, 0x0, 0x0, 0xc, 0x65, 0xde, 0x80, + 0x0, 0x7b, 0xf, 0x63, 0xf3, 0x2, 0xe1, 0x1f, + 0x10, 0xd5, 0xc, 0x60, 0xf, 0x52, 0xe4, 0x7b, + 0x0, 0x6, 0xef, 0x90, + + /* U+0026 "&" */ + 0x0, 0x3c, 0xfd, 0x40, 0x0, 0x0, 0xfb, 0x4a, + 0xf1, 0x0, 0x3, 0xf3, 0x0, 0xf6, 0x0, 0x0, + 0xe7, 0x0, 0x0, 0x0, 0x0, 0x5f, 0x30, 0x0, + 0x0, 0x6, 0xdf, 0xe1, 0x0, 0x0, 0x3f, 0x72, + 0xcc, 0x3, 0xf6, 0x8e, 0x0, 0x1e, 0xae, 0x90, + 0x9d, 0x0, 0x5, 0xfc, 0x0, 0x7e, 0x0, 0xa, + 0xfe, 0x10, 0x3f, 0xa5, 0xaf, 0x3c, 0xb0, 0x5, + 0xdf, 0xc3, 0x2, 0xf7, + + /* U+0027 "'" */ + 0xf, 0x90, 0xf9, 0xf, 0x80, 0xe8, 0xb, 0x60, + + /* U+0028 "(" */ + 0x0, 0x0, 0x14, 0x0, 0x8, 0xfb, 0x0, 0xaf, + 0x70, 0x4, 0xf6, 0x0, 0xb, 0xd0, 0x0, 0xf, + 0x80, 0x0, 0xf, 0x60, 0x0, 0xf, 0x60, 0x0, + 0xf, 0x60, 0x0, 0xf, 0x60, 0x0, 0xf, 0x70, + 0x0, 0xd, 0xb0, 0x0, 0x8, 0xf2, 0x0, 0x1, + 0xec, 0x10, 0x0, 0x3e, 0xe7, 0x0, 0x1, 0x8a, + + /* U+0029 ")" */ + 0x15, 0x0, 0x0, 0x2f, 0xe4, 0x0, 0x2, 0xbf, + 0x40, 0x0, 0xc, 0xd0, 0x0, 0x3, 0xf4, 0x0, + 0x0, 0xe8, 0x0, 0x0, 0xd9, 0x0, 0x0, 0xca, + 0x0, 0x0, 0xca, 0x0, 0x0, 0xca, 0x0, 0x0, + 0xd9, 0x0, 0x1, 0xf6, 0x0, 0x8, 0xf1, 0x0, + 0x5f, 0x80, 0x1b, 0xfa, 0x0, 0x2b, 0x50, 0x0, + + /* U+002A "*" */ + 0x0, 0x0, 0xe7, 0x0, 0x0, 0x0, 0x0, 0xe7, + 0x0, 0x0, 0x19, 0x30, 0xd6, 0x5, 0x70, 0x3d, + 0xfc, 0xeb, 0xef, 0xa0, 0x0, 0x38, 0xfe, 0x61, + 0x0, 0x0, 0xc, 0xaf, 0x60, 0x0, 0x0, 0x8f, + 0x17, 0xf2, 0x0, 0x1, 0xf6, 0x0, 0xc9, 0x0, + 0x0, 0x10, 0x0, 0x10, 0x0, + + /* U+002B "+" */ + 0x0, 0xe, 0x80, 0x0, 0x0, 0xe, 0x80, 0x0, + 0x0, 0xe, 0x80, 0x0, 0xff, 0xff, 0xff, 0xf9, + 0x33, 0x3e, 0x93, 0x32, 0x0, 0xe, 0x80, 0x0, + 0x0, 0xe, 0x80, 0x0, 0x0, 0x8, 0x40, 0x0, + + /* U+002C "," */ + 0xc, 0xc0, 0xfa, 0x3f, 0x66, 0xf2, 0x8f, 0x0, + + /* U+002D "-" */ + 0x0, 0x0, 0x0, 0xcf, 0xff, 0xf5, 0x23, 0x33, + 0x31, + + /* U+002E "." */ + 0x8, 0x50, 0x7f, 0xf0, 0x3e, 0xc0, + + /* U+002F "/" */ + 0x0, 0x0, 0x5, 0xf3, 0x0, 0x0, 0xb, 0xd0, + 0x0, 0x0, 0x1f, 0x70, 0x0, 0x0, 0x7f, 0x10, + 0x0, 0x0, 0xdb, 0x0, 0x0, 0x3, 0xf5, 0x0, + 0x0, 0x9, 0xe0, 0x0, 0x0, 0xe, 0x80, 0x0, + 0x0, 0x5f, 0x20, 0x0, 0x0, 0xbc, 0x0, 0x0, + 0x1, 0xf6, 0x0, 0x0, 0x7, 0xf1, 0x0, 0x0, + 0xd, 0xa0, 0x0, 0x0, 0x3f, 0x40, 0x0, 0x0, + 0x9e, 0x0, 0x0, 0x0, + + /* U+0030 "0" */ + 0x3, 0xcf, 0xe9, 0x10, 0x2f, 0xb4, 0x6e, 0xb0, + 0x8e, 0x0, 0x4, 0xf2, 0xbb, 0x0, 0x1, 0xf4, + 0xba, 0x0, 0x1, 0xf5, 0xba, 0x1e, 0x91, 0xf5, + 0xba, 0xb, 0x61, 0xf5, 0xba, 0x0, 0x1, 0xf5, + 0xba, 0x0, 0x1, 0xf4, 0x9d, 0x0, 0x4, 0xf2, + 0x2f, 0xb4, 0x6e, 0xc0, 0x3, 0xcf, 0xe9, 0x10, + + /* U+0031 "1" */ + 0x0, 0x8f, 0xf0, 0x0, 0x1c, 0xfb, 0xf0, 0x0, + 0x8d, 0x26, 0xf0, 0x0, 0x40, 0x6, 0xf0, 0x0, + 0x0, 0x6, 0xf0, 0x0, 0x0, 0x6, 0xf0, 0x0, + 0x0, 0x6, 0xf0, 0x0, 0x0, 0x6, 0xf0, 0x0, + 0x0, 0x6, 0xf0, 0x0, 0x0, 0x6, 0xf0, 0x0, + 0x25, 0x59, 0xf5, 0x53, 0x9f, 0xff, 0xff, 0xfa, + + /* U+0032 "2" */ + 0x3, 0xcf, 0xe9, 0x0, 0x2f, 0xb5, 0x7f, 0xb0, + 0x9d, 0x0, 0x6, 0xf1, 0x55, 0x0, 0x3, 0xf3, + 0x0, 0x0, 0x6, 0xf1, 0x0, 0x0, 0x1e, 0xa0, + 0x0, 0x0, 0xce, 0x10, 0x0, 0xb, 0xe2, 0x0, + 0x0, 0x9f, 0x30, 0x0, 0x8, 0xf4, 0x0, 0x0, + 0x6f, 0x95, 0x55, 0x52, 0xaf, 0xff, 0xff, 0xf7, + + /* U+0033 "3" */ + 0x9f, 0xff, 0xff, 0xe0, 0x25, 0x55, 0x6f, 0xa0, + 0x0, 0x0, 0xcc, 0x0, 0x0, 0xc, 0xd1, 0x0, + 0x0, 0x8f, 0x92, 0x0, 0x0, 0x6a, 0xdf, 0x50, + 0x0, 0x0, 0xb, 0xe0, 0x0, 0x0, 0x5, 0xf1, + 0x53, 0x0, 0x4, 0xf2, 0xbc, 0x0, 0x7, 0xf0, + 0x5f, 0x95, 0x7f, 0x90, 0x5, 0xdf, 0xd8, 0x0, + + /* U+0034 "4" */ + 0x0, 0x0, 0xeb, 0x0, 0x0, 0x8f, 0x20, 0x0, + 0x2f, 0x70, 0x0, 0xb, 0xd0, 0x0, 0x5, 0xf4, + 0x0, 0x0, 0xea, 0x0, 0x7a, 0x8f, 0x10, 0x9, + 0xdd, 0xa1, 0x11, 0x9d, 0xef, 0xff, 0xff, 0xd3, + 0x44, 0x44, 0xbd, 0x0, 0x0, 0x9, 0xd0, 0x0, + 0x0, 0x9d, + + /* U+0035 "5" */ + 0x6f, 0xff, 0xff, 0xd0, 0x6f, 0x55, 0x55, 0x40, + 0x6f, 0x0, 0x0, 0x0, 0x6f, 0x0, 0x0, 0x0, + 0x6f, 0x10, 0x0, 0x0, 0x6f, 0xff, 0xfb, 0x20, + 0x14, 0x44, 0x6e, 0xc0, 0x0, 0x0, 0x5, 0xf2, + 0x21, 0x0, 0x3, 0xf3, 0xac, 0x0, 0x5, 0xf1, + 0x4f, 0xa5, 0x6e, 0xb0, 0x5, 0xcf, 0xe9, 0x10, + + /* U+0036 "6" */ + 0x0, 0x7, 0xf2, 0x0, 0x0, 0x1f, 0x90, 0x0, + 0x0, 0x9f, 0x20, 0x0, 0x2, 0xf9, 0x0, 0x0, + 0xa, 0xf1, 0x0, 0x0, 0x2f, 0xdd, 0xeb, 0x20, + 0x9f, 0x83, 0x4c, 0xe1, 0xeb, 0x0, 0x1, 0xf7, + 0xe8, 0x0, 0x0, 0xe8, 0xcb, 0x0, 0x2, 0xf6, + 0x4f, 0xa5, 0x6e, 0xd0, 0x4, 0xcf, 0xea, 0x10, + + /* U+0037 "7" */ + 0xbf, 0xff, 0xff, 0xfb, 0xbd, 0x55, 0x55, 0xfa, + 0xbc, 0x0, 0x4, 0xf4, 0x23, 0x0, 0xa, 0xe0, + 0x0, 0x0, 0x1f, 0x80, 0x0, 0x0, 0x6f, 0x20, + 0x0, 0x0, 0xdb, 0x0, 0x0, 0x3, 0xf5, 0x0, + 0x0, 0x9, 0xe0, 0x0, 0x0, 0xf, 0x90, 0x0, + 0x0, 0x5f, 0x30, 0x0, 0x0, 0xcc, 0x0, 0x0, + + /* U+0038 "8" */ + 0x4, 0xcf, 0xe9, 0x10, 0x3f, 0xb5, 0x7e, 0xc0, + 0x8e, 0x0, 0x6, 0xf2, 0x8e, 0x0, 0x4, 0xf2, + 0x2f, 0x81, 0x2c, 0xb0, 0x4, 0xef, 0xfb, 0x0, + 0x3f, 0xa4, 0x5d, 0xc0, 0xbc, 0x0, 0x2, 0xf5, + 0xe8, 0x0, 0x0, 0xe8, 0xcc, 0x0, 0x2, 0xf6, + 0x5f, 0xb5, 0x6e, 0xd0, 0x5, 0xcf, 0xea, 0x10, + + /* U+0039 "9" */ + 0x4, 0xcf, 0xe9, 0x10, 0x4f, 0xb5, 0x6e, 0xd0, + 0xcc, 0x0, 0x2, 0xf5, 0xf8, 0x0, 0x0, 0xe8, + 0xda, 0x0, 0x0, 0xf7, 0x7f, 0x60, 0x1b, 0xf3, + 0x9, 0xff, 0xef, 0xc0, 0x0, 0x1, 0x7f, 0x40, + 0x0, 0x1, 0xeb, 0x0, 0x0, 0x8, 0xf2, 0x0, + 0x0, 0x1f, 0x90, 0x0, 0x0, 0x9f, 0x10, 0x0, + + /* U+003A ":" */ + 0x4f, 0xc0, 0x7f, 0xf0, 0x5, 0x30, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x5, 0x30, 0x7f, 0xf0, + 0x4f, 0xc0, + + /* U+003B ";" */ + 0x4f, 0xc0, 0x7f, 0xf1, 0x5, 0x30, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xd, 0xb0, + 0x1f, 0x90, 0x4f, 0x50, 0x7f, 0x10, 0xae, 0x0, + + /* U+003C "<" */ + 0x0, 0x0, 0x0, 0x31, 0x0, 0x0, 0x3b, 0xf3, + 0x0, 0x3a, 0xfb, 0x30, 0x2a, 0xfa, 0x30, 0x0, + 0xad, 0x20, 0x0, 0x0, 0x6f, 0xd5, 0x0, 0x0, + 0x1, 0x9f, 0xd5, 0x0, 0x0, 0x1, 0x9f, 0xd2, + 0x0, 0x0, 0x1, 0x93, + + /* U+003D "=" */ + 0x0, 0x0, 0x0, 0x0, 0xaf, 0xff, 0xff, 0xf3, + 0x23, 0x33, 0x33, 0x30, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xaf, 0xff, 0xff, 0xf3, + 0x23, 0x33, 0x33, 0x30, + + /* U+003E ">" */ + 0x40, 0x0, 0x0, 0x0, 0xae, 0x70, 0x0, 0x0, + 0x7, 0xee, 0x70, 0x0, 0x0, 0x7, 0xee, 0x70, + 0x0, 0x0, 0x7, 0xf3, 0x0, 0x0, 0x7e, 0xd2, + 0x1, 0x7e, 0xd5, 0x0, 0x6f, 0xd6, 0x0, 0x0, + 0x86, 0x0, 0x0, 0x0, + + /* U+003F "?" */ + 0xef, 0xfb, 0x30, 0x55, 0x6d, 0xf2, 0x0, 0x1, + 0xe9, 0x0, 0x0, 0xbb, 0x0, 0x0, 0xda, 0x0, + 0x18, 0xf5, 0xb, 0xff, 0x80, 0xb, 0xc1, 0x0, + 0x6, 0x70, 0x0, 0x0, 0x0, 0x0, 0x1d, 0xd0, + 0x0, 0x1e, 0xe1, 0x0, + + /* U+0040 "@" */ + 0x0, 0x4b, 0xff, 0xc4, 0x0, 0x4f, 0x93, 0x38, + 0xf3, 0xd, 0x90, 0x0, 0xa, 0xb2, 0xf2, 0x0, + 0x0, 0x5e, 0x4f, 0x0, 0x4d, 0xc9, 0xf4, 0xf0, + 0xe, 0x82, 0xbf, 0x4f, 0x2, 0xf2, 0x5, 0xf4, + 0xf0, 0x2f, 0x20, 0x5f, 0x4f, 0x2, 0xf2, 0x5, + 0xe4, 0xf0, 0xe, 0x60, 0x9b, 0x4f, 0x0, 0x5e, + 0xfd, 0x22, 0xf3, 0x0, 0x1, 0x0, 0xd, 0xa0, + 0x0, 0x0, 0x0, 0x3f, 0xb5, 0x33, 0x0, 0x0, + 0x3a, 0xef, 0xf0, 0x0, + + /* U+0041 "A" */ + 0x0, 0x4, 0xfe, 0x0, 0x0, 0x0, 0x8e, 0xf2, + 0x0, 0x0, 0xc, 0x9f, 0x60, 0x0, 0x0, 0xf5, + 0xca, 0x0, 0x0, 0x4f, 0x18, 0xe0, 0x0, 0x8, + 0xe0, 0x4f, 0x20, 0x0, 0xca, 0x1, 0xf6, 0x0, + 0x1f, 0x70, 0xd, 0xa0, 0x5, 0xff, 0xff, 0xfe, + 0x0, 0x9f, 0x33, 0x37, 0xf2, 0xd, 0xa0, 0x0, + 0x1f, 0x61, 0xf6, 0x0, 0x0, 0xca, + + /* U+0042 "B" */ + 0x8f, 0xff, 0xea, 0x10, 0x8e, 0x44, 0x6e, 0xc0, + 0x8e, 0x0, 0x5, 0xf1, 0x8e, 0x0, 0x4, 0xf1, + 0x8e, 0x0, 0x2c, 0xa0, 0x8f, 0xff, 0xfb, 0x0, + 0x8e, 0x33, 0x5d, 0xa0, 0x8e, 0x0, 0x2, 0xf4, + 0x8e, 0x0, 0x0, 0xf7, 0x8e, 0x0, 0x2, 0xf5, + 0x8e, 0x44, 0x6d, 0xe0, 0x8f, 0xff, 0xeb, 0x20, + + /* U+0043 "C" */ + 0x2, 0xbe, 0xea, 0x10, 0x1e, 0xd6, 0x6e, 0xc0, + 0x6f, 0x10, 0x4, 0xf3, 0x8e, 0x0, 0x0, 0x51, + 0x8e, 0x0, 0x0, 0x0, 0x8e, 0x0, 0x0, 0x0, + 0x8e, 0x0, 0x0, 0x0, 0x8e, 0x0, 0x0, 0x0, + 0x8e, 0x0, 0x0, 0x51, 0x6f, 0x10, 0x4, 0xf3, + 0x1e, 0xc5, 0x6e, 0xc0, 0x2, 0xbe, 0xea, 0x10, + + /* U+0044 "D" */ + 0x8f, 0xff, 0xd7, 0x0, 0x8e, 0x44, 0x8f, 0x90, + 0x8e, 0x0, 0x8, 0xf0, 0x8e, 0x0, 0x4, 0xf2, + 0x8e, 0x0, 0x4, 0xf3, 0x8e, 0x0, 0x4, 0xf3, + 0x8e, 0x0, 0x4, 0xf3, 0x8e, 0x0, 0x4, 0xf3, + 0x8e, 0x0, 0x4, 0xf2, 0x8e, 0x0, 0x8, 0xf0, + 0x8e, 0x44, 0x8f, 0x90, 0x8f, 0xff, 0xd7, 0x0, + + /* U+0045 "E" */ + 0x6f, 0xff, 0xff, 0xf5, 0x6f, 0x55, 0x55, 0x51, + 0x6f, 0x0, 0x0, 0x0, 0x6f, 0x0, 0x0, 0x0, + 0x6f, 0x10, 0x0, 0x0, 0x6f, 0xff, 0xff, 0xc0, + 0x6f, 0x43, 0x33, 0x20, 0x6f, 0x0, 0x0, 0x0, + 0x6f, 0x0, 0x0, 0x0, 0x6f, 0x0, 0x0, 0x0, + 0x6f, 0x55, 0x55, 0x51, 0x6f, 0xff, 0xff, 0xf5, + + /* U+0046 "F" */ + 0x7f, 0xff, 0xff, 0xf6, 0x7f, 0x55, 0x55, 0x52, + 0x7e, 0x0, 0x0, 0x0, 0x7e, 0x0, 0x0, 0x0, + 0x7e, 0x0, 0x0, 0x0, 0x7e, 0x11, 0x11, 0x0, + 0x7f, 0xff, 0xff, 0xf0, 0x7f, 0x44, 0x44, 0x30, + 0x7f, 0x0, 0x0, 0x0, 0x7f, 0x0, 0x0, 0x0, + 0x7f, 0x0, 0x0, 0x0, 0x7f, 0x0, 0x0, 0x0, + + /* U+0047 "G" */ + 0x3, 0xbf, 0xe9, 0x10, 0x1f, 0xc5, 0x7e, 0xb0, + 0x7f, 0x0, 0x5, 0xf2, 0x9d, 0x0, 0x1, 0x71, + 0x9d, 0x0, 0x0, 0x0, 0x9d, 0x0, 0x11, 0x10, + 0x9d, 0x8, 0xff, 0xf4, 0x9d, 0x2, 0x45, 0xf4, + 0x9d, 0x0, 0x2, 0xf4, 0x7f, 0x0, 0x5, 0xf2, + 0x1f, 0xc5, 0x6e, 0xc0, 0x3, 0xbf, 0xea, 0x10, + + /* U+0048 "H" */ + 0x8e, 0x0, 0x5, 0xf1, 0x8e, 0x0, 0x5, 0xf1, + 0x8e, 0x0, 0x5, 0xf1, 0x8e, 0x0, 0x5, 0xf1, + 0x8e, 0x11, 0x15, 0xf1, 0x8f, 0xff, 0xff, 0xf1, + 0x8f, 0x44, 0x47, 0xf1, 0x8e, 0x0, 0x5, 0xf1, + 0x8e, 0x0, 0x5, 0xf1, 0x8e, 0x0, 0x5, 0xf1, + 0x8e, 0x0, 0x5, 0xf1, 0x8e, 0x0, 0x5, 0xf1, + + /* U+0049 "I" */ + 0x5f, 0xff, 0xff, 0xe1, 0x55, 0xfa, 0x54, 0x0, + 0xf, 0x80, 0x0, 0x0, 0xf8, 0x0, 0x0, 0xf, + 0x80, 0x0, 0x0, 0xf8, 0x0, 0x0, 0xf, 0x80, + 0x0, 0x0, 0xf8, 0x0, 0x0, 0xf, 0x80, 0x0, + 0x0, 0xf8, 0x0, 0x15, 0x5f, 0xa5, 0x45, 0xff, + 0xff, 0xfe, + + /* U+004A "J" */ + 0x0, 0x0, 0x0, 0x8e, 0x0, 0x0, 0x0, 0x8e, + 0x0, 0x0, 0x0, 0x8e, 0x0, 0x0, 0x0, 0x8e, + 0x0, 0x0, 0x0, 0x8e, 0x0, 0x0, 0x0, 0x8e, + 0x0, 0x0, 0x0, 0x8e, 0x0, 0x0, 0x0, 0x8e, + 0x28, 0x10, 0x0, 0x8e, 0x1f, 0x60, 0x0, 0xcb, + 0xa, 0xe7, 0x5a, 0xf4, 0x0, 0x8d, 0xfc, 0x50, + + /* U+004B "K" */ + 0x8e, 0x0, 0x1, 0xf8, 0x8e, 0x0, 0x8, 0xf1, + 0x8e, 0x0, 0x1f, 0x70, 0x8e, 0x0, 0x9e, 0x0, + 0x8e, 0x2, 0xf7, 0x0, 0x8f, 0xff, 0xf0, 0x0, + 0x8e, 0x36, 0xf5, 0x0, 0x8e, 0x0, 0xcd, 0x0, + 0x8e, 0x0, 0x5f, 0x40, 0x8e, 0x0, 0xd, 0xc0, + 0x8e, 0x0, 0x6, 0xf3, 0x8e, 0x0, 0x0, 0xeb, + + /* U+004C "L" */ + 0xe8, 0x0, 0x0, 0xe, 0x80, 0x0, 0x0, 0xe8, + 0x0, 0x0, 0xe, 0x80, 0x0, 0x0, 0xe8, 0x0, + 0x0, 0xe, 0x80, 0x0, 0x0, 0xe8, 0x0, 0x0, + 0xe, 0x80, 0x0, 0x0, 0xe8, 0x0, 0x0, 0xe, + 0x80, 0x0, 0x0, 0xea, 0x55, 0x55, 0x3e, 0xff, + 0xff, 0xfc, + + /* U+004D "M" */ + 0xdf, 0x60, 0xd, 0xf7, 0xdc, 0xb0, 0x2e, 0xc7, + 0xd9, 0xf0, 0x6a, 0xd7, 0xd8, 0xd4, 0xb5, 0xe7, + 0xd8, 0x89, 0xf0, 0xe7, 0xd8, 0x3f, 0xb0, 0xe7, + 0xd8, 0x9, 0x40, 0xf7, 0xd8, 0x0, 0x0, 0xf7, + 0xd8, 0x0, 0x0, 0xf7, 0xd8, 0x0, 0x0, 0xf7, + 0xd8, 0x0, 0x0, 0xf7, 0xd8, 0x0, 0x0, 0xf7, + + /* U+004E "N" */ + 0x9f, 0x80, 0x3, 0xf2, 0x9f, 0xd0, 0x3, 0xf2, + 0x9c, 0xf3, 0x3, 0xf2, 0x9c, 0xb9, 0x3, 0xf2, + 0x9c, 0x5e, 0x3, 0xf2, 0x9d, 0xf, 0x43, 0xf2, + 0x9d, 0xa, 0x93, 0xf2, 0x9d, 0x5, 0xe4, 0xf2, + 0x9d, 0x0, 0xf7, 0xf2, 0x9d, 0x0, 0xac, 0xf2, + 0x9d, 0x0, 0x4f, 0xf2, 0x9d, 0x0, 0xe, 0xf2, + + /* U+004F "O" */ + 0x3, 0xbf, 0xe9, 0x0, 0x1f, 0xc5, 0x7f, 0xa0, + 0x7f, 0x0, 0x6, 0xf0, 0x9d, 0x0, 0x4, 0xf2, + 0x9d, 0x0, 0x4, 0xf3, 0x9d, 0x0, 0x4, 0xf3, + 0x9d, 0x0, 0x4, 0xf3, 0x9d, 0x0, 0x4, 0xf3, + 0x9d, 0x0, 0x4, 0xf2, 0x7f, 0x0, 0x6, 0xf0, + 0x1f, 0xb5, 0x7e, 0xa0, 0x3, 0xcf, 0xe9, 0x0, + + /* U+0050 "P" */ + 0x8f, 0xff, 0xfc, 0x30, 0x8e, 0x44, 0x5c, 0xf2, + 0x8e, 0x0, 0x0, 0xe9, 0x8e, 0x0, 0x0, 0xbc, + 0x8e, 0x0, 0x0, 0xda, 0x8e, 0x0, 0x18, 0xf4, + 0x8f, 0xff, 0xff, 0x70, 0x8e, 0x33, 0x20, 0x0, + 0x8e, 0x0, 0x0, 0x0, 0x8e, 0x0, 0x0, 0x0, + 0x8e, 0x0, 0x0, 0x0, 0x8e, 0x0, 0x0, 0x0, + + /* U+0051 "Q" */ + 0x3, 0xcf, 0xe9, 0x10, 0x2f, 0xb5, 0x7e, 0xb0, + 0x8e, 0x0, 0x5, 0xf2, 0xbb, 0x0, 0x2, 0xf4, + 0xbb, 0x0, 0x2, 0xf5, 0xbb, 0x0, 0x2, 0xf5, + 0xbb, 0x0, 0x2, 0xf5, 0xbb, 0x0, 0x2, 0xf5, + 0xbb, 0x0, 0x2, 0xf4, 0x9e, 0x0, 0x5, 0xf2, + 0x2f, 0xb5, 0x6e, 0xb0, 0x3, 0xcf, 0xfc, 0x10, + 0x0, 0x0, 0x9f, 0x10, 0x0, 0x0, 0x1f, 0x90, + 0x0, 0x0, 0x8, 0xf2, + + /* U+0052 "R" */ + 0x8f, 0xff, 0xfb, 0x20, 0x8e, 0x44, 0x6d, 0xe0, + 0x8e, 0x0, 0x2, 0xf6, 0x8e, 0x0, 0x0, 0xf8, + 0x8e, 0x0, 0x1, 0xf7, 0x8e, 0x0, 0x2b, 0xf1, + 0x8f, 0xff, 0xfe, 0x50, 0x8e, 0x34, 0xf8, 0x0, + 0x8e, 0x0, 0x8f, 0x10, 0x8e, 0x0, 0x1f, 0x80, + 0x8e, 0x0, 0x9, 0xe0, 0x8e, 0x0, 0x1, 0xf7, + + /* U+0053 "S" */ + 0x3, 0xcf, 0xe8, 0x0, 0x2f, 0xb5, 0x7f, 0xa0, + 0x7f, 0x0, 0x7, 0xf0, 0x8e, 0x0, 0x0, 0x10, + 0x3f, 0x81, 0x0, 0x0, 0x7, 0xff, 0xc7, 0x0, + 0x0, 0x16, 0xbf, 0xb0, 0x0, 0x0, 0x5, 0xf3, + 0x43, 0x0, 0x0, 0xf6, 0xbc, 0x0, 0x2, 0xf4, + 0x4f, 0xa5, 0x6d, 0xd0, 0x4, 0xcf, 0xea, 0x10, + + /* U+0054 "T" */ + 0x2f, 0xff, 0xff, 0xff, 0xb0, 0x55, 0x5f, 0xa5, + 0x53, 0x0, 0x0, 0xe8, 0x0, 0x0, 0x0, 0xe, + 0x80, 0x0, 0x0, 0x0, 0xe8, 0x0, 0x0, 0x0, + 0xe, 0x80, 0x0, 0x0, 0x0, 0xe8, 0x0, 0x0, + 0x0, 0xe, 0x80, 0x0, 0x0, 0x0, 0xe8, 0x0, + 0x0, 0x0, 0xe, 0x80, 0x0, 0x0, 0x0, 0xe8, + 0x0, 0x0, 0x0, 0xe, 0x80, 0x0, + + /* U+0055 "U" */ + 0x9e, 0x0, 0x4, 0xf2, 0x9e, 0x0, 0x4, 0xf2, + 0x9e, 0x0, 0x4, 0xf2, 0x9e, 0x0, 0x4, 0xf2, + 0x9e, 0x0, 0x4, 0xf2, 0x9e, 0x0, 0x4, 0xf2, + 0x9e, 0x0, 0x4, 0xf2, 0x9e, 0x0, 0x4, 0xf2, + 0x8e, 0x0, 0x4, 0xf2, 0x6f, 0x10, 0x7, 0xf0, + 0x1f, 0xb5, 0x6e, 0xa0, 0x3, 0xcf, 0xe9, 0x0, + + /* U+0056 "V" */ + 0x1f, 0x60, 0x0, 0xc, 0xa0, 0xda, 0x0, 0x0, + 0xf6, 0x9, 0xe0, 0x0, 0x4f, 0x20, 0x5f, 0x10, + 0x8, 0xe0, 0x1, 0xf5, 0x0, 0xca, 0x0, 0xd, + 0x90, 0xf, 0x60, 0x0, 0x9d, 0x3, 0xf2, 0x0, + 0x5, 0xf1, 0x7e, 0x0, 0x0, 0x1f, 0x5b, 0xa0, + 0x0, 0x0, 0xd8, 0xe6, 0x0, 0x0, 0x9, 0xdf, + 0x20, 0x0, 0x0, 0x5f, 0xe0, 0x0, + + /* U+0057 "W" */ + 0xab, 0x0, 0xfa, 0x0, 0xf3, 0x8c, 0x2, 0xec, + 0x2, 0xf1, 0x6e, 0x4, 0xce, 0x4, 0xf0, 0x4f, + 0x6, 0x9f, 0x5, 0xd0, 0x2f, 0x18, 0x7d, 0x27, + 0xb0, 0xf, 0x3a, 0x5b, 0x49, 0xa0, 0xe, 0x5c, + 0x39, 0x6a, 0x80, 0xd, 0x6e, 0x17, 0x8c, 0x60, + 0xb, 0x9f, 0x5, 0xae, 0x40, 0x9, 0xcd, 0x4, + 0xbf, 0x20, 0x7, 0xfb, 0x2, 0xef, 0x0, 0x5, + 0xf9, 0x0, 0xfe, 0x0, + + /* U+0058 "X" */ + 0xe, 0xb0, 0x0, 0x1f, 0x80, 0x6f, 0x30, 0x9, + 0xe0, 0x0, 0xdc, 0x1, 0xf6, 0x0, 0x4, 0xf4, + 0x9d, 0x0, 0x0, 0xc, 0xcf, 0x50, 0x0, 0x0, + 0x3f, 0xc0, 0x0, 0x0, 0x5, 0xfe, 0x0, 0x0, + 0x0, 0xda, 0xf8, 0x0, 0x0, 0x6f, 0x18, 0xf1, + 0x0, 0xe, 0x80, 0x1e, 0x90, 0x8, 0xf1, 0x0, + 0x7f, 0x21, 0xf7, 0x0, 0x0, 0xea, + + /* U+0059 "Y" */ + 0x3f, 0x50, 0x0, 0xa, 0xc0, 0xb, 0xc0, 0x0, + 0x2f, 0x50, 0x4, 0xf4, 0x0, 0x9d, 0x0, 0x0, + 0xcb, 0x1, 0xf6, 0x0, 0x0, 0x5f, 0x28, 0xe0, + 0x0, 0x0, 0xd, 0xae, 0x70, 0x0, 0x0, 0x6, + 0xff, 0x0, 0x0, 0x0, 0x0, 0xf9, 0x0, 0x0, + 0x0, 0x0, 0xe8, 0x0, 0x0, 0x0, 0x0, 0xe8, + 0x0, 0x0, 0x0, 0x0, 0xe8, 0x0, 0x0, 0x0, + 0x0, 0xe8, 0x0, 0x0, + + /* U+005A "Z" */ + 0x9f, 0xff, 0xff, 0xf1, 0x25, 0x55, 0x5b, 0xf0, + 0x0, 0x0, 0x1f, 0x70, 0x0, 0x0, 0x9d, 0x0, + 0x0, 0x3, 0xf5, 0x0, 0x0, 0xc, 0xc0, 0x0, + 0x0, 0x5f, 0x30, 0x0, 0x0, 0xda, 0x0, 0x0, + 0x7, 0xf1, 0x0, 0x0, 0x1f, 0x70, 0x0, 0x0, + 0x8f, 0x55, 0x55, 0x51, 0xaf, 0xff, 0xff, 0xf3, + + /* U+005B "[" */ + 0x0, 0x0, 0xb, 0xff, 0xf3, 0xbc, 0x33, 0xb, + 0xb0, 0x0, 0xbb, 0x0, 0xb, 0xb0, 0x0, 0xbb, + 0x0, 0xb, 0xb0, 0x0, 0xbb, 0x0, 0xb, 0xb0, + 0x0, 0xbb, 0x0, 0xb, 0xb0, 0x0, 0xbb, 0x0, + 0xb, 0xb0, 0x0, 0xbb, 0x0, 0xb, 0xff, 0xf3, + 0x23, 0x33, 0x0, + + /* U+005C "\\" */ + 0x9e, 0x0, 0x0, 0x0, 0x3f, 0x40, 0x0, 0x0, + 0xd, 0xa0, 0x0, 0x0, 0x7, 0xf1, 0x0, 0x0, + 0x1, 0xf6, 0x0, 0x0, 0x0, 0xbc, 0x0, 0x0, + 0x0, 0x5f, 0x20, 0x0, 0x0, 0xe, 0x80, 0x0, + 0x0, 0x9, 0xe0, 0x0, 0x0, 0x3, 0xf5, 0x0, + 0x0, 0x0, 0xdb, 0x0, 0x0, 0x0, 0x7f, 0x10, + 0x0, 0x0, 0x1f, 0x70, 0x0, 0x0, 0xb, 0xd0, + 0x0, 0x0, 0x5, 0xf3, + + /* U+005D "]" */ + 0x0, 0x0, 0x9, 0xff, 0xf5, 0x23, 0x5f, 0x50, + 0x2, 0xf5, 0x0, 0x2f, 0x50, 0x2, 0xf5, 0x0, + 0x2f, 0x50, 0x2, 0xf5, 0x0, 0x2f, 0x50, 0x2, + 0xf5, 0x0, 0x2f, 0x50, 0x2, 0xf5, 0x0, 0x2f, + 0x50, 0x2, 0xf5, 0x0, 0x2f, 0x59, 0xff, 0xf5, + 0x23, 0x33, 0x10, + + /* U+005E "^" */ + 0x0, 0x7, 0x40, 0x0, 0x0, 0x4f, 0xe0, 0x0, + 0x0, 0xb7, 0xd5, 0x0, 0x2, 0xf1, 0x6c, 0x0, + 0x9, 0xa0, 0xf, 0x30, 0x1f, 0x30, 0x9, 0xa0, + 0x8c, 0x0, 0x2, 0xf1, + + /* U+005F "_" */ + 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, + 0xfa, 0x3, 0x33, 0x33, 0x33, 0x10, + + /* U+0060 "`" */ + 0x18, 0x20, 0xa, 0xd0, 0x0, 0xd9, + + /* U+0061 "a" */ + 0x5, 0xdf, 0xea, 0x10, 0x4f, 0x84, 0x5d, 0xc0, + 0x1, 0x0, 0x5, 0xf0, 0x8, 0xef, 0xff, 0xf2, + 0x8f, 0x52, 0x26, 0xf2, 0xda, 0x0, 0x5, 0xf2, + 0xda, 0x0, 0x8, 0xf2, 0x8f, 0x74, 0x7d, 0xf2, + 0x9, 0xef, 0xa5, 0xf2, + + /* U+0062 "b" */ + 0x8e, 0x0, 0x0, 0x0, 0x8e, 0x0, 0x0, 0x0, + 0x8e, 0x0, 0x0, 0x0, 0x8e, 0x5d, 0xfb, 0x10, + 0x8e, 0xb4, 0x6e, 0xc0, 0x8f, 0x10, 0x5, 0xf1, + 0x8e, 0x0, 0x3, 0xf3, 0x8e, 0x0, 0x3, 0xf3, + 0x8e, 0x0, 0x3, 0xf3, 0x8f, 0x10, 0x5, 0xf1, + 0x8e, 0xb4, 0x5e, 0xc0, 0x8e, 0x5d, 0xfb, 0x20, + + /* U+0063 "c" */ + 0x3, 0xbe, 0xea, 0x10, 0x1f, 0xc5, 0x6d, 0xd0, + 0x7f, 0x0, 0x3, 0xf4, 0x9d, 0x0, 0x0, 0x0, + 0x9d, 0x0, 0x0, 0x0, 0x9d, 0x0, 0x0, 0x0, + 0x7f, 0x0, 0x3, 0xf4, 0x1f, 0xc5, 0x6d, 0xd0, + 0x3, 0xbe, 0xea, 0x20, + + /* U+0064 "d" */ + 0x0, 0x0, 0x5, 0xf2, 0x0, 0x0, 0x5, 0xf2, + 0x0, 0x0, 0x4, 0xf2, 0x5, 0xdf, 0xb6, 0xf2, + 0x3f, 0xa4, 0x6d, 0xf2, 0x8f, 0x0, 0x7, 0xf2, + 0x9d, 0x0, 0x5, 0xf2, 0x9d, 0x0, 0x5, 0xf2, + 0x9d, 0x0, 0x5, 0xf2, 0x8f, 0x0, 0x7, 0xf2, + 0x3f, 0xa4, 0x6d, 0xf2, 0x5, 0xdf, 0xb6, 0xf2, + + /* U+0065 "e" */ + 0x3, 0xbf, 0xe9, 0x0, 0x2f, 0xa3, 0x5e, 0xa0, + 0x7e, 0x0, 0x5, 0xf1, 0xac, 0x0, 0x2, 0xf3, + 0xaf, 0xff, 0xff, 0xf4, 0xac, 0x22, 0x22, 0x20, + 0x7e, 0x0, 0x1, 0x40, 0x2f, 0xa4, 0x5c, 0xd0, + 0x3, 0xcf, 0xea, 0x10, + + /* U+0066 "f" */ + 0x0, 0x0, 0xaf, 0xff, 0x70, 0x0, 0x6f, 0x65, + 0x52, 0x0, 0x8, 0xe0, 0x0, 0x0, 0x11, 0x9e, + 0x11, 0x10, 0x2f, 0xff, 0xff, 0xff, 0x70, 0x44, + 0xae, 0x44, 0x41, 0x0, 0x9, 0xe0, 0x0, 0x0, + 0x0, 0x9e, 0x0, 0x0, 0x0, 0x9, 0xe0, 0x0, + 0x0, 0x0, 0x9e, 0x0, 0x0, 0x0, 0x9, 0xe0, + 0x0, 0x0, 0x0, 0x9e, 0x0, 0x0, + + /* U+0067 "g" */ + 0x5, 0xdf, 0xb6, 0xf1, 0x3f, 0xb4, 0x6d, 0xf1, + 0x7f, 0x0, 0x7, 0xf1, 0x9d, 0x0, 0x5, 0xf1, + 0x9d, 0x0, 0x5, 0xf1, 0x8e, 0x0, 0x6, 0xf1, + 0x4f, 0x70, 0x2c, 0xf1, 0x8, 0xff, 0xe8, 0xf1, + 0x0, 0x2, 0x5, 0xf1, 0x0, 0x0, 0x6, 0xf0, + 0x2, 0x55, 0x6e, 0xb0, 0x6, 0xff, 0xea, 0x10, + + /* U+0068 "h" */ + 0x8e, 0x0, 0x0, 0x0, 0x8e, 0x0, 0x0, 0x0, + 0x8e, 0x0, 0x0, 0x0, 0x8e, 0x5d, 0xfb, 0x10, + 0x8e, 0xb4, 0x5e, 0xc0, 0x8f, 0x10, 0x6, 0xf1, + 0x8e, 0x0, 0x4, 0xf2, 0x8e, 0x0, 0x4, 0xf2, + 0x8e, 0x0, 0x4, 0xf2, 0x8e, 0x0, 0x4, 0xf2, + 0x8e, 0x0, 0x4, 0xf2, 0x8e, 0x0, 0x4, 0xf2, + + /* U+0069 "i" */ + 0x0, 0xd, 0xd0, 0x0, 0x0, 0xe, 0xe1, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x5f, 0xff, 0xe0, 0x0, 0x15, 0x5a, 0xe0, 0x0, + 0x0, 0x8, 0xe0, 0x0, 0x0, 0x8, 0xe0, 0x0, + 0x0, 0x8, 0xe0, 0x0, 0x0, 0x8, 0xe0, 0x0, + 0x0, 0x8, 0xe0, 0x0, 0x35, 0x5a, 0xf5, 0x54, + 0xaf, 0xff, 0xff, 0xfe, + + /* U+006A "j" */ + 0x0, 0x0, 0xce, 0x10, 0x0, 0xd, 0xf1, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xaf, 0xff, + 0xff, 0x3, 0x55, 0x5a, 0xf0, 0x0, 0x0, 0x7f, + 0x0, 0x0, 0x7, 0xf0, 0x0, 0x0, 0x7f, 0x0, + 0x0, 0x7, 0xf0, 0x0, 0x0, 0x7f, 0x0, 0x0, + 0x7, 0xf0, 0x0, 0x0, 0x8e, 0x0, 0x0, 0xb, + 0xc0, 0x25, 0x59, 0xf5, 0x9, 0xff, 0xd6, 0x0, + + /* U+006B "k" */ + 0x7f, 0x0, 0x0, 0x0, 0x7f, 0x0, 0x0, 0x0, + 0x7f, 0x0, 0x0, 0x0, 0x7f, 0x0, 0x2, 0xf7, + 0x7f, 0x0, 0xc, 0xd0, 0x7f, 0x0, 0x6f, 0x30, + 0x7f, 0x1, 0xf9, 0x0, 0x7f, 0xff, 0xf1, 0x0, + 0x7f, 0x34, 0xf9, 0x0, 0x7f, 0x0, 0x6f, 0x40, + 0x7f, 0x0, 0xb, 0xe0, 0x7f, 0x0, 0x2, 0xf9, + + /* U+006C "l" */ + 0x8f, 0xff, 0xf0, 0x0, 0x2, 0x55, 0xaf, 0x0, + 0x0, 0x0, 0x7, 0xf0, 0x0, 0x0, 0x0, 0x7f, + 0x0, 0x0, 0x0, 0x7, 0xf0, 0x0, 0x0, 0x0, + 0x7f, 0x0, 0x0, 0x0, 0x7, 0xf0, 0x0, 0x0, + 0x0, 0x7f, 0x0, 0x0, 0x0, 0x7, 0xf0, 0x0, + 0x0, 0x0, 0x7f, 0x0, 0x0, 0x0, 0x4, 0xf8, + 0x55, 0x30, 0x0, 0x7, 0xef, 0xfc, + + /* U+006D "m" */ + 0xf, 0x9f, 0xb6, 0xec, 0x10, 0xf8, 0x1f, 0x90, + 0xd8, 0xf, 0x40, 0xc6, 0xb, 0xa0, 0xf4, 0xc, + 0x60, 0xba, 0xf, 0x40, 0xc6, 0xb, 0xa0, 0xf4, + 0xc, 0x60, 0xba, 0xf, 0x40, 0xc6, 0xb, 0xa0, + 0xf4, 0xc, 0x60, 0xba, 0xf, 0x40, 0xc6, 0xb, + 0xa0, + + /* U+006E "n" */ + 0x8e, 0x5e, 0xfb, 0x10, 0x8f, 0x92, 0x3d, 0xc0, + 0x8f, 0x0, 0x6, 0xf1, 0x8e, 0x0, 0x4, 0xf2, + 0x8e, 0x0, 0x4, 0xf2, 0x8e, 0x0, 0x4, 0xf2, + 0x8e, 0x0, 0x4, 0xf2, 0x8e, 0x0, 0x4, 0xf2, + 0x8e, 0x0, 0x4, 0xf2, + + /* U+006F "o" */ + 0x3, 0xcf, 0xe9, 0x0, 0x2f, 0xb5, 0x6e, 0xb0, + 0x8e, 0x0, 0x5, 0xf1, 0xac, 0x0, 0x3, 0xf3, + 0xac, 0x0, 0x3, 0xf4, 0xac, 0x0, 0x3, 0xf3, + 0x7e, 0x0, 0x5, 0xf1, 0x2f, 0xb5, 0x6e, 0xa0, + 0x3, 0xcf, 0xe9, 0x0, + + /* U+0070 "p" */ + 0x8e, 0x5d, 0xfb, 0x20, 0x8f, 0x92, 0x3d, 0xc0, + 0x8f, 0x0, 0x5, 0xf1, 0x8e, 0x0, 0x3, 0xf3, + 0x8e, 0x0, 0x3, 0xf3, 0x8e, 0x0, 0x3, 0xf3, + 0x8f, 0x10, 0x6, 0xf1, 0x8e, 0xb5, 0x6e, 0xc0, + 0x8e, 0x4d, 0xfb, 0x20, 0x8e, 0x0, 0x0, 0x0, + 0x8e, 0x0, 0x0, 0x0, 0x8e, 0x0, 0x0, 0x0, + + /* U+0071 "q" */ + 0x5, 0xdf, 0xb6, 0xf2, 0x3f, 0xa4, 0x6d, 0xf2, + 0x8e, 0x0, 0x7, 0xf2, 0x9d, 0x0, 0x5, 0xf2, + 0x9d, 0x0, 0x5, 0xf2, 0x9d, 0x0, 0x5, 0xf2, + 0x8e, 0x0, 0x7, 0xf2, 0x3f, 0xa4, 0x6c, 0xf2, + 0x5, 0xdf, 0xb6, 0xf2, 0x0, 0x0, 0x4, 0xf2, + 0x0, 0x0, 0x5, 0xf2, 0x0, 0x0, 0x5, 0xf2, + + /* U+0072 "r" */ + 0x3f, 0x6c, 0xfd, 0x50, 0x3f, 0xb3, 0x29, 0xf2, + 0x3f, 0x50, 0x0, 0xf6, 0x3f, 0x30, 0x0, 0xc6, + 0x3f, 0x30, 0x0, 0x0, 0x3f, 0x30, 0x0, 0x0, + 0x3f, 0x30, 0x0, 0x0, 0x3f, 0x30, 0x0, 0x0, + 0x3f, 0x30, 0x0, 0x0, + + /* U+0073 "s" */ + 0x6, 0xdf, 0xfb, 0x20, 0x4f, 0x73, 0x4c, 0xd0, + 0x7e, 0x0, 0x1, 0x40, 0x4f, 0xa6, 0x30, 0x0, + 0x6, 0xcf, 0xff, 0x70, 0x0, 0x0, 0x19, 0xf1, + 0x57, 0x0, 0x3, 0xf3, 0x6f, 0x74, 0x4b, 0xe0, + 0x8, 0xef, 0xfc, 0x30, + + /* U+0074 "t" */ + 0x0, 0x5, 0x50, 0x0, 0x0, 0x0, 0xbb, 0x0, + 0x0, 0x0, 0xb, 0xb0, 0x0, 0x4, 0xff, 0xff, + 0xff, 0xf5, 0x15, 0x5c, 0xc5, 0x55, 0x10, 0x0, + 0xbb, 0x0, 0x0, 0x0, 0xb, 0xb0, 0x0, 0x0, + 0x0, 0xbb, 0x0, 0x0, 0x0, 0xb, 0xb0, 0x0, + 0x0, 0x0, 0xbb, 0x0, 0x0, 0x0, 0x8, 0xf6, + 0x55, 0x10, 0x0, 0x1b, 0xff, 0xf3, + + /* U+0075 "u" */ + 0x9e, 0x0, 0x4, 0xf2, 0x9e, 0x0, 0x4, 0xf2, + 0x9e, 0x0, 0x4, 0xf2, 0x9e, 0x0, 0x4, 0xf2, + 0x9e, 0x0, 0x4, 0xf2, 0x8e, 0x0, 0x4, 0xf2, + 0x6f, 0x10, 0x7, 0xf0, 0x1e, 0xc5, 0x6f, 0x90, + 0x3, 0xbf, 0xe8, 0x0, + + /* U+0076 "v" */ + 0xf, 0x90, 0x0, 0xe, 0x90, 0xae, 0x0, 0x4, + 0xf3, 0x4, 0xf3, 0x0, 0x9e, 0x0, 0xf, 0x80, + 0xe, 0x90, 0x0, 0xad, 0x3, 0xf3, 0x0, 0x4, + 0xf2, 0x8e, 0x0, 0x0, 0xf, 0x7d, 0x90, 0x0, + 0x0, 0xad, 0xf3, 0x0, 0x0, 0x4, 0xfe, 0x0, + 0x0, + + /* U+0077 "w" */ + 0x6d, 0x0, 0xf9, 0x2, 0xf0, 0x4f, 0x2, 0xec, + 0x4, 0xd0, 0x1f, 0x15, 0xaf, 0x7, 0xa0, 0xf, + 0x38, 0x7d, 0x29, 0x80, 0xc, 0x6b, 0x4b, 0x4b, + 0x50, 0x9, 0x8e, 0x18, 0x7e, 0x20, 0x7, 0xbf, + 0x6, 0xaf, 0x0, 0x4, 0xec, 0x3, 0xed, 0x0, + 0x2, 0xf9, 0x1, 0xfa, 0x0, + + /* U+0078 "x" */ + 0xa, 0xe1, 0x0, 0x6f, 0x40, 0x1e, 0xa0, 0x1e, + 0xa0, 0x0, 0x5f, 0x4a, 0xe1, 0x0, 0x0, 0xad, + 0xf4, 0x0, 0x0, 0x4, 0xfd, 0x0, 0x0, 0x0, + 0xdc, 0xf7, 0x0, 0x0, 0x8f, 0x28, 0xf2, 0x0, + 0x3f, 0x70, 0xd, 0xc0, 0xd, 0xc0, 0x0, 0x3f, + 0x70, + + /* U+0079 "y" */ + 0xe, 0x90, 0x0, 0xe, 0x80, 0x8f, 0x0, 0x4, + 0xf2, 0x2, 0xf5, 0x0, 0xad, 0x0, 0xc, 0xb0, + 0xf, 0x70, 0x0, 0x6f, 0x15, 0xf1, 0x0, 0x0, + 0xf7, 0xab, 0x0, 0x0, 0xa, 0xdf, 0x50, 0x0, + 0x0, 0x3f, 0xf0, 0x0, 0x0, 0x0, 0xfa, 0x0, + 0x0, 0x0, 0x3f, 0x40, 0x0, 0x0, 0x9, 0xe0, + 0x0, 0x0, 0x0, 0xf8, 0x0, 0x0, + + /* U+007A "z" */ + 0x7f, 0xff, 0xff, 0xf0, 0x25, 0x55, 0x5e, 0xd0, + 0x0, 0x0, 0x9f, 0x20, 0x0, 0x5, 0xf5, 0x0, + 0x0, 0x2f, 0x80, 0x0, 0x1, 0xdb, 0x0, 0x0, + 0xb, 0xd0, 0x0, 0x0, 0x7f, 0x75, 0x55, 0x50, + 0x9f, 0xff, 0xff, 0xf2, + + /* U+007B "{" */ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8e, 0xf1, + 0x0, 0x6, 0xf7, 0x30, 0x0, 0x9, 0xd0, 0x0, + 0x0, 0x8, 0xe0, 0x0, 0x0, 0x6, 0xf0, 0x0, + 0x0, 0x5, 0xf0, 0x0, 0x0, 0x1a, 0xc0, 0x0, + 0xcf, 0xfb, 0x10, 0x0, 0x23, 0x4c, 0xa0, 0x0, + 0x0, 0x6, 0xf0, 0x0, 0x0, 0x6, 0xf0, 0x0, + 0x0, 0x8, 0xe0, 0x0, 0x0, 0x9, 0xd0, 0x0, + 0x0, 0x7, 0xf4, 0x0, 0x0, 0x0, 0xbf, 0xf1, + 0x0, 0x0, 0x1, 0x30, + + /* U+007C "|" */ + 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, + 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, + + /* U+007D "}" */ + 0x0, 0x0, 0x0, 0x0, 0x7f, 0xd4, 0x0, 0x0, + 0x14, 0xbf, 0x10, 0x0, 0x0, 0x4f, 0x30, 0x0, + 0x0, 0x5f, 0x10, 0x0, 0x0, 0x8e, 0x0, 0x0, + 0x0, 0xac, 0x0, 0x0, 0x0, 0x7e, 0x30, 0x0, + 0x0, 0xa, 0xff, 0xf6, 0x0, 0x6f, 0x63, 0x31, + 0x0, 0xac, 0x0, 0x0, 0x0, 0x8e, 0x0, 0x0, + 0x0, 0x6f, 0x0, 0x0, 0x0, 0x4f, 0x20, 0x0, + 0x1, 0x9f, 0x20, 0x0, 0x7f, 0xf7, 0x0, 0x0, + 0x13, 0x0, 0x0, 0x0, + + /* U+007E "~" */ + 0x3d, 0xe8, 0x0, 0xe7, 0xcb, 0x5e, 0x81, 0xf6, + 0xd7, 0x4, 0xff, 0xd1, 0x21, 0x0, 0x2, 0x0 +}; + + +/*--------------------- + * GLYPH DESCRIPTION + *--------------------*/ + +static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = { + {.bitmap_index = 0, .adv_w = 0, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0} /* id = 0 reserved */, + {.bitmap_index = 0, .adv_w = 154, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 0, .adv_w = 154, .box_w = 3, .box_h = 12, .ofs_x = 3, .ofs_y = 0}, + {.bitmap_index = 18, .adv_w = 154, .box_w = 6, .box_h = 5, .ofs_x = 2, .ofs_y = 7}, + {.bitmap_index = 33, .adv_w = 154, .box_w = 10, .box_h = 12, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 93, .adv_w = 154, .box_w = 8, .box_h = 17, .ofs_x = 1, .ofs_y = -2}, + {.bitmap_index = 161, .adv_w = 154, .box_w = 10, .box_h = 12, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 221, .adv_w = 154, .box_w = 10, .box_h = 12, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 281, .adv_w = 154, .box_w = 3, .box_h = 5, .ofs_x = 3, .ofs_y = 7}, + {.bitmap_index = 289, .adv_w = 154, .box_w = 6, .box_h = 16, .ofs_x = 2, .ofs_y = -2}, + {.bitmap_index = 337, .adv_w = 154, .box_w = 6, .box_h = 16, .ofs_x = 1, .ofs_y = -2}, + {.bitmap_index = 385, .adv_w = 154, .box_w = 10, .box_h = 9, .ofs_x = 0, .ofs_y = 1}, + {.bitmap_index = 430, .adv_w = 154, .box_w = 8, .box_h = 8, .ofs_x = 1, .ofs_y = 1}, + {.bitmap_index = 462, .adv_w = 154, .box_w = 3, .box_h = 5, .ofs_x = 3, .ofs_y = -3}, + {.bitmap_index = 470, .adv_w = 154, .box_w = 6, .box_h = 3, .ofs_x = 2, .ofs_y = 4}, + {.bitmap_index = 479, .adv_w = 154, .box_w = 4, .box_h = 3, .ofs_x = 3, .ofs_y = 0}, + {.bitmap_index = 485, .adv_w = 154, .box_w = 8, .box_h = 15, .ofs_x = 1, .ofs_y = -2}, + {.bitmap_index = 545, .adv_w = 154, .box_w = 8, .box_h = 12, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 593, .adv_w = 154, .box_w = 8, .box_h = 12, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 641, .adv_w = 154, .box_w = 8, .box_h = 12, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 689, .adv_w = 154, .box_w = 8, .box_h = 12, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 737, .adv_w = 154, .box_w = 7, .box_h = 12, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 779, .adv_w = 154, .box_w = 8, .box_h = 12, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 827, .adv_w = 154, .box_w = 8, .box_h = 12, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 875, .adv_w = 154, .box_w = 8, .box_h = 12, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 923, .adv_w = 154, .box_w = 8, .box_h = 12, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 971, .adv_w = 154, .box_w = 8, .box_h = 12, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1019, .adv_w = 154, .box_w = 4, .box_h = 9, .ofs_x = 3, .ofs_y = 0}, + {.bitmap_index = 1037, .adv_w = 154, .box_w = 4, .box_h = 12, .ofs_x = 3, .ofs_y = -3}, + {.bitmap_index = 1061, .adv_w = 154, .box_w = 8, .box_h = 9, .ofs_x = 1, .ofs_y = 1}, + {.bitmap_index = 1097, .adv_w = 154, .box_w = 8, .box_h = 7, .ofs_x = 1, .ofs_y = 2}, + {.bitmap_index = 1125, .adv_w = 154, .box_w = 8, .box_h = 9, .ofs_x = 1, .ofs_y = 1}, + {.bitmap_index = 1161, .adv_w = 154, .box_w = 6, .box_h = 12, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 1197, .adv_w = 154, .box_w = 9, .box_h = 15, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 1265, .adv_w = 154, .box_w = 9, .box_h = 12, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1319, .adv_w = 154, .box_w = 8, .box_h = 12, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1367, .adv_w = 154, .box_w = 8, .box_h = 12, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1415, .adv_w = 154, .box_w = 8, .box_h = 12, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1463, .adv_w = 154, .box_w = 8, .box_h = 12, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1511, .adv_w = 154, .box_w = 8, .box_h = 12, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1559, .adv_w = 154, .box_w = 8, .box_h = 12, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1607, .adv_w = 154, .box_w = 8, .box_h = 12, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1655, .adv_w = 154, .box_w = 7, .box_h = 12, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1697, .adv_w = 154, .box_w = 8, .box_h = 12, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1745, .adv_w = 154, .box_w = 8, .box_h = 12, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1793, .adv_w = 154, .box_w = 7, .box_h = 12, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 1835, .adv_w = 154, .box_w = 8, .box_h = 12, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1883, .adv_w = 154, .box_w = 8, .box_h = 12, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1931, .adv_w = 154, .box_w = 8, .box_h = 12, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1979, .adv_w = 154, .box_w = 8, .box_h = 12, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 2027, .adv_w = 154, .box_w = 8, .box_h = 15, .ofs_x = 1, .ofs_y = -3}, + {.bitmap_index = 2087, .adv_w = 154, .box_w = 8, .box_h = 12, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 2135, .adv_w = 154, .box_w = 8, .box_h = 12, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 2183, .adv_w = 154, .box_w = 9, .box_h = 12, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 2237, .adv_w = 154, .box_w = 8, .box_h = 12, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 2285, .adv_w = 154, .box_w = 9, .box_h = 12, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 2339, .adv_w = 154, .box_w = 10, .box_h = 12, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 2399, .adv_w = 154, .box_w = 9, .box_h = 12, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 2453, .adv_w = 154, .box_w = 10, .box_h = 12, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 2513, .adv_w = 154, .box_w = 8, .box_h = 12, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 2561, .adv_w = 154, .box_w = 5, .box_h = 17, .ofs_x = 3, .ofs_y = -3}, + {.bitmap_index = 2604, .adv_w = 154, .box_w = 8, .box_h = 15, .ofs_x = 1, .ofs_y = -2}, + {.bitmap_index = 2664, .adv_w = 154, .box_w = 5, .box_h = 17, .ofs_x = 2, .ofs_y = -3}, + {.bitmap_index = 2707, .adv_w = 154, .box_w = 8, .box_h = 7, .ofs_x = 1, .ofs_y = 5}, + {.bitmap_index = 2735, .adv_w = 154, .box_w = 9, .box_h = 3, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 2749, .adv_w = 154, .box_w = 4, .box_h = 3, .ofs_x = 2, .ofs_y = 10}, + {.bitmap_index = 2755, .adv_w = 154, .box_w = 8, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 2791, .adv_w = 154, .box_w = 8, .box_h = 12, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 2839, .adv_w = 154, .box_w = 8, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 2875, .adv_w = 154, .box_w = 8, .box_h = 12, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 2923, .adv_w = 154, .box_w = 8, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 2959, .adv_w = 154, .box_w = 9, .box_h = 12, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 3013, .adv_w = 154, .box_w = 8, .box_h = 12, .ofs_x = 1, .ofs_y = -3}, + {.bitmap_index = 3061, .adv_w = 154, .box_w = 8, .box_h = 12, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 3109, .adv_w = 154, .box_w = 8, .box_h = 13, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 3161, .adv_w = 154, .box_w = 7, .box_h = 16, .ofs_x = 1, .ofs_y = -3}, + {.bitmap_index = 3217, .adv_w = 154, .box_w = 8, .box_h = 12, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 3265, .adv_w = 154, .box_w = 9, .box_h = 12, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 3319, .adv_w = 154, .box_w = 9, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 3360, .adv_w = 154, .box_w = 8, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 3396, .adv_w = 154, .box_w = 8, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 3432, .adv_w = 154, .box_w = 8, .box_h = 12, .ofs_x = 1, .ofs_y = -3}, + {.bitmap_index = 3480, .adv_w = 154, .box_w = 8, .box_h = 12, .ofs_x = 1, .ofs_y = -3}, + {.bitmap_index = 3528, .adv_w = 154, .box_w = 8, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 3564, .adv_w = 154, .box_w = 8, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 3600, .adv_w = 154, .box_w = 9, .box_h = 12, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 3654, .adv_w = 154, .box_w = 8, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 3690, .adv_w = 154, .box_w = 9, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 3731, .adv_w = 154, .box_w = 10, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 3776, .adv_w = 154, .box_w = 9, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 3817, .adv_w = 154, .box_w = 9, .box_h = 12, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 3871, .adv_w = 154, .box_w = 8, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 3907, .adv_w = 154, .box_w = 8, .box_h = 17, .ofs_x = 1, .ofs_y = -3}, + {.bitmap_index = 3975, .adv_w = 154, .box_w = 2, .box_h = 15, .ofs_x = 4, .ofs_y = -2}, + {.bitmap_index = 3990, .adv_w = 154, .box_w = 8, .box_h = 17, .ofs_x = 1, .ofs_y = -3}, + {.bitmap_index = 4058, .adv_w = 154, .box_w = 8, .box_h = 4, .ofs_x = 1, .ofs_y = 3} +}; + +/*--------------------- + * CHARACTER MAPPING + *--------------------*/ + + + +/*Collect the unicode lists and glyph_id offsets*/ +static const lv_font_fmt_txt_cmap_t cmaps[] = +{ + { + .range_start = 32, .range_length = 95, .glyph_id_start = 1, + .unicode_list = NULL, .glyph_id_ofs_list = NULL, .list_length = 0, .type = LV_FONT_FMT_TXT_CMAP_FORMAT0_TINY + } +}; + + + +/*-------------------- + * ALL CUSTOM DATA + *--------------------*/ + +#if LVGL_VERSION_MAJOR == 8 +/*Store all the custom data of the font*/ +static lv_font_fmt_txt_glyph_cache_t cache; +#endif + +#if LVGL_VERSION_MAJOR >= 8 +static const lv_font_fmt_txt_dsc_t font_dsc = { +#else +static lv_font_fmt_txt_dsc_t font_dsc = { +#endif + .glyph_bitmap = glyph_bitmap, + .glyph_dsc = glyph_dsc, + .cmaps = cmaps, + .kern_dsc = NULL, + .kern_scale = 0, + .cmap_num = 1, + .bpp = 4, + .kern_classes = 0, + .bitmap_format = 0, +#if LVGL_VERSION_MAJOR == 8 + .cache = &cache +#endif +}; + + +/*----------------- + * PUBLIC FONT + *----------------*/ + +/*Initialize a public general font descriptor*/ +#if LVGL_VERSION_MAJOR >= 8 +const lv_font_t JetBrainsMono16 = { +#else +lv_font_t JetBrainsMono16 = { +#endif + .get_glyph_dsc = lv_font_get_glyph_dsc_fmt_txt, /*Function pointer to get glyph's data*/ + .get_glyph_bitmap = lv_font_get_bitmap_fmt_txt, /*Function pointer to get glyph's bitmap*/ + .line_height = 18, /*The maximum line height required by the font*/ + .base_line = 3, /*Baseline measured from the bottom of the line*/ +#if !(LVGL_VERSION_MAJOR == 6 && LVGL_VERSION_MINOR == 0) + .subpx = LV_FONT_SUBPX_NONE, +#endif +#if LV_VERSION_CHECK(7, 4, 0) || LVGL_VERSION_MAJOR >= 8 + .underline_position = -2, + .underline_thickness = 1, +#endif + .dsc = &font_dsc, /*The custom font data. Will be accessed by `get_glyph_bitmap/dsc` */ + .fallback = NULL, + .user_data = NULL +}; + + + +#endif /*#if JETBRAINSMONO16*/ + diff --git a/device/src/keyboard/oled/fonts/jet_brains_mono_24.c b/device/src/keyboard/oled/fonts/jet_brains_mono_24.c new file mode 100644 index 000000000..62e5aeda9 --- /dev/null +++ b/device/src/keyboard/oled/fonts/jet_brains_mono_24.c @@ -0,0 +1,1527 @@ +/******************************************************************************* + * Size: 24 px + * Bpp: 4 + * Opts: + ******************************************************************************/ + +#ifdef LV_LVGL_H_INCLUDE_SIMPLE +#include "lvgl.h" +#else +#include "lvgl/lvgl.h" +#endif + +#ifndef JETBRAINSMONO24 +#define JETBRAINSMONO24 1 +#endif + +#if JETBRAINSMONO24 + +/*----------------- + * BITMAPS + *----------------*/ + +/*Store the image of the glyphs*/ +static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { + /* U+0020 " " */ + + /* U+0021 "!" */ + 0x1f, 0xf7, 0xf, 0xf6, 0xf, 0xf6, 0xf, 0xf6, + 0xf, 0xf5, 0xf, 0xf5, 0xe, 0xf5, 0xe, 0xf4, + 0xe, 0xf4, 0xd, 0xf4, 0xd, 0xf3, 0xd, 0xf3, + 0xb, 0xe2, 0x0, 0x0, 0x0, 0x0, 0x3e, 0xf9, + 0x8f, 0xff, 0x3e, 0xf8, + + /* U+0022 "\"" */ + 0x8f, 0xd0, 0x7, 0xff, 0x8f, 0xd0, 0x7, 0xfe, + 0x8f, 0xd0, 0x6, 0xfe, 0x7f, 0xc0, 0x6, 0xfe, + 0x7f, 0xc0, 0x5, 0xfd, 0x6f, 0xc0, 0x5, 0xfd, + 0x6f, 0xb0, 0x4, 0xfd, 0x38, 0x50, 0x2, 0x86, + + /* U+0023 "#" */ + 0x0, 0x0, 0xe, 0xc0, 0x0, 0x5f, 0x40, 0x0, + 0x0, 0x1f, 0x90, 0x0, 0x8f, 0x10, 0x0, 0x0, + 0x4f, 0x60, 0x0, 0xbe, 0x0, 0x0, 0x0, 0x7f, + 0x30, 0x0, 0xeb, 0x0, 0x0, 0x0, 0xaf, 0x0, + 0x1, 0xf8, 0x0, 0x5, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xf9, 0x3, 0xaa, 0xfd, 0xaa, 0xad, 0xfb, + 0xa5, 0x0, 0x2, 0xf8, 0x0, 0xa, 0xf0, 0x0, + 0x0, 0x5, 0xf5, 0x0, 0xd, 0xd0, 0x0, 0x0, + 0x8, 0xf2, 0x0, 0xf, 0xa0, 0x0, 0x0, 0xb, + 0xf0, 0x0, 0x3f, 0x70, 0x0, 0x2f, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xb0, 0x1a, 0xaf, 0xda, 0xaa, + 0xdf, 0xaa, 0x70, 0x0, 0x3f, 0x70, 0x0, 0xbf, + 0x0, 0x0, 0x0, 0x6f, 0x40, 0x0, 0xec, 0x0, + 0x0, 0x0, 0x9f, 0x10, 0x0, 0xf9, 0x0, 0x0, + 0x0, 0xce, 0x0, 0x3, 0xf7, 0x0, 0x0, 0x0, + 0xec, 0x0, 0x6, 0xf4, 0x0, 0x0, + + /* U+0024 "$" */ + 0x0, 0x0, 0x3, 0x80, 0x0, 0x0, 0x0, 0x0, + 0x6, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x6, 0xf0, + 0x0, 0x0, 0x0, 0x0, 0x6, 0xf0, 0x0, 0x0, + 0x0, 0x6, 0xdf, 0xff, 0xb2, 0x0, 0x0, 0x9f, + 0xff, 0xff, 0xff, 0x30, 0x4, 0xff, 0x87, 0xf3, + 0xcf, 0xd0, 0xa, 0xfa, 0x6, 0xf0, 0x1f, 0xf4, + 0xc, 0xf6, 0x6, 0xf0, 0xc, 0xf6, 0xb, 0xf8, + 0x6, 0xf0, 0x0, 0x0, 0x7, 0xfd, 0x6, 0xf0, + 0x0, 0x0, 0x1, 0xff, 0xc9, 0xf0, 0x0, 0x0, + 0x0, 0x4f, 0xff, 0xf9, 0x30, 0x0, 0x0, 0x2, + 0xaf, 0xff, 0xfa, 0x0, 0x0, 0x0, 0x6, 0xfb, + 0xff, 0xa0, 0x0, 0x0, 0x6, 0xf0, 0x5f, 0xf3, + 0x0, 0x0, 0x6, 0xf0, 0xb, 0xf8, 0x18, 0x70, + 0x6, 0xf0, 0x8, 0xfa, 0x2f, 0xf1, 0x6, 0xf0, + 0xa, 0xf9, 0xe, 0xf9, 0x6, 0xf0, 0x2f, 0xf5, + 0x5, 0xff, 0xcb, 0xf9, 0xff, 0xc0, 0x0, 0x7f, + 0xff, 0xff, 0xfc, 0x10, 0x0, 0x1, 0x6c, 0xf9, + 0x40, 0x0, 0x0, 0x0, 0x6, 0xf0, 0x0, 0x0, + 0x0, 0x0, 0x6, 0xf0, 0x0, 0x0, 0x0, 0x0, + 0x6, 0xf0, 0x0, 0x0, + + /* U+0025 "%" */ + 0x4, 0xcf, 0xd8, 0x0, 0x0, 0x1, 0xfb, 0x2, + 0xff, 0xce, 0xf8, 0x0, 0x0, 0xbf, 0x10, 0x8f, + 0x50, 0xe, 0xe0, 0x0, 0x6f, 0x60, 0xa, 0xf2, + 0x0, 0xcf, 0x0, 0x1e, 0xb0, 0x0, 0xaf, 0x20, + 0xc, 0xf0, 0xb, 0xf1, 0x0, 0x8, 0xf5, 0x0, + 0xee, 0x5, 0xf6, 0x0, 0x0, 0x2f, 0xfc, 0xef, + 0x81, 0xeb, 0x0, 0x0, 0x0, 0x4c, 0xfd, 0x80, + 0xbf, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5f, + 0x60, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1e, 0xb0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xa, 0xf2, 0x4c, + 0xfd, 0x80, 0x0, 0x0, 0x5, 0xf6, 0x2f, 0xfc, + 0xef, 0x80, 0x0, 0x1, 0xec, 0x8, 0xf5, 0x0, + 0xee, 0x0, 0x0, 0xaf, 0x20, 0x9f, 0x20, 0xb, + 0xf0, 0x0, 0x5f, 0x60, 0x9, 0xf2, 0x0, 0xbf, + 0x0, 0x1e, 0xc0, 0x0, 0x8f, 0x40, 0xe, 0xe0, + 0xa, 0xf2, 0x0, 0x2, 0xfe, 0xac, 0xf8, 0x5, + 0xf7, 0x0, 0x0, 0x4, 0xcf, 0xe8, 0x0, + + /* U+0026 "&" */ + 0x0, 0x0, 0x7d, 0xfe, 0xa2, 0x0, 0x0, 0x0, + 0x0, 0xaf, 0xff, 0xff, 0xf3, 0x0, 0x0, 0x0, + 0x3f, 0xf6, 0x1, 0xbf, 0xc0, 0x0, 0x0, 0x5, + 0xfd, 0x0, 0x1, 0xff, 0x10, 0x0, 0x0, 0x3f, + 0xe0, 0x0, 0x5, 0x61, 0x0, 0x0, 0x0, 0xcf, + 0x60, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xff, + 0x30, 0x0, 0x0, 0x0, 0x0, 0x2, 0x8d, 0xfd, + 0x10, 0x0, 0x0, 0x0, 0x4, 0xff, 0xff, 0xfb, + 0x0, 0x0, 0x45, 0x30, 0xef, 0xa2, 0xb, 0xf8, + 0x0, 0x5f, 0xe2, 0x4f, 0xe0, 0x0, 0x1e, 0xf5, + 0x2f, 0xf4, 0x6, 0xfc, 0x0, 0x0, 0x4f, 0xfd, + 0xf7, 0x0, 0x6f, 0xb0, 0x0, 0x0, 0x8f, 0xfb, + 0x0, 0x6, 0xfc, 0x0, 0x0, 0x7, 0xff, 0x90, + 0x0, 0x4f, 0xf1, 0x0, 0x4, 0xff, 0xef, 0x40, + 0x0, 0xef, 0xb2, 0x5, 0xef, 0x54, 0xfe, 0x10, + 0x5, 0xff, 0xff, 0xff, 0x70, 0xa, 0xfb, 0x0, + 0x4, 0xbf, 0xfc, 0x40, 0x0, 0x1e, 0xf6, + + /* U+0027 "'" */ + 0xf, 0xf6, 0xf, 0xf6, 0xf, 0xf5, 0xf, 0xf5, + 0xe, 0xf5, 0xe, 0xf4, 0xd, 0xf4, 0x6, 0x82, + + /* U+0028 "(" */ + 0x0, 0x0, 0x3, 0xa9, 0x0, 0x1, 0xaf, 0xfa, + 0x0, 0x1d, 0xff, 0x93, 0x0, 0xcf, 0xe3, 0x0, + 0x6, 0xff, 0x30, 0x0, 0xd, 0xf9, 0x0, 0x0, + 0x2f, 0xf2, 0x0, 0x0, 0x5f, 0xd0, 0x0, 0x0, + 0x7f, 0xb0, 0x0, 0x0, 0x8f, 0x90, 0x0, 0x0, + 0x9f, 0x90, 0x0, 0x0, 0x9f, 0x90, 0x0, 0x0, + 0x9f, 0x90, 0x0, 0x0, 0x9f, 0x90, 0x0, 0x0, + 0x8f, 0x90, 0x0, 0x0, 0x7f, 0xb0, 0x0, 0x0, + 0x5f, 0xd0, 0x0, 0x0, 0x2f, 0xf2, 0x0, 0x0, + 0xd, 0xf9, 0x0, 0x0, 0x6, 0xff, 0x30, 0x0, + 0x0, 0xcf, 0xe3, 0x0, 0x0, 0x1d, 0xff, 0x93, + 0x0, 0x1, 0xaf, 0xfa, 0x0, 0x0, 0x3, 0xa9, + + /* U+0029 ")" */ + 0x3c, 0x60, 0x0, 0x0, 0x3f, 0xfe, 0x30, 0x0, + 0x7, 0xef, 0xf5, 0x0, 0x0, 0xa, 0xff, 0x20, + 0x0, 0x0, 0xcf, 0xc0, 0x0, 0x0, 0x2f, 0xf3, + 0x0, 0x0, 0xb, 0xf8, 0x0, 0x0, 0x7, 0xfb, + 0x0, 0x0, 0x4, 0xfd, 0x0, 0x0, 0x3, 0xfe, + 0x0, 0x0, 0x3, 0xff, 0x0, 0x0, 0x3, 0xff, + 0x0, 0x0, 0x3, 0xff, 0x0, 0x0, 0x3, 0xff, + 0x0, 0x0, 0x3, 0xfe, 0x0, 0x0, 0x4, 0xfd, + 0x0, 0x0, 0x7, 0xfb, 0x0, 0x0, 0xb, 0xf8, + 0x0, 0x0, 0x3f, 0xf3, 0x0, 0x0, 0xcf, 0xc0, + 0x0, 0xa, 0xff, 0x20, 0x7, 0xef, 0xf5, 0x0, + 0x3f, 0xfe, 0x30, 0x0, 0x3c, 0x60, 0x0, 0x0, + + /* U+002A "*" */ + 0x0, 0x0, 0x0, 0xdf, 0x30, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xdf, 0x30, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xdf, 0x30, 0x0, 0x0, 0x4, 0x20, 0x0, + 0xcf, 0x20, 0x0, 0x50, 0xd, 0xfc, 0x50, 0xbf, + 0x13, 0x9f, 0xf3, 0xb, 0xff, 0xfd, 0xcf, 0xaf, + 0xff, 0xd4, 0x0, 0x17, 0xcf, 0xff, 0xfe, 0x93, + 0x0, 0x0, 0x0, 0x5, 0xff, 0xb0, 0x0, 0x0, + 0x0, 0x0, 0x3f, 0xe9, 0xf8, 0x0, 0x0, 0x0, + 0x0, 0xdf, 0x61, 0xff, 0x50, 0x0, 0x0, 0x9, + 0xfd, 0x0, 0x7f, 0xe1, 0x0, 0x0, 0x2f, 0xf3, + 0x0, 0xc, 0xf9, 0x0, 0x0, 0x5, 0x70, 0x0, + 0x2, 0xa0, 0x0, + + /* U+002B "+" */ + 0x0, 0x0, 0xd, 0xf4, 0x0, 0x0, 0x0, 0x0, + 0xd, 0xf4, 0x0, 0x0, 0x0, 0x0, 0xd, 0xf4, + 0x0, 0x0, 0x0, 0x0, 0xd, 0xf4, 0x0, 0x0, + 0x0, 0x0, 0xd, 0xf4, 0x0, 0x0, 0x7f, 0xff, + 0xff, 0xff, 0xff, 0xfd, 0x7f, 0xff, 0xff, 0xff, + 0xff, 0xfd, 0x0, 0x0, 0xd, 0xf4, 0x0, 0x0, + 0x0, 0x0, 0xd, 0xf4, 0x0, 0x0, 0x0, 0x0, + 0xd, 0xf4, 0x0, 0x0, 0x0, 0x0, 0xd, 0xf4, + 0x0, 0x0, 0x0, 0x0, 0xa, 0xc3, 0x0, 0x0, + + /* U+002C "," */ + 0x7, 0xa9, 0xd, 0xfb, 0xf, 0xf7, 0x2f, 0xf4, + 0x5f, 0xf0, 0x8f, 0xd0, 0xbf, 0x90, 0xdf, 0x60, + + /* U+002D "-" */ + 0xaf, 0xff, 0xff, 0xff, 0xa, 0xff, 0xff, 0xff, + 0xf0, + + /* U+002E "." */ + 0x0, 0x0, 0x3, 0xef, 0x70, 0xaf, 0xff, 0x1a, + 0xff, 0xf1, 0x3d, 0xf7, 0x0, + + /* U+002F "/" */ + 0x0, 0x0, 0x0, 0x0, 0x6, 0x84, 0x0, 0x0, + 0x0, 0x0, 0x1f, 0xf3, 0x0, 0x0, 0x0, 0x0, + 0x6f, 0xd0, 0x0, 0x0, 0x0, 0x0, 0xcf, 0x80, + 0x0, 0x0, 0x0, 0x2, 0xff, 0x20, 0x0, 0x0, + 0x0, 0x8, 0xfc, 0x0, 0x0, 0x0, 0x0, 0xd, + 0xf6, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xf1, 0x0, + 0x0, 0x0, 0x0, 0x9f, 0xb0, 0x0, 0x0, 0x0, + 0x0, 0xef, 0x50, 0x0, 0x0, 0x0, 0x5, 0xfe, + 0x0, 0x0, 0x0, 0x0, 0xa, 0xf9, 0x0, 0x0, + 0x0, 0x0, 0x1f, 0xf3, 0x0, 0x0, 0x0, 0x0, + 0x6f, 0xe0, 0x0, 0x0, 0x0, 0x0, 0xcf, 0x80, + 0x0, 0x0, 0x0, 0x2, 0xff, 0x20, 0x0, 0x0, + 0x0, 0x7, 0xfc, 0x0, 0x0, 0x0, 0x0, 0xd, + 0xf6, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xf1, 0x0, + 0x0, 0x0, 0x0, 0x9f, 0xb0, 0x0, 0x0, 0x0, + 0x0, 0xef, 0x50, 0x0, 0x0, 0x0, 0x4, 0xff, + 0x0, 0x0, 0x0, 0x0, 0xa, 0xf9, 0x0, 0x0, + 0x0, 0x0, 0xf, 0xf4, 0x0, 0x0, 0x0, 0x0, + + /* U+0030 "0" */ + 0x0, 0x6, 0xcf, 0xfd, 0x91, 0x0, 0x0, 0xaf, + 0xff, 0xff, 0xfe, 0x20, 0x7, 0xff, 0x60, 0x3, + 0xdf, 0xd0, 0xd, 0xf7, 0x0, 0x0, 0x1f, 0xf3, + 0xf, 0xf2, 0x0, 0x0, 0xb, 0xf6, 0x1f, 0xf0, + 0x0, 0x0, 0x9, 0xf7, 0x1f, 0xf0, 0x0, 0x0, + 0x9, 0xf7, 0x1f, 0xf0, 0xa, 0xc3, 0x9, 0xf7, + 0x1f, 0xf0, 0x3f, 0xf9, 0x9, 0xf7, 0x1f, 0xf0, + 0xc, 0xe4, 0x9, 0xf7, 0x1f, 0xf0, 0x0, 0x0, + 0x9, 0xf7, 0x1f, 0xf0, 0x0, 0x0, 0x9, 0xf7, + 0x1f, 0xf0, 0x0, 0x0, 0x9, 0xf7, 0xf, 0xf2, + 0x0, 0x0, 0xb, 0xf6, 0xd, 0xf7, 0x0, 0x0, + 0x1f, 0xf3, 0x7, 0xff, 0x60, 0x3, 0xdf, 0xd0, + 0x0, 0xaf, 0xff, 0xff, 0xfe, 0x20, 0x0, 0x6, + 0xcf, 0xfd, 0x81, 0x0, + + /* U+0031 "1" */ + 0x0, 0x8, 0xff, 0xf1, 0x0, 0x0, 0x1b, 0xff, + 0xff, 0x10, 0x0, 0x3e, 0xfe, 0x5f, 0xf1, 0x0, + 0xd, 0xfc, 0x11, 0xff, 0x10, 0x0, 0xd8, 0x0, + 0x1f, 0xf1, 0x0, 0x3, 0x0, 0x1, 0xff, 0x10, + 0x0, 0x0, 0x0, 0x1f, 0xf1, 0x0, 0x0, 0x0, + 0x1, 0xff, 0x10, 0x0, 0x0, 0x0, 0x1f, 0xf1, + 0x0, 0x0, 0x0, 0x1, 0xff, 0x10, 0x0, 0x0, + 0x0, 0x1f, 0xf1, 0x0, 0x0, 0x0, 0x1, 0xff, + 0x10, 0x0, 0x0, 0x0, 0x1f, 0xf1, 0x0, 0x0, + 0x0, 0x1, 0xff, 0x10, 0x0, 0x0, 0x0, 0x1f, + 0xf1, 0x0, 0x0, 0x0, 0x2, 0xff, 0x10, 0x0, + 0xdf, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, + 0xff, 0xff, 0xff, + + /* U+0032 "2" */ + 0x0, 0x6, 0xcf, 0xfd, 0x81, 0x0, 0x0, 0xaf, + 0xff, 0xff, 0xfe, 0x20, 0x7, 0xff, 0x71, 0x15, + 0xef, 0xc0, 0xe, 0xf7, 0x0, 0x0, 0x3f, 0xf3, + 0x1f, 0xf1, 0x0, 0x0, 0xe, 0xf6, 0x4, 0x40, + 0x0, 0x0, 0xd, 0xf6, 0x0, 0x0, 0x0, 0x0, + 0x1f, 0xf3, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xd0, + 0x0, 0x0, 0x0, 0x2, 0xff, 0x50, 0x0, 0x0, + 0x0, 0x1e, 0xfa, 0x0, 0x0, 0x0, 0x1, 0xdf, + 0xc0, 0x0, 0x0, 0x0, 0xc, 0xfd, 0x10, 0x0, + 0x0, 0x0, 0xbf, 0xd1, 0x0, 0x0, 0x0, 0xa, + 0xfe, 0x10, 0x0, 0x0, 0x0, 0x9f, 0xe2, 0x0, + 0x0, 0x0, 0x8, 0xff, 0x30, 0x0, 0x0, 0x0, + 0xf, 0xff, 0xff, 0xff, 0xff, 0xfa, 0xf, 0xff, + 0xff, 0xff, 0xff, 0xfa, + + /* U+0033 "3" */ + 0xd, 0xff, 0xff, 0xff, 0xff, 0xd0, 0xd, 0xff, + 0xff, 0xff, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x3, + 0xef, 0x60, 0x0, 0x0, 0x0, 0x1e, 0xf7, 0x0, + 0x0, 0x0, 0x1, 0xdf, 0x80, 0x0, 0x0, 0x0, + 0xc, 0xf9, 0x0, 0x0, 0x0, 0x0, 0xbf, 0xe3, + 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xe4, 0x0, + 0x0, 0x0, 0x78, 0x9d, 0xff, 0x40, 0x0, 0x0, + 0x0, 0x0, 0xbf, 0xd0, 0x0, 0x0, 0x0, 0x0, + 0x2f, 0xf1, 0x0, 0x0, 0x0, 0x0, 0xf, 0xf3, + 0x2, 0x10, 0x0, 0x0, 0xe, 0xf3, 0x4f, 0xf0, + 0x0, 0x0, 0xf, 0xf2, 0x1f, 0xf4, 0x0, 0x0, + 0x5f, 0xf0, 0xb, 0xfe, 0x51, 0x16, 0xff, 0x90, + 0x1, 0xdf, 0xff, 0xff, 0xfd, 0x10, 0x0, 0x18, + 0xdf, 0xfd, 0x70, 0x0, + + /* U+0034 "4" */ + 0x0, 0x0, 0x0, 0x3f, 0xf3, 0x0, 0x0, 0x0, + 0xd, 0xf9, 0x0, 0x0, 0x0, 0x7, 0xfe, 0x10, + 0x0, 0x0, 0x1, 0xff, 0x60, 0x0, 0x0, 0x0, + 0xaf, 0xc0, 0x0, 0x0, 0x0, 0x4f, 0xf3, 0x0, + 0x0, 0x0, 0xd, 0xf9, 0x0, 0x0, 0x0, 0x8, + 0xfe, 0x0, 0x3, 0x86, 0x2, 0xff, 0x50, 0x0, + 0x6f, 0xc0, 0xbf, 0xb0, 0x0, 0x6, 0xfc, 0x3f, + 0xf2, 0x0, 0x0, 0x6f, 0xc5, 0xfd, 0x0, 0x0, + 0x6, 0xfc, 0x5f, 0xff, 0xff, 0xff, 0xff, 0xc5, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0x0, 0x0, 0x0, + 0x0, 0x6f, 0xc0, 0x0, 0x0, 0x0, 0x6, 0xfc, + 0x0, 0x0, 0x0, 0x0, 0x6f, 0xc0, 0x0, 0x0, + 0x0, 0x6, 0xfc, + + /* U+0035 "5" */ + 0x9, 0xff, 0xff, 0xff, 0xff, 0xb0, 0x9, 0xff, + 0xff, 0xff, 0xff, 0xb0, 0x9, 0xf7, 0x0, 0x0, + 0x0, 0x0, 0x9, 0xf6, 0x0, 0x0, 0x0, 0x0, + 0x9, 0xf7, 0x0, 0x0, 0x0, 0x0, 0x9, 0xf7, + 0x0, 0x0, 0x0, 0x0, 0x9, 0xff, 0xff, 0xfd, + 0x91, 0x0, 0x9, 0xff, 0xff, 0xff, 0xfe, 0x20, + 0x0, 0x0, 0x0, 0x16, 0xff, 0xb0, 0x0, 0x0, + 0x0, 0x0, 0x5f, 0xf1, 0x0, 0x0, 0x0, 0x0, + 0xe, 0xf4, 0x0, 0x0, 0x0, 0x0, 0xc, 0xf5, + 0x16, 0x60, 0x0, 0x0, 0xc, 0xf5, 0x2f, 0xf1, + 0x0, 0x0, 0xe, 0xf4, 0xe, 0xf7, 0x0, 0x0, + 0x4f, 0xf1, 0x8, 0xff, 0x61, 0x15, 0xef, 0xa0, + 0x0, 0xcf, 0xff, 0xff, 0xfd, 0x10, 0x0, 0x7, + 0xcf, 0xfd, 0x80, 0x0, + + /* U+0036 "6" */ + 0x0, 0x0, 0x1, 0xff, 0x40, 0x0, 0x0, 0x0, + 0xa, 0xfa, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xf1, + 0x0, 0x0, 0x0, 0x0, 0xbf, 0x70, 0x0, 0x0, + 0x0, 0x4, 0xfd, 0x0, 0x0, 0x0, 0x0, 0xd, + 0xf3, 0x0, 0x0, 0x0, 0x0, 0x6f, 0xb8, 0xba, + 0x60, 0x0, 0x0, 0xef, 0xff, 0xff, 0xfd, 0x20, + 0x6, 0xff, 0x71, 0x4, 0xdf, 0xd0, 0xd, 0xf7, + 0x0, 0x0, 0x1f, 0xf6, 0x2f, 0xe0, 0x0, 0x0, + 0x8, 0xfb, 0x6f, 0xc0, 0x0, 0x0, 0x5, 0xfc, + 0x7f, 0xc0, 0x0, 0x0, 0x6, 0xfc, 0x5f, 0xe0, + 0x0, 0x0, 0x8, 0xfa, 0x1f, 0xf7, 0x0, 0x0, + 0x1f, 0xf5, 0x9, 0xff, 0x71, 0x4, 0xdf, 0xd0, + 0x0, 0xbf, 0xff, 0xff, 0xfe, 0x20, 0x0, 0x6, + 0xce, 0xfd, 0x81, 0x0, + + /* U+0037 "7" */ + 0xf, 0xff, 0xff, 0xff, 0xff, 0xff, 0x10, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xf1, 0xf, 0xf2, 0x0, + 0x0, 0x6, 0xfe, 0x0, 0xff, 0x20, 0x0, 0x0, + 0xcf, 0x80, 0xf, 0xf1, 0x0, 0x0, 0x2f, 0xf2, + 0x0, 0x0, 0x0, 0x0, 0x8, 0xfc, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xef, 0x60, 0x0, 0x0, 0x0, + 0x0, 0x5f, 0xf0, 0x0, 0x0, 0x0, 0x0, 0xb, + 0xf9, 0x0, 0x0, 0x0, 0x0, 0x1, 0xff, 0x30, + 0x0, 0x0, 0x0, 0x0, 0x8f, 0xd0, 0x0, 0x0, + 0x0, 0x0, 0xe, 0xf7, 0x0, 0x0, 0x0, 0x0, + 0x4, 0xff, 0x10, 0x0, 0x0, 0x0, 0x0, 0xaf, + 0xa0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xf4, 0x0, + 0x0, 0x0, 0x0, 0x7, 0xfd, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xdf, 0x70, 0x0, 0x0, 0x0, 0x0, + 0x3f, 0xf1, 0x0, 0x0, 0x0, + + /* U+0038 "8" */ + 0x0, 0x6, 0xce, 0xfd, 0x91, 0x0, 0x0, 0xbf, + 0xff, 0xff, 0xff, 0x30, 0x7, 0xff, 0x71, 0x4, + 0xdf, 0xd0, 0xd, 0xf7, 0x0, 0x0, 0x1f, 0xf3, + 0xe, 0xf4, 0x0, 0x0, 0xe, 0xf4, 0xb, 0xf7, + 0x0, 0x0, 0x1f, 0xf1, 0x3, 0xff, 0x71, 0x4, + 0xdf, 0x80, 0x0, 0x2a, 0xff, 0xff, 0xd6, 0x0, + 0x0, 0x5d, 0xff, 0xff, 0xf9, 0x0, 0x6, 0xff, + 0x72, 0x4, 0xdf, 0xc0, 0xe, 0xf5, 0x0, 0x0, + 0x1e, 0xf5, 0x4f, 0xe0, 0x0, 0x0, 0x8, 0xfa, + 0x6f, 0xc0, 0x0, 0x0, 0x6, 0xfc, 0x5f, 0xe0, + 0x0, 0x0, 0x8, 0xfb, 0x1f, 0xf6, 0x0, 0x0, + 0x1e, 0xf7, 0x9, 0xff, 0x72, 0x14, 0xdf, 0xe1, + 0x0, 0xbf, 0xff, 0xff, 0xfe, 0x30, 0x0, 0x6, + 0xce, 0xfd, 0x81, 0x0, + + /* U+0039 "9" */ + 0x0, 0x5, 0xce, 0xfd, 0x81, 0x0, 0x0, 0xbf, + 0xff, 0xff, 0xfe, 0x30, 0x9, 0xff, 0x72, 0x4, + 0xdf, 0xe1, 0x1f, 0xf5, 0x0, 0x0, 0xe, 0xf7, + 0x5f, 0xe0, 0x0, 0x0, 0x7, 0xfb, 0x7f, 0xb0, + 0x0, 0x0, 0x5, 0xfd, 0x6f, 0xd0, 0x0, 0x0, + 0x7, 0xfc, 0x2f, 0xf3, 0x0, 0x0, 0xc, 0xf9, + 0xc, 0xfd, 0x30, 0x0, 0x9f, 0xf3, 0x1, 0xef, + 0xfd, 0xcf, 0xff, 0xd0, 0x0, 0x18, 0xdf, 0xda, + 0xff, 0x40, 0x0, 0x0, 0x0, 0xb, 0xfc, 0x0, + 0x0, 0x0, 0x0, 0x4f, 0xf3, 0x0, 0x0, 0x0, + 0x0, 0xdf, 0xa0, 0x0, 0x0, 0x0, 0x6, 0xff, + 0x20, 0x0, 0x0, 0x0, 0xe, 0xf9, 0x0, 0x0, + 0x0, 0x0, 0x7f, 0xf1, 0x0, 0x0, 0x0, 0x1, + 0xff, 0x70, 0x0, 0x0, + + /* U+003A ":" */ + 0x4d, 0xf9, 0xb, 0xff, 0xf1, 0xaf, 0xff, 0x11, + 0x9a, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x19, 0xa4, 0xa, 0xff, 0xf1, 0xbf, 0xff, + 0x14, 0xdf, 0x90, + + /* U+003B ";" */ + 0x4, 0xef, 0x90, 0xc, 0xff, 0xf2, 0xb, 0xff, + 0xf1, 0x2, 0xab, 0x50, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8a, + 0x70, 0x0, 0xff, 0x90, 0x2, 0xff, 0x50, 0x4, + 0xff, 0x20, 0x7, 0xfe, 0x0, 0xa, 0xfb, 0x0, + 0xd, 0xf7, 0x0, 0xf, 0xf4, 0x0, + + /* U+003C "<" */ + 0x0, 0x0, 0x0, 0x0, 0x6, 0x40, 0x0, 0x0, + 0x0, 0x6e, 0xf5, 0x0, 0x0, 0x5, 0xdf, 0xfb, + 0x20, 0x0, 0x4d, 0xff, 0xc3, 0x0, 0x4, 0xcf, + 0xfc, 0x40, 0x0, 0xb, 0xff, 0xc4, 0x0, 0x0, + 0x0, 0xfe, 0x40, 0x0, 0x0, 0x0, 0xf, 0xfe, + 0x60, 0x0, 0x0, 0x0, 0x3c, 0xff, 0xd6, 0x0, + 0x0, 0x0, 0x4, 0xcf, 0xfd, 0x50, 0x0, 0x0, + 0x0, 0x5d, 0xff, 0xd5, 0x0, 0x0, 0x0, 0x5, + 0xdf, 0xf5, 0x0, 0x0, 0x0, 0x0, 0x6e, 0x50, + 0x0, 0x0, 0x0, 0x0, 0x1, + + /* U+003D "=" */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0x5f, 0xff, 0xff, + 0xff, 0xff, 0xf5, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x5f, 0xff, + 0xff, 0xff, 0xff, 0xf5, + + /* U+003E ">" */ + 0x92, 0x0, 0x0, 0x0, 0x0, 0xf, 0xf9, 0x10, + 0x0, 0x0, 0x0, 0x9f, 0xff, 0x81, 0x0, 0x0, + 0x0, 0x2a, 0xff, 0xf8, 0x0, 0x0, 0x0, 0x2, + 0xaf, 0xfe, 0x70, 0x0, 0x0, 0x0, 0x3b, 0xff, + 0xe3, 0x0, 0x0, 0x0, 0x3, 0xbf, 0x50, 0x0, + 0x0, 0x1, 0x9f, 0xf5, 0x0, 0x0, 0x19, 0xff, + 0xe7, 0x0, 0x1, 0x8f, 0xff, 0x70, 0x0, 0x18, + 0xff, 0xf8, 0x10, 0x0, 0xe, 0xff, 0x91, 0x0, + 0x0, 0x0, 0xf9, 0x10, 0x0, 0x0, 0x0, 0x2, + 0x0, 0x0, 0x0, 0x0, 0x0, + + /* U+003F "?" */ + 0xef, 0xff, 0xd8, 0x10, 0xe, 0xff, 0xff, 0xfe, + 0x30, 0x12, 0x22, 0x6e, 0xfe, 0x0, 0x0, 0x0, + 0x1e, 0xf6, 0x0, 0x0, 0x0, 0xaf, 0x90, 0x0, + 0x0, 0x9, 0xf9, 0x0, 0x0, 0x0, 0xdf, 0x70, + 0x0, 0x1, 0xaf, 0xf1, 0x0, 0xde, 0xff, 0xf6, + 0x0, 0x1f, 0xff, 0xc4, 0x0, 0x1, 0xff, 0x10, + 0x0, 0x0, 0x1f, 0xf1, 0x0, 0x0, 0x0, 0x77, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x6f, 0xf6, 0x0, 0x0, + 0xc, 0xff, 0xc0, 0x0, 0x0, 0x6f, 0xf5, 0x0, + 0x0, + + /* U+0040 "@" */ + 0x0, 0x5, 0xbe, 0xfe, 0xb6, 0x0, 0x0, 0xb, + 0xff, 0xdc, 0xef, 0xfb, 0x0, 0xa, 0xfc, 0x30, + 0x0, 0x2b, 0xf9, 0x3, 0xfe, 0x10, 0x0, 0x0, + 0xe, 0xf1, 0x9f, 0x60, 0x0, 0x0, 0x0, 0x9f, + 0x5c, 0xf2, 0x0, 0x3, 0x78, 0x37, 0xf6, 0xef, + 0x0, 0x6, 0xff, 0xff, 0xbf, 0x7e, 0xf0, 0x0, + 0xef, 0x60, 0x4f, 0xf7, 0xef, 0x0, 0x2f, 0xc0, + 0x0, 0x9f, 0x7e, 0xf0, 0x3, 0xfb, 0x0, 0x7, + 0xf7, 0xef, 0x0, 0x3f, 0xb0, 0x0, 0x7f, 0x7e, + 0xf0, 0x3, 0xfb, 0x0, 0x7, 0xf7, 0xef, 0x0, + 0x3f, 0xb0, 0x0, 0x8f, 0x6e, 0xf0, 0x0, 0xff, + 0x20, 0xd, 0xf3, 0xef, 0x0, 0x8, 0xfe, 0xbe, + 0xfb, 0xe, 0xf0, 0x0, 0x7, 0xdf, 0xe9, 0x0, + 0xcf, 0x20, 0x0, 0x0, 0x0, 0x0, 0x8, 0xf7, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xf2, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x8f, 0xe5, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x9f, 0xff, 0xee, 0xe6, 0x0, + 0x0, 0x0, 0x3a, 0xdf, 0xff, 0x70, 0x0, + + /* U+0041 "A" */ + 0x0, 0x0, 0x5f, 0xfc, 0x0, 0x0, 0x0, 0x0, + 0x9, 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, 0xdf, + 0xbf, 0x40, 0x0, 0x0, 0x0, 0x1f, 0xd7, 0xf8, + 0x0, 0x0, 0x0, 0x6, 0xf9, 0x3f, 0xc0, 0x0, + 0x0, 0x0, 0xaf, 0x60, 0xff, 0x0, 0x0, 0x0, + 0xe, 0xf2, 0xb, 0xf4, 0x0, 0x0, 0x2, 0xfe, + 0x0, 0x7f, 0x80, 0x0, 0x0, 0x6f, 0xa0, 0x3, + 0xfc, 0x0, 0x0, 0xa, 0xf6, 0x0, 0xf, 0xf1, + 0x0, 0x0, 0xef, 0x20, 0x0, 0xbf, 0x40, 0x0, + 0x2f, 0xfe, 0xee, 0xef, 0xf8, 0x0, 0x6, 0xff, + 0xff, 0xff, 0xff, 0xc0, 0x0, 0xaf, 0x70, 0x0, + 0x0, 0xff, 0x10, 0xe, 0xf3, 0x0, 0x0, 0xc, + 0xf5, 0x2, 0xff, 0x0, 0x0, 0x0, 0x9f, 0x90, + 0x6f, 0xc0, 0x0, 0x0, 0x5, 0xfd, 0xa, 0xf8, + 0x0, 0x0, 0x0, 0x1f, 0xf1, + + /* U+0042 "B" */ + 0xcf, 0xff, 0xff, 0xea, 0x20, 0xc, 0xff, 0xff, + 0xff, 0xff, 0x40, 0xcf, 0x50, 0x0, 0x4d, 0xfe, + 0xc, 0xf5, 0x0, 0x0, 0x1f, 0xf3, 0xcf, 0x50, + 0x0, 0x0, 0xef, 0x4c, 0xf5, 0x0, 0x0, 0x1f, + 0xf1, 0xcf, 0x50, 0x0, 0x3c, 0xf7, 0xc, 0xff, + 0xff, 0xff, 0xd6, 0x0, 0xcf, 0xff, 0xff, 0xfe, + 0x80, 0xc, 0xf5, 0x0, 0x3, 0xcf, 0xa0, 0xcf, + 0x50, 0x0, 0x1, 0xff, 0x3c, 0xf5, 0x0, 0x0, + 0x9, 0xf9, 0xcf, 0x50, 0x0, 0x0, 0x7f, 0xbc, + 0xf5, 0x0, 0x0, 0x9, 0xfa, 0xcf, 0x50, 0x0, + 0x0, 0xef, 0x7c, 0xf5, 0x0, 0x14, 0xcf, 0xf1, + 0xcf, 0xff, 0xff, 0xff, 0xf5, 0xc, 0xff, 0xff, + 0xfe, 0xb3, 0x0, + + /* U+0043 "C" */ + 0x0, 0x4b, 0xef, 0xea, 0x20, 0x0, 0x8f, 0xff, + 0xff, 0xff, 0x40, 0x3f, 0xf9, 0x20, 0x3c, 0xfe, + 0x9, 0xfc, 0x0, 0x0, 0x1e, 0xf5, 0xcf, 0x70, + 0x0, 0x0, 0xbf, 0x7c, 0xf6, 0x0, 0x0, 0x0, + 0x10, 0xcf, 0x60, 0x0, 0x0, 0x0, 0xc, 0xf6, + 0x0, 0x0, 0x0, 0x0, 0xcf, 0x60, 0x0, 0x0, + 0x0, 0xc, 0xf6, 0x0, 0x0, 0x0, 0x0, 0xcf, + 0x60, 0x0, 0x0, 0x0, 0xc, 0xf6, 0x0, 0x0, + 0x0, 0x0, 0xcf, 0x60, 0x0, 0x0, 0x1, 0xc, + 0xf7, 0x0, 0x0, 0xb, 0xf7, 0x9f, 0xc0, 0x0, + 0x1, 0xef, 0x53, 0xff, 0xa2, 0x13, 0xcf, 0xe0, + 0x8, 0xff, 0xff, 0xff, 0xf4, 0x0, 0x4, 0xbe, + 0xfe, 0xa2, 0x0, + + /* U+0044 "D" */ + 0xcf, 0xff, 0xfe, 0xc6, 0x0, 0xc, 0xff, 0xff, + 0xff, 0xfb, 0x0, 0xcf, 0x60, 0x1, 0x7f, 0xf8, + 0xc, 0xf6, 0x0, 0x0, 0x6f, 0xe0, 0xcf, 0x60, + 0x0, 0x0, 0xff, 0x2c, 0xf6, 0x0, 0x0, 0xe, + 0xf4, 0xcf, 0x60, 0x0, 0x0, 0xef, 0x4c, 0xf6, + 0x0, 0x0, 0xe, 0xf4, 0xcf, 0x60, 0x0, 0x0, + 0xef, 0x4c, 0xf6, 0x0, 0x0, 0xe, 0xf4, 0xcf, + 0x60, 0x0, 0x0, 0xef, 0x4c, 0xf6, 0x0, 0x0, + 0xe, 0xf4, 0xcf, 0x60, 0x0, 0x0, 0xef, 0x4c, + 0xf6, 0x0, 0x0, 0xf, 0xf2, 0xcf, 0x60, 0x0, + 0x6, 0xfe, 0xc, 0xf6, 0x0, 0x17, 0xff, 0x80, + 0xcf, 0xff, 0xff, 0xff, 0xb0, 0xc, 0xff, 0xff, + 0xec, 0x60, 0x0, + + /* U+0045 "E" */ + 0x9f, 0xff, 0xff, 0xff, 0xff, 0x79, 0xff, 0xff, + 0xff, 0xff, 0xf7, 0x9f, 0x80, 0x0, 0x0, 0x0, + 0x9, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x9f, 0x80, + 0x0, 0x0, 0x0, 0x9, 0xf8, 0x0, 0x0, 0x0, + 0x0, 0x9f, 0x80, 0x0, 0x0, 0x0, 0x9, 0xff, + 0xff, 0xff, 0xff, 0xa0, 0x9f, 0xff, 0xff, 0xff, + 0xfa, 0x9, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x9f, + 0x80, 0x0, 0x0, 0x0, 0x9, 0xf8, 0x0, 0x0, + 0x0, 0x0, 0x9f, 0x80, 0x0, 0x0, 0x0, 0x9, + 0xf8, 0x0, 0x0, 0x0, 0x0, 0x9f, 0x80, 0x0, + 0x0, 0x0, 0x9, 0xf8, 0x0, 0x0, 0x0, 0x0, + 0x9f, 0xff, 0xff, 0xff, 0xff, 0x79, 0xff, 0xff, + 0xff, 0xff, 0xf7, + + /* U+0046 "F" */ + 0xbf, 0xff, 0xff, 0xff, 0xff, 0x9b, 0xff, 0xff, + 0xff, 0xff, 0xf9, 0xbf, 0x60, 0x0, 0x0, 0x0, + 0xb, 0xf6, 0x0, 0x0, 0x0, 0x0, 0xbf, 0x60, + 0x0, 0x0, 0x0, 0xb, 0xf6, 0x0, 0x0, 0x0, + 0x0, 0xbf, 0x60, 0x0, 0x0, 0x0, 0xb, 0xf6, + 0x11, 0x11, 0x11, 0x0, 0xbf, 0xff, 0xff, 0xff, + 0xff, 0xb, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xbf, + 0x70, 0x0, 0x0, 0x0, 0xb, 0xf7, 0x0, 0x0, + 0x0, 0x0, 0xbf, 0x70, 0x0, 0x0, 0x0, 0xb, + 0xf7, 0x0, 0x0, 0x0, 0x0, 0xbf, 0x70, 0x0, + 0x0, 0x0, 0xb, 0xf7, 0x0, 0x0, 0x0, 0x0, + 0xbf, 0x70, 0x0, 0x0, 0x0, 0xb, 0xf7, 0x0, + 0x0, 0x0, 0x0, + + /* U+0047 "G" */ + 0x0, 0x5b, 0xef, 0xe9, 0x20, 0x0, 0x9f, 0xff, + 0xff, 0xff, 0x30, 0x5f, 0xf8, 0x20, 0x3c, 0xfe, + 0xb, 0xfa, 0x0, 0x0, 0x1f, 0xf4, 0xdf, 0x50, + 0x0, 0x0, 0xad, 0x5e, 0xf4, 0x0, 0x0, 0x0, + 0x0, 0xef, 0x40, 0x0, 0x0, 0x0, 0xe, 0xf4, + 0x0, 0x0, 0x0, 0x0, 0xef, 0x40, 0x4f, 0xff, + 0xff, 0x7e, 0xf4, 0x4, 0xff, 0xff, 0xf7, 0xef, + 0x40, 0x0, 0x0, 0xbf, 0x7e, 0xf4, 0x0, 0x0, + 0xb, 0xf7, 0xef, 0x40, 0x0, 0x0, 0xbf, 0x6d, + 0xf5, 0x0, 0x0, 0xd, 0xf5, 0xbf, 0xa0, 0x0, + 0x2, 0xff, 0x25, 0xff, 0x81, 0x4, 0xdf, 0xc0, + 0x9, 0xff, 0xff, 0xff, 0xe2, 0x0, 0x5, 0xcf, + 0xfd, 0x91, 0x0, + + /* U+0048 "H" */ + 0xcf, 0x60, 0x0, 0x0, 0xff, 0x2c, 0xf6, 0x0, + 0x0, 0xf, 0xf2, 0xcf, 0x60, 0x0, 0x0, 0xff, + 0x2c, 0xf6, 0x0, 0x0, 0xf, 0xf2, 0xcf, 0x60, + 0x0, 0x0, 0xff, 0x2c, 0xf6, 0x0, 0x0, 0xf, + 0xf2, 0xcf, 0x60, 0x0, 0x0, 0xff, 0x2c, 0xf6, + 0x0, 0x0, 0xf, 0xf2, 0xcf, 0xff, 0xff, 0xff, + 0xff, 0x2c, 0xff, 0xff, 0xff, 0xff, 0xf2, 0xcf, + 0x60, 0x0, 0x0, 0xff, 0x2c, 0xf6, 0x0, 0x0, + 0xf, 0xf2, 0xcf, 0x60, 0x0, 0x0, 0xff, 0x2c, + 0xf6, 0x0, 0x0, 0xf, 0xf2, 0xcf, 0x60, 0x0, + 0x0, 0xff, 0x2c, 0xf6, 0x0, 0x0, 0xf, 0xf2, + 0xcf, 0x60, 0x0, 0x0, 0xff, 0x2c, 0xf6, 0x0, + 0x0, 0xf, 0xf2, + + /* U+0049 "I" */ + 0x7f, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, + 0xff, 0xfe, 0x0, 0x0, 0xef, 0x50, 0x0, 0x0, + 0x0, 0xef, 0x40, 0x0, 0x0, 0x0, 0xef, 0x40, + 0x0, 0x0, 0x0, 0xef, 0x40, 0x0, 0x0, 0x0, + 0xef, 0x40, 0x0, 0x0, 0x0, 0xef, 0x40, 0x0, + 0x0, 0x0, 0xef, 0x40, 0x0, 0x0, 0x0, 0xef, + 0x40, 0x0, 0x0, 0x0, 0xef, 0x40, 0x0, 0x0, + 0x0, 0xef, 0x40, 0x0, 0x0, 0x0, 0xef, 0x40, + 0x0, 0x0, 0x0, 0xef, 0x40, 0x0, 0x0, 0x0, + 0xef, 0x40, 0x0, 0x0, 0x0, 0xef, 0x50, 0x0, + 0x7f, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, + 0xff, 0xfe, + + /* U+004A "J" */ + 0x0, 0x0, 0x0, 0x0, 0x4f, 0xe0, 0x0, 0x0, + 0x0, 0x4, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x4f, + 0xe0, 0x0, 0x0, 0x0, 0x4, 0xfe, 0x0, 0x0, + 0x0, 0x0, 0x4f, 0xe0, 0x0, 0x0, 0x0, 0x4, + 0xfe, 0x0, 0x0, 0x0, 0x0, 0x4f, 0xe0, 0x0, + 0x0, 0x0, 0x4, 0xfe, 0x0, 0x0, 0x0, 0x0, + 0x4f, 0xe0, 0x0, 0x0, 0x0, 0x4, 0xfe, 0x0, + 0x0, 0x0, 0x0, 0x4f, 0xe0, 0x0, 0x0, 0x0, + 0x4, 0xfe, 0x56, 0x10, 0x0, 0x0, 0x4f, 0xdd, + 0xf5, 0x0, 0x0, 0x6, 0xfc, 0xaf, 0xb0, 0x0, + 0x0, 0xcf, 0x93, 0xff, 0x92, 0x2, 0xaf, 0xf3, + 0x7, 0xff, 0xff, 0xff, 0xf6, 0x0, 0x4, 0xbe, + 0xfe, 0xa3, 0x0, + + /* U+004B "K" */ + 0xcf, 0x60, 0x0, 0x0, 0x6f, 0xe0, 0xcf, 0x60, + 0x0, 0x0, 0xdf, 0x70, 0xcf, 0x60, 0x0, 0x6, + 0xfe, 0x0, 0xcf, 0x60, 0x0, 0xd, 0xf8, 0x0, + 0xcf, 0x60, 0x0, 0x5f, 0xf1, 0x0, 0xcf, 0x60, + 0x0, 0xdf, 0x80, 0x0, 0xcf, 0x60, 0x5, 0xff, + 0x10, 0x0, 0xcf, 0x60, 0xc, 0xf9, 0x0, 0x0, + 0xcf, 0xff, 0xff, 0xf1, 0x0, 0x0, 0xcf, 0xff, + 0xff, 0xf2, 0x0, 0x0, 0xcf, 0x60, 0xd, 0xfa, + 0x0, 0x0, 0xcf, 0x60, 0x5, 0xff, 0x20, 0x0, + 0xcf, 0x60, 0x0, 0xdf, 0xa0, 0x0, 0xcf, 0x60, + 0x0, 0x5f, 0xf2, 0x0, 0xcf, 0x60, 0x0, 0xc, + 0xfa, 0x0, 0xcf, 0x60, 0x0, 0x4, 0xff, 0x20, + 0xcf, 0x60, 0x0, 0x0, 0xcf, 0xa0, 0xcf, 0x60, + 0x0, 0x0, 0x4f, 0xf3, + + /* U+004C "L" */ + 0xef, 0x40, 0x0, 0x0, 0x0, 0xe, 0xf4, 0x0, + 0x0, 0x0, 0x0, 0xef, 0x40, 0x0, 0x0, 0x0, + 0xe, 0xf4, 0x0, 0x0, 0x0, 0x0, 0xef, 0x40, + 0x0, 0x0, 0x0, 0xe, 0xf4, 0x0, 0x0, 0x0, + 0x0, 0xef, 0x40, 0x0, 0x0, 0x0, 0xe, 0xf4, + 0x0, 0x0, 0x0, 0x0, 0xef, 0x40, 0x0, 0x0, + 0x0, 0xe, 0xf4, 0x0, 0x0, 0x0, 0x0, 0xef, + 0x40, 0x0, 0x0, 0x0, 0xe, 0xf4, 0x0, 0x0, + 0x0, 0x0, 0xef, 0x40, 0x0, 0x0, 0x0, 0xe, + 0xf4, 0x0, 0x0, 0x0, 0x0, 0xef, 0x40, 0x0, + 0x0, 0x0, 0xe, 0xf5, 0x0, 0x0, 0x0, 0x0, + 0xef, 0xff, 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, + 0xff, 0xff, 0xf3, + + /* U+004D "M" */ + 0x4f, 0xff, 0x10, 0x0, 0xaf, 0xfa, 0x4f, 0xdf, + 0x50, 0x0, 0xfc, 0xfa, 0x4f, 0xaf, 0xa0, 0x4, + 0xf8, 0xfa, 0x4f, 0xab, 0xe0, 0x9, 0xf5, 0xfa, + 0x4f, 0xb7, 0xf3, 0xd, 0xb5, 0xfa, 0x4f, 0xb2, + 0xf8, 0x2f, 0x65, 0xfa, 0x4f, 0xc0, 0xdc, 0x7f, + 0x16, 0xfa, 0x4f, 0xc0, 0x8f, 0xdc, 0x6, 0xfa, + 0x4f, 0xc0, 0x3f, 0xf8, 0x6, 0xfa, 0x4f, 0xc0, + 0xe, 0xf3, 0x6, 0xfa, 0x4f, 0xd0, 0x0, 0x0, + 0x6, 0xfa, 0x4f, 0xd0, 0x0, 0x0, 0x6, 0xfa, + 0x4f, 0xd0, 0x0, 0x0, 0x6, 0xfa, 0x4f, 0xd0, + 0x0, 0x0, 0x6, 0xfa, 0x4f, 0xd0, 0x0, 0x0, + 0x6, 0xfa, 0x4f, 0xd0, 0x0, 0x0, 0x6, 0xfa, + 0x4f, 0xd0, 0x0, 0x0, 0x6, 0xfa, 0x4f, 0xd0, + 0x0, 0x0, 0x6, 0xfa, + + /* U+004E "N" */ + 0xdf, 0xf3, 0x0, 0x0, 0xdf, 0x3d, 0xff, 0x90, + 0x0, 0xd, 0xf3, 0xdf, 0xfe, 0x0, 0x0, 0xdf, + 0x3d, 0xfb, 0xf4, 0x0, 0xd, 0xf3, 0xdf, 0x7f, + 0x90, 0x0, 0xdf, 0x3d, 0xf3, 0xfe, 0x0, 0xd, + 0xf3, 0xdf, 0x39, 0xf4, 0x0, 0xdf, 0x3d, 0xf3, + 0x4f, 0xa0, 0xd, 0xf3, 0xdf, 0x40, 0xef, 0x0, + 0xdf, 0x3d, 0xf4, 0x9, 0xf5, 0xd, 0xf3, 0xdf, + 0x40, 0x3f, 0xa0, 0xdf, 0x3d, 0xf4, 0x0, 0xef, + 0xd, 0xf3, 0xdf, 0x40, 0x8, 0xf6, 0xcf, 0x3d, + 0xf4, 0x0, 0x3f, 0xbb, 0xf3, 0xdf, 0x40, 0x0, + 0xdf, 0xcf, 0x3d, 0xf4, 0x0, 0x8, 0xff, 0xf3, + 0xdf, 0x40, 0x0, 0x2f, 0xff, 0x3d, 0xf4, 0x0, + 0x0, 0xdf, 0xf3, + + /* U+004F "O" */ + 0x0, 0x5c, 0xff, 0xd8, 0x10, 0x0, 0x9f, 0xff, + 0xff, 0xfd, 0x10, 0x4f, 0xf8, 0x21, 0x4e, 0xfa, + 0xa, 0xfa, 0x0, 0x0, 0x3f, 0xf1, 0xdf, 0x50, + 0x0, 0x0, 0xff, 0x3e, 0xf4, 0x0, 0x0, 0xe, + 0xf4, 0xef, 0x40, 0x0, 0x0, 0xef, 0x4e, 0xf4, + 0x0, 0x0, 0xe, 0xf4, 0xef, 0x40, 0x0, 0x0, + 0xef, 0x4e, 0xf4, 0x0, 0x0, 0xe, 0xf4, 0xef, + 0x40, 0x0, 0x0, 0xef, 0x4e, 0xf4, 0x0, 0x0, + 0xe, 0xf4, 0xef, 0x40, 0x0, 0x0, 0xef, 0x4d, + 0xf5, 0x0, 0x0, 0xf, 0xf3, 0xaf, 0xa0, 0x0, + 0x3, 0xff, 0x14, 0xff, 0x82, 0x15, 0xef, 0xa0, + 0x9, 0xff, 0xff, 0xff, 0xe1, 0x0, 0x5, 0xcf, + 0xfd, 0x81, 0x0, + + /* U+0050 "P" */ + 0xcf, 0xff, 0xff, 0xfc, 0x70, 0x0, 0xcf, 0xff, + 0xff, 0xff, 0xfc, 0x0, 0xcf, 0x60, 0x0, 0x17, + 0xff, 0x90, 0xcf, 0x60, 0x0, 0x0, 0x7f, 0xf0, + 0xcf, 0x60, 0x0, 0x0, 0x1f, 0xf2, 0xcf, 0x60, + 0x0, 0x0, 0x1f, 0xf2, 0xcf, 0x60, 0x0, 0x0, + 0x7f, 0xf0, 0xcf, 0x60, 0x0, 0x17, 0xff, 0x90, + 0xcf, 0xff, 0xff, 0xff, 0xfc, 0x0, 0xcf, 0xff, + 0xff, 0xfd, 0x70, 0x0, 0xcf, 0x60, 0x0, 0x0, + 0x0, 0x0, 0xcf, 0x60, 0x0, 0x0, 0x0, 0x0, + 0xcf, 0x60, 0x0, 0x0, 0x0, 0x0, 0xcf, 0x60, + 0x0, 0x0, 0x0, 0x0, 0xcf, 0x60, 0x0, 0x0, + 0x0, 0x0, 0xcf, 0x60, 0x0, 0x0, 0x0, 0x0, + 0xcf, 0x60, 0x0, 0x0, 0x0, 0x0, 0xcf, 0x60, + 0x0, 0x0, 0x0, 0x0, + + /* U+0051 "Q" */ + 0x0, 0x6, 0xcf, 0xfd, 0x91, 0x0, 0x0, 0xaf, + 0xff, 0xff, 0xfe, 0x20, 0x7, 0xff, 0x71, 0x4, + 0xdf, 0xd0, 0xd, 0xf8, 0x0, 0x0, 0x2f, 0xf3, + 0xf, 0xf3, 0x0, 0x0, 0xc, 0xf6, 0x1f, 0xf1, + 0x0, 0x0, 0xb, 0xf7, 0x1f, 0xf1, 0x0, 0x0, + 0xb, 0xf7, 0x1f, 0xf1, 0x0, 0x0, 0xb, 0xf7, + 0x1f, 0xf1, 0x0, 0x0, 0xb, 0xf7, 0x1f, 0xf1, + 0x0, 0x0, 0xb, 0xf7, 0x1f, 0xf1, 0x0, 0x0, + 0xb, 0xf7, 0x1f, 0xf1, 0x0, 0x0, 0xb, 0xf7, + 0x1f, 0xf1, 0x0, 0x0, 0xb, 0xf7, 0xf, 0xf3, + 0x0, 0x0, 0xc, 0xf6, 0xd, 0xf8, 0x0, 0x0, + 0x2f, 0xf3, 0x7, 0xff, 0x71, 0x4, 0xdf, 0xc0, + 0x0, 0xaf, 0xff, 0xff, 0xfe, 0x20, 0x0, 0x6, + 0xcf, 0xff, 0xf1, 0x0, 0x0, 0x0, 0x0, 0x1e, + 0xf7, 0x0, 0x0, 0x0, 0x0, 0x6, 0xff, 0x20, + 0x0, 0x0, 0x0, 0x0, 0xcf, 0xb0, 0x0, 0x0, + 0x0, 0x0, 0x3f, 0xf5, + + /* U+0052 "R" */ + 0xcf, 0xff, 0xff, 0xea, 0x30, 0x0, 0xcf, 0xff, + 0xff, 0xff, 0xf7, 0x0, 0xcf, 0x60, 0x0, 0x2a, + 0xff, 0x30, 0xcf, 0x60, 0x0, 0x0, 0xcf, 0x90, + 0xcf, 0x60, 0x0, 0x0, 0x7f, 0xc0, 0xcf, 0x60, + 0x0, 0x0, 0x7f, 0xc0, 0xcf, 0x60, 0x0, 0x0, + 0xcf, 0x90, 0xcf, 0x60, 0x0, 0x2a, 0xff, 0x30, + 0xcf, 0xff, 0xff, 0xff, 0xf7, 0x0, 0xcf, 0xff, + 0xff, 0xfd, 0x40, 0x0, 0xcf, 0x60, 0x8, 0xfc, + 0x0, 0x0, 0xcf, 0x60, 0x1, 0xff, 0x30, 0x0, + 0xcf, 0x60, 0x0, 0xaf, 0xa0, 0x0, 0xcf, 0x60, + 0x0, 0x3f, 0xf1, 0x0, 0xcf, 0x60, 0x0, 0xc, + 0xf8, 0x0, 0xcf, 0x60, 0x0, 0x6, 0xfe, 0x0, + 0xcf, 0x60, 0x0, 0x0, 0xef, 0x60, 0xcf, 0x60, + 0x0, 0x0, 0x8f, 0xd0, + + /* U+0053 "S" */ + 0x0, 0x5, 0xce, 0xfd, 0x70, 0x0, 0x0, 0x9f, + 0xff, 0xff, 0xfd, 0x10, 0x5, 0xff, 0x71, 0x15, + 0xef, 0xa0, 0xa, 0xf9, 0x0, 0x0, 0x4f, 0xf0, + 0xc, 0xf5, 0x0, 0x0, 0xa, 0xb1, 0xb, 0xf6, + 0x0, 0x0, 0x0, 0x0, 0x7, 0xfd, 0x10, 0x0, + 0x0, 0x0, 0x0, 0xdf, 0xfa, 0x51, 0x0, 0x0, + 0x0, 0x1b, 0xff, 0xff, 0xb3, 0x0, 0x0, 0x0, + 0x27, 0xcf, 0xff, 0x50, 0x0, 0x0, 0x0, 0x1, + 0x9f, 0xf1, 0x0, 0x0, 0x0, 0x0, 0xc, 0xf7, + 0x1, 0x10, 0x0, 0x0, 0x7, 0xf9, 0x3f, 0xf0, + 0x0, 0x0, 0x8, 0xfa, 0xf, 0xf5, 0x0, 0x0, + 0xd, 0xf7, 0xa, 0xff, 0x61, 0x3, 0xcf, 0xf1, + 0x1, 0xcf, 0xff, 0xff, 0xff, 0x50, 0x0, 0x7, + 0xcf, 0xfe, 0xa2, 0x0, + + /* U+0054 "T" */ + 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1b, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xf1, 0x0, 0x0, 0xe, + 0xf5, 0x0, 0x0, 0x0, 0x0, 0x0, 0xef, 0x40, + 0x0, 0x0, 0x0, 0x0, 0xe, 0xf4, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xef, 0x40, 0x0, 0x0, 0x0, + 0x0, 0xe, 0xf4, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xef, 0x40, 0x0, 0x0, 0x0, 0x0, 0xe, 0xf4, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xef, 0x40, 0x0, + 0x0, 0x0, 0x0, 0xe, 0xf4, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xef, 0x40, 0x0, 0x0, 0x0, 0x0, + 0xe, 0xf4, 0x0, 0x0, 0x0, 0x0, 0x0, 0xef, + 0x40, 0x0, 0x0, 0x0, 0x0, 0xe, 0xf4, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xef, 0x40, 0x0, 0x0, + 0x0, 0x0, 0xe, 0xf4, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xef, 0x40, 0x0, 0x0, + + /* U+0055 "U" */ + 0xdf, 0x50, 0x0, 0x0, 0xef, 0x3d, 0xf5, 0x0, + 0x0, 0xe, 0xf3, 0xdf, 0x50, 0x0, 0x0, 0xef, + 0x3d, 0xf5, 0x0, 0x0, 0xe, 0xf3, 0xdf, 0x50, + 0x0, 0x0, 0xef, 0x3d, 0xf5, 0x0, 0x0, 0xe, + 0xf3, 0xdf, 0x50, 0x0, 0x0, 0xef, 0x3d, 0xf5, + 0x0, 0x0, 0xe, 0xf3, 0xdf, 0x50, 0x0, 0x0, + 0xef, 0x3d, 0xf5, 0x0, 0x0, 0xe, 0xf3, 0xdf, + 0x50, 0x0, 0x0, 0xef, 0x3d, 0xf5, 0x0, 0x0, + 0xe, 0xf3, 0xdf, 0x50, 0x0, 0x0, 0xef, 0x3c, + 0xf6, 0x0, 0x0, 0xf, 0xf3, 0xaf, 0xa0, 0x0, + 0x4, 0xff, 0x4, 0xff, 0x81, 0x4, 0xef, 0xb0, + 0x9, 0xff, 0xff, 0xff, 0xe2, 0x0, 0x6, 0xcf, + 0xfd, 0x91, 0x0, + + /* U+0056 "V" */ + 0xaf, 0x80, 0x0, 0x0, 0x2, 0xff, 0x16, 0xfc, + 0x0, 0x0, 0x0, 0x6f, 0xd0, 0x2f, 0xf0, 0x0, + 0x0, 0x9, 0xf9, 0x0, 0xef, 0x40, 0x0, 0x0, + 0xdf, 0x50, 0xa, 0xf8, 0x0, 0x0, 0x1f, 0xf1, + 0x0, 0x6f, 0xc0, 0x0, 0x5, 0xfc, 0x0, 0x2, + 0xff, 0x0, 0x0, 0x8f, 0x80, 0x0, 0xe, 0xf3, + 0x0, 0xc, 0xf4, 0x0, 0x0, 0xaf, 0x70, 0x0, + 0xff, 0x10, 0x0, 0x6, 0xfb, 0x0, 0x4f, 0xc0, + 0x0, 0x0, 0x2f, 0xf0, 0x8, 0xf8, 0x0, 0x0, + 0x0, 0xef, 0x30, 0xbf, 0x40, 0x0, 0x0, 0xa, + 0xf7, 0xf, 0xf0, 0x0, 0x0, 0x0, 0x6f, 0xa3, + 0xfc, 0x0, 0x0, 0x0, 0x2, 0xfe, 0x6f, 0x80, + 0x0, 0x0, 0x0, 0xe, 0xfb, 0xf4, 0x0, 0x0, + 0x0, 0x0, 0xaf, 0xff, 0x0, 0x0, 0x0, 0x0, + 0x6, 0xff, 0xc0, 0x0, 0x0, + + /* U+0057 "W" */ + 0x7f, 0x80, 0x0, 0xff, 0x70, 0x0, 0xfd, 0x5f, + 0x90, 0x1, 0xff, 0x90, 0x2, 0xfb, 0x3f, 0xb0, + 0x3, 0xfd, 0xb0, 0x3, 0xf9, 0x1f, 0xd0, 0x5, + 0xfa, 0xd0, 0x5, 0xf8, 0xf, 0xe0, 0x7, 0xf8, + 0xf0, 0x7, 0xf6, 0xe, 0xf0, 0x9, 0xd6, 0xf1, + 0x8, 0xf4, 0xc, 0xf2, 0xb, 0xb4, 0xf3, 0xa, + 0xf2, 0xa, 0xf3, 0xe, 0x92, 0xf5, 0xc, 0xf0, + 0x8, 0xf5, 0xf, 0x70, 0xf7, 0xe, 0xe0, 0x6, + 0xf7, 0x2f, 0x50, 0xe8, 0xf, 0xc0, 0x4, 0xf8, + 0x4f, 0x30, 0xca, 0x1f, 0xa0, 0x3, 0xfa, 0x6f, + 0x10, 0xbc, 0x3f, 0x80, 0x1, 0xfc, 0x8f, 0x0, + 0x9e, 0x4f, 0x60, 0x0, 0xfd, 0xad, 0x0, 0x7f, + 0x7f, 0x50, 0x0, 0xdf, 0xcb, 0x0, 0x5f, 0xaf, + 0x30, 0x0, 0xbf, 0xd9, 0x0, 0x3f, 0xdf, 0x10, + 0x0, 0x9f, 0xf7, 0x0, 0x1f, 0xff, 0x0, 0x0, + 0x7f, 0xf5, 0x0, 0xf, 0xfd, 0x0, + + /* U+0058 "X" */ + 0x8, 0xfe, 0x0, 0x0, 0x0, 0x7f, 0xd0, 0x0, + 0xef, 0x70, 0x0, 0x0, 0xef, 0x50, 0x0, 0x7f, + 0xe1, 0x0, 0x8, 0xfc, 0x0, 0x0, 0xd, 0xf8, + 0x0, 0x1f, 0xf4, 0x0, 0x0, 0x5, 0xff, 0x10, + 0x8f, 0xb0, 0x0, 0x0, 0x0, 0xcf, 0x81, 0xff, + 0x20, 0x0, 0x0, 0x0, 0x4f, 0xf9, 0xf9, 0x0, + 0x0, 0x0, 0x0, 0xb, 0xff, 0xf1, 0x0, 0x0, + 0x0, 0x0, 0x3, 0xff, 0x90, 0x0, 0x0, 0x0, + 0x0, 0x5, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, + 0xd, 0xfe, 0xf5, 0x0, 0x0, 0x0, 0x0, 0x7f, + 0xc6, 0xfe, 0x0, 0x0, 0x0, 0x1, 0xef, 0x40, + 0xef, 0x70, 0x0, 0x0, 0x8, 0xfb, 0x0, 0x6f, + 0xe1, 0x0, 0x0, 0x2f, 0xf3, 0x0, 0xd, 0xf8, + 0x0, 0x0, 0xaf, 0xa0, 0x0, 0x5, 0xff, 0x10, + 0x3, 0xff, 0x20, 0x0, 0x0, 0xdf, 0x90, 0xc, + 0xf9, 0x0, 0x0, 0x0, 0x4f, 0xf2, + + /* U+0059 "Y" */ + 0xe, 0xf5, 0x0, 0x0, 0x0, 0xe, 0xf5, 0x7, + 0xfd, 0x0, 0x0, 0x0, 0x5f, 0xd0, 0x0, 0xef, + 0x40, 0x0, 0x0, 0xdf, 0x60, 0x0, 0x8f, 0xc0, + 0x0, 0x4, 0xfe, 0x0, 0x0, 0x1f, 0xf3, 0x0, + 0xb, 0xf7, 0x0, 0x0, 0x9, 0xfa, 0x0, 0x3f, + 0xe0, 0x0, 0x0, 0x2, 0xff, 0x20, 0xaf, 0x80, + 0x0, 0x0, 0x0, 0xaf, 0x92, 0xff, 0x10, 0x0, + 0x0, 0x0, 0x2f, 0xf9, 0xf9, 0x0, 0x0, 0x0, + 0x0, 0xb, 0xff, 0xf1, 0x0, 0x0, 0x0, 0x0, + 0x3, 0xff, 0xa0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xef, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0xef, + 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0xef, 0x40, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xef, 0x40, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xef, 0x40, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xef, 0x40, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xef, 0x40, 0x0, 0x0, + + /* U+005A "Z" */ + 0xdf, 0xff, 0xff, 0xff, 0xff, 0x2d, 0xff, 0xff, + 0xff, 0xff, 0xf2, 0x0, 0x0, 0x0, 0x5, 0xfe, + 0x0, 0x0, 0x0, 0x0, 0xdf, 0x60, 0x0, 0x0, + 0x0, 0x7f, 0xd0, 0x0, 0x0, 0x0, 0x1f, 0xf3, + 0x0, 0x0, 0x0, 0xa, 0xfa, 0x0, 0x0, 0x0, + 0x3, 0xff, 0x20, 0x0, 0x0, 0x0, 0xcf, 0x80, + 0x0, 0x0, 0x0, 0x5f, 0xe0, 0x0, 0x0, 0x0, + 0xe, 0xf5, 0x0, 0x0, 0x0, 0x8, 0xfc, 0x0, + 0x0, 0x0, 0x1, 0xff, 0x30, 0x0, 0x0, 0x0, + 0xaf, 0xa0, 0x0, 0x0, 0x0, 0x3f, 0xf1, 0x0, + 0x0, 0x0, 0xc, 0xf8, 0x0, 0x0, 0x0, 0x0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x5f, 0xff, 0xff, + 0xff, 0xff, 0xf5, + + /* U+005B "[" */ + 0x1f, 0xff, 0xff, 0xc1, 0xff, 0xff, 0xfc, 0x1f, + 0xf1, 0x0, 0x1, 0xff, 0x10, 0x0, 0x1f, 0xf1, + 0x0, 0x1, 0xff, 0x10, 0x0, 0x1f, 0xf1, 0x0, + 0x1, 0xff, 0x10, 0x0, 0x1f, 0xf1, 0x0, 0x1, + 0xff, 0x10, 0x0, 0x1f, 0xf1, 0x0, 0x1, 0xff, + 0x10, 0x0, 0x1f, 0xf1, 0x0, 0x1, 0xff, 0x10, + 0x0, 0x1f, 0xf1, 0x0, 0x1, 0xff, 0x10, 0x0, + 0x1f, 0xf1, 0x0, 0x1, 0xff, 0x10, 0x0, 0x1f, + 0xf1, 0x0, 0x1, 0xff, 0x10, 0x0, 0x1f, 0xf1, + 0x0, 0x1, 0xff, 0x10, 0x0, 0x1f, 0xff, 0xff, + 0xc1, 0xff, 0xff, 0xfc, + + /* U+005C "\\" */ + 0x8, 0x81, 0x0, 0x0, 0x0, 0x0, 0xd, 0xf7, + 0x0, 0x0, 0x0, 0x0, 0x7, 0xfc, 0x0, 0x0, + 0x0, 0x0, 0x1, 0xff, 0x20, 0x0, 0x0, 0x0, + 0x0, 0xcf, 0x80, 0x0, 0x0, 0x0, 0x0, 0x6f, + 0xe0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xf4, 0x0, + 0x0, 0x0, 0x0, 0xa, 0xf9, 0x0, 0x0, 0x0, + 0x0, 0x4, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xef, 0x50, 0x0, 0x0, 0x0, 0x0, 0x9f, 0xb0, + 0x0, 0x0, 0x0, 0x0, 0x3f, 0xf1, 0x0, 0x0, + 0x0, 0x0, 0xd, 0xf6, 0x0, 0x0, 0x0, 0x0, + 0x7, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x2, 0xff, + 0x20, 0x0, 0x0, 0x0, 0x0, 0xcf, 0x80, 0x0, + 0x0, 0x0, 0x0, 0x6f, 0xd0, 0x0, 0x0, 0x0, + 0x0, 0x1f, 0xf3, 0x0, 0x0, 0x0, 0x0, 0xa, + 0xf9, 0x0, 0x0, 0x0, 0x0, 0x5, 0xfe, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xef, 0x50, 0x0, 0x0, + 0x0, 0x0, 0x9f, 0xa0, 0x0, 0x0, 0x0, 0x0, + 0x3f, 0xf1, 0x0, 0x0, 0x0, 0x0, 0xd, 0xf6, + + /* U+005D "]" */ + 0x6f, 0xff, 0xff, 0x76, 0xff, 0xff, 0xf7, 0x0, + 0x0, 0xbf, 0x70, 0x0, 0xb, 0xf7, 0x0, 0x0, + 0xbf, 0x70, 0x0, 0xb, 0xf7, 0x0, 0x0, 0xbf, + 0x70, 0x0, 0xb, 0xf7, 0x0, 0x0, 0xbf, 0x70, + 0x0, 0xb, 0xf7, 0x0, 0x0, 0xbf, 0x70, 0x0, + 0xb, 0xf7, 0x0, 0x0, 0xbf, 0x70, 0x0, 0xb, + 0xf7, 0x0, 0x0, 0xbf, 0x70, 0x0, 0xb, 0xf7, + 0x0, 0x0, 0xbf, 0x70, 0x0, 0xb, 0xf7, 0x0, + 0x0, 0xbf, 0x70, 0x0, 0xb, 0xf7, 0x0, 0x0, + 0xbf, 0x70, 0x0, 0xb, 0xf7, 0x6f, 0xff, 0xff, + 0x76, 0xff, 0xff, 0xf7, + + /* U+005E "^" */ + 0x0, 0x0, 0xf, 0xf7, 0x0, 0x0, 0x0, 0x0, + 0x6f, 0xfd, 0x0, 0x0, 0x0, 0x0, 0xde, 0x7f, + 0x40, 0x0, 0x0, 0x4, 0xf9, 0x1f, 0xb0, 0x0, + 0x0, 0xb, 0xf2, 0xb, 0xf2, 0x0, 0x0, 0x2f, + 0xb0, 0x4, 0xf9, 0x0, 0x0, 0x9f, 0x50, 0x0, + 0xef, 0x0, 0x0, 0xfe, 0x0, 0x0, 0x7f, 0x60, + 0x7, 0xf7, 0x0, 0x0, 0x1f, 0xd0, 0xd, 0xf1, + 0x0, 0x0, 0xa, 0xf4, + + /* U+005F "_" */ + 0x7e, 0xee, 0xee, 0xee, 0xee, 0xed, 0x9f, 0xff, + 0xff, 0xff, 0xff, 0xff, + + /* U+0060 "`" */ + 0x7, 0x83, 0x0, 0x5, 0xfe, 0x10, 0x0, 0x8f, + 0xc0, 0x0, 0xb, 0xf8, + + /* U+0061 "a" */ + 0x0, 0x6, 0xce, 0xfe, 0x92, 0x0, 0x0, 0xcf, + 0xff, 0xff, 0xff, 0x30, 0x7, 0xfe, 0x40, 0x2, + 0xbf, 0xc0, 0x6, 0x84, 0x0, 0x0, 0x2f, 0xf1, + 0x0, 0x0, 0x0, 0x0, 0xf, 0xf2, 0x0, 0x17, + 0xbc, 0xcc, 0xcf, 0xf3, 0x3, 0xef, 0xff, 0xff, + 0xff, 0xf3, 0xe, 0xfb, 0x20, 0x0, 0xf, 0xf3, + 0x3f, 0xf1, 0x0, 0x0, 0xf, 0xf3, 0x5f, 0xd0, + 0x0, 0x0, 0x1f, 0xf3, 0x4f, 0xf0, 0x0, 0x0, + 0x6f, 0xf3, 0xf, 0xfb, 0x10, 0x6, 0xdf, 0xf3, + 0x6, 0xff, 0xff, 0xff, 0x7f, 0xf3, 0x0, 0x4c, + 0xff, 0xc5, 0xf, 0xf3, + + /* U+0062 "b" */ + 0xcf, 0x60, 0x0, 0x0, 0x0, 0xc, 0xf6, 0x0, + 0x0, 0x0, 0x0, 0xcf, 0x60, 0x0, 0x0, 0x0, + 0xc, 0xf5, 0x0, 0x0, 0x0, 0x0, 0xcf, 0x53, + 0xbe, 0xfb, 0x30, 0xc, 0xf7, 0xff, 0xff, 0xff, + 0x30, 0xcf, 0xd9, 0x10, 0x3c, 0xfd, 0xc, 0xfc, + 0x0, 0x0, 0x2f, 0xf2, 0xcf, 0x70, 0x0, 0x0, + 0xef, 0x4c, 0xf6, 0x0, 0x0, 0xd, 0xf4, 0xcf, + 0x60, 0x0, 0x0, 0xdf, 0x5c, 0xf6, 0x0, 0x0, + 0xd, 0xf5, 0xcf, 0x60, 0x0, 0x0, 0xdf, 0x5c, + 0xf7, 0x0, 0x0, 0xe, 0xf4, 0xcf, 0xc0, 0x0, + 0x2, 0xff, 0x2c, 0xfd, 0x81, 0x3, 0xcf, 0xd0, + 0xcf, 0x8f, 0xff, 0xff, 0xf3, 0xc, 0xf6, 0x3b, + 0xef, 0xb3, 0x0, + + /* U+0063 "c" */ + 0x0, 0x4b, 0xef, 0xea, 0x20, 0x0, 0x8f, 0xff, + 0xff, 0xff, 0x40, 0x4f, 0xf9, 0x20, 0x3b, 0xfe, + 0x1a, 0xfa, 0x0, 0x0, 0xe, 0xf5, 0xdf, 0x50, + 0x0, 0x0, 0x7b, 0x5e, 0xf4, 0x0, 0x0, 0x0, + 0x0, 0xef, 0x40, 0x0, 0x0, 0x0, 0xe, 0xf4, + 0x0, 0x0, 0x0, 0x0, 0xef, 0x40, 0x0, 0x0, + 0x0, 0xd, 0xf5, 0x0, 0x0, 0x7, 0xb5, 0xaf, + 0xb0, 0x0, 0x0, 0xef, 0x54, 0xff, 0x92, 0x3, + 0xbf, 0xe1, 0x8, 0xff, 0xff, 0xff, 0xf5, 0x0, + 0x4, 0xbe, 0xfe, 0xa2, 0x0, + + /* U+0064 "d" */ + 0x0, 0x0, 0x0, 0x0, 0xff, 0x30, 0x0, 0x0, + 0x0, 0xf, 0xf3, 0x0, 0x0, 0x0, 0x0, 0xff, + 0x30, 0x0, 0x0, 0x0, 0xf, 0xf3, 0x0, 0x8e, + 0xfd, 0x60, 0xff, 0x30, 0xcf, 0xff, 0xff, 0x7f, + 0xf3, 0x6f, 0xf6, 0x0, 0x4d, 0xff, 0x3b, 0xf8, + 0x0, 0x0, 0x5f, 0xf3, 0xef, 0x50, 0x0, 0x1, + 0xff, 0x3e, 0xf4, 0x0, 0x0, 0xf, 0xf3, 0xef, + 0x40, 0x0, 0x0, 0xff, 0x3e, 0xf4, 0x0, 0x0, + 0xf, 0xf3, 0xef, 0x40, 0x0, 0x0, 0xff, 0x3e, + 0xf5, 0x0, 0x0, 0x1f, 0xf3, 0xbf, 0x80, 0x0, + 0x5, 0xff, 0x36, 0xff, 0x60, 0x4, 0xcf, 0xf3, + 0xc, 0xff, 0xff, 0xf7, 0xff, 0x30, 0x8, 0xef, + 0xd7, 0xf, 0xf3, + + /* U+0065 "e" */ + 0x0, 0x5b, 0xff, 0xd8, 0x0, 0x0, 0x9f, 0xff, + 0xef, 0xfd, 0x10, 0x4f, 0xf5, 0x0, 0x2c, 0xfb, + 0xb, 0xf8, 0x0, 0x0, 0x2f, 0xf1, 0xef, 0x30, + 0x0, 0x0, 0xdf, 0x4f, 0xf2, 0x0, 0x0, 0xb, + 0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0xfc, + 0xcc, 0xcc, 0xcc, 0xc4, 0xff, 0x20, 0x0, 0x0, + 0x0, 0xe, 0xf3, 0x0, 0x0, 0x0, 0x0, 0xbf, + 0x80, 0x0, 0x0, 0x9a, 0x24, 0xff, 0x71, 0x2, + 0xaf, 0xe0, 0x9, 0xff, 0xff, 0xff, 0xf4, 0x0, + 0x5, 0xbf, 0xfd, 0x91, 0x0, + + /* U+0066 "f" */ + 0x0, 0x0, 0x4, 0xcf, 0xff, 0xfb, 0x0, 0x0, + 0x4f, 0xff, 0xff, 0xfb, 0x0, 0x0, 0xbf, 0xa1, + 0x0, 0x0, 0x0, 0x0, 0xdf, 0x50, 0x0, 0x0, + 0x0, 0x0, 0xdf, 0x50, 0x0, 0x0, 0x0, 0x0, + 0xdf, 0x50, 0x0, 0x0, 0xbf, 0xff, 0xff, 0xff, + 0xff, 0xfb, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xfb, + 0x0, 0x0, 0xdf, 0x50, 0x0, 0x0, 0x0, 0x0, + 0xdf, 0x50, 0x0, 0x0, 0x0, 0x0, 0xdf, 0x50, + 0x0, 0x0, 0x0, 0x0, 0xdf, 0x50, 0x0, 0x0, + 0x0, 0x0, 0xdf, 0x50, 0x0, 0x0, 0x0, 0x0, + 0xdf, 0x50, 0x0, 0x0, 0x0, 0x0, 0xdf, 0x50, + 0x0, 0x0, 0x0, 0x0, 0xdf, 0x50, 0x0, 0x0, + 0x0, 0x0, 0xdf, 0x50, 0x0, 0x0, 0x0, 0x0, + 0xdf, 0x50, 0x0, 0x0, + + /* U+0067 "g" */ + 0x0, 0x8e, 0xfd, 0x70, 0xff, 0x20, 0xcf, 0xff, + 0xff, 0x8f, 0xf2, 0x6f, 0xf7, 0x10, 0x4d, 0xff, + 0x2b, 0xf9, 0x0, 0x0, 0x5f, 0xf2, 0xdf, 0x50, + 0x0, 0x1, 0xff, 0x2e, 0xf4, 0x0, 0x0, 0xf, + 0xf2, 0xef, 0x40, 0x0, 0x0, 0xff, 0x2e, 0xf4, + 0x0, 0x0, 0xf, 0xf2, 0xdf, 0x50, 0x0, 0x1, + 0xff, 0x2b, 0xf9, 0x0, 0x0, 0x6f, 0xf2, 0x5f, + 0xf7, 0x11, 0x5d, 0xff, 0x20, 0xbf, 0xff, 0xff, + 0x7f, 0xf2, 0x0, 0x6c, 0xdb, 0x60, 0xff, 0x20, + 0x0, 0x0, 0x0, 0xf, 0xf2, 0x0, 0x0, 0x0, + 0x2, 0xff, 0x10, 0x0, 0x0, 0x3, 0xcf, 0xc0, + 0x2, 0xff, 0xff, 0xff, 0xf3, 0x0, 0x2f, 0xff, + 0xfe, 0xa2, 0x0, + + /* U+0068 "h" */ + 0xcf, 0x60, 0x0, 0x0, 0x0, 0xc, 0xf6, 0x0, + 0x0, 0x0, 0x0, 0xcf, 0x60, 0x0, 0x0, 0x0, + 0xc, 0xf6, 0x0, 0x0, 0x0, 0x0, 0xcf, 0x63, + 0xcf, 0xfb, 0x30, 0xc, 0xf8, 0xff, 0xff, 0xff, + 0x30, 0xcf, 0xe8, 0x0, 0x3d, 0xfc, 0xc, 0xfb, + 0x0, 0x0, 0x4f, 0xf1, 0xcf, 0x70, 0x0, 0x0, + 0xff, 0x3c, 0xf6, 0x0, 0x0, 0xe, 0xf3, 0xcf, + 0x60, 0x0, 0x0, 0xef, 0x3c, 0xf6, 0x0, 0x0, + 0xe, 0xf3, 0xcf, 0x60, 0x0, 0x0, 0xef, 0x3c, + 0xf6, 0x0, 0x0, 0xe, 0xf3, 0xcf, 0x60, 0x0, + 0x0, 0xef, 0x3c, 0xf6, 0x0, 0x0, 0xe, 0xf3, + 0xcf, 0x60, 0x0, 0x0, 0xef, 0x3c, 0xf6, 0x0, + 0x0, 0xe, 0xf3, + + /* U+0069 "i" */ + 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xcf, 0xd0, 0x0, 0x0, 0x0, 0x1, 0xff, 0xf3, + 0x0, 0x0, 0x0, 0x0, 0xaf, 0xb0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x7f, 0xff, 0xff, 0xe0, + 0x0, 0x0, 0x7f, 0xff, 0xff, 0xe0, 0x0, 0x0, + 0x0, 0x0, 0x5f, 0xe0, 0x0, 0x0, 0x0, 0x0, + 0x4f, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x4f, 0xe0, + 0x0, 0x0, 0x0, 0x0, 0x4f, 0xe0, 0x0, 0x0, + 0x0, 0x0, 0x4f, 0xe0, 0x0, 0x0, 0x0, 0x0, + 0x4f, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x4f, 0xe0, + 0x0, 0x0, 0x0, 0x0, 0x4f, 0xe0, 0x0, 0x0, + 0x0, 0x0, 0x4f, 0xe0, 0x0, 0x0, 0x0, 0x0, + 0x5f, 0xe0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xf5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf5, + + /* U+006A "j" */ + 0x0, 0x0, 0x2, 0xde, 0x50, 0x0, 0x0, 0x8f, + 0xfc, 0x0, 0x0, 0x4, 0xff, 0x80, 0x0, 0x0, + 0x1, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0x7f, + 0xff, 0xff, 0xff, 0xf7, 0x0, 0x0, 0x0, 0xbf, + 0x70, 0x0, 0x0, 0xb, 0xf7, 0x0, 0x0, 0x0, + 0xbf, 0x70, 0x0, 0x0, 0xb, 0xf7, 0x0, 0x0, + 0x0, 0xbf, 0x70, 0x0, 0x0, 0xb, 0xf7, 0x0, + 0x0, 0x0, 0xbf, 0x70, 0x0, 0x0, 0xb, 0xf7, + 0x0, 0x0, 0x0, 0xbf, 0x70, 0x0, 0x0, 0xb, + 0xf7, 0x0, 0x0, 0x0, 0xbf, 0x60, 0x0, 0x0, + 0xd, 0xf6, 0x0, 0x0, 0x2, 0xff, 0x30, 0x0, + 0x15, 0xdf, 0xc0, 0xdf, 0xff, 0xff, 0xe2, 0xd, + 0xff, 0xfd, 0x81, 0x0, + + /* U+006B "k" */ + 0xaf, 0x70, 0x0, 0x0, 0x0, 0x0, 0xaf, 0x70, + 0x0, 0x0, 0x0, 0x0, 0xaf, 0x70, 0x0, 0x0, + 0x0, 0x0, 0xaf, 0x70, 0x0, 0x0, 0x0, 0x0, + 0xaf, 0x70, 0x0, 0x0, 0x9f, 0xd0, 0xaf, 0x70, + 0x0, 0x3, 0xff, 0x30, 0xaf, 0x70, 0x0, 0xd, + 0xfa, 0x0, 0xaf, 0x70, 0x0, 0x7f, 0xe1, 0x0, + 0xaf, 0x70, 0x1, 0xff, 0x60, 0x0, 0xaf, 0x70, + 0xa, 0xfc, 0x0, 0x0, 0xaf, 0xff, 0xff, 0xf2, + 0x0, 0x0, 0xaf, 0xff, 0xff, 0xf5, 0x0, 0x0, + 0xaf, 0x70, 0x9, 0xfe, 0x0, 0x0, 0xaf, 0x70, + 0x0, 0xef, 0x90, 0x0, 0xaf, 0x70, 0x0, 0x5f, + 0xf3, 0x0, 0xaf, 0x70, 0x0, 0xb, 0xfd, 0x0, + 0xaf, 0x70, 0x0, 0x1, 0xff, 0x70, 0xaf, 0x70, + 0x0, 0x0, 0x6f, 0xf2, + + /* U+006C "l" */ + 0x4f, 0xff, 0xff, 0xf7, 0x0, 0x0, 0x0, 0x4f, + 0xff, 0xff, 0xf7, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xb, 0xf7, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, + 0xf7, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xf7, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xf7, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xb, 0xf7, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xb, 0xf7, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xb, 0xf7, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xb, 0xf7, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xb, 0xf7, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, + 0xf7, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xf7, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xf7, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xb, 0xf7, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x8, 0xfe, 0x30, 0x0, 0x0, + 0x0, 0x0, 0x1, 0xef, 0xff, 0xff, 0xf3, 0x0, + 0x0, 0x0, 0x2b, 0xff, 0xff, 0xf3, + + /* U+006D "m" */ + 0x9f, 0x5b, 0xfc, 0x14, 0xde, 0x90, 0x9f, 0xcd, + 0xef, 0xbe, 0xcf, 0xf7, 0x9f, 0xb0, 0xe, 0xf5, + 0x5, 0xfc, 0x9f, 0x70, 0xb, 0xf1, 0x1, 0xfe, + 0x9f, 0x70, 0xb, 0xf1, 0x1, 0xff, 0x9f, 0x70, + 0xb, 0xf1, 0x1, 0xff, 0x9f, 0x70, 0xb, 0xf1, + 0x1, 0xff, 0x9f, 0x70, 0xb, 0xf1, 0x1, 0xff, + 0x9f, 0x70, 0xb, 0xf1, 0x1, 0xff, 0x9f, 0x70, + 0xb, 0xf1, 0x1, 0xff, 0x9f, 0x70, 0xb, 0xf1, + 0x1, 0xff, 0x9f, 0x70, 0xb, 0xf1, 0x1, 0xff, + 0x9f, 0x70, 0xb, 0xf1, 0x1, 0xff, 0x9f, 0x70, + 0xb, 0xf1, 0x1, 0xff, + + /* U+006E "n" */ + 0xcf, 0x63, 0xcf, 0xfb, 0x30, 0xc, 0xf8, 0xff, + 0xff, 0xff, 0x30, 0xcf, 0xe8, 0x0, 0x3d, 0xfc, + 0xc, 0xfb, 0x0, 0x0, 0x4f, 0xf1, 0xcf, 0x70, + 0x0, 0x0, 0xff, 0x3c, 0xf6, 0x0, 0x0, 0xe, + 0xf3, 0xcf, 0x60, 0x0, 0x0, 0xef, 0x3c, 0xf6, + 0x0, 0x0, 0xe, 0xf3, 0xcf, 0x60, 0x0, 0x0, + 0xef, 0x3c, 0xf6, 0x0, 0x0, 0xe, 0xf3, 0xcf, + 0x60, 0x0, 0x0, 0xef, 0x3c, 0xf6, 0x0, 0x0, + 0xe, 0xf3, 0xcf, 0x60, 0x0, 0x0, 0xef, 0x3c, + 0xf6, 0x0, 0x0, 0xe, 0xf3, + + /* U+006F "o" */ + 0x0, 0x5c, 0xff, 0xd8, 0x10, 0x0, 0x9f, 0xff, + 0xff, 0xfe, 0x10, 0x5f, 0xf7, 0x10, 0x4d, 0xfb, + 0xb, 0xf9, 0x0, 0x0, 0x3f, 0xf1, 0xef, 0x40, + 0x0, 0x0, 0xef, 0x5f, 0xf2, 0x0, 0x0, 0xc, + 0xf6, 0xff, 0x20, 0x0, 0x0, 0xcf, 0x6f, 0xf2, + 0x0, 0x0, 0xc, 0xf6, 0xff, 0x20, 0x0, 0x0, + 0xcf, 0x6e, 0xf4, 0x0, 0x0, 0xe, 0xf5, 0xbf, + 0x90, 0x0, 0x3, 0xff, 0x15, 0xff, 0x71, 0x4, + 0xdf, 0xb0, 0x9, 0xff, 0xff, 0xff, 0xe1, 0x0, + 0x5, 0xcf, 0xfd, 0x81, 0x0, + + /* U+0070 "p" */ + 0xcf, 0x63, 0xbe, 0xfb, 0x30, 0xc, 0xf8, 0xff, + 0xff, 0xff, 0x30, 0xcf, 0xe9, 0x10, 0x3c, 0xfd, + 0xc, 0xfc, 0x0, 0x0, 0x2f, 0xf2, 0xcf, 0x70, + 0x0, 0x0, 0xef, 0x4c, 0xf6, 0x0, 0x0, 0xd, + 0xf5, 0xcf, 0x60, 0x0, 0x0, 0xdf, 0x5c, 0xf6, + 0x0, 0x0, 0xd, 0xf5, 0xcf, 0x60, 0x0, 0x0, + 0xdf, 0x4c, 0xf7, 0x0, 0x0, 0xe, 0xf4, 0xcf, + 0xc0, 0x0, 0x2, 0xff, 0x2c, 0xfd, 0x81, 0x3, + 0xcf, 0xd0, 0xcf, 0x7f, 0xff, 0xff, 0xf3, 0xc, + 0xf5, 0x3b, 0xef, 0xb3, 0x0, 0xcf, 0x50, 0x0, + 0x0, 0x0, 0xc, 0xf6, 0x0, 0x0, 0x0, 0x0, + 0xcf, 0x60, 0x0, 0x0, 0x0, 0xc, 0xf6, 0x0, + 0x0, 0x0, 0x0, + + /* U+0071 "q" */ + 0x0, 0x8e, 0xfd, 0x70, 0xff, 0x30, 0xcf, 0xff, + 0xff, 0x7f, 0xf3, 0x6f, 0xf6, 0x0, 0x4d, 0xff, + 0x3b, 0xf8, 0x0, 0x0, 0x5f, 0xf3, 0xdf, 0x40, + 0x0, 0x1, 0xff, 0x3e, 0xf4, 0x0, 0x0, 0xf, + 0xf3, 0xef, 0x40, 0x0, 0x0, 0xff, 0x3e, 0xf4, + 0x0, 0x0, 0xf, 0xf3, 0xef, 0x40, 0x0, 0x0, + 0xff, 0x3e, 0xf4, 0x0, 0x0, 0x1f, 0xf3, 0xbf, + 0x80, 0x0, 0x5, 0xff, 0x36, 0xff, 0x60, 0x4, + 0xcf, 0xf3, 0xc, 0xff, 0xff, 0xf7, 0xff, 0x30, + 0x9, 0xef, 0xd6, 0xf, 0xf3, 0x0, 0x0, 0x0, + 0x0, 0xff, 0x30, 0x0, 0x0, 0x0, 0xf, 0xf3, + 0x0, 0x0, 0x0, 0x0, 0xff, 0x30, 0x0, 0x0, + 0x0, 0xf, 0xf3, + + /* U+0072 "r" */ + 0x5f, 0xd0, 0x8d, 0xfd, 0x80, 0x5, 0xfd, 0x9f, + 0xff, 0xff, 0xb0, 0x5f, 0xec, 0x30, 0x17, 0xff, + 0x45, 0xff, 0x30, 0x0, 0xb, 0xf9, 0x5f, 0xf0, + 0x0, 0x0, 0x7f, 0xb5, 0xfd, 0x0, 0x0, 0x7, + 0xfb, 0x5f, 0xd0, 0x0, 0x0, 0x2, 0x15, 0xfd, + 0x0, 0x0, 0x0, 0x0, 0x5f, 0xd0, 0x0, 0x0, + 0x0, 0x5, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x5f, + 0xd0, 0x0, 0x0, 0x0, 0x5, 0xfd, 0x0, 0x0, + 0x0, 0x0, 0x5f, 0xd0, 0x0, 0x0, 0x0, 0x5, + 0xfd, 0x0, 0x0, 0x0, 0x0, + + /* U+0073 "s" */ + 0x1, 0x9e, 0xff, 0xeb, 0x30, 0x1, 0xef, 0xfe, + 0xef, 0xff, 0x50, 0x9f, 0xd2, 0x0, 0x9, 0xfe, + 0xc, 0xf6, 0x0, 0x0, 0x8, 0x81, 0xbf, 0x70, + 0x0, 0x0, 0x0, 0x7, 0xff, 0x96, 0x41, 0x0, + 0x0, 0xc, 0xff, 0xff, 0xfe, 0x80, 0x0, 0x4, + 0x8a, 0xdf, 0xff, 0xa0, 0x0, 0x0, 0x0, 0x5, + 0xff, 0x20, 0x0, 0x0, 0x0, 0xd, 0xf4, 0xdf, + 0x40, 0x0, 0x0, 0xdf, 0x5b, 0xfc, 0x20, 0x0, + 0x8f, 0xf1, 0x3f, 0xff, 0xff, 0xff, 0xf8, 0x0, + 0x2a, 0xef, 0xff, 0xc5, 0x0, + + /* U+0074 "t" */ + 0x0, 0x0, 0x88, 0x0, 0x0, 0x0, 0x0, 0x1, + 0xff, 0x10, 0x0, 0x0, 0x0, 0x1, 0xff, 0x10, + 0x0, 0x0, 0x0, 0x1, 0xff, 0x10, 0x0, 0x0, + 0xef, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xef, 0xff, + 0xff, 0xff, 0xff, 0xf7, 0x0, 0x1, 0xff, 0x10, + 0x0, 0x0, 0x0, 0x1, 0xff, 0x10, 0x0, 0x0, + 0x0, 0x1, 0xff, 0x10, 0x0, 0x0, 0x0, 0x1, + 0xff, 0x10, 0x0, 0x0, 0x0, 0x1, 0xff, 0x10, + 0x0, 0x0, 0x0, 0x1, 0xff, 0x10, 0x0, 0x0, + 0x0, 0x1, 0xff, 0x10, 0x0, 0x0, 0x0, 0x1, + 0xff, 0x10, 0x0, 0x0, 0x0, 0x0, 0xff, 0x10, + 0x0, 0x0, 0x0, 0x0, 0xef, 0x81, 0x0, 0x0, + 0x0, 0x0, 0x6f, 0xff, 0xff, 0xf5, 0x0, 0x0, + 0x6, 0xdf, 0xff, 0xf5, + + /* U+0075 "u" */ + 0xdf, 0x50, 0x0, 0x0, 0xef, 0x3d, 0xf5, 0x0, + 0x0, 0xe, 0xf3, 0xdf, 0x50, 0x0, 0x0, 0xef, + 0x3d, 0xf5, 0x0, 0x0, 0xe, 0xf3, 0xdf, 0x50, + 0x0, 0x0, 0xef, 0x3d, 0xf5, 0x0, 0x0, 0xe, + 0xf3, 0xdf, 0x50, 0x0, 0x0, 0xef, 0x3d, 0xf5, + 0x0, 0x0, 0xe, 0xf3, 0xdf, 0x50, 0x0, 0x0, + 0xef, 0x3c, 0xf6, 0x0, 0x0, 0xf, 0xf2, 0x9f, + 0xb0, 0x0, 0x5, 0xff, 0x3, 0xff, 0x81, 0x5, + 0xef, 0x90, 0x8, 0xff, 0xff, 0xff, 0xd0, 0x0, + 0x5, 0xcf, 0xfd, 0x80, 0x0, + + /* U+0076 "v" */ + 0x8f, 0xc0, 0x0, 0x0, 0x5, 0xfe, 0x3, 0xff, + 0x10, 0x0, 0x0, 0xaf, 0xa0, 0xe, 0xf6, 0x0, + 0x0, 0xe, 0xf4, 0x0, 0x9f, 0xb0, 0x0, 0x3, + 0xff, 0x0, 0x4, 0xff, 0x0, 0x0, 0x8f, 0xa0, + 0x0, 0xe, 0xf4, 0x0, 0xd, 0xf5, 0x0, 0x0, + 0xaf, 0x90, 0x2, 0xff, 0x0, 0x0, 0x4, 0xfe, + 0x0, 0x7f, 0xb0, 0x0, 0x0, 0xf, 0xf3, 0xc, + 0xf6, 0x0, 0x0, 0x0, 0xaf, 0x81, 0xff, 0x10, + 0x0, 0x0, 0x5, 0xfc, 0x5f, 0xb0, 0x0, 0x0, + 0x0, 0xf, 0xfa, 0xf6, 0x0, 0x0, 0x0, 0x0, + 0xbf, 0xff, 0x10, 0x0, 0x0, 0x0, 0x6, 0xff, + 0xc0, 0x0, 0x0, + + /* U+0077 "w" */ + 0x2f, 0xa0, 0x0, 0xff, 0x50, 0x3, 0xf9, 0xf, + 0xc0, 0x2, 0xff, 0x80, 0x5, 0xf6, 0xd, 0xf0, + 0x4, 0xfd, 0xb0, 0x7, 0xf4, 0xb, 0xf1, 0x7, + 0xf9, 0xd0, 0x9, 0xf1, 0x8, 0xf3, 0xa, 0xd7, + 0xf0, 0xc, 0xe0, 0x6, 0xf5, 0xc, 0xa4, 0xf3, + 0xe, 0xc0, 0x4, 0xf7, 0xf, 0x82, 0xf5, 0xf, + 0x90, 0x1, 0xfa, 0x2f, 0x50, 0xf8, 0x2f, 0x70, + 0x0, 0xfc, 0x4f, 0x20, 0xdb, 0x5f, 0x40, 0x0, + 0xce, 0x7f, 0x0, 0xad, 0x7f, 0x20, 0x0, 0xaf, + 0xad, 0x0, 0x8f, 0x9f, 0x0, 0x0, 0x7f, 0xdb, + 0x0, 0x5f, 0xdc, 0x0, 0x0, 0x5f, 0xf8, 0x0, + 0x3f, 0xfa, 0x0, 0x0, 0x2f, 0xf5, 0x0, 0xf, + 0xf7, 0x0, + + /* U+0078 "x" */ + 0x3f, 0xf5, 0x0, 0x0, 0xd, 0xf9, 0x0, 0x8f, + 0xe0, 0x0, 0x8, 0xfe, 0x10, 0x0, 0xdf, 0x80, + 0x2, 0xff, 0x50, 0x0, 0x4, 0xff, 0x20, 0xbf, + 0xa0, 0x0, 0x0, 0x9, 0xfb, 0x4f, 0xf1, 0x0, + 0x0, 0x0, 0x1e, 0xfe, 0xf6, 0x0, 0x0, 0x0, + 0x0, 0x5f, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x9, + 0xff, 0xe1, 0x0, 0x0, 0x0, 0x3, 0xff, 0xbf, + 0xa0, 0x0, 0x0, 0x0, 0xdf, 0x82, 0xff, 0x40, + 0x0, 0x0, 0x8f, 0xd0, 0x8, 0xfe, 0x0, 0x0, + 0x3f, 0xf4, 0x0, 0xd, 0xf9, 0x0, 0xc, 0xfa, + 0x0, 0x0, 0x4f, 0xf3, 0x7, 0xff, 0x10, 0x0, + 0x0, 0xaf, 0xd0, + + /* U+0079 "y" */ + 0x8f, 0xc0, 0x0, 0x0, 0x5, 0xfe, 0x2, 0xff, + 0x20, 0x0, 0x0, 0xbf, 0x80, 0xb, 0xf8, 0x0, + 0x0, 0x1f, 0xf3, 0x0, 0x5f, 0xe0, 0x0, 0x6, + 0xfd, 0x0, 0x0, 0xef, 0x40, 0x0, 0xbf, 0x70, + 0x0, 0x9, 0xfa, 0x0, 0x1f, 0xf1, 0x0, 0x0, + 0x3f, 0xf1, 0x6, 0xfb, 0x0, 0x0, 0x0, 0xcf, + 0x60, 0xcf, 0x50, 0x0, 0x0, 0x6, 0xfc, 0x1f, + 0xf0, 0x0, 0x0, 0x0, 0x1f, 0xf8, 0xfa, 0x0, + 0x0, 0x0, 0x0, 0xaf, 0xff, 0x40, 0x0, 0x0, + 0x0, 0x4, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, + 0xe, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x1, 0xff, + 0x20, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xc0, 0x0, + 0x0, 0x0, 0x0, 0xc, 0xf7, 0x0, 0x0, 0x0, + 0x0, 0x2, 0xff, 0x10, 0x0, 0x0, 0x0, 0x0, + 0x8f, 0xb0, 0x0, 0x0, 0x0, + + /* U+007A "z" */ + 0xaf, 0xff, 0xff, 0xff, 0xff, 0xa, 0xff, 0xff, + 0xff, 0xff, 0xf0, 0x0, 0x0, 0x0, 0x1c, 0xfb, + 0x0, 0x0, 0x0, 0x8, 0xfe, 0x10, 0x0, 0x0, + 0x5, 0xff, 0x30, 0x0, 0x0, 0x2, 0xff, 0x70, + 0x0, 0x0, 0x0, 0xcf, 0xa0, 0x0, 0x0, 0x0, + 0x9f, 0xd0, 0x0, 0x0, 0x0, 0x5f, 0xf2, 0x0, + 0x0, 0x0, 0x2f, 0xf5, 0x0, 0x0, 0x0, 0xd, + 0xf9, 0x0, 0x0, 0x0, 0xa, 0xfc, 0x10, 0x0, + 0x0, 0x0, 0xdf, 0xff, 0xff, 0xff, 0xff, 0x3d, + 0xff, 0xff, 0xff, 0xff, 0xf3, + + /* U+007B "{" */ + 0x0, 0x0, 0x0, 0x6, 0xcf, 0xf2, 0x0, 0x0, + 0x0, 0xaf, 0xff, 0xf2, 0x0, 0x0, 0x3, 0xff, + 0x71, 0x0, 0x0, 0x0, 0x6, 0xfd, 0x0, 0x0, + 0x0, 0x0, 0x6, 0xfc, 0x0, 0x0, 0x0, 0x0, + 0x4, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, + 0x0, 0x0, 0x0, 0x0, 0x2, 0xff, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xff, 0x10, 0x0, 0x0, 0x0, + 0x1, 0xff, 0x0, 0x0, 0x0, 0x0, 0x19, 0xf9, + 0x0, 0x0, 0x3f, 0xff, 0xfd, 0x70, 0x0, 0x0, + 0x3f, 0xff, 0xff, 0x90, 0x0, 0x0, 0x0, 0x0, + 0x19, 0xfa, 0x0, 0x0, 0x0, 0x0, 0x1, 0xff, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x10, 0x0, + 0x0, 0x0, 0x2, 0xff, 0x0, 0x0, 0x0, 0x0, + 0x3, 0xff, 0x0, 0x0, 0x0, 0x0, 0x4, 0xfe, + 0x0, 0x0, 0x0, 0x0, 0x6, 0xfc, 0x0, 0x0, + 0x0, 0x0, 0x6, 0xfd, 0x0, 0x0, 0x0, 0x0, + 0x3, 0xff, 0x71, 0x0, 0x0, 0x0, 0x0, 0xaf, + 0xff, 0xf2, 0x0, 0x0, 0x0, 0x6, 0xcf, 0xf2, + + /* U+007C "|" */ + 0x78, 0x2e, 0xf4, 0xef, 0x4e, 0xf4, 0xef, 0x4e, + 0xf4, 0xef, 0x4e, 0xf4, 0xef, 0x4e, 0xf4, 0xef, + 0x4e, 0xf4, 0xef, 0x4e, 0xf4, 0xef, 0x4e, 0xf4, + 0xef, 0x4e, 0xf4, 0xef, 0x4e, 0xf4, 0xef, 0x4e, + 0xf4, 0xef, 0x4e, 0xf4, + + /* U+007D "}" */ + 0xbf, 0xe9, 0x10, 0x0, 0x0, 0xb, 0xff, 0xfe, + 0x20, 0x0, 0x0, 0x0, 0x3d, 0xfa, 0x0, 0x0, + 0x0, 0x0, 0x6f, 0xc0, 0x0, 0x0, 0x0, 0x6, + 0xfc, 0x0, 0x0, 0x0, 0x0, 0x8f, 0x90, 0x0, + 0x0, 0x0, 0xa, 0xf7, 0x0, 0x0, 0x0, 0x0, + 0xdf, 0x50, 0x0, 0x0, 0x0, 0xf, 0xf3, 0x0, + 0x0, 0x0, 0x0, 0xef, 0x30, 0x0, 0x0, 0x0, + 0x9, 0xfb, 0x10, 0x0, 0x0, 0x0, 0x8, 0xef, + 0xff, 0xf9, 0x0, 0x1, 0xbf, 0xff, 0xff, 0x90, + 0x0, 0xaf, 0xb2, 0x0, 0x0, 0x0, 0xe, 0xf3, + 0x0, 0x0, 0x0, 0x0, 0xff, 0x30, 0x0, 0x0, + 0x0, 0xd, 0xf5, 0x0, 0x0, 0x0, 0x0, 0xaf, + 0x70, 0x0, 0x0, 0x0, 0x8, 0xf9, 0x0, 0x0, + 0x0, 0x0, 0x6f, 0xc0, 0x0, 0x0, 0x0, 0x6, + 0xfc, 0x0, 0x0, 0x0, 0x3, 0xdf, 0xa0, 0x0, + 0x0, 0xbf, 0xff, 0xf2, 0x0, 0x0, 0xb, 0xfe, + 0x92, 0x0, 0x0, 0x0, + + /* U+007E "~" */ + 0x1, 0xbf, 0xe8, 0x0, 0x5, 0xfb, 0xd, 0xff, + 0xff, 0x90, 0x5, 0xfb, 0x3f, 0xd0, 0x2e, 0xf7, + 0x8, 0xf9, 0x4f, 0xb0, 0x3, 0xff, 0xef, 0xf3, + 0x5f, 0xb0, 0x0, 0x3d, 0xfd, 0x50 +}; + + +/*--------------------- + * GLYPH DESCRIPTION + *--------------------*/ + +static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = { + {.bitmap_index = 0, .adv_w = 0, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0} /* id = 0 reserved */, + {.bitmap_index = 0, .adv_w = 230, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 0, .adv_w = 230, .box_w = 4, .box_h = 18, .ofs_x = 5, .ofs_y = 0}, + {.bitmap_index = 36, .adv_w = 230, .box_w = 8, .box_h = 8, .ofs_x = 3, .ofs_y = 10}, + {.bitmap_index = 68, .adv_w = 230, .box_w = 14, .box_h = 18, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 194, .adv_w = 230, .box_w = 12, .box_h = 26, .ofs_x = 1, .ofs_y = -3}, + {.bitmap_index = 350, .adv_w = 230, .box_w = 15, .box_h = 18, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 485, .adv_w = 230, .box_w = 15, .box_h = 18, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 620, .adv_w = 230, .box_w = 4, .box_h = 8, .ofs_x = 5, .ofs_y = 10}, + {.bitmap_index = 636, .adv_w = 230, .box_w = 8, .box_h = 24, .ofs_x = 4, .ofs_y = -3}, + {.bitmap_index = 732, .adv_w = 230, .box_w = 8, .box_h = 24, .ofs_x = 2, .ofs_y = -3}, + {.bitmap_index = 828, .adv_w = 230, .box_w = 14, .box_h = 13, .ofs_x = 0, .ofs_y = 3}, + {.bitmap_index = 919, .adv_w = 230, .box_w = 12, .box_h = 12, .ofs_x = 1, .ofs_y = 2}, + {.bitmap_index = 991, .adv_w = 230, .box_w = 4, .box_h = 8, .ofs_x = 5, .ofs_y = -4}, + {.bitmap_index = 1007, .adv_w = 230, .box_w = 9, .box_h = 2, .ofs_x = 3, .ofs_y = 7}, + {.bitmap_index = 1016, .adv_w = 230, .box_w = 5, .box_h = 5, .ofs_x = 5, .ofs_y = 0}, + {.bitmap_index = 1029, .adv_w = 230, .box_w = 12, .box_h = 24, .ofs_x = 1, .ofs_y = -3}, + {.bitmap_index = 1173, .adv_w = 230, .box_w = 12, .box_h = 18, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1281, .adv_w = 230, .box_w = 11, .box_h = 18, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 1380, .adv_w = 230, .box_w = 12, .box_h = 18, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1488, .adv_w = 230, .box_w = 12, .box_h = 18, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1596, .adv_w = 230, .box_w = 11, .box_h = 18, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1695, .adv_w = 230, .box_w = 12, .box_h = 18, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1803, .adv_w = 230, .box_w = 12, .box_h = 18, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1911, .adv_w = 230, .box_w = 13, .box_h = 18, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 2028, .adv_w = 230, .box_w = 12, .box_h = 18, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 2136, .adv_w = 230, .box_w = 12, .box_h = 18, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 2244, .adv_w = 230, .box_w = 5, .box_h = 14, .ofs_x = 5, .ofs_y = 0}, + {.bitmap_index = 2279, .adv_w = 230, .box_w = 6, .box_h = 18, .ofs_x = 4, .ofs_y = -4}, + {.bitmap_index = 2333, .adv_w = 230, .box_w = 11, .box_h = 14, .ofs_x = 2, .ofs_y = 1}, + {.bitmap_index = 2410, .adv_w = 230, .box_w = 11, .box_h = 8, .ofs_x = 2, .ofs_y = 4}, + {.bitmap_index = 2454, .adv_w = 230, .box_w = 11, .box_h = 14, .ofs_x = 2, .ofs_y = 1}, + {.bitmap_index = 2531, .adv_w = 230, .box_w = 9, .box_h = 18, .ofs_x = 3, .ofs_y = 0}, + {.bitmap_index = 2612, .adv_w = 230, .box_w = 13, .box_h = 22, .ofs_x = 1, .ofs_y = -4}, + {.bitmap_index = 2755, .adv_w = 230, .box_w = 13, .box_h = 18, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 2872, .adv_w = 230, .box_w = 11, .box_h = 18, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 2971, .adv_w = 230, .box_w = 11, .box_h = 18, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 3070, .adv_w = 230, .box_w = 11, .box_h = 18, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 3169, .adv_w = 230, .box_w = 11, .box_h = 18, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 3268, .adv_w = 230, .box_w = 11, .box_h = 18, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 3367, .adv_w = 230, .box_w = 11, .box_h = 18, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 3466, .adv_w = 230, .box_w = 11, .box_h = 18, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 3565, .adv_w = 230, .box_w = 10, .box_h = 18, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 3655, .adv_w = 230, .box_w = 11, .box_h = 18, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 3754, .adv_w = 230, .box_w = 12, .box_h = 18, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 3862, .adv_w = 230, .box_w = 11, .box_h = 18, .ofs_x = 3, .ofs_y = 0}, + {.bitmap_index = 3961, .adv_w = 230, .box_w = 12, .box_h = 18, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 4069, .adv_w = 230, .box_w = 11, .box_h = 18, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 4168, .adv_w = 230, .box_w = 11, .box_h = 18, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 4267, .adv_w = 230, .box_w = 12, .box_h = 18, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 4375, .adv_w = 230, .box_w = 12, .box_h = 22, .ofs_x = 1, .ofs_y = -4}, + {.bitmap_index = 4507, .adv_w = 230, .box_w = 12, .box_h = 18, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 4615, .adv_w = 230, .box_w = 12, .box_h = 18, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 4723, .adv_w = 230, .box_w = 13, .box_h = 18, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 4840, .adv_w = 230, .box_w = 11, .box_h = 18, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 4939, .adv_w = 230, .box_w = 13, .box_h = 18, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 5056, .adv_w = 230, .box_w = 14, .box_h = 18, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 5182, .adv_w = 230, .box_w = 14, .box_h = 18, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 5308, .adv_w = 230, .box_w = 14, .box_h = 18, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 5434, .adv_w = 230, .box_w = 11, .box_h = 18, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 5533, .adv_w = 230, .box_w = 7, .box_h = 24, .ofs_x = 4, .ofs_y = -3}, + {.bitmap_index = 5617, .adv_w = 230, .box_w = 12, .box_h = 24, .ofs_x = 1, .ofs_y = -3}, + {.bitmap_index = 5761, .adv_w = 230, .box_w = 7, .box_h = 24, .ofs_x = 3, .ofs_y = -3}, + {.bitmap_index = 5845, .adv_w = 230, .box_w = 12, .box_h = 10, .ofs_x = 1, .ofs_y = 9}, + {.bitmap_index = 5905, .adv_w = 230, .box_w = 12, .box_h = 2, .ofs_x = 1, .ofs_y = -2}, + {.bitmap_index = 5917, .adv_w = 230, .box_w = 6, .box_h = 4, .ofs_x = 3, .ofs_y = 16}, + {.bitmap_index = 5929, .adv_w = 230, .box_w = 12, .box_h = 14, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 6013, .adv_w = 230, .box_w = 11, .box_h = 18, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 6112, .adv_w = 230, .box_w = 11, .box_h = 14, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 6189, .adv_w = 230, .box_w = 11, .box_h = 18, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 6288, .adv_w = 230, .box_w = 11, .box_h = 14, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 6365, .adv_w = 230, .box_w = 12, .box_h = 18, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 6473, .adv_w = 230, .box_w = 11, .box_h = 18, .ofs_x = 2, .ofs_y = -4}, + {.bitmap_index = 6572, .adv_w = 230, .box_w = 11, .box_h = 18, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 6671, .adv_w = 230, .box_w = 12, .box_h = 20, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 6791, .adv_w = 230, .box_w = 9, .box_h = 24, .ofs_x = 2, .ofs_y = -4}, + {.bitmap_index = 6899, .adv_w = 230, .box_w = 12, .box_h = 18, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 7007, .adv_w = 230, .box_w = 14, .box_h = 18, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 7133, .adv_w = 230, .box_w = 12, .box_h = 14, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 7217, .adv_w = 230, .box_w = 11, .box_h = 14, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 7294, .adv_w = 230, .box_w = 11, .box_h = 14, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 7371, .adv_w = 230, .box_w = 11, .box_h = 18, .ofs_x = 2, .ofs_y = -4}, + {.bitmap_index = 7470, .adv_w = 230, .box_w = 11, .box_h = 18, .ofs_x = 2, .ofs_y = -4}, + {.bitmap_index = 7569, .adv_w = 230, .box_w = 11, .box_h = 14, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 7646, .adv_w = 230, .box_w = 11, .box_h = 14, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 7723, .adv_w = 230, .box_w = 12, .box_h = 18, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 7831, .adv_w = 230, .box_w = 11, .box_h = 14, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 7908, .adv_w = 230, .box_w = 13, .box_h = 14, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 7999, .adv_w = 230, .box_w = 14, .box_h = 14, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 8097, .adv_w = 230, .box_w = 13, .box_h = 14, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 8188, .adv_w = 230, .box_w = 13, .box_h = 18, .ofs_x = 1, .ofs_y = -4}, + {.bitmap_index = 8305, .adv_w = 230, .box_w = 11, .box_h = 14, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 8382, .adv_w = 230, .box_w = 12, .box_h = 24, .ofs_x = 1, .ofs_y = -3}, + {.bitmap_index = 8526, .adv_w = 230, .box_w = 3, .box_h = 24, .ofs_x = 6, .ofs_y = -3}, + {.bitmap_index = 8562, .adv_w = 230, .box_w = 11, .box_h = 24, .ofs_x = 2, .ofs_y = -3}, + {.bitmap_index = 8694, .adv_w = 230, .box_w = 12, .box_h = 5, .ofs_x = 1, .ofs_y = 6} +}; + +/*--------------------- + * CHARACTER MAPPING + *--------------------*/ + + + +/*Collect the unicode lists and glyph_id offsets*/ +static const lv_font_fmt_txt_cmap_t cmaps[] = +{ + { + .range_start = 32, .range_length = 95, .glyph_id_start = 1, + .unicode_list = NULL, .glyph_id_ofs_list = NULL, .list_length = 0, .type = LV_FONT_FMT_TXT_CMAP_FORMAT0_TINY + } +}; + + + +/*-------------------- + * ALL CUSTOM DATA + *--------------------*/ + +#if LVGL_VERSION_MAJOR == 8 +/*Store all the custom data of the font*/ +static lv_font_fmt_txt_glyph_cache_t cache; +#endif + +#if LVGL_VERSION_MAJOR >= 8 +static const lv_font_fmt_txt_dsc_t font_dsc = { +#else +static lv_font_fmt_txt_dsc_t font_dsc = { +#endif + .glyph_bitmap = glyph_bitmap, + .glyph_dsc = glyph_dsc, + .cmaps = cmaps, + .kern_dsc = NULL, + .kern_scale = 0, + .cmap_num = 1, + .bpp = 4, + .kern_classes = 0, + .bitmap_format = 0, +#if LVGL_VERSION_MAJOR == 8 + .cache = &cache +#endif +}; + + +/*----------------- + * PUBLIC FONT + *----------------*/ + +/*Initialize a public general font descriptor*/ +#if LVGL_VERSION_MAJOR >= 8 +const lv_font_t JetBrainsMono24 = { +#else +lv_font_t JetBrainsMono24 = { +#endif + .get_glyph_dsc = lv_font_get_glyph_dsc_fmt_txt, /*Function pointer to get glyph's data*/ + .get_glyph_bitmap = lv_font_get_bitmap_fmt_txt, /*Function pointer to get glyph's bitmap*/ + .line_height = 27, /*The maximum line height required by the font*/ + .base_line = 4, /*Baseline measured from the bottom of the line*/ +#if !(LVGL_VERSION_MAJOR == 6 && LVGL_VERSION_MINOR == 0) + .subpx = LV_FONT_SUBPX_NONE, +#endif +#if LV_VERSION_CHECK(7, 4, 0) || LVGL_VERSION_MAJOR >= 8 + .underline_position = -4, + .underline_thickness = 1, +#endif + .dsc = &font_dsc, /*The custom font data. Will be accessed by `get_glyph_bitmap/dsc` */ + .fallback = NULL, + .user_data = NULL +}; + + + +#endif /*#if JETBRAINSMONO24*/ + diff --git a/device/src/keyboard/oled/fonts/jet_brains_mono_32.c b/device/src/keyboard/oled/fonts/jet_brains_mono_32.c new file mode 100644 index 000000000..e62871beb --- /dev/null +++ b/device/src/keyboard/oled/fonts/jet_brains_mono_32.c @@ -0,0 +1,2274 @@ +/******************************************************************************* + * Size: 32 px + * Bpp: 4 + * Opts: + ******************************************************************************/ + +#ifdef LV_LVGL_H_INCLUDE_SIMPLE +#include "lvgl.h" +#else +#include "lvgl/lvgl.h" +#endif + +#ifndef JETBRAINSMONO32 +#define JETBRAINSMONO32 1 +#endif + +#if JETBRAINSMONO32 + +/*----------------- + * BITMAPS + *----------------*/ + +/*Store the image of the glyphs*/ +static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { + /* U+0020 " " */ + + /* U+0021 "!" */ + 0x1f, 0xff, 0x41, 0xff, 0xf4, 0xf, 0xff, 0x30, + 0xff, 0xf3, 0xf, 0xff, 0x30, 0xff, 0xf2, 0xf, + 0xff, 0x20, 0xef, 0xf1, 0xe, 0xff, 0x10, 0xef, + 0xf1, 0xd, 0xff, 0x0, 0xdf, 0xf0, 0xd, 0xff, + 0x0, 0xcf, 0xf0, 0xc, 0xff, 0x0, 0xbf, 0xe0, + 0x6, 0x98, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, + 0xbd, 0xc4, 0xaf, 0xff, 0xeb, 0xff, 0xfe, 0x3d, + 0xfe, 0x50, + + /* U+0022 "\"" */ + 0x6f, 0xfd, 0x0, 0xa, 0xff, 0x96, 0xff, 0xc0, + 0x0, 0x9f, 0xf9, 0x5f, 0xfc, 0x0, 0x9, 0xff, + 0x95, 0xff, 0xc0, 0x0, 0x8f, 0xf8, 0x4f, 0xfb, + 0x0, 0x8, 0xff, 0x84, 0xff, 0xb0, 0x0, 0x8f, + 0xf8, 0x4f, 0xfa, 0x0, 0x7, 0xff, 0x73, 0xff, + 0xa0, 0x0, 0x7f, 0xf7, 0x3f, 0xfa, 0x0, 0x6, + 0xff, 0x61, 0xaa, 0x60, 0x0, 0x4a, 0xa4, + + /* U+0023 "#" */ + 0x0, 0x0, 0x2, 0xff, 0x10, 0x0, 0xc, 0xf7, + 0x0, 0x0, 0x0, 0x5, 0xfd, 0x0, 0x0, 0xf, + 0xf3, 0x0, 0x0, 0x0, 0x9, 0xfa, 0x0, 0x0, + 0x3f, 0xf0, 0x0, 0x0, 0x0, 0xc, 0xf7, 0x0, + 0x0, 0x6f, 0xd0, 0x0, 0x0, 0x0, 0xf, 0xf3, + 0x0, 0x0, 0xaf, 0x90, 0x0, 0x0, 0x0, 0x3f, + 0xf0, 0x0, 0x0, 0xdf, 0x60, 0x0, 0xc, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf1, 0xc, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf1, + 0x1, 0x11, 0xcf, 0x81, 0x11, 0x17, 0xfd, 0x11, + 0x10, 0x0, 0x0, 0xef, 0x50, 0x0, 0x8, 0xfa, + 0x0, 0x0, 0x0, 0x1, 0xff, 0x20, 0x0, 0xb, + 0xf7, 0x0, 0x0, 0x0, 0x4, 0xff, 0x0, 0x0, + 0xe, 0xf5, 0x0, 0x0, 0x0, 0x7, 0xfc, 0x0, + 0x0, 0x1f, 0xf2, 0x0, 0x0, 0x0, 0xa, 0xf9, + 0x0, 0x0, 0x4f, 0xf0, 0x0, 0x0, 0xef, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0xef, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, + 0x11, 0x4f, 0xf2, 0x11, 0x11, 0xdf, 0x71, 0x11, + 0x0, 0x0, 0x5f, 0xe0, 0x0, 0x0, 0xff, 0x30, + 0x0, 0x0, 0x0, 0x8f, 0xb0, 0x0, 0x2, 0xff, + 0x10, 0x0, 0x0, 0x0, 0xbf, 0x80, 0x0, 0x5, + 0xfe, 0x0, 0x0, 0x0, 0x0, 0xef, 0x50, 0x0, + 0x8, 0xfb, 0x0, 0x0, 0x0, 0x1, 0xff, 0x20, + 0x0, 0xb, 0xf8, 0x0, 0x0, 0x0, 0x4, 0xff, + 0x0, 0x0, 0xe, 0xf5, 0x0, 0x0, 0x0, + + /* U+0024 "$" */ + 0x0, 0x0, 0x0, 0x18, 0x50, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x3, 0xfb, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x3f, 0xb0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x3, 0xfb, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x5f, 0xc2, 0x0, 0x0, 0x0, 0x0, 0x2a, + 0xff, 0xff, 0xfd, 0x60, 0x0, 0x0, 0x4f, 0xff, + 0xff, 0xff, 0xff, 0xb0, 0x0, 0x2f, 0xff, 0xc9, + 0xfd, 0x9f, 0xff, 0x90, 0x9, 0xff, 0xa0, 0x3f, + 0xb0, 0x3f, 0xff, 0x20, 0xef, 0xf1, 0x3, 0xfb, + 0x0, 0x8f, 0xf6, 0xf, 0xfd, 0x0, 0x3f, 0xb0, + 0x5, 0xff, 0x90, 0xff, 0xf0, 0x3, 0xfb, 0x0, + 0x0, 0x0, 0xe, 0xff, 0x30, 0x3f, 0xb0, 0x0, + 0x0, 0x0, 0x9f, 0xfc, 0x13, 0xfb, 0x0, 0x0, + 0x0, 0x2, 0xff, 0xfd, 0x8f, 0xb0, 0x0, 0x0, + 0x0, 0x6, 0xff, 0xff, 0xfe, 0x60, 0x0, 0x0, + 0x0, 0x5, 0xef, 0xff, 0xff, 0xf8, 0x0, 0x0, + 0x0, 0x0, 0x6c, 0xff, 0xff, 0xfc, 0x10, 0x0, + 0x0, 0x0, 0x3f, 0xdc, 0xff, 0xfb, 0x0, 0x0, + 0x0, 0x3, 0xfb, 0x5, 0xff, 0xf4, 0x0, 0x0, + 0x0, 0x3f, 0xb0, 0x8, 0xff, 0xa0, 0x0, 0x0, + 0x3, 0xfb, 0x0, 0x2f, 0xfd, 0x58, 0x81, 0x0, + 0x3f, 0xb0, 0x0, 0xff, 0xd9, 0xff, 0x50, 0x3, + 0xfb, 0x0, 0x2f, 0xfc, 0x5f, 0xfc, 0x0, 0x3f, + 0xb0, 0x8, 0xff, 0x80, 0xef, 0xfb, 0x13, 0xfb, + 0x7, 0xff, 0xf2, 0x4, 0xff, 0xff, 0xef, 0xff, + 0xff, 0xf6, 0x0, 0x4, 0xdf, 0xff, 0xff, 0xff, + 0xf6, 0x0, 0x0, 0x0, 0x59, 0xdf, 0xfb, 0x61, + 0x0, 0x0, 0x0, 0x0, 0x3, 0xfb, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x3f, 0xb0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x3, 0xfb, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x3f, 0xb0, 0x0, 0x0, 0x0, + + /* U+0025 "%" */ + 0x0, 0x7d, 0xff, 0xc5, 0x0, 0x0, 0x0, 0x1, + 0xef, 0x60, 0xaf, 0xff, 0xff, 0xf7, 0x0, 0x0, + 0x0, 0xaf, 0xb0, 0x3f, 0xfb, 0x44, 0xcf, 0xf1, + 0x0, 0x0, 0x5f, 0xe1, 0x7, 0xff, 0x0, 0x2, + 0xff, 0x40, 0x0, 0x1e, 0xf5, 0x0, 0x8f, 0xd0, + 0x0, 0xf, 0xf5, 0x0, 0xb, 0xfa, 0x0, 0x8, + 0xfd, 0x0, 0x0, 0xff, 0x60, 0x6, 0xfe, 0x0, + 0x0, 0x7f, 0xe0, 0x0, 0x1f, 0xf5, 0x2, 0xff, + 0x40, 0x0, 0x4, 0xff, 0x81, 0x1a, 0xff, 0x20, + 0xcf, 0x80, 0x0, 0x0, 0xc, 0xff, 0xff, 0xff, + 0xa0, 0x8f, 0xd0, 0x0, 0x0, 0x0, 0x1a, 0xff, + 0xff, 0x80, 0x3f, 0xf3, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x22, 0x0, 0xd, 0xf7, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x9, 0xfc, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0xff, 0x23, + 0xbe, 0xfd, 0x70, 0x0, 0x0, 0x0, 0x1, 0xef, + 0x64, 0xff, 0xff, 0xff, 0xb0, 0x0, 0x0, 0x0, + 0xaf, 0xb0, 0xdf, 0xe5, 0x39, 0xff, 0x50, 0x0, + 0x0, 0x5f, 0xe1, 0x1f, 0xf6, 0x0, 0xd, 0xf9, + 0x0, 0x0, 0x1e, 0xf5, 0x2, 0xff, 0x30, 0x0, + 0xaf, 0xb0, 0x0, 0xb, 0xf9, 0x0, 0x2f, 0xf3, + 0x0, 0xa, 0xfb, 0x0, 0x6, 0xfe, 0x0, 0x2, + 0xff, 0x30, 0x0, 0xaf, 0xb0, 0x2, 0xff, 0x30, + 0x0, 0x1f, 0xf5, 0x0, 0xc, 0xf9, 0x0, 0xcf, + 0x80, 0x0, 0x0, 0xcf, 0xd3, 0x17, 0xff, 0x50, + 0x8f, 0xd0, 0x0, 0x0, 0x3, 0xff, 0xff, 0xff, + 0xb0, 0x3f, 0xf2, 0x0, 0x0, 0x0, 0x3, 0xbe, + 0xfd, 0x80, 0x0, + + /* U+0026 "&" */ + 0x0, 0x0, 0x1, 0x9d, 0xff, 0xd8, 0x10, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x4f, 0xff, 0xff, 0xff, + 0xe4, 0x0, 0x0, 0x0, 0x0, 0x1, 0xff, 0xfd, + 0x88, 0xdf, 0xff, 0x20, 0x0, 0x0, 0x0, 0x6, + 0xff, 0xc0, 0x0, 0xa, 0xff, 0x90, 0x0, 0x0, + 0x0, 0x7, 0xff, 0x60, 0x0, 0x1, 0xff, 0xd0, + 0x0, 0x0, 0x0, 0x4, 0xff, 0x70, 0x0, 0x0, + 0x67, 0x60, 0x0, 0x0, 0x0, 0x0, 0xdf, 0xd0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x3f, 0xf9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x5, 0xff, 0x70, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x5, 0xcf, 0xff, 0xf4, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xaf, 0xff, 0xff, + 0xff, 0x30, 0x0, 0x0, 0x0, 0x0, 0x6, 0xff, + 0xf8, 0x43, 0xdf, 0xe1, 0x0, 0x0, 0xab, 0xb3, + 0xd, 0xff, 0x40, 0x0, 0x3f, 0xfc, 0x0, 0xb, + 0xff, 0x80, 0x1f, 0xfd, 0x0, 0x0, 0x6, 0xff, + 0xb0, 0xaf, 0xfa, 0x0, 0x2f, 0xfa, 0x0, 0x0, + 0x0, 0xaf, 0xfd, 0xff, 0xc0, 0x0, 0x3f, 0xf9, + 0x0, 0x0, 0x0, 0xd, 0xff, 0xfd, 0x10, 0x0, + 0x3f, 0xf9, 0x0, 0x0, 0x0, 0x5, 0xff, 0xf3, + 0x0, 0x0, 0x2f, 0xfb, 0x0, 0x0, 0x0, 0xd, + 0xff, 0xfc, 0x0, 0x0, 0xf, 0xfe, 0x10, 0x0, + 0x0, 0xaf, 0xfd, 0xff, 0x70, 0x0, 0xb, 0xff, + 0xa0, 0x0, 0x9, 0xff, 0xa0, 0xdf, 0xf3, 0x0, + 0x3, 0xff, 0xfe, 0xba, 0xef, 0xfc, 0x0, 0x3f, + 0xfd, 0x0, 0x0, 0x5f, 0xff, 0xff, 0xff, 0xb1, + 0x0, 0x8, 0xff, 0x90, 0x0, 0x2, 0x9d, 0xfe, + 0xb5, 0x0, 0x0, 0x0, 0xcf, 0xf5, + + /* U+0027 "'" */ + 0xf, 0xff, 0x30, 0xff, 0xf3, 0xf, 0xff, 0x20, + 0xff, 0xf2, 0xe, 0xff, 0x20, 0xef, 0xf1, 0xd, + 0xff, 0x10, 0xdf, 0xf1, 0xd, 0xff, 0x0, 0x8a, + 0xa0, + + /* U+0028 "(" */ + 0x0, 0x0, 0x0, 0x0, 0x6b, 0x70, 0x0, 0x0, + 0x6, 0xef, 0xf8, 0x0, 0x0, 0x1b, 0xff, 0xff, + 0x70, 0x0, 0xc, 0xff, 0xf9, 0x20, 0x0, 0xa, + 0xff, 0xe4, 0x0, 0x0, 0x5, 0xff, 0xf3, 0x0, + 0x0, 0x0, 0xdf, 0xf6, 0x0, 0x0, 0x0, 0x4f, + 0xfd, 0x0, 0x0, 0x0, 0x8, 0xff, 0x70, 0x0, + 0x0, 0x0, 0xcf, 0xf2, 0x0, 0x0, 0x0, 0xf, + 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xe0, 0x0, + 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x0, 0x0, 0x1, + 0xff, 0xc0, 0x0, 0x0, 0x0, 0x1f, 0xfc, 0x0, + 0x0, 0x0, 0x1, 0xff, 0xc0, 0x0, 0x0, 0x0, + 0x1f, 0xfc, 0x0, 0x0, 0x0, 0x1, 0xff, 0xc0, + 0x0, 0x0, 0x0, 0x1f, 0xfd, 0x0, 0x0, 0x0, + 0x0, 0xff, 0xe0, 0x0, 0x0, 0x0, 0xe, 0xff, + 0x0, 0x0, 0x0, 0x0, 0xcf, 0xf3, 0x0, 0x0, + 0x0, 0x8, 0xff, 0x80, 0x0, 0x0, 0x0, 0x3f, + 0xfe, 0x0, 0x0, 0x0, 0x0, 0xcf, 0xf8, 0x0, + 0x0, 0x0, 0x3, 0xff, 0xf5, 0x0, 0x0, 0x0, + 0x9, 0xff, 0xf6, 0x0, 0x0, 0x0, 0xa, 0xff, + 0xfb, 0x40, 0x0, 0x0, 0x9, 0xff, 0xff, 0x80, + 0x0, 0x0, 0x4, 0xcf, 0xf8, 0x0, 0x0, 0x0, + 0x0, 0x38, 0x60, + + /* U+0029 ")" */ + 0x4c, 0x71, 0x0, 0x0, 0x0, 0x5, 0xff, 0xf8, + 0x0, 0x0, 0x0, 0x4f, 0xff, 0xfc, 0x20, 0x0, + 0x0, 0x17, 0xff, 0xfe, 0x10, 0x0, 0x0, 0x2, + 0xdf, 0xfd, 0x0, 0x0, 0x0, 0x1, 0xef, 0xf8, + 0x0, 0x0, 0x0, 0x3, 0xff, 0xf1, 0x0, 0x0, + 0x0, 0xb, 0xff, 0x70, 0x0, 0x0, 0x0, 0x4f, + 0xfc, 0x0, 0x0, 0x0, 0x0, 0xff, 0xf0, 0x0, + 0x0, 0x0, 0xc, 0xff, 0x20, 0x0, 0x0, 0x0, + 0xaf, 0xf3, 0x0, 0x0, 0x0, 0x9, 0xff, 0x40, + 0x0, 0x0, 0x0, 0x9f, 0xf4, 0x0, 0x0, 0x0, + 0x9, 0xff, 0x40, 0x0, 0x0, 0x0, 0x9f, 0xf4, + 0x0, 0x0, 0x0, 0x9, 0xff, 0x40, 0x0, 0x0, + 0x0, 0x9f, 0xf4, 0x0, 0x0, 0x0, 0x9, 0xff, + 0x40, 0x0, 0x0, 0x0, 0xbf, 0xf3, 0x0, 0x0, + 0x0, 0xc, 0xff, 0x20, 0x0, 0x0, 0x0, 0xff, + 0xf0, 0x0, 0x0, 0x0, 0x5f, 0xfb, 0x0, 0x0, + 0x0, 0xc, 0xff, 0x60, 0x0, 0x0, 0x4, 0xff, + 0xf0, 0x0, 0x0, 0x2, 0xef, 0xf6, 0x0, 0x0, + 0x3, 0xef, 0xfc, 0x0, 0x0, 0x39, 0xff, 0xfd, + 0x10, 0x0, 0x4f, 0xff, 0xfb, 0x10, 0x0, 0x5, + 0xff, 0xd6, 0x0, 0x0, 0x0, 0x49, 0x40, 0x0, + 0x0, 0x0, 0x0, + + /* U+002A "*" */ + 0x0, 0x0, 0x0, 0xc, 0xff, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xc, 0xff, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xc, 0xff, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc, 0xff, + 0x0, 0x0, 0x0, 0x0, 0x5, 0x0, 0x0, 0xb, + 0xfe, 0x0, 0x0, 0x4, 0x20, 0x5f, 0xf9, 0x30, + 0xa, 0xfd, 0x0, 0x28, 0xef, 0x80, 0xaf, 0xff, + 0xfd, 0x58, 0xfb, 0x3c, 0xff, 0xff, 0xd0, 0x28, + 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe9, 0x30, + 0x0, 0x4, 0x9d, 0xff, 0xff, 0xfe, 0xa5, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x5f, 0xff, 0x80, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, 0xbf, 0xf6, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x1e, 0xfe, 0xc, + 0xff, 0x40, 0x0, 0x0, 0x0, 0x0, 0xcf, 0xf6, + 0x3, 0xff, 0xe1, 0x0, 0x0, 0x0, 0x7, 0xff, + 0xc0, 0x0, 0x9f, 0xfa, 0x0, 0x0, 0x0, 0x3f, + 0xff, 0x20, 0x0, 0xd, 0xff, 0x60, 0x0, 0x0, + 0x1c, 0xf6, 0x0, 0x0, 0x3, 0xfd, 0x30, 0x0, + 0x0, 0x0, 0x50, 0x0, 0x0, 0x0, 0x50, 0x0, + 0x0, + + /* U+002B "+" */ + 0x0, 0x0, 0x0, 0xdf, 0xf0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xdf, 0xf0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xdf, 0xf0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xdf, 0xf0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xdf, 0xf0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xdf, 0xf0, 0x0, 0x0, 0x0, + 0x89, 0x99, 0x99, 0xef, 0xf9, 0x99, 0x99, 0x91, + 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf2, + 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf2, + 0x0, 0x0, 0x0, 0xdf, 0xf0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xdf, 0xf0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xdf, 0xf0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xdf, 0xf0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xdf, 0xf0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xdf, 0xf0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x11, 0x10, 0x0, 0x0, 0x0, + + /* U+002C "," */ + 0x0, 0x7d, 0xdb, 0x0, 0xcf, 0xfa, 0x0, 0xef, + 0xf6, 0x1, 0xff, 0xf2, 0x4, 0xff, 0xf0, 0x7, + 0xff, 0xb0, 0xa, 0xff, 0x70, 0xd, 0xff, 0x40, + 0xf, 0xff, 0x0, 0x3f, 0xfd, 0x0, + + /* U+002D "-" */ + 0x49, 0x99, 0x99, 0x99, 0x99, 0x68, 0xff, 0xff, + 0xff, 0xff, 0xfb, 0x8f, 0xff, 0xff, 0xff, 0xff, + 0xb0, + + /* U+002E "." */ + 0x0, 0x2, 0x0, 0x0, 0x3e, 0xff, 0x60, 0xd, + 0xff, 0xff, 0x0, 0xff, 0xff, 0xf2, 0xc, 0xff, + 0xfe, 0x0, 0x2c, 0xfd, 0x40, + + /* U+002F "/" */ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x6, 0xff, 0x90, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xcf, 0xf3, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x2f, 0xfd, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x8, 0xff, 0x70, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xef, 0xf1, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x5f, 0xfb, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xb, 0xff, 0x50, 0x0, 0x0, 0x0, 0x0, + 0x1, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x7f, 0xf9, 0x0, 0x0, 0x0, 0x0, 0x0, 0xd, + 0xff, 0x30, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, + 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9f, 0xf7, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xe, 0xff, 0x10, + 0x0, 0x0, 0x0, 0x0, 0x5, 0xff, 0xa0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xbf, 0xf4, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x1f, 0xfe, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x7, 0xff, 0x80, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xdf, 0xf2, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x3f, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x9, 0xff, 0x60, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xff, 0xf1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6f, + 0xfa, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc, 0xff, + 0x40, 0x0, 0x0, 0x0, 0x0, 0x2, 0xff, 0xe0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x8f, 0xf8, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xe, 0xff, 0x20, 0x0, + 0x0, 0x0, 0x0, 0x4, 0xff, 0xc0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xaf, 0xf6, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xf, 0xff, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x6, 0xff, 0xa0, 0x0, 0x0, 0x0, 0x0, + 0x0, + + /* U+0030 "0" */ + 0x0, 0x0, 0x7b, 0xef, 0xec, 0x81, 0x0, 0x0, + 0x3, 0xef, 0xff, 0xff, 0xff, 0xf5, 0x0, 0x2, + 0xff, 0xfe, 0x97, 0x9d, 0xff, 0xf5, 0x0, 0xcf, + 0xfa, 0x0, 0x0, 0x8, 0xff, 0xe0, 0x2f, 0xfd, + 0x0, 0x0, 0x0, 0xb, 0xff, 0x55, 0xff, 0x70, + 0x0, 0x0, 0x0, 0x4f, 0xf8, 0x6f, 0xf5, 0x0, + 0x0, 0x0, 0x2, 0xff, 0xa7, 0xff, 0x50, 0x0, + 0x0, 0x0, 0x2f, 0xfa, 0x7f, 0xf5, 0x0, 0x0, + 0x0, 0x2, 0xff, 0xa7, 0xff, 0x50, 0xa, 0xfc, + 0x10, 0x2f, 0xfa, 0x7f, 0xf5, 0x4, 0xff, 0xf7, + 0x2, 0xff, 0xa7, 0xff, 0x50, 0x2f, 0xff, 0x50, + 0x2f, 0xfa, 0x7f, 0xf5, 0x0, 0x59, 0x70, 0x2, + 0xff, 0xa7, 0xff, 0x50, 0x0, 0x0, 0x0, 0x2f, + 0xfa, 0x7f, 0xf5, 0x0, 0x0, 0x0, 0x2, 0xff, + 0xa7, 0xff, 0x50, 0x0, 0x0, 0x0, 0x2f, 0xfa, + 0x6f, 0xf5, 0x0, 0x0, 0x0, 0x2, 0xff, 0x95, + 0xff, 0x70, 0x0, 0x0, 0x0, 0x4f, 0xf8, 0x2f, + 0xfd, 0x0, 0x0, 0x0, 0xb, 0xff, 0x50, 0xcf, + 0xfa, 0x0, 0x0, 0x8, 0xff, 0xe0, 0x2, 0xff, + 0xfe, 0x98, 0x9d, 0xff, 0xf4, 0x0, 0x3, 0xef, + 0xff, 0xff, 0xff, 0xf5, 0x0, 0x0, 0x0, 0x7c, + 0xef, 0xec, 0x71, 0x0, 0x0, + + /* U+0031 "1" */ + 0x0, 0x0, 0x8, 0xff, 0xff, 0x10, 0x0, 0x0, + 0x0, 0x1, 0xcf, 0xff, 0xff, 0x10, 0x0, 0x0, + 0x0, 0x5e, 0xff, 0xee, 0xff, 0x10, 0x0, 0x0, + 0x9, 0xff, 0xfb, 0x1c, 0xff, 0x10, 0x0, 0x0, + 0x2f, 0xff, 0x70, 0xc, 0xff, 0x10, 0x0, 0x0, + 0x2f, 0xd3, 0x0, 0xc, 0xff, 0x10, 0x0, 0x0, + 0x2a, 0x0, 0x0, 0xc, 0xff, 0x10, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xc, 0xff, 0x10, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xc, 0xff, 0x10, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xc, 0xff, 0x10, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xc, 0xff, 0x10, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xc, 0xff, 0x10, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xc, 0xff, 0x10, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xc, 0xff, 0x10, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xc, 0xff, 0x10, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xc, 0xff, 0x10, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xc, 0xff, 0x10, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xc, 0xff, 0x10, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xc, 0xff, 0x10, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xc, 0xff, 0x10, 0x0, 0x0, + 0x1a, 0xaa, 0xaa, 0xae, 0xff, 0xaa, 0xaa, 0xa2, + 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf4, + 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf4, + + /* U+0032 "2" */ + 0x0, 0x0, 0x7c, 0xef, 0xec, 0x81, 0x0, 0x0, + 0x3, 0xef, 0xff, 0xff, 0xff, 0xf5, 0x0, 0x2, + 0xff, 0xfe, 0xa9, 0xae, 0xff, 0xf4, 0x0, 0xcf, + 0xfa, 0x0, 0x0, 0xa, 0xff, 0xe0, 0x2f, 0xfd, + 0x0, 0x0, 0x0, 0xd, 0xff, 0x46, 0xff, 0x70, + 0x0, 0x0, 0x0, 0x8f, 0xf7, 0x6b, 0xb3, 0x0, + 0x0, 0x0, 0x6, 0xff, 0x80, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x7f, 0xf7, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xc, 0xff, 0x30, 0x0, 0x0, 0x0, 0x0, + 0x4, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xdf, 0xf5, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf, + 0xfb, 0x0, 0x0, 0x0, 0x0, 0x0, 0xaf, 0xfd, + 0x10, 0x0, 0x0, 0x0, 0x0, 0x9f, 0xfe, 0x10, + 0x0, 0x0, 0x0, 0x0, 0x9f, 0xfe, 0x20, 0x0, + 0x0, 0x0, 0x0, 0x8f, 0xfe, 0x20, 0x0, 0x0, + 0x0, 0x0, 0x8f, 0xfe, 0x20, 0x0, 0x0, 0x0, + 0x0, 0x8f, 0xfe, 0x20, 0x0, 0x0, 0x0, 0x0, + 0x7f, 0xfe, 0x20, 0x0, 0x0, 0x0, 0x0, 0x7f, + 0xfe, 0x20, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xff, + 0xca, 0xaa, 0xaa, 0xaa, 0xaa, 0x84, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xfd, 0x4f, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xd0, + + /* U+0033 "3" */ + 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x2, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x1a, + 0xaa, 0xaa, 0xaa, 0xaa, 0xef, 0xfb, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x5f, 0xfd, 0x10, 0x0, 0x0, + 0x0, 0x0, 0x5f, 0xfd, 0x10, 0x0, 0x0, 0x0, + 0x0, 0x5f, 0xfe, 0x20, 0x0, 0x0, 0x0, 0x0, + 0x5f, 0xfe, 0x20, 0x0, 0x0, 0x0, 0x0, 0x4f, + 0xfe, 0x20, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xff, + 0xa5, 0x0, 0x0, 0x0, 0x0, 0x4, 0xff, 0xff, + 0xff, 0x70, 0x0, 0x0, 0x0, 0x3e, 0xee, 0xff, + 0xff, 0xa0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6f, + 0xff, 0x70, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4f, + 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xcf, + 0xf2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9, 0xff, + 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9f, 0xf5, + 0x69, 0x91, 0x0, 0x0, 0x0, 0x9, 0xff, 0x4a, + 0xff, 0x40, 0x0, 0x0, 0x0, 0xbf, 0xf3, 0x7f, + 0xfa, 0x0, 0x0, 0x0, 0x1f, 0xff, 0x2, 0xff, + 0xf7, 0x0, 0x0, 0x1c, 0xff, 0xa0, 0x7, 0xff, + 0xfe, 0xa9, 0xbf, 0xff, 0xe2, 0x0, 0x8, 0xff, + 0xff, 0xff, 0xff, 0xd3, 0x0, 0x0, 0x2, 0x9d, + 0xff, 0xeb, 0x60, 0x0, 0x0, + + /* U+0034 "4" */ + 0x0, 0x0, 0x0, 0x0, 0x9f, 0xfb, 0x0, 0x0, + 0x0, 0x0, 0x3, 0xff, 0xf1, 0x0, 0x0, 0x0, + 0x0, 0xd, 0xff, 0x60, 0x0, 0x0, 0x0, 0x0, + 0x7f, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x2, 0xff, + 0xf3, 0x0, 0x0, 0x0, 0x0, 0xb, 0xff, 0x80, + 0x0, 0x0, 0x0, 0x0, 0x6f, 0xfd, 0x0, 0x0, + 0x0, 0x0, 0x1, 0xef, 0xf4, 0x0, 0x0, 0x0, + 0x0, 0xa, 0xff, 0xa0, 0x0, 0x0, 0x0, 0x0, + 0x4f, 0xfe, 0x10, 0x0, 0x18, 0x85, 0x0, 0xdf, + 0xf6, 0x0, 0x0, 0x3f, 0xfb, 0x8, 0xff, 0xb0, + 0x0, 0x0, 0x3f, 0xfb, 0x3f, 0xff, 0x20, 0x0, + 0x0, 0x3f, 0xfb, 0xbf, 0xf7, 0x0, 0x0, 0x0, + 0x3f, 0xfb, 0xcf, 0xf2, 0x0, 0x0, 0x0, 0x3f, + 0xfb, 0xcf, 0xfa, 0xaa, 0xaa, 0xaa, 0xbf, 0xfb, + 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xcf, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfb, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x3f, 0xfb, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x3f, 0xfb, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x3f, 0xfb, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x3f, 0xfb, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, + 0xfb, + + /* U+0035 "5" */ + 0xc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfa, 0x0, + 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa0, 0xc, + 0xff, 0xaa, 0xaa, 0xaa, 0xaa, 0xa6, 0x0, 0xcf, + 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc, 0xfe, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xcf, 0xe0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xc, 0xfe, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xcf, 0xf0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xc, 0xff, 0xff, 0xff, + 0xfd, 0x82, 0x0, 0x0, 0xcf, 0xff, 0xff, 0xff, + 0xff, 0xf6, 0x0, 0x8, 0xaa, 0xaa, 0xaa, 0xbf, + 0xff, 0xf4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1c, + 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1e, + 0xff, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9f, + 0xf6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6, 0xff, + 0x70, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6f, 0xf7, + 0x6c, 0xc3, 0x0, 0x0, 0x0, 0x6, 0xff, 0x77, + 0xff, 0x70, 0x0, 0x0, 0x0, 0x9f, 0xf5, 0x4f, + 0xfd, 0x0, 0x0, 0x0, 0xe, 0xff, 0x20, 0xdf, + 0xfa, 0x0, 0x0, 0x1b, 0xff, 0xc0, 0x4, 0xff, + 0xfe, 0xa9, 0xbf, 0xff, 0xf3, 0x0, 0x5, 0xff, + 0xff, 0xff, 0xff, 0xe4, 0x0, 0x0, 0x1, 0x8c, + 0xef, 0xec, 0x70, 0x0, 0x0, + + /* U+0036 "6" */ + 0x0, 0x0, 0x0, 0xb, 0xff, 0x70, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x4f, 0xfd, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xdf, 0xf3, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x6, 0xff, 0x90, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x1e, 0xfe, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x9f, 0xf4, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x2, 0xff, 0xa0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xb, 0xff, 0x10, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x4f, 0xf9, 0xbf, 0xfd, 0x93, 0x0, 0x0, + 0x0, 0xdf, 0xff, 0xff, 0xff, 0xff, 0x80, 0x0, + 0x6, 0xff, 0xfb, 0x64, 0x5a, 0xff, 0xf8, 0x0, + 0xd, 0xff, 0x60, 0x0, 0x0, 0x4f, 0xff, 0x30, + 0x4f, 0xfa, 0x0, 0x0, 0x0, 0x7, 0xff, 0xa0, + 0x9f, 0xf3, 0x0, 0x0, 0x0, 0x0, 0xff, 0xf0, + 0xdf, 0xf0, 0x0, 0x0, 0x0, 0x0, 0xcf, 0xf1, + 0xef, 0xf0, 0x0, 0x0, 0x0, 0x0, 0xcf, 0xf1, + 0xdf, 0xf0, 0x0, 0x0, 0x0, 0x0, 0xdf, 0xf0, + 0xbf, 0xf5, 0x0, 0x0, 0x0, 0x2, 0xff, 0xd0, + 0x6f, 0xfc, 0x0, 0x0, 0x0, 0xa, 0xff, 0x70, + 0xe, 0xff, 0xb1, 0x0, 0x0, 0x9f, 0xfe, 0x10, + 0x3, 0xff, 0xff, 0xb9, 0xae, 0xff, 0xf4, 0x0, + 0x0, 0x3e, 0xff, 0xff, 0xff, 0xfe, 0x40, 0x0, + 0x0, 0x0, 0x6b, 0xef, 0xec, 0x71, 0x0, 0x0, + + /* U+0037 "7" */ + 0x6f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, + 0x6f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, + 0x6f, 0xfd, 0xaa, 0xaa, 0xaa, 0xaa, 0xef, 0xf7, + 0x6f, 0xf8, 0x0, 0x0, 0x0, 0x0, 0xef, 0xf2, + 0x6f, 0xf8, 0x0, 0x0, 0x0, 0x5, 0xff, 0xb0, + 0x6f, 0xf8, 0x0, 0x0, 0x0, 0xc, 0xff, 0x50, + 0x25, 0x52, 0x0, 0x0, 0x0, 0x2f, 0xfe, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x9f, 0xf8, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xf1, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x6, 0xff, 0xb0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xc, 0xff, 0x40, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x3f, 0xfe, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xaf, 0xf7, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x1, 0xff, 0xf1, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x7, 0xff, 0xa0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xd, 0xff, 0x40, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x4f, 0xfd, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xaf, 0xf7, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x1, 0xff, 0xf1, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x7, 0xff, 0xa0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xe, 0xff, 0x30, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x4f, 0xfd, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xbf, 0xf6, 0x0, 0x0, 0x0, 0x0, + + /* U+0038 "8" */ + 0x0, 0x1, 0x7c, 0xef, 0xec, 0x82, 0x0, 0x0, + 0x0, 0x4e, 0xff, 0xff, 0xff, 0xff, 0x60, 0x0, + 0x3, 0xff, 0xff, 0xb9, 0xbe, 0xff, 0xf6, 0x0, + 0xc, 0xff, 0xa1, 0x0, 0x0, 0x8f, 0xfe, 0x0, + 0x1f, 0xfe, 0x0, 0x0, 0x0, 0xb, 0xff, 0x40, + 0x3f, 0xfa, 0x0, 0x0, 0x0, 0x7, 0xff, 0x60, + 0x2f, 0xfb, 0x0, 0x0, 0x0, 0x8, 0xff, 0x50, + 0xc, 0xff, 0x30, 0x0, 0x0, 0x1e, 0xfe, 0x0, + 0x2, 0xef, 0xf7, 0x20, 0x16, 0xef, 0xf4, 0x0, + 0x0, 0x1a, 0xff, 0xff, 0xff, 0xfb, 0x30, 0x0, + 0x0, 0x6, 0xcf, 0xff, 0xff, 0xd7, 0x10, 0x0, + 0x1, 0xdf, 0xff, 0xb9, 0xae, 0xff, 0xe3, 0x0, + 0xc, 0xff, 0xa0, 0x0, 0x0, 0x7f, 0xfe, 0x10, + 0x5f, 0xfb, 0x0, 0x0, 0x0, 0x8, 0xff, 0x90, + 0xbf, 0xf3, 0x0, 0x0, 0x0, 0x0, 0xff, 0xe0, + 0xdf, 0xf0, 0x0, 0x0, 0x0, 0x0, 0xdf, 0xf0, + 0xdf, 0xf0, 0x0, 0x0, 0x0, 0x0, 0xdf, 0xf0, + 0xbf, 0xf3, 0x0, 0x0, 0x0, 0x1, 0xff, 0xe0, + 0x7f, 0xfb, 0x0, 0x0, 0x0, 0x8, 0xff, 0xa0, + 0x1f, 0xff, 0xa1, 0x0, 0x0, 0x8f, 0xff, 0x30, + 0x4, 0xff, 0xff, 0xba, 0xbe, 0xff, 0xf7, 0x0, + 0x0, 0x4e, 0xff, 0xff, 0xff, 0xff, 0x60, 0x0, + 0x0, 0x1, 0x6b, 0xef, 0xec, 0x71, 0x0, 0x0, + + /* U+0039 "9" */ + 0x0, 0x0, 0x6b, 0xef, 0xec, 0x71, 0x0, 0x0, + 0x0, 0x4e, 0xff, 0xff, 0xff, 0xff, 0x60, 0x0, + 0x4, 0xff, 0xff, 0xb9, 0xae, 0xff, 0xf6, 0x0, + 0x1e, 0xff, 0x90, 0x0, 0x0, 0x7f, 0xff, 0x20, + 0x6f, 0xfb, 0x0, 0x0, 0x0, 0x8, 0xff, 0x90, + 0xbf, 0xf3, 0x0, 0x0, 0x0, 0x0, 0xff, 0xf0, + 0xdf, 0xf0, 0x0, 0x0, 0x0, 0x0, 0xcf, 0xf1, + 0xef, 0xf0, 0x0, 0x0, 0x0, 0x0, 0xcf, 0xf1, + 0xcf, 0xf1, 0x0, 0x0, 0x0, 0x0, 0xef, 0xf0, + 0x9f, 0xf8, 0x0, 0x0, 0x0, 0x5, 0xff, 0xc0, + 0x2f, 0xff, 0x40, 0x0, 0x0, 0x2e, 0xff, 0x70, + 0x8, 0xff, 0xfa, 0x54, 0x59, 0xff, 0xff, 0x10, + 0x0, 0x8f, 0xff, 0xff, 0xff, 0xff, 0xf9, 0x0, + 0x0, 0x3, 0x9d, 0xff, 0xb9, 0xff, 0xf1, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xd, 0xff, 0x70, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x7f, 0xfe, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x1, 0xff, 0xf5, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x9, 0xff, 0xc0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x3f, 0xff, 0x30, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xcf, 0xf9, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x5, 0xff, 0xf1, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xd, 0xff, 0x70, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x7f, 0xfd, 0x0, 0x0, 0x0, 0x0, + + /* U+003A ":" */ + 0x3, 0xcf, 0xd5, 0x0, 0xdf, 0xff, 0xf1, 0xf, + 0xff, 0xff, 0x30, 0xcf, 0xff, 0xe0, 0x1, 0x9b, + 0xa2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x19, 0xb9, + 0x20, 0xc, 0xff, 0xfe, 0x0, 0xff, 0xff, 0xf3, + 0xd, 0xff, 0xff, 0x10, 0x3c, 0xfd, 0x50, + + /* U+003B ";" */ + 0x3, 0xdf, 0xe5, 0x0, 0xef, 0xff, 0xf1, 0x1f, + 0xff, 0xff, 0x40, 0xdf, 0xff, 0xf1, 0x2, 0xad, + 0xb3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa, 0xdd, + 0x90, 0x0, 0xef, 0xf7, 0x0, 0x1f, 0xff, 0x30, + 0x4, 0xff, 0xf0, 0x0, 0x7f, 0xfc, 0x0, 0xa, + 0xff, 0x80, 0x0, 0xdf, 0xf5, 0x0, 0xf, 0xff, + 0x10, 0x2, 0xff, 0xd0, 0x0, 0x5f, 0xfa, 0x0, + 0x0, + + /* U+003C "<" */ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xa7, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x2a, 0xff, 0x70, 0x0, + 0x0, 0x0, 0x2, 0x9f, 0xff, 0xf6, 0x0, 0x0, + 0x0, 0x29, 0xff, 0xff, 0xa2, 0x0, 0x0, 0x2, + 0x9f, 0xff, 0xfa, 0x20, 0x0, 0x0, 0x29, 0xff, + 0xff, 0xa2, 0x0, 0x0, 0x1, 0x9f, 0xff, 0xf9, + 0x20, 0x0, 0x0, 0x0, 0x4f, 0xff, 0x91, 0x0, + 0x0, 0x0, 0x0, 0x4, 0xff, 0x60, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x4f, 0xff, 0xe7, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x6d, 0xff, 0xfe, 0x70, 0x0, + 0x0, 0x0, 0x0, 0x6, 0xef, 0xff, 0xe7, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x6e, 0xff, 0xfe, 0x70, + 0x0, 0x0, 0x0, 0x0, 0x6, 0xef, 0xff, 0xe7, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x6e, 0xff, 0xf7, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x6, 0xef, 0x70, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x66, + + /* U+003D "=" */ + 0x4f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x74, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0x29, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x40, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x2, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x94, 0x4f, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x74, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xf7, + + /* U+003E ">" */ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, + 0xb3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4f, + 0xfb, 0x30, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, + 0xff, 0xb3, 0x0, 0x0, 0x0, 0x0, 0x2, 0xaf, + 0xff, 0xfb, 0x30, 0x0, 0x0, 0x0, 0x0, 0x2a, + 0xff, 0xff, 0xb3, 0x0, 0x0, 0x0, 0x0, 0x2, + 0xaf, 0xff, 0xfb, 0x30, 0x0, 0x0, 0x0, 0x0, + 0x2a, 0xff, 0xff, 0xb2, 0x0, 0x0, 0x0, 0x0, + 0x2, 0x9f, 0xff, 0x70, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x3e, 0xf7, 0x0, 0x0, 0x0, 0x0, 0x3, + 0xbf, 0xff, 0x70, 0x0, 0x0, 0x0, 0x3b, 0xff, + 0xfe, 0x70, 0x0, 0x0, 0x3, 0xbf, 0xff, 0xe8, + 0x0, 0x0, 0x0, 0x4b, 0xff, 0xff, 0x80, 0x0, + 0x0, 0x4, 0xcf, 0xff, 0xf8, 0x10, 0x0, 0x0, + 0x4, 0xff, 0xff, 0x81, 0x0, 0x0, 0x0, 0x0, + 0x4f, 0xf8, 0x10, 0x0, 0x0, 0x0, 0x0, 0x3, + 0x81, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + + /* U+003F "?" */ + 0xdf, 0xff, 0xfd, 0xb5, 0x0, 0x0, 0xdf, 0xff, + 0xff, 0xff, 0xd3, 0x0, 0x9b, 0xbb, 0xce, 0xff, + 0xfe, 0x20, 0x0, 0x0, 0x0, 0x3d, 0xff, 0xb0, + 0x0, 0x0, 0x0, 0x1, 0xef, 0xf2, 0x0, 0x0, + 0x0, 0x0, 0x8f, 0xf5, 0x0, 0x0, 0x0, 0x0, + 0x6f, 0xf7, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xf6, + 0x0, 0x0, 0x0, 0x0, 0xcf, 0xf4, 0x0, 0x0, + 0x0, 0x8, 0xff, 0xe0, 0x0, 0x26, 0x68, 0xdf, + 0xff, 0x50, 0x0, 0x6f, 0xff, 0xff, 0xf7, 0x0, + 0x0, 0x6f, 0xff, 0xea, 0x30, 0x0, 0x0, 0x6f, + 0xf7, 0x0, 0x0, 0x0, 0x0, 0x6f, 0xf7, 0x0, + 0x0, 0x0, 0x0, 0x6f, 0xf7, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x8d, 0xd9, 0x0, 0x0, 0x0, + 0x4, 0xff, 0xff, 0x40, 0x0, 0x0, 0x5, 0xff, + 0xff, 0x50, 0x0, 0x0, 0x0, 0xaf, 0xfa, 0x0, + 0x0, 0x0, + + /* U+0040 "@" */ + 0x0, 0x0, 0x5, 0xad, 0xff, 0xeb, 0x60, 0x0, + 0x0, 0x0, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xe3, + 0x0, 0x0, 0x4f, 0xff, 0xc7, 0x44, 0x6b, 0xff, + 0xf3, 0x0, 0x1e, 0xff, 0x40, 0x0, 0x0, 0x4, + 0xff, 0xe0, 0x9, 0xff, 0x40, 0x0, 0x0, 0x0, + 0x6, 0xff, 0x60, 0xff, 0xb0, 0x0, 0x0, 0x0, + 0x0, 0xf, 0xfa, 0x4f, 0xf5, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xbf, 0xd7, 0xff, 0x20, 0x0, 0x0, + 0x0, 0x0, 0xa, 0xfe, 0x8f, 0xf0, 0x0, 0x0, + 0x5c, 0xff, 0xc3, 0xaf, 0xe8, 0xff, 0x0, 0x0, + 0x6f, 0xff, 0xff, 0xfc, 0xfe, 0x9f, 0xf0, 0x0, + 0xe, 0xff, 0x50, 0x1a, 0xff, 0xe9, 0xff, 0x0, + 0x3, 0xff, 0x70, 0x0, 0xe, 0xfe, 0x9f, 0xf0, + 0x0, 0x4f, 0xf4, 0x0, 0x0, 0xaf, 0xe9, 0xff, + 0x0, 0x5, 0xff, 0x30, 0x0, 0xa, 0xfe, 0x9f, + 0xf0, 0x0, 0x5f, 0xf3, 0x0, 0x0, 0xaf, 0xe9, + 0xff, 0x0, 0x5, 0xff, 0x30, 0x0, 0xa, 0xfe, + 0x9f, 0xf0, 0x0, 0x4f, 0xf4, 0x0, 0x0, 0xaf, + 0xe9, 0xff, 0x0, 0x2, 0xff, 0x70, 0x0, 0xe, + 0xfb, 0x9f, 0xf0, 0x0, 0xd, 0xff, 0x50, 0x1a, + 0xff, 0x68, 0xff, 0x0, 0x0, 0x3f, 0xff, 0xff, + 0xff, 0xb0, 0x8f, 0xf0, 0x0, 0x0, 0x2b, 0xff, + 0xfe, 0x80, 0x7, 0xff, 0x20, 0x0, 0x0, 0x0, + 0x21, 0x0, 0x0, 0x4f, 0xf6, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xff, 0xd0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x8, 0xff, 0x80, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xd, 0xff, 0x90, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2e, 0xff, + 0xea, 0x76, 0x66, 0x50, 0x0, 0x0, 0x0, 0x1c, + 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, + 0x4, 0x9d, 0xff, 0xff, 0xe0, 0x0, 0x0, + + /* U+0041 "A" */ + 0x0, 0x0, 0x0, 0x7f, 0xff, 0xa0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xb, 0xff, 0xfe, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xff, 0xef, 0xf3, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x3f, 0xf8, 0xff, 0x70, + 0x0, 0x0, 0x0, 0x0, 0x8, 0xff, 0x2f, 0xfb, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xcf, 0xe0, 0xbf, + 0xf0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfa, 0x7, + 0xff, 0x40, 0x0, 0x0, 0x0, 0x4, 0xff, 0x60, + 0x3f, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x9f, 0xf2, + 0x0, 0xff, 0xc0, 0x0, 0x0, 0x0, 0xd, 0xfe, + 0x0, 0xb, 0xff, 0x0, 0x0, 0x0, 0x1, 0xff, + 0xa0, 0x0, 0x7f, 0xf4, 0x0, 0x0, 0x0, 0x5f, + 0xf6, 0x0, 0x3, 0xff, 0x90, 0x0, 0x0, 0xa, + 0xff, 0x20, 0x0, 0xf, 0xfd, 0x0, 0x0, 0x0, + 0xef, 0xe0, 0x0, 0x0, 0xbf, 0xf1, 0x0, 0x0, + 0x2f, 0xfd, 0x77, 0x77, 0x7b, 0xff, 0x50, 0x0, + 0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf9, 0x0, + 0x0, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, + 0x0, 0xf, 0xff, 0x0, 0x0, 0x0, 0xb, 0xff, + 0x20, 0x3, 0xff, 0xb0, 0x0, 0x0, 0x0, 0x7f, + 0xf6, 0x0, 0x7f, 0xf7, 0x0, 0x0, 0x0, 0x3, + 0xff, 0xa0, 0xb, 0xff, 0x20, 0x0, 0x0, 0x0, + 0xf, 0xfe, 0x0, 0xff, 0xe0, 0x0, 0x0, 0x0, + 0x0, 0xbf, 0xf3, 0x4f, 0xfa, 0x0, 0x0, 0x0, + 0x0, 0x7, 0xff, 0x70, + + /* U+0042 "B" */ + 0xf, 0xff, 0xff, 0xff, 0xfd, 0x92, 0x0, 0x0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x0, 0xf, + 0xfe, 0x99, 0x99, 0xbe, 0xff, 0xf7, 0x0, 0xff, + 0xc0, 0x0, 0x0, 0x19, 0xff, 0xf0, 0xf, 0xfc, + 0x0, 0x0, 0x0, 0xc, 0xff, 0x40, 0xff, 0xc0, + 0x0, 0x0, 0x0, 0x7f, 0xf6, 0xf, 0xfc, 0x0, + 0x0, 0x0, 0x7, 0xff, 0x50, 0xff, 0xc0, 0x0, + 0x0, 0x0, 0xcf, 0xf1, 0xf, 0xfc, 0x0, 0x0, + 0x0, 0x8f, 0xf8, 0x0, 0xff, 0xe8, 0x88, 0x8a, + 0xef, 0xfa, 0x0, 0xf, 0xff, 0xff, 0xff, 0xff, + 0xd4, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf7, 0x0, 0xf, 0xfc, 0x0, 0x0, 0x14, 0xdf, + 0xf8, 0x0, 0xff, 0xc0, 0x0, 0x0, 0x0, 0xcf, + 0xf3, 0xf, 0xfc, 0x0, 0x0, 0x0, 0x4, 0xff, + 0x90, 0xff, 0xc0, 0x0, 0x0, 0x0, 0xf, 0xfd, + 0xf, 0xfc, 0x0, 0x0, 0x0, 0x0, 0xef, 0xe0, + 0xff, 0xc0, 0x0, 0x0, 0x0, 0xf, 0xfd, 0xf, + 0xfc, 0x0, 0x0, 0x0, 0x7, 0xff, 0xa0, 0xff, + 0xc0, 0x0, 0x0, 0x5, 0xff, 0xf5, 0xf, 0xfe, + 0x99, 0x99, 0xae, 0xff, 0xfb, 0x0, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xfb, 0x0, 0xf, 0xff, 0xff, + 0xff, 0xfe, 0xa4, 0x0, 0x0, + + /* U+0043 "C" */ + 0x0, 0x0, 0x5b, 0xef, 0xfd, 0x92, 0x0, 0x0, + 0x1, 0xcf, 0xff, 0xff, 0xff, 0xf8, 0x0, 0x0, + 0xdf, 0xff, 0xc9, 0xad, 0xff, 0xf7, 0x0, 0x7f, + 0xfe, 0x30, 0x0, 0x6, 0xff, 0xf1, 0xc, 0xff, + 0x40, 0x0, 0x0, 0x9, 0xff, 0x60, 0xff, 0xe0, + 0x0, 0x0, 0x0, 0x4f, 0xf9, 0xf, 0xfd, 0x0, + 0x0, 0x0, 0x1, 0x88, 0x51, 0xff, 0xd0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x1f, 0xfd, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x1, 0xff, 0xd0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x1f, 0xfd, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x1, 0xff, 0xd0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x1f, 0xfd, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x1, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x1f, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x1, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xf, 0xfd, 0x0, 0x0, 0x0, 0x1, 0x88, 0x50, + 0xff, 0xe0, 0x0, 0x0, 0x0, 0x4f, 0xf9, 0xc, + 0xff, 0x40, 0x0, 0x0, 0x9, 0xff, 0x60, 0x7f, + 0xfe, 0x30, 0x0, 0x6, 0xff, 0xf1, 0x0, 0xdf, + 0xff, 0xca, 0xad, 0xff, 0xf7, 0x0, 0x1, 0xcf, + 0xff, 0xff, 0xff, 0xf8, 0x0, 0x0, 0x0, 0x5b, + 0xef, 0xfd, 0x92, 0x0, 0x0, + + /* U+0044 "D" */ + 0x1f, 0xff, 0xff, 0xff, 0xda, 0x40, 0x0, 0x1, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xb1, 0x0, 0x1f, + 0xfe, 0x99, 0x99, 0xcf, 0xff, 0xd0, 0x1, 0xff, + 0xd0, 0x0, 0x0, 0x2d, 0xff, 0x80, 0x1f, 0xfd, + 0x0, 0x0, 0x0, 0x2f, 0xfe, 0x1, 0xff, 0xd0, + 0x0, 0x0, 0x0, 0xbf, 0xf3, 0x1f, 0xfd, 0x0, + 0x0, 0x0, 0x8, 0xff, 0x51, 0xff, 0xd0, 0x0, + 0x0, 0x0, 0x8f, 0xf6, 0x1f, 0xfd, 0x0, 0x0, + 0x0, 0x8, 0xff, 0x61, 0xff, 0xd0, 0x0, 0x0, + 0x0, 0x8f, 0xf6, 0x1f, 0xfd, 0x0, 0x0, 0x0, + 0x8, 0xff, 0x61, 0xff, 0xd0, 0x0, 0x0, 0x0, + 0x8f, 0xf6, 0x1f, 0xfd, 0x0, 0x0, 0x0, 0x8, + 0xff, 0x61, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x8f, + 0xf6, 0x1f, 0xfd, 0x0, 0x0, 0x0, 0x8, 0xff, + 0x61, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x8f, 0xf6, + 0x1f, 0xfd, 0x0, 0x0, 0x0, 0x8, 0xff, 0x51, + 0xff, 0xd0, 0x0, 0x0, 0x0, 0xbf, 0xf3, 0x1f, + 0xfd, 0x0, 0x0, 0x0, 0x2f, 0xfe, 0x1, 0xff, + 0xd0, 0x0, 0x0, 0x2d, 0xff, 0x80, 0x1f, 0xfe, + 0x99, 0x99, 0xcf, 0xff, 0xd0, 0x1, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xb1, 0x0, 0x1f, 0xff, 0xff, + 0xff, 0xda, 0x40, 0x0, 0x0, + + /* U+0045 "E" */ + 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfa, 0xcf, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfa, 0xcf, 0xfa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xa6, 0xcf, 0xf0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xcf, 0xf0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xcf, 0xf0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xcf, 0xf0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xcf, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xcf, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xcf, + 0xf9, 0x99, 0x99, 0x99, 0x99, 0x40, 0xcf, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x80, 0xcf, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x80, 0xcf, 0xf0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xcf, 0xf0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xcf, 0xf0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xcf, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xcf, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xcf, + 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xcf, 0xf0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xcf, 0xf0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xcf, 0xfa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xa6, 0xcf, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xfa, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfa, + + /* U+0046 "F" */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xfa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xa8, 0xff, 0xd0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xff, 0xd0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xff, 0xd0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, + 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xf0, 0xff, 0xfa, 0xaa, 0xaa, + 0xaa, 0xaa, 0x90, 0xff, 0xe0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, + 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xe0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xe0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xff, 0xe0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xff, 0xe0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, + 0x0, + + /* U+0047 "G" */ + 0x0, 0x0, 0x6b, 0xef, 0xfd, 0x92, 0x0, 0x0, + 0x2, 0xdf, 0xff, 0xff, 0xff, 0xf7, 0x0, 0x1, + 0xef, 0xff, 0xca, 0xbe, 0xff, 0xf6, 0x0, 0x9f, + 0xfd, 0x20, 0x0, 0x7, 0xff, 0xf1, 0xe, 0xff, + 0x20, 0x0, 0x0, 0xa, 0xff, 0x51, 0xff, 0xc0, + 0x0, 0x0, 0x0, 0x5f, 0xf8, 0x2f, 0xfb, 0x0, + 0x0, 0x0, 0x1, 0x33, 0x13, 0xff, 0xb0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x3f, 0xfb, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x3, 0xff, 0xb0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x3f, 0xfb, 0x0, 0xa, 0xaa, + 0xaa, 0xaa, 0x53, 0xff, 0xb0, 0x0, 0xff, 0xff, + 0xff, 0xf9, 0x3f, 0xfb, 0x0, 0xf, 0xff, 0xff, + 0xff, 0x93, 0xff, 0xb0, 0x0, 0x0, 0x0, 0x4f, + 0xf9, 0x3f, 0xfb, 0x0, 0x0, 0x0, 0x4, 0xff, + 0x93, 0xff, 0xb0, 0x0, 0x0, 0x0, 0x4f, 0xf9, + 0x2f, 0xfb, 0x0, 0x0, 0x0, 0x5, 0xff, 0x81, + 0xff, 0xc0, 0x0, 0x0, 0x0, 0x7f, 0xf7, 0xe, + 0xff, 0x20, 0x0, 0x0, 0xc, 0xff, 0x40, 0x9f, + 0xfd, 0x20, 0x0, 0x9, 0xff, 0xd0, 0x1, 0xef, + 0xff, 0xb9, 0xae, 0xff, 0xf4, 0x0, 0x2, 0xdf, + 0xff, 0xff, 0xff, 0xf5, 0x0, 0x0, 0x0, 0x6b, + 0xef, 0xfc, 0x81, 0x0, 0x0, + + /* U+0048 "H" */ + 0xf, 0xfd, 0x0, 0x0, 0x0, 0xa, 0xff, 0x30, + 0xff, 0xd0, 0x0, 0x0, 0x0, 0xaf, 0xf3, 0xf, + 0xfd, 0x0, 0x0, 0x0, 0xa, 0xff, 0x30, 0xff, + 0xd0, 0x0, 0x0, 0x0, 0xaf, 0xf3, 0xf, 0xfd, + 0x0, 0x0, 0x0, 0xa, 0xff, 0x30, 0xff, 0xd0, + 0x0, 0x0, 0x0, 0xaf, 0xf3, 0xf, 0xfd, 0x0, + 0x0, 0x0, 0xa, 0xff, 0x30, 0xff, 0xd0, 0x0, + 0x0, 0x0, 0xaf, 0xf3, 0xf, 0xfd, 0x0, 0x0, + 0x0, 0xa, 0xff, 0x30, 0xff, 0xfa, 0xaa, 0xaa, + 0xaa, 0xef, 0xf3, 0xf, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x30, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xf3, 0xf, 0xfd, 0x0, 0x0, 0x0, 0xa, + 0xff, 0x30, 0xff, 0xd0, 0x0, 0x0, 0x0, 0xaf, + 0xf3, 0xf, 0xfd, 0x0, 0x0, 0x0, 0xa, 0xff, + 0x30, 0xff, 0xd0, 0x0, 0x0, 0x0, 0xaf, 0xf3, + 0xf, 0xfd, 0x0, 0x0, 0x0, 0xa, 0xff, 0x30, + 0xff, 0xd0, 0x0, 0x0, 0x0, 0xaf, 0xf3, 0xf, + 0xfd, 0x0, 0x0, 0x0, 0xa, 0xff, 0x30, 0xff, + 0xd0, 0x0, 0x0, 0x0, 0xaf, 0xf3, 0xf, 0xfd, + 0x0, 0x0, 0x0, 0xa, 0xff, 0x30, 0xff, 0xd0, + 0x0, 0x0, 0x0, 0xaf, 0xf3, 0xf, 0xfd, 0x0, + 0x0, 0x0, 0xa, 0xff, 0x30, + + /* U+0049 "I" */ + 0xaf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xda, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xfd, 0x6a, 0xaa, 0xaf, + 0xff, 0xaa, 0xaa, 0x80, 0x0, 0x0, 0xef, 0xf1, + 0x0, 0x0, 0x0, 0x0, 0xe, 0xff, 0x10, 0x0, + 0x0, 0x0, 0x0, 0xef, 0xf1, 0x0, 0x0, 0x0, + 0x0, 0xe, 0xff, 0x10, 0x0, 0x0, 0x0, 0x0, + 0xef, 0xf1, 0x0, 0x0, 0x0, 0x0, 0xe, 0xff, + 0x10, 0x0, 0x0, 0x0, 0x0, 0xef, 0xf1, 0x0, + 0x0, 0x0, 0x0, 0xe, 0xff, 0x10, 0x0, 0x0, + 0x0, 0x0, 0xef, 0xf1, 0x0, 0x0, 0x0, 0x0, + 0xe, 0xff, 0x10, 0x0, 0x0, 0x0, 0x0, 0xef, + 0xf1, 0x0, 0x0, 0x0, 0x0, 0xe, 0xff, 0x10, + 0x0, 0x0, 0x0, 0x0, 0xef, 0xf1, 0x0, 0x0, + 0x0, 0x0, 0xe, 0xff, 0x10, 0x0, 0x0, 0x0, + 0x0, 0xef, 0xf1, 0x0, 0x0, 0x0, 0x0, 0xe, + 0xff, 0x10, 0x0, 0x0, 0x0, 0x0, 0xef, 0xf1, + 0x0, 0x0, 0x6a, 0xaa, 0xaf, 0xff, 0xaa, 0xaa, + 0x8a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xaf, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xd0, + + /* U+004A "J" */ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xd0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xd0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xff, 0xd0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xf, 0xfd, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xff, 0xd0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xf, 0xfd, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xf, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xf, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, + 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, + 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, + 0x7e, 0xe4, 0x0, 0x0, 0x0, 0x1, 0xff, 0xd7, + 0xff, 0x70, 0x0, 0x0, 0x0, 0x3f, 0xfb, 0x3f, + 0xfd, 0x0, 0x0, 0x0, 0x9, 0xff, 0x70, 0xcf, + 0xfa, 0x10, 0x0, 0x7, 0xff, 0xf1, 0x3, 0xff, + 0xff, 0xb9, 0xae, 0xff, 0xf7, 0x0, 0x4, 0xef, + 0xff, 0xff, 0xff, 0xf7, 0x0, 0x0, 0x0, 0x7c, + 0xef, 0xfd, 0x82, 0x0, 0x0, + + /* U+004B "K" */ + 0x1f, 0xfd, 0x0, 0x0, 0x0, 0x0, 0xcf, 0xf5, + 0x1f, 0xfd, 0x0, 0x0, 0x0, 0x5, 0xff, 0xc0, + 0x1f, 0xfd, 0x0, 0x0, 0x0, 0xd, 0xff, 0x30, + 0x1f, 0xfd, 0x0, 0x0, 0x0, 0x7f, 0xfb, 0x0, + 0x1f, 0xfd, 0x0, 0x0, 0x1, 0xef, 0xf2, 0x0, + 0x1f, 0xfd, 0x0, 0x0, 0x8, 0xff, 0x90, 0x0, + 0x1f, 0xfd, 0x0, 0x0, 0x2f, 0xff, 0x10, 0x0, + 0x1f, 0xfd, 0x0, 0x0, 0xaf, 0xf8, 0x0, 0x0, + 0x1f, 0xfd, 0x0, 0x3, 0xff, 0xe0, 0x0, 0x0, + 0x1f, 0xfe, 0x88, 0x8d, 0xff, 0x70, 0x0, 0x0, + 0x1f, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, + 0x1f, 0xff, 0xff, 0xff, 0xff, 0x30, 0x0, 0x0, + 0x1f, 0xfd, 0x0, 0x9, 0xff, 0xb0, 0x0, 0x0, + 0x1f, 0xfd, 0x0, 0x1, 0xff, 0xf3, 0x0, 0x0, + 0x1f, 0xfd, 0x0, 0x0, 0x9f, 0xfb, 0x0, 0x0, + 0x1f, 0xfd, 0x0, 0x0, 0x1f, 0xff, 0x30, 0x0, + 0x1f, 0xfd, 0x0, 0x0, 0x9, 0xff, 0xb0, 0x0, + 0x1f, 0xfd, 0x0, 0x0, 0x1, 0xff, 0xf3, 0x0, + 0x1f, 0xfd, 0x0, 0x0, 0x0, 0x9f, 0xfb, 0x0, + 0x1f, 0xfd, 0x0, 0x0, 0x0, 0x2f, 0xff, 0x30, + 0x1f, 0xfd, 0x0, 0x0, 0x0, 0x9, 0xff, 0xa0, + 0x1f, 0xfd, 0x0, 0x0, 0x0, 0x2, 0xff, 0xf2, + 0x1f, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x9f, 0xfa, + + /* U+004C "L" */ + 0xdf, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xdf, + 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xdf, 0xf0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xdf, 0xf0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xdf, 0xf0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xdf, 0xf0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xdf, 0xf0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xdf, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xdf, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xdf, + 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xdf, 0xf0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xdf, 0xf0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xdf, 0xf0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xdf, 0xf0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xdf, 0xf0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xdf, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xdf, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xdf, + 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xdf, 0xf0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xdf, 0xf0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xdf, 0xfa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xa6, 0xdf, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xf9, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf9, + + /* U+004D "M" */ + 0xbf, 0xff, 0xb0, 0x0, 0x0, 0x8f, 0xff, 0xeb, + 0xfe, 0xff, 0x0, 0x0, 0xd, 0xfd, 0xfe, 0xbf, + 0xce, 0xf4, 0x0, 0x2, 0xff, 0xaf, 0xeb, 0xfd, + 0xaf, 0x90, 0x0, 0x7f, 0xaa, 0xfe, 0xbf, 0xe5, + 0xfe, 0x0, 0xc, 0xf5, 0xbf, 0xeb, 0xff, 0xf, + 0xf3, 0x1, 0xff, 0x1b, 0xfe, 0xbf, 0xf0, 0xbf, + 0x80, 0x6f, 0xb0, 0xcf, 0xeb, 0xff, 0x6, 0xfc, + 0xb, 0xf6, 0xc, 0xfe, 0xbf, 0xf0, 0x1f, 0xf2, + 0xff, 0x10, 0xdf, 0xeb, 0xff, 0x10, 0xcf, 0xbf, + 0xc0, 0xd, 0xfe, 0xbf, 0xf1, 0x7, 0xff, 0xf7, + 0x0, 0xef, 0xeb, 0xff, 0x10, 0x2f, 0xff, 0x20, + 0xe, 0xfe, 0xbf, 0xf1, 0x0, 0x9b, 0x90, 0x0, + 0xef, 0xeb, 0xff, 0x10, 0x0, 0x0, 0x0, 0xe, + 0xfe, 0xbf, 0xf1, 0x0, 0x0, 0x0, 0x0, 0xef, + 0xeb, 0xff, 0x10, 0x0, 0x0, 0x0, 0xe, 0xfe, + 0xbf, 0xf1, 0x0, 0x0, 0x0, 0x0, 0xef, 0xeb, + 0xff, 0x10, 0x0, 0x0, 0x0, 0xe, 0xfe, 0xbf, + 0xf1, 0x0, 0x0, 0x0, 0x0, 0xef, 0xeb, 0xff, + 0x10, 0x0, 0x0, 0x0, 0xe, 0xfe, 0xbf, 0xf1, + 0x0, 0x0, 0x0, 0x0, 0xef, 0xeb, 0xff, 0x10, + 0x0, 0x0, 0x0, 0xe, 0xfe, 0xbf, 0xf1, 0x0, + 0x0, 0x0, 0x0, 0xef, 0xe0, + + /* U+004E "N" */ + 0x2f, 0xff, 0xe0, 0x0, 0x0, 0x7, 0xff, 0x52, + 0xff, 0xff, 0x40, 0x0, 0x0, 0x7f, 0xf5, 0x2f, + 0xff, 0xf9, 0x0, 0x0, 0x7, 0xff, 0x52, 0xff, + 0xef, 0xf0, 0x0, 0x0, 0x7f, 0xf5, 0x2f, 0xfa, + 0xff, 0x50, 0x0, 0x7, 0xff, 0x52, 0xff, 0x8d, + 0xfb, 0x0, 0x0, 0x7f, 0xf5, 0x2f, 0xf8, 0x7f, + 0xf1, 0x0, 0x7, 0xff, 0x52, 0xff, 0x91, 0xff, + 0x60, 0x0, 0x7f, 0xf5, 0x2f, 0xf9, 0xc, 0xfc, + 0x0, 0x7, 0xff, 0x52, 0xff, 0xa0, 0x6f, 0xf2, + 0x0, 0x7f, 0xf5, 0x2f, 0xfa, 0x0, 0xff, 0x80, + 0x7, 0xff, 0x52, 0xff, 0xa0, 0xa, 0xfe, 0x0, + 0x7f, 0xf5, 0x2f, 0xfa, 0x0, 0x4f, 0xf4, 0x7, + 0xff, 0x52, 0xff, 0xa0, 0x0, 0xef, 0x90, 0x7f, + 0xf5, 0x2f, 0xfa, 0x0, 0x9, 0xff, 0x7, 0xff, + 0x52, 0xff, 0xa0, 0x0, 0x3f, 0xf5, 0x6f, 0xf5, + 0x2f, 0xfa, 0x0, 0x0, 0xdf, 0xb5, 0xff, 0x52, + 0xff, 0xa0, 0x0, 0x8, 0xff, 0x6f, 0xf5, 0x2f, + 0xfa, 0x0, 0x0, 0x2f, 0xfa, 0xff, 0x52, 0xff, + 0xa0, 0x0, 0x0, 0xcf, 0xef, 0xf5, 0x2f, 0xfa, + 0x0, 0x0, 0x6, 0xff, 0xff, 0x52, 0xff, 0xa0, + 0x0, 0x0, 0x1f, 0xff, 0xf5, 0x2f, 0xfa, 0x0, + 0x0, 0x0, 0xbf, 0xff, 0x50, + + /* U+004F "O" */ + 0x0, 0x0, 0x6b, 0xef, 0xec, 0x71, 0x0, 0x0, + 0x2, 0xdf, 0xff, 0xff, 0xff, 0xe4, 0x0, 0x1, + 0xef, 0xff, 0xb9, 0xae, 0xff, 0xf3, 0x0, 0x8f, + 0xfc, 0x10, 0x0, 0xa, 0xff, 0xc0, 0xe, 0xff, + 0x20, 0x0, 0x0, 0xe, 0xff, 0x11, 0xff, 0xc0, + 0x0, 0x0, 0x0, 0x9f, 0xf4, 0x2f, 0xfb, 0x0, + 0x0, 0x0, 0x8, 0xff, 0x53, 0xff, 0xb0, 0x0, + 0x0, 0x0, 0x8f, 0xf6, 0x3f, 0xfb, 0x0, 0x0, + 0x0, 0x8, 0xff, 0x63, 0xff, 0xb0, 0x0, 0x0, + 0x0, 0x8f, 0xf6, 0x3f, 0xfb, 0x0, 0x0, 0x0, + 0x8, 0xff, 0x63, 0xff, 0xb0, 0x0, 0x0, 0x0, + 0x8f, 0xf6, 0x3f, 0xfb, 0x0, 0x0, 0x0, 0x8, + 0xff, 0x63, 0xff, 0xb0, 0x0, 0x0, 0x0, 0x8f, + 0xf6, 0x3f, 0xfb, 0x0, 0x0, 0x0, 0x8, 0xff, + 0x63, 0xff, 0xb0, 0x0, 0x0, 0x0, 0x8f, 0xf6, + 0x2f, 0xfb, 0x0, 0x0, 0x0, 0x8, 0xff, 0x51, + 0xff, 0xc0, 0x0, 0x0, 0x0, 0x9f, 0xf4, 0xe, + 0xff, 0x20, 0x0, 0x0, 0xe, 0xff, 0x10, 0x8f, + 0xfc, 0x10, 0x0, 0xa, 0xff, 0xb0, 0x1, 0xef, + 0xff, 0xba, 0xbe, 0xff, 0xf3, 0x0, 0x2, 0xdf, + 0xff, 0xff, 0xff, 0xe4, 0x0, 0x0, 0x0, 0x6b, + 0xef, 0xec, 0x81, 0x0, 0x0, + + /* U+0050 "P" */ + 0x1f, 0xff, 0xff, 0xff, 0xfe, 0xc7, 0x0, 0x0, + 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe4, 0x0, + 0x1f, 0xfe, 0x99, 0x99, 0x9b, 0xff, 0xff, 0x30, + 0x1f, 0xfd, 0x0, 0x0, 0x0, 0x1b, 0xff, 0xd0, + 0x1f, 0xfd, 0x0, 0x0, 0x0, 0x0, 0xef, 0xf3, + 0x1f, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x8f, 0xf7, + 0x1f, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x6f, 0xf9, + 0x1f, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xf8, + 0x1f, 0xfd, 0x0, 0x0, 0x0, 0x0, 0xaf, 0xf6, + 0x1f, 0xfd, 0x0, 0x0, 0x0, 0x4, 0xff, 0xf2, + 0x1f, 0xfd, 0x0, 0x0, 0x1, 0x7f, 0xff, 0xa0, + 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0x0, + 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0x90, 0x0, + 0x1f, 0xfe, 0x99, 0x99, 0x98, 0x61, 0x0, 0x0, + 0x1f, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x1f, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x1f, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x1f, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x1f, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x1f, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x1f, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x1f, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x1f, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + + /* U+0051 "Q" */ + 0x0, 0x0, 0x7b, 0xef, 0xec, 0x81, 0x0, 0x0, + 0x3, 0xef, 0xff, 0xff, 0xff, 0xf5, 0x0, 0x2, + 0xff, 0xff, 0xb9, 0xae, 0xff, 0xf5, 0x0, 0xcf, + 0xfb, 0x10, 0x0, 0x9, 0xff, 0xe0, 0x2f, 0xfe, + 0x0, 0x0, 0x0, 0xc, 0xff, 0x55, 0xff, 0x90, + 0x0, 0x0, 0x0, 0x6f, 0xf8, 0x6f, 0xf7, 0x0, + 0x0, 0x0, 0x4, 0xff, 0xa7, 0xff, 0x70, 0x0, + 0x0, 0x0, 0x3f, 0xfa, 0x7f, 0xf7, 0x0, 0x0, + 0x0, 0x3, 0xff, 0xa7, 0xff, 0x70, 0x0, 0x0, + 0x0, 0x3f, 0xfa, 0x7f, 0xf7, 0x0, 0x0, 0x0, + 0x3, 0xff, 0xa7, 0xff, 0x70, 0x0, 0x0, 0x0, + 0x3f, 0xfa, 0x7f, 0xf7, 0x0, 0x0, 0x0, 0x3, + 0xff, 0xa7, 0xff, 0x70, 0x0, 0x0, 0x0, 0x3f, + 0xfa, 0x7f, 0xf7, 0x0, 0x0, 0x0, 0x3, 0xff, + 0xa7, 0xff, 0x70, 0x0, 0x0, 0x0, 0x3f, 0xfa, + 0x6f, 0xf7, 0x0, 0x0, 0x0, 0x4, 0xff, 0x95, + 0xff, 0x90, 0x0, 0x0, 0x0, 0x6f, 0xf8, 0x2f, + 0xfe, 0x10, 0x0, 0x0, 0xc, 0xff, 0x40, 0xcf, + 0xfc, 0x10, 0x0, 0x9, 0xff, 0xe0, 0x2, 0xff, + 0xff, 0xb9, 0xae, 0xff, 0xf4, 0x0, 0x3, 0xef, + 0xff, 0xff, 0xff, 0xe5, 0x0, 0x0, 0x0, 0x7c, + 0xef, 0xff, 0xf4, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x8, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xe, 0xff, 0x50, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x6f, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xdf, 0xf7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5, + 0xff, 0xe1, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc, + 0xff, 0x80, + + /* U+0052 "R" */ + 0xf, 0xff, 0xff, 0xff, 0xfd, 0xa4, 0x0, 0x0, + 0xf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb1, 0x0, + 0xf, 0xfe, 0x99, 0x99, 0xac, 0xff, 0xfb, 0x0, + 0xf, 0xfd, 0x0, 0x0, 0x0, 0x4f, 0xff, 0x60, + 0xf, 0xfd, 0x0, 0x0, 0x0, 0x5, 0xff, 0xd0, + 0xf, 0xfd, 0x0, 0x0, 0x0, 0x0, 0xff, 0xf0, + 0xf, 0xfd, 0x0, 0x0, 0x0, 0x0, 0xef, 0xf1, + 0xf, 0xfd, 0x0, 0x0, 0x0, 0x0, 0xff, 0xf0, + 0xf, 0xfd, 0x0, 0x0, 0x0, 0x5, 0xff, 0xd0, + 0xf, 0xfd, 0x0, 0x0, 0x0, 0x4e, 0xff, 0x70, + 0xf, 0xfe, 0x99, 0x99, 0x9c, 0xff, 0xfc, 0x0, + 0xf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x0, + 0xf, 0xff, 0xff, 0xff, 0xff, 0xe5, 0x0, 0x0, + 0xf, 0xfd, 0x0, 0x1, 0xff, 0xf1, 0x0, 0x0, + 0xf, 0xfd, 0x0, 0x0, 0x9f, 0xf7, 0x0, 0x0, + 0xf, 0xfd, 0x0, 0x0, 0x2f, 0xfe, 0x0, 0x0, + 0xf, 0xfd, 0x0, 0x0, 0xb, 0xff, 0x60, 0x0, + 0xf, 0xfd, 0x0, 0x0, 0x3, 0xff, 0xd0, 0x0, + 0xf, 0xfd, 0x0, 0x0, 0x0, 0xcf, 0xf5, 0x0, + 0xf, 0xfd, 0x0, 0x0, 0x0, 0x5f, 0xfc, 0x0, + 0xf, 0xfd, 0x0, 0x0, 0x0, 0xd, 0xff, 0x40, + 0xf, 0xfd, 0x0, 0x0, 0x0, 0x6, 0xff, 0xb0, + 0xf, 0xfd, 0x0, 0x0, 0x0, 0x0, 0xef, 0xf3, + + /* U+0053 "S" */ + 0x0, 0x0, 0x6b, 0xef, 0xeb, 0x60, 0x0, 0x0, + 0x2, 0xdf, 0xff, 0xff, 0xff, 0xd3, 0x0, 0x1, + 0xef, 0xff, 0xb9, 0xbf, 0xff, 0xe2, 0x0, 0x9f, + 0xfc, 0x10, 0x0, 0x1b, 0xff, 0xa0, 0xe, 0xff, + 0x10, 0x0, 0x0, 0xe, 0xff, 0x1, 0xff, 0xc0, + 0x0, 0x0, 0x0, 0xaf, 0xf2, 0x1f, 0xfc, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xef, 0xf1, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x8, 0xff, 0xc1, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x1d, 0xff, 0xfa, 0x51, + 0x0, 0x0, 0x0, 0x0, 0x1c, 0xff, 0xff, 0xfd, + 0x82, 0x0, 0x0, 0x0, 0x5, 0xcf, 0xff, 0xff, + 0xf7, 0x0, 0x0, 0x0, 0x0, 0x15, 0x9e, 0xff, + 0xf7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6, 0xff, + 0xf2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, + 0x90, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xfc, + 0x58, 0x81, 0x0, 0x0, 0x0, 0x0, 0xff, 0xd9, + 0xff, 0x50, 0x0, 0x0, 0x0, 0x1f, 0xfc, 0x6f, + 0xfb, 0x0, 0x0, 0x0, 0x7, 0xff, 0x91, 0xff, + 0xf9, 0x0, 0x0, 0x6, 0xff, 0xf3, 0x6, 0xff, + 0xff, 0xb9, 0xad, 0xff, 0xf9, 0x0, 0x6, 0xff, + 0xff, 0xff, 0xff, 0xf9, 0x0, 0x0, 0x1, 0x7c, + 0xef, 0xfd, 0x93, 0x0, 0x0, + + /* U+0054 "T" */ + 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf7, 0x2a, 0xaa, 0xaa, 0xaf, 0xff, 0xaa, 0xaa, + 0xaa, 0x40, 0x0, 0x0, 0x0, 0xdf, 0xf0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xd, 0xff, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xdf, 0xf0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xd, 0xff, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xdf, + 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xd, + 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xdf, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xd, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xdf, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xd, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xdf, 0xf0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xd, 0xff, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xdf, 0xf0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xd, 0xff, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xdf, 0xf0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xd, 0xff, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xdf, 0xf0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xd, 0xff, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xdf, 0xf0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xd, 0xff, + 0x0, 0x0, 0x0, 0x0, + + /* U+0055 "U" */ + 0x2f, 0xfc, 0x0, 0x0, 0x0, 0x9, 0xff, 0x52, + 0xff, 0xc0, 0x0, 0x0, 0x0, 0x9f, 0xf5, 0x2f, + 0xfc, 0x0, 0x0, 0x0, 0x9, 0xff, 0x52, 0xff, + 0xc0, 0x0, 0x0, 0x0, 0x9f, 0xf5, 0x2f, 0xfc, + 0x0, 0x0, 0x0, 0x9, 0xff, 0x52, 0xff, 0xc0, + 0x0, 0x0, 0x0, 0x9f, 0xf5, 0x2f, 0xfc, 0x0, + 0x0, 0x0, 0x9, 0xff, 0x52, 0xff, 0xc0, 0x0, + 0x0, 0x0, 0x9f, 0xf5, 0x2f, 0xfc, 0x0, 0x0, + 0x0, 0x9, 0xff, 0x52, 0xff, 0xc0, 0x0, 0x0, + 0x0, 0x9f, 0xf5, 0x2f, 0xfc, 0x0, 0x0, 0x0, + 0x9, 0xff, 0x52, 0xff, 0xc0, 0x0, 0x0, 0x0, + 0x9f, 0xf5, 0x2f, 0xfc, 0x0, 0x0, 0x0, 0x9, + 0xff, 0x52, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x9f, + 0xf5, 0x2f, 0xfc, 0x0, 0x0, 0x0, 0x9, 0xff, + 0x52, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x9f, 0xf5, + 0x1f, 0xfc, 0x0, 0x0, 0x0, 0x9, 0xff, 0x40, + 0xff, 0xe0, 0x0, 0x0, 0x0, 0xbf, 0xf3, 0xd, + 0xff, 0x30, 0x0, 0x0, 0x1f, 0xff, 0x10, 0x8f, + 0xfd, 0x10, 0x0, 0xb, 0xff, 0xb0, 0x1, 0xef, + 0xff, 0xb9, 0xae, 0xff, 0xf3, 0x0, 0x2, 0xef, + 0xff, 0xff, 0xff, 0xf5, 0x0, 0x0, 0x0, 0x7c, + 0xef, 0xfc, 0x81, 0x0, 0x0, + + /* U+0056 "V" */ + 0x4f, 0xfa, 0x0, 0x0, 0x0, 0x0, 0x8, 0xff, + 0x70, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, 0xbf, + 0xf3, 0xc, 0xff, 0x20, 0x0, 0x0, 0x0, 0xf, + 0xfe, 0x0, 0x7f, 0xf7, 0x0, 0x0, 0x0, 0x3, + 0xff, 0xa0, 0x3, 0xff, 0xb0, 0x0, 0x0, 0x0, + 0x7f, 0xf6, 0x0, 0xf, 0xff, 0x0, 0x0, 0x0, + 0xb, 0xff, 0x20, 0x0, 0xbf, 0xf3, 0x0, 0x0, + 0x0, 0xff, 0xe0, 0x0, 0x7, 0xff, 0x70, 0x0, + 0x0, 0x3f, 0xf9, 0x0, 0x0, 0x2f, 0xfb, 0x0, + 0x0, 0x7, 0xff, 0x50, 0x0, 0x0, 0xef, 0xf0, + 0x0, 0x0, 0xbf, 0xf1, 0x0, 0x0, 0xa, 0xff, + 0x30, 0x0, 0xf, 0xfd, 0x0, 0x0, 0x0, 0x6f, + 0xf7, 0x0, 0x3, 0xff, 0x90, 0x0, 0x0, 0x2, + 0xff, 0xb0, 0x0, 0x7f, 0xf4, 0x0, 0x0, 0x0, + 0xe, 0xff, 0x0, 0xb, 0xff, 0x0, 0x0, 0x0, + 0x0, 0x9f, 0xf3, 0x0, 0xef, 0xc0, 0x0, 0x0, + 0x0, 0x5, 0xff, 0x80, 0x2f, 0xf8, 0x0, 0x0, + 0x0, 0x0, 0x1f, 0xfb, 0x6, 0xff, 0x40, 0x0, + 0x0, 0x0, 0x0, 0xdf, 0xf0, 0xaf, 0xf0, 0x0, + 0x0, 0x0, 0x0, 0x9, 0xff, 0x2e, 0xfb, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x4f, 0xf7, 0xff, 0x70, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xef, 0xf3, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xc, 0xff, 0xfe, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8f, 0xff, + 0xa0, 0x0, 0x0, 0x0, + + /* U+0057 "W" */ + 0x4f, 0xf5, 0x0, 0x0, 0xff, 0xf4, 0x0, 0x0, + 0xff, 0x72, 0xff, 0x70, 0x0, 0x1f, 0xff, 0x60, + 0x0, 0x2f, 0xf6, 0xf, 0xf9, 0x0, 0x3, 0xfe, + 0xf8, 0x0, 0x3, 0xff, 0x40, 0xff, 0xa0, 0x0, + 0x5f, 0xbf, 0xa0, 0x0, 0x5f, 0xf2, 0xd, 0xfc, + 0x0, 0x7, 0xf8, 0xfc, 0x0, 0x7, 0xff, 0x0, + 0xbf, 0xe0, 0x0, 0x9f, 0x5f, 0xe0, 0x0, 0x9f, + 0xe0, 0x9, 0xff, 0x0, 0xc, 0xf3, 0xef, 0x0, + 0xb, 0xfc, 0x0, 0x7f, 0xf1, 0x0, 0xef, 0x1c, + 0xf2, 0x0, 0xcf, 0xa0, 0x5, 0xff, 0x30, 0xf, + 0xf0, 0xaf, 0x40, 0xe, 0xf8, 0x0, 0x3f, 0xf5, + 0x2, 0xfc, 0x8, 0xf6, 0x0, 0xff, 0x60, 0x1, + 0xff, 0x60, 0x4f, 0xa0, 0x6f, 0x80, 0x2f, 0xf4, + 0x0, 0xf, 0xf8, 0x6, 0xf8, 0x4, 0xfa, 0x3, + 0xff, 0x20, 0x0, 0xdf, 0xa0, 0x9f, 0x60, 0x2f, + 0xc0, 0x5f, 0xf0, 0x0, 0xb, 0xfb, 0xb, 0xf4, + 0x1, 0xfe, 0x7, 0xfe, 0x0, 0x0, 0x9f, 0xd0, + 0xdf, 0x20, 0xf, 0xf0, 0x9f, 0xc0, 0x0, 0x7, + 0xff, 0xf, 0xf0, 0x0, 0xdf, 0x2b, 0xfa, 0x0, + 0x0, 0x5f, 0xf2, 0xfe, 0x0, 0xb, 0xf4, 0xcf, + 0x80, 0x0, 0x3, 0xff, 0x6f, 0xc0, 0x0, 0x9f, + 0x6e, 0xf6, 0x0, 0x0, 0x1f, 0xf9, 0xfa, 0x0, + 0x7, 0xf8, 0xff, 0x40, 0x0, 0x0, 0xff, 0xcf, + 0x80, 0x0, 0x5f, 0xbf, 0xf2, 0x0, 0x0, 0xe, + 0xfe, 0xf5, 0x0, 0x3, 0xfe, 0xff, 0x0, 0x0, + 0x0, 0xcf, 0xff, 0x30, 0x0, 0x1f, 0xff, 0xe0, + 0x0, 0x0, 0xa, 0xff, 0xf1, 0x0, 0x0, 0xff, + 0xfc, 0x0, 0x0, + + /* U+0058 "X" */ + 0x2f, 0xff, 0x30, 0x0, 0x0, 0x0, 0xd, 0xff, + 0x40, 0x8f, 0xfc, 0x0, 0x0, 0x0, 0x6, 0xff, + 0xb0, 0x0, 0xef, 0xf4, 0x0, 0x0, 0x0, 0xef, + 0xf2, 0x0, 0x6, 0xff, 0xc0, 0x0, 0x0, 0x7f, + 0xf9, 0x0, 0x0, 0xd, 0xff, 0x50, 0x0, 0x1f, + 0xfe, 0x10, 0x0, 0x0, 0x4f, 0xfd, 0x0, 0x9, + 0xff, 0x60, 0x0, 0x0, 0x0, 0xbf, 0xf6, 0x2, + 0xff, 0xd0, 0x0, 0x0, 0x0, 0x2, 0xff, 0xe0, + 0xaf, 0xf4, 0x0, 0x0, 0x0, 0x0, 0x9, 0xff, + 0x9f, 0xfb, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, + 0xff, 0xff, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x7f, 0xff, 0x90, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x2, 0xff, 0xf6, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xaf, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x3f, 0xfe, 0xff, 0x80, 0x0, 0x0, 0x0, + 0x0, 0xc, 0xff, 0x2e, 0xff, 0x20, 0x0, 0x0, + 0x0, 0x6, 0xff, 0x90, 0x7f, 0xfa, 0x0, 0x0, + 0x0, 0x0, 0xef, 0xf1, 0x0, 0xef, 0xf3, 0x0, + 0x0, 0x0, 0x8f, 0xf8, 0x0, 0x6, 0xff, 0xc0, + 0x0, 0x0, 0x2f, 0xfe, 0x0, 0x0, 0xd, 0xff, + 0x50, 0x0, 0xb, 0xff, 0x60, 0x0, 0x0, 0x4f, + 0xfe, 0x0, 0x4, 0xff, 0xd0, 0x0, 0x0, 0x0, + 0xbf, 0xf8, 0x0, 0xdf, 0xf4, 0x0, 0x0, 0x0, + 0x3, 0xff, 0xf1, 0x6f, 0xfc, 0x0, 0x0, 0x0, + 0x0, 0xa, 0xff, 0xa0, + + /* U+0059 "Y" */ + 0xaf, 0xf6, 0x0, 0x0, 0x0, 0x0, 0x2, 0xff, + 0xd0, 0x2f, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x9, + 0xff, 0x50, 0xa, 0xff, 0x60, 0x0, 0x0, 0x0, + 0x1f, 0xfd, 0x0, 0x2, 0xff, 0xd0, 0x0, 0x0, + 0x0, 0x9f, 0xf5, 0x0, 0x0, 0xaf, 0xf5, 0x0, + 0x0, 0x1, 0xff, 0xd0, 0x0, 0x0, 0x3f, 0xfd, + 0x0, 0x0, 0x8, 0xff, 0x60, 0x0, 0x0, 0xb, + 0xff, 0x40, 0x0, 0x1f, 0xfe, 0x0, 0x0, 0x0, + 0x3, 0xff, 0xc0, 0x0, 0x7f, 0xf6, 0x0, 0x0, + 0x0, 0x0, 0xbf, 0xf4, 0x0, 0xef, 0xe0, 0x0, + 0x0, 0x0, 0x0, 0x3f, 0xfb, 0x7, 0xff, 0x70, + 0x0, 0x0, 0x0, 0x0, 0xc, 0xff, 0x3e, 0xfe, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0xff, 0xef, + 0xf7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xcf, + 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x4f, 0xff, 0x70, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xe, 0xff, 0x10, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xd, 0xff, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xd, 0xff, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xd, 0xff, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xd, 0xff, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xd, 0xff, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xd, + 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xd, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xd, 0xff, 0x0, 0x0, 0x0, 0x0, + + /* U+005A "Z" */ + 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x22, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf2, 0x1a, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaf, 0xff, 0x20, 0x0, + 0x0, 0x0, 0x0, 0x4, 0xff, 0xc0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xdf, 0xf3, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x7f, 0xf9, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x1f, 0xfe, 0x10, 0x0, 0x0, 0x0, 0x0, + 0xa, 0xff, 0x60, 0x0, 0x0, 0x0, 0x0, 0x4, + 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xdf, + 0xf2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xf9, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xfe, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xb, 0xff, 0x50, 0x0, + 0x0, 0x0, 0x0, 0x4, 0xff, 0xc0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xdf, 0xf2, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x8f, 0xf8, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x2f, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xb, 0xff, 0x50, 0x0, 0x0, 0x0, 0x0, 0x5, + 0xff, 0xb0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xef, + 0xf2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4f, 0xfe, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x44, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xf7, 0x4f, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x70, + + /* U+005B "[" */ + 0x7f, 0xff, 0xff, 0xff, 0x67, 0xff, 0xff, 0xff, + 0xf6, 0x7f, 0xfc, 0x99, 0x99, 0x37, 0xff, 0x70, + 0x0, 0x0, 0x7f, 0xf7, 0x0, 0x0, 0x7, 0xff, + 0x70, 0x0, 0x0, 0x7f, 0xf7, 0x0, 0x0, 0x7, + 0xff, 0x70, 0x0, 0x0, 0x7f, 0xf7, 0x0, 0x0, + 0x7, 0xff, 0x70, 0x0, 0x0, 0x7f, 0xf7, 0x0, + 0x0, 0x7, 0xff, 0x70, 0x0, 0x0, 0x7f, 0xf7, + 0x0, 0x0, 0x7, 0xff, 0x70, 0x0, 0x0, 0x7f, + 0xf7, 0x0, 0x0, 0x7, 0xff, 0x70, 0x0, 0x0, + 0x7f, 0xf7, 0x0, 0x0, 0x7, 0xff, 0x70, 0x0, + 0x0, 0x7f, 0xf7, 0x0, 0x0, 0x7, 0xff, 0x70, + 0x0, 0x0, 0x7f, 0xf7, 0x0, 0x0, 0x7, 0xff, + 0x70, 0x0, 0x0, 0x7f, 0xf7, 0x0, 0x0, 0x7, + 0xff, 0x70, 0x0, 0x0, 0x7f, 0xf7, 0x0, 0x0, + 0x7, 0xff, 0x70, 0x0, 0x0, 0x7f, 0xf7, 0x0, + 0x0, 0x7, 0xff, 0xc9, 0x99, 0x93, 0x7f, 0xff, + 0xff, 0xff, 0x67, 0xff, 0xff, 0xff, 0xf6, + + /* U+005C "\\" */ + 0x6f, 0xf9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa, + 0xff, 0x60, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4f, + 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xef, + 0xf2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0xff, + 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xfe, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xcf, 0xf4, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x6, 0xff, 0xa0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, 0x10, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x9f, 0xf6, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, 0xc0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xd, 0xff, 0x20, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x7f, 0xf8, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x1, 0xff, 0xe0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xb, 0xff, 0x40, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x5f, 0xfa, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xef, 0xf1, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x9, 0xff, 0x70, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x3f, 0xfd, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xdf, 0xf3, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x7, 0xff, 0x90, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x1f, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xbf, 0xf5, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x5, 0xff, 0xb0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xe, 0xff, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x8f, 0xf7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, + 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc, + 0xff, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6f, + 0xf9, + + /* U+005D "]" */ + 0x3f, 0xff, 0xff, 0xff, 0xa3, 0xff, 0xff, 0xff, + 0xfa, 0x19, 0x99, 0x9a, 0xff, 0xa0, 0x0, 0x0, + 0x3f, 0xfa, 0x0, 0x0, 0x3, 0xff, 0xa0, 0x0, + 0x0, 0x3f, 0xfa, 0x0, 0x0, 0x3, 0xff, 0xa0, + 0x0, 0x0, 0x3f, 0xfa, 0x0, 0x0, 0x3, 0xff, + 0xa0, 0x0, 0x0, 0x3f, 0xfa, 0x0, 0x0, 0x3, + 0xff, 0xa0, 0x0, 0x0, 0x3f, 0xfa, 0x0, 0x0, + 0x3, 0xff, 0xa0, 0x0, 0x0, 0x3f, 0xfa, 0x0, + 0x0, 0x3, 0xff, 0xa0, 0x0, 0x0, 0x3f, 0xfa, + 0x0, 0x0, 0x3, 0xff, 0xa0, 0x0, 0x0, 0x3f, + 0xfa, 0x0, 0x0, 0x3, 0xff, 0xa0, 0x0, 0x0, + 0x3f, 0xfa, 0x0, 0x0, 0x3, 0xff, 0xa0, 0x0, + 0x0, 0x3f, 0xfa, 0x0, 0x0, 0x3, 0xff, 0xa0, + 0x0, 0x0, 0x3f, 0xfa, 0x0, 0x0, 0x3, 0xff, + 0xa0, 0x0, 0x0, 0x3f, 0xfa, 0x0, 0x0, 0x3, + 0xff, 0xa1, 0x99, 0x99, 0xaf, 0xfa, 0x3f, 0xff, + 0xff, 0xff, 0xa3, 0xff, 0xff, 0xff, 0xfa, + + /* U+005E "^" */ + 0x0, 0x0, 0x0, 0x68, 0x70, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x2f, 0xff, 0x60, 0x0, 0x0, 0x0, + 0x0, 0xa, 0xfe, 0xfd, 0x0, 0x0, 0x0, 0x0, + 0x1, 0xff, 0x6f, 0xf5, 0x0, 0x0, 0x0, 0x0, + 0x8f, 0xe0, 0x9f, 0xc0, 0x0, 0x0, 0x0, 0xf, + 0xf7, 0x3, 0xff, 0x30, 0x0, 0x0, 0x7, 0xff, + 0x10, 0xc, 0xfb, 0x0, 0x0, 0x0, 0xef, 0x90, + 0x0, 0x5f, 0xf2, 0x0, 0x0, 0x6f, 0xf2, 0x0, + 0x0, 0xef, 0x90, 0x0, 0xd, 0xfb, 0x0, 0x0, + 0x7, 0xff, 0x10, 0x4, 0xff, 0x40, 0x0, 0x0, + 0x1f, 0xf8, 0x0, 0xcf, 0xd0, 0x0, 0x0, 0x0, + 0x9f, 0xe0, 0x3f, 0xf6, 0x0, 0x0, 0x0, 0x2, + 0xff, 0x60, + + /* U+005F "_" */ + 0x6, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x11, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf4, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x40, + + /* U+0060 "`" */ + 0x48, 0x84, 0x0, 0x1, 0xef, 0xf3, 0x0, 0x3, + 0xff, 0xe1, 0x0, 0x5, 0xff, 0xb0, 0x0, 0x8, + 0xff, 0x80, + + /* U+0061 "a" */ + 0x0, 0x1, 0x7c, 0xef, 0xfd, 0x92, 0x0, 0x0, + 0x5, 0xff, 0xff, 0xff, 0xff, 0xf6, 0x0, 0x3, + 0xff, 0xfe, 0xa8, 0xad, 0xff, 0xf4, 0x0, 0xbf, + 0xf7, 0x0, 0x0, 0x7, 0xff, 0xd0, 0xa, 0xaa, + 0x0, 0x0, 0x0, 0xd, 0xff, 0x10, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xaf, 0xf3, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xa, 0xff, 0x40, 0x1, 0x8d, 0xff, + 0xff, 0xff, 0xff, 0xf4, 0x3, 0xef, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x41, 0xef, 0xfc, 0x64, 0x44, + 0x44, 0xbf, 0xf4, 0x7f, 0xfb, 0x0, 0x0, 0x0, + 0xa, 0xff, 0x4b, 0xff, 0x30, 0x0, 0x0, 0x0, + 0xaf, 0xf4, 0xdf, 0xf2, 0x0, 0x0, 0x0, 0xb, + 0xff, 0x4c, 0xff, 0x50, 0x0, 0x0, 0x1, 0xff, + 0xf4, 0x8f, 0xfd, 0x10, 0x0, 0x1, 0xce, 0xff, + 0x41, 0xef, 0xff, 0xa7, 0x8a, 0xff, 0xaf, 0xf4, + 0x3, 0xef, 0xff, 0xff, 0xff, 0x59, 0xff, 0x40, + 0x1, 0x8d, 0xff, 0xd9, 0x20, 0x9f, 0xf4, + + /* U+0062 "b" */ + 0x1f, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, + 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, + 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xff, + 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xfd, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xff, 0xd0, + 0x19, 0xdf, 0xeb, 0x40, 0x0, 0x1f, 0xfc, 0x3f, + 0xff, 0xff, 0xff, 0x90, 0x1, 0xff, 0xcd, 0xfa, + 0x8a, 0xdf, 0xff, 0x60, 0x1f, 0xfe, 0xe2, 0x0, + 0x0, 0x8f, 0xfe, 0x1, 0xff, 0xf4, 0x0, 0x0, + 0x0, 0xdf, 0xf3, 0x1f, 0xff, 0x0, 0x0, 0x0, + 0x8, 0xff, 0x51, 0xff, 0xd0, 0x0, 0x0, 0x0, + 0x7f, 0xf6, 0x1f, 0xfd, 0x0, 0x0, 0x0, 0x7, + 0xff, 0x61, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x7f, + 0xf6, 0x1f, 0xfd, 0x0, 0x0, 0x0, 0x7, 0xff, + 0x61, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x7f, 0xf6, + 0x1f, 0xfd, 0x0, 0x0, 0x0, 0x7, 0xff, 0x61, + 0xff, 0xf0, 0x0, 0x0, 0x0, 0x8f, 0xf5, 0x1f, + 0xff, 0x40, 0x0, 0x0, 0xd, 0xff, 0x31, 0xff, + 0xee, 0x20, 0x0, 0x8, 0xff, 0xe0, 0x1f, 0xfd, + 0xcf, 0xa8, 0xad, 0xff, 0xf6, 0x1, 0xff, 0xd3, + 0xff, 0xff, 0xff, 0xf9, 0x0, 0x1f, 0xfd, 0x1, + 0x9d, 0xfe, 0xb4, 0x0, 0x0, + + /* U+0063 "c" */ + 0x0, 0x0, 0x5a, 0xef, 0xfd, 0x93, 0x0, 0x0, + 0x1, 0xcf, 0xff, 0xff, 0xff, 0xf8, 0x0, 0x0, + 0xdf, 0xff, 0xc9, 0xad, 0xff, 0xf8, 0x0, 0x8f, + 0xfd, 0x20, 0x0, 0x6, 0xff, 0xf2, 0xe, 0xff, + 0x30, 0x0, 0x0, 0x9, 0xff, 0x71, 0xff, 0xd0, + 0x0, 0x0, 0x0, 0x4f, 0xfa, 0x2f, 0xfb, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, 0xb0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x3f, 0xfb, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x3, 0xff, 0xb0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x3f, 0xfb, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x2, 0xff, 0xb0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x1f, 0xfd, 0x0, 0x0, 0x0, 0x4, + 0xff, 0xa0, 0xef, 0xf3, 0x0, 0x0, 0x0, 0x9f, + 0xf8, 0x8, 0xff, 0xd2, 0x0, 0x0, 0x6f, 0xff, + 0x20, 0xd, 0xff, 0xfc, 0x9a, 0xdf, 0xff, 0x80, + 0x0, 0x1c, 0xff, 0xff, 0xff, 0xff, 0x90, 0x0, + 0x0, 0x5, 0xbe, 0xff, 0xd9, 0x30, 0x0, + + /* U+0064 "d" */ + 0x0, 0x0, 0x0, 0x0, 0x0, 0xa, 0xff, 0x40, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xaf, 0xf4, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xa, 0xff, 0x40, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xaf, 0xf4, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xa, 0xff, 0x40, 0x0, 0x3a, + 0xef, 0xda, 0x30, 0x9f, 0xf4, 0x0, 0x6f, 0xff, + 0xff, 0xff, 0x59, 0xff, 0x40, 0x3f, 0xff, 0xea, + 0x8a, 0xef, 0xaf, 0xf4, 0xb, 0xff, 0xa0, 0x0, + 0x1, 0xce, 0xff, 0x40, 0xff, 0xf0, 0x0, 0x0, + 0x1, 0xff, 0xf4, 0x2f, 0xfb, 0x0, 0x0, 0x0, + 0xc, 0xff, 0x43, 0xff, 0xa0, 0x0, 0x0, 0x0, + 0xaf, 0xf4, 0x3f, 0xfa, 0x0, 0x0, 0x0, 0xa, + 0xff, 0x43, 0xff, 0xa0, 0x0, 0x0, 0x0, 0xaf, + 0xf4, 0x3f, 0xfa, 0x0, 0x0, 0x0, 0xa, 0xff, + 0x43, 0xff, 0xa0, 0x0, 0x0, 0x0, 0xaf, 0xf4, + 0x3f, 0xfa, 0x0, 0x0, 0x0, 0xa, 0xff, 0x42, + 0xff, 0xb0, 0x0, 0x0, 0x0, 0xcf, 0xf4, 0xf, + 0xff, 0x0, 0x0, 0x0, 0x1f, 0xff, 0x40, 0xbf, + 0xfa, 0x10, 0x0, 0x1c, 0xef, 0xf4, 0x3, 0xff, + 0xfe, 0xa8, 0xae, 0xfa, 0xff, 0x40, 0x6, 0xff, + 0xff, 0xff, 0xf5, 0xaf, 0xf4, 0x0, 0x3, 0xae, + 0xfe, 0xa3, 0xa, 0xff, 0x40, + + /* U+0065 "e" */ + 0x0, 0x0, 0x6b, 0xef, 0xec, 0x71, 0x0, 0x0, + 0x2, 0xdf, 0xff, 0xff, 0xff, 0xe5, 0x0, 0x1, + 0xdf, 0xfd, 0x86, 0x8b, 0xff, 0xf4, 0x0, 0x8f, + 0xf8, 0x0, 0x0, 0x5, 0xff, 0xd0, 0xf, 0xfd, + 0x0, 0x0, 0x0, 0xa, 0xff, 0x42, 0xff, 0x90, + 0x0, 0x0, 0x0, 0x5f, 0xf6, 0x4f, 0xf8, 0x0, + 0x0, 0x0, 0x4, 0xff, 0x85, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xf8, 0x5f, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x85, 0xff, 0xa4, 0x44, 0x44, + 0x44, 0x44, 0x42, 0x5f, 0xf8, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x4, 0xff, 0x80, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x2f, 0xfb, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xff, 0xf1, 0x0, 0x0, 0x0, 0xaf, + 0xf4, 0x9, 0xff, 0xc1, 0x0, 0x0, 0x6f, 0xfe, + 0x0, 0x1d, 0xff, 0xfa, 0x89, 0xdf, 0xff, 0x60, + 0x0, 0x2d, 0xff, 0xff, 0xff, 0xff, 0x60, 0x0, + 0x0, 0x6, 0xbe, 0xff, 0xc8, 0x20, 0x0, + + /* U+0066 "f" */ + 0x0, 0x0, 0x0, 0x1, 0x9d, 0xff, 0xff, 0xff, + 0x0, 0x0, 0x0, 0x2e, 0xff, 0xff, 0xff, 0xff, + 0x0, 0x0, 0x0, 0xbf, 0xfe, 0xaa, 0xaa, 0xa9, + 0x0, 0x0, 0x0, 0xff, 0xf1, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x1, 0xff, 0xc0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x2, 0xff, 0xc0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x2, 0xff, 0xc0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x2, 0xff, 0xc0, 0x0, 0x0, 0x0, + 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x2a, 0xaa, 0xaa, 0xff, 0xea, 0xaa, 0xaa, 0xa9, + 0x0, 0x0, 0x2, 0xff, 0xc0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x2, 0xff, 0xc0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x2, 0xff, 0xc0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x2, 0xff, 0xc0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x2, 0xff, 0xc0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x2, 0xff, 0xc0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x2, 0xff, 0xc0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x2, 0xff, 0xc0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x2, 0xff, 0xc0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x2, 0xff, 0xc0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x2, 0xff, 0xc0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x2, 0xff, 0xc0, 0x0, 0x0, 0x0, + + /* U+0067 "g" */ + 0x0, 0x2, 0x9e, 0xfe, 0xb3, 0xa, 0xff, 0x30, + 0x5, 0xff, 0xff, 0xff, 0xf5, 0xaf, 0xf3, 0x2, + 0xff, 0xfe, 0xa8, 0xaf, 0xfa, 0xff, 0x30, 0x9f, + 0xfc, 0x10, 0x0, 0x1c, 0xff, 0xf3, 0xe, 0xff, + 0x20, 0x0, 0x0, 0x2f, 0xff, 0x31, 0xff, 0xd0, + 0x0, 0x0, 0x0, 0xcf, 0xf3, 0x2f, 0xfb, 0x0, + 0x0, 0x0, 0xa, 0xff, 0x33, 0xff, 0xb0, 0x0, + 0x0, 0x0, 0xaf, 0xf3, 0x3f, 0xfb, 0x0, 0x0, + 0x0, 0xa, 0xff, 0x33, 0xff, 0xb0, 0x0, 0x0, + 0x0, 0xaf, 0xf3, 0x2f, 0xfb, 0x0, 0x0, 0x0, + 0xa, 0xff, 0x31, 0xff, 0xd0, 0x0, 0x0, 0x0, + 0xcf, 0xf3, 0xf, 0xff, 0x20, 0x0, 0x0, 0x1f, + 0xff, 0x30, 0xaf, 0xfb, 0x0, 0x0, 0xb, 0xff, + 0xf3, 0x2, 0xff, 0xfd, 0x86, 0x8d, 0xfa, 0xff, + 0x30, 0x5, 0xff, 0xff, 0xff, 0xf6, 0xaf, 0xf3, + 0x0, 0x2, 0xae, 0xfe, 0xb4, 0xa, 0xff, 0x30, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xaf, 0xf3, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xb, 0xff, 0x20, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xef, 0xf1, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x9f, 0xfc, 0x0, 0x0, 0x8a, + 0xaa, 0xaa, 0xef, 0xff, 0x40, 0x0, 0xd, 0xff, + 0xff, 0xff, 0xff, 0x60, 0x0, 0x0, 0xdf, 0xff, + 0xff, 0xd9, 0x20, 0x0, + + /* U+0068 "h" */ + 0x1f, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, + 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, + 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xff, + 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xfd, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xff, 0xd0, + 0x2a, 0xdf, 0xeb, 0x40, 0x0, 0x1f, 0xfd, 0x3f, + 0xff, 0xff, 0xff, 0x80, 0x1, 0xff, 0xdc, 0xf9, + 0x78, 0xdf, 0xff, 0x50, 0x1f, 0xfe, 0xd1, 0x0, + 0x0, 0xaf, 0xfd, 0x1, 0xff, 0xf4, 0x0, 0x0, + 0x0, 0xef, 0xf2, 0x1f, 0xff, 0x0, 0x0, 0x0, + 0xa, 0xff, 0x41, 0xff, 0xd0, 0x0, 0x0, 0x0, + 0x9f, 0xf4, 0x1f, 0xfd, 0x0, 0x0, 0x0, 0x9, + 0xff, 0x51, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x9f, + 0xf5, 0x1f, 0xfd, 0x0, 0x0, 0x0, 0x9, 0xff, + 0x51, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x9f, 0xf5, + 0x1f, 0xfd, 0x0, 0x0, 0x0, 0x9, 0xff, 0x51, + 0xff, 0xd0, 0x0, 0x0, 0x0, 0x9f, 0xf5, 0x1f, + 0xfd, 0x0, 0x0, 0x0, 0x9, 0xff, 0x51, 0xff, + 0xd0, 0x0, 0x0, 0x0, 0x9f, 0xf5, 0x1f, 0xfd, + 0x0, 0x0, 0x0, 0x9, 0xff, 0x51, 0xff, 0xd0, + 0x0, 0x0, 0x0, 0x9f, 0xf5, 0x1f, 0xfd, 0x0, + 0x0, 0x0, 0x9, 0xff, 0x50, + + /* U+0069 "i" */ + 0x0, 0x0, 0x0, 0x6e, 0xe8, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x1, 0xff, 0xff, 0x30, 0x0, 0x0, + 0x0, 0x0, 0x1, 0xff, 0xff, 0x40, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x8f, 0xfa, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xa, 0xff, 0xff, 0xff, 0xfd, 0x0, 0x0, 0x0, + 0xa, 0xff, 0xff, 0xff, 0xfd, 0x0, 0x0, 0x0, + 0x6, 0xaa, 0xaa, 0xaf, 0xfd, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xf, 0xfd, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xf, 0xfd, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xf, 0xfd, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xf, 0xfd, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xf, 0xfd, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xf, 0xfd, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xf, 0xfd, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xf, 0xfd, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xf, 0xfd, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xf, 0xfd, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xf, 0xfd, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xf, 0xfd, 0x0, 0x0, 0x0, + 0x2a, 0xaa, 0xaa, 0xaf, 0xff, 0xaa, 0xaa, 0xa7, + 0x4f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, + 0x4f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, + + /* U+006A "j" */ + 0x0, 0x0, 0x0, 0x0, 0x5e, 0xf9, 0x0, 0x0, + 0x0, 0x0, 0xf, 0xff, 0xf5, 0x0, 0x0, 0x0, + 0x0, 0xff, 0xff, 0x50, 0x0, 0x0, 0x0, 0x7, + 0xff, 0xb0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xe0, 0x4f, 0xff, 0xff, 0xff, + 0xff, 0xfe, 0x2, 0xaa, 0xaa, 0xaa, 0xaa, 0xff, + 0xe0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfe, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xff, 0xe0, 0x0, 0x0, + 0x0, 0x0, 0xf, 0xfe, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, 0xf, + 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xe0, + 0x0, 0x0, 0x0, 0x0, 0xf, 0xfe, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xff, 0xe0, 0x0, 0x0, 0x0, + 0x0, 0xf, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfe, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xe0, 0x0, + 0x0, 0x0, 0x0, 0xf, 0xfe, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, + 0xf, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x2, 0xff, + 0xc0, 0x0, 0x0, 0x0, 0x0, 0x8f, 0xf8, 0x0, + 0x0, 0x0, 0x0, 0x6f, 0xff, 0x20, 0x1a, 0xaa, + 0xaa, 0xef, 0xff, 0x80, 0x2, 0xff, 0xff, 0xff, + 0xff, 0x80, 0x0, 0x2f, 0xff, 0xff, 0xd9, 0x20, + 0x0, 0x0, + + /* U+006B "k" */ + 0xef, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe, + 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xef, + 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe, 0xff, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xef, 0xf0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xe, 0xff, 0x0, + 0x0, 0x0, 0x1, 0xff, 0xf3, 0xef, 0xf0, 0x0, + 0x0, 0x0, 0xbf, 0xf9, 0xe, 0xff, 0x0, 0x0, + 0x0, 0x6f, 0xfd, 0x0, 0xef, 0xf0, 0x0, 0x0, + 0x1e, 0xff, 0x40, 0xe, 0xff, 0x0, 0x0, 0xb, + 0xff, 0x90, 0x0, 0xef, 0xf0, 0x0, 0x5, 0xff, + 0xe0, 0x0, 0xe, 0xff, 0x0, 0x1, 0xef, 0xf4, + 0x0, 0x0, 0xef, 0xf8, 0x88, 0xbf, 0xfa, 0x0, + 0x0, 0xe, 0xff, 0xff, 0xff, 0xff, 0x10, 0x0, + 0x0, 0xef, 0xff, 0xff, 0xff, 0xf7, 0x0, 0x0, + 0xe, 0xff, 0x0, 0x4, 0xff, 0xf2, 0x0, 0x0, + 0xef, 0xf0, 0x0, 0xa, 0xff, 0xb0, 0x0, 0xe, + 0xff, 0x0, 0x0, 0x1e, 0xff, 0x60, 0x0, 0xef, + 0xf0, 0x0, 0x0, 0x5f, 0xfe, 0x10, 0xe, 0xff, + 0x0, 0x0, 0x0, 0xbf, 0xfa, 0x0, 0xef, 0xf0, + 0x0, 0x0, 0x1, 0xff, 0xf4, 0xe, 0xff, 0x0, + 0x0, 0x0, 0x6, 0xff, 0xe0, 0xef, 0xf0, 0x0, + 0x0, 0x0, 0xc, 0xff, 0x90, + + /* U+006C "l" */ + 0xf, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, + 0x0, 0xf, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, + 0x0, 0x0, 0xa, 0xaa, 0xaa, 0xaf, 0xfe, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfe, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, + 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xf, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xf, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xf, 0xfe, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xf, 0xfe, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xf, 0xfe, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfe, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfe, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, + 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xf, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xf, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xf, 0xfe, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xf, 0xfe, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xf, 0xfe, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xe, 0xff, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc, 0xff, + 0x60, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6, + 0xff, 0xfc, 0xaa, 0xaa, 0xa6, 0x0, 0x0, 0x0, + 0x0, 0xaf, 0xff, 0xff, 0xff, 0xf9, 0x0, 0x0, + 0x0, 0x0, 0x6, 0xcf, 0xff, 0xff, 0xf9, + + /* U+006D "m" */ + 0x1f, 0xf6, 0x4d, 0xfc, 0x30, 0x3c, 0xfd, 0x60, + 0x1, 0xff, 0x8f, 0xff, 0xfe, 0x2f, 0xff, 0xff, + 0x60, 0x1f, 0xfe, 0x94, 0x8f, 0xfe, 0xa4, 0x7f, + 0xfe, 0x1, 0xff, 0xc0, 0x0, 0xcf, 0xf0, 0x0, + 0x9f, 0xf2, 0x1f, 0xfa, 0x0, 0x9, 0xfc, 0x0, + 0x6, 0xff, 0x41, 0xff, 0x90, 0x0, 0x9f, 0xc0, + 0x0, 0x6f, 0xf4, 0x1f, 0xf9, 0x0, 0x9, 0xfc, + 0x0, 0x6, 0xff, 0x41, 0xff, 0x90, 0x0, 0x9f, + 0xc0, 0x0, 0x6f, 0xf4, 0x1f, 0xf9, 0x0, 0x9, + 0xfc, 0x0, 0x6, 0xff, 0x41, 0xff, 0x90, 0x0, + 0x9f, 0xc0, 0x0, 0x6f, 0xf4, 0x1f, 0xf9, 0x0, + 0x9, 0xfc, 0x0, 0x6, 0xff, 0x41, 0xff, 0x90, + 0x0, 0x9f, 0xc0, 0x0, 0x6f, 0xf4, 0x1f, 0xf9, + 0x0, 0x9, 0xfc, 0x0, 0x6, 0xff, 0x41, 0xff, + 0x90, 0x0, 0x9f, 0xc0, 0x0, 0x6f, 0xf4, 0x1f, + 0xf9, 0x0, 0x9, 0xfc, 0x0, 0x6, 0xff, 0x41, + 0xff, 0x90, 0x0, 0x9f, 0xc0, 0x0, 0x6f, 0xf4, + 0x1f, 0xf9, 0x0, 0x9, 0xfc, 0x0, 0x6, 0xff, + 0x41, 0xff, 0x90, 0x0, 0x9f, 0xc0, 0x0, 0x6f, + 0xf4, + + /* U+006E "n" */ + 0x1f, 0xfd, 0x2, 0xad, 0xfe, 0xb4, 0x0, 0x1, + 0xff, 0xd3, 0xff, 0xff, 0xff, 0xf8, 0x0, 0x1f, + 0xfd, 0xcf, 0x97, 0x8d, 0xff, 0xf5, 0x1, 0xff, + 0xed, 0x10, 0x0, 0xa, 0xff, 0xd0, 0x1f, 0xff, + 0x40, 0x0, 0x0, 0xe, 0xff, 0x21, 0xff, 0xf0, + 0x0, 0x0, 0x0, 0xaf, 0xf4, 0x1f, 0xfd, 0x0, + 0x0, 0x0, 0x9, 0xff, 0x41, 0xff, 0xd0, 0x0, + 0x0, 0x0, 0x9f, 0xf5, 0x1f, 0xfd, 0x0, 0x0, + 0x0, 0x9, 0xff, 0x51, 0xff, 0xd0, 0x0, 0x0, + 0x0, 0x9f, 0xf5, 0x1f, 0xfd, 0x0, 0x0, 0x0, + 0x9, 0xff, 0x51, 0xff, 0xd0, 0x0, 0x0, 0x0, + 0x9f, 0xf5, 0x1f, 0xfd, 0x0, 0x0, 0x0, 0x9, + 0xff, 0x51, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x9f, + 0xf5, 0x1f, 0xfd, 0x0, 0x0, 0x0, 0x9, 0xff, + 0x51, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x9f, 0xf5, + 0x1f, 0xfd, 0x0, 0x0, 0x0, 0x9, 0xff, 0x51, + 0xff, 0xd0, 0x0, 0x0, 0x0, 0x9f, 0xf5, + + /* U+006F "o" */ + 0x0, 0x0, 0x6b, 0xef, 0xec, 0x71, 0x0, 0x0, + 0x2, 0xdf, 0xff, 0xff, 0xff, 0xe4, 0x0, 0x1, + 0xef, 0xff, 0xb9, 0xae, 0xff, 0xf3, 0x0, 0x9f, + 0xfc, 0x10, 0x0, 0x9, 0xff, 0xc0, 0xf, 0xff, + 0x10, 0x0, 0x0, 0xd, 0xff, 0x23, 0xff, 0xb0, + 0x0, 0x0, 0x0, 0x8f, 0xf6, 0x4f, 0xf9, 0x0, + 0x0, 0x0, 0x6, 0xff, 0x75, 0xff, 0x90, 0x0, + 0x0, 0x0, 0x6f, 0xf8, 0x5f, 0xf9, 0x0, 0x0, + 0x0, 0x6, 0xff, 0x85, 0xff, 0x90, 0x0, 0x0, + 0x0, 0x6f, 0xf8, 0x5f, 0xf9, 0x0, 0x0, 0x0, + 0x6, 0xff, 0x84, 0xff, 0x90, 0x0, 0x0, 0x0, + 0x6f, 0xf7, 0x2f, 0xfb, 0x0, 0x0, 0x0, 0x8, + 0xff, 0x60, 0xff, 0xf1, 0x0, 0x0, 0x0, 0xdf, + 0xf2, 0x9, 0xff, 0xc1, 0x0, 0x0, 0x9f, 0xfc, + 0x0, 0x1e, 0xff, 0xfa, 0x9a, 0xef, 0xff, 0x30, + 0x0, 0x2d, 0xff, 0xff, 0xff, 0xfe, 0x40, 0x0, + 0x0, 0x6, 0xbe, 0xfe, 0xc7, 0x10, 0x0, + + /* U+0070 "p" */ + 0x1f, 0xfd, 0x1, 0x9d, 0xfe, 0xb4, 0x0, 0x1, + 0xff, 0xd3, 0xff, 0xff, 0xff, 0xf9, 0x0, 0x1f, + 0xfd, 0xcf, 0xa8, 0xad, 0xff, 0xf6, 0x1, 0xff, + 0xee, 0x20, 0x0, 0x8, 0xff, 0xe0, 0x1f, 0xff, + 0x40, 0x0, 0x0, 0xd, 0xff, 0x31, 0xff, 0xf0, + 0x0, 0x0, 0x0, 0x8f, 0xf5, 0x1f, 0xfd, 0x0, + 0x0, 0x0, 0x7, 0xff, 0x61, 0xff, 0xd0, 0x0, + 0x0, 0x0, 0x7f, 0xf6, 0x1f, 0xfd, 0x0, 0x0, + 0x0, 0x7, 0xff, 0x61, 0xff, 0xd0, 0x0, 0x0, + 0x0, 0x7f, 0xf6, 0x1f, 0xfd, 0x0, 0x0, 0x0, + 0x7, 0xff, 0x61, 0xff, 0xd0, 0x0, 0x0, 0x0, + 0x7f, 0xf6, 0x1f, 0xff, 0x0, 0x0, 0x0, 0x8, + 0xff, 0x51, 0xff, 0xf4, 0x0, 0x0, 0x0, 0xdf, + 0xf3, 0x1f, 0xfe, 0xe2, 0x0, 0x0, 0x8f, 0xfe, + 0x1, 0xff, 0xcc, 0xfa, 0x8a, 0xdf, 0xff, 0x60, + 0x1f, 0xfc, 0x3f, 0xff, 0xff, 0xff, 0x90, 0x1, + 0xff, 0xc0, 0x19, 0xdf, 0xeb, 0x40, 0x0, 0x1f, + 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xff, + 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xfd, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xff, 0xd0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xfd, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x1, 0xff, 0xd0, 0x0, + 0x0, 0x0, 0x0, 0x0, + + /* U+0071 "q" */ + 0x0, 0x3, 0xae, 0xfd, 0xa3, 0xa, 0xff, 0x40, + 0x6, 0xff, 0xff, 0xff, 0xf5, 0xaf, 0xf4, 0x3, + 0xff, 0xfe, 0xa8, 0xae, 0xfa, 0xff, 0x40, 0xbf, + 0xfa, 0x0, 0x0, 0x1c, 0xef, 0xf4, 0xf, 0xff, + 0x0, 0x0, 0x0, 0x1f, 0xff, 0x42, 0xff, 0xb0, + 0x0, 0x0, 0x0, 0xcf, 0xf4, 0x3f, 0xfa, 0x0, + 0x0, 0x0, 0xa, 0xff, 0x43, 0xff, 0xa0, 0x0, + 0x0, 0x0, 0xaf, 0xf4, 0x3f, 0xfa, 0x0, 0x0, + 0x0, 0xa, 0xff, 0x43, 0xff, 0xa0, 0x0, 0x0, + 0x0, 0xaf, 0xf4, 0x3f, 0xfa, 0x0, 0x0, 0x0, + 0xa, 0xff, 0x43, 0xff, 0xa0, 0x0, 0x0, 0x0, + 0xaf, 0xf4, 0x2f, 0xfb, 0x0, 0x0, 0x0, 0xc, + 0xff, 0x40, 0xff, 0xf0, 0x0, 0x0, 0x1, 0xff, + 0xf4, 0xb, 0xff, 0xa0, 0x0, 0x1, 0xce, 0xff, + 0x40, 0x3f, 0xff, 0xea, 0x8a, 0xef, 0xaf, 0xf4, + 0x0, 0x6f, 0xff, 0xff, 0xff, 0x59, 0xff, 0x40, + 0x0, 0x3a, 0xef, 0xea, 0x30, 0x9f, 0xf4, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x9, 0xff, 0x40, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xaf, 0xf4, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xa, 0xff, 0x40, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xaf, 0xf4, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xa, 0xff, 0x40, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xaf, 0xf4, + + /* U+0072 "r" */ + 0x6f, 0xf7, 0x4, 0xbe, 0xfe, 0x92, 0x0, 0x6f, + 0xf7, 0x7f, 0xff, 0xff, 0xff, 0x40, 0x6f, 0xf9, + 0xfe, 0x98, 0xaf, 0xff, 0xf1, 0x6f, 0xfe, 0x90, + 0x0, 0x1, 0xdf, 0xf8, 0x6f, 0xfe, 0x0, 0x0, + 0x0, 0x4f, 0xfc, 0x6f, 0xfa, 0x0, 0x0, 0x0, + 0xf, 0xfe, 0x6f, 0xf8, 0x0, 0x0, 0x0, 0xe, + 0xff, 0x6f, 0xf7, 0x0, 0x0, 0x0, 0xc, 0xed, + 0x6f, 0xf7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6f, + 0xf7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6f, 0xf7, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x6f, 0xf7, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x6f, 0xf7, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x6f, 0xf7, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x6f, 0xf7, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x6f, 0xf7, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x6f, 0xf7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6f, + 0xf7, 0x0, 0x0, 0x0, 0x0, 0x0, + + /* U+0073 "s" */ + 0x0, 0x4, 0xae, 0xff, 0xfe, 0xb4, 0x0, 0x0, + 0xa, 0xff, 0xff, 0xff, 0xff, 0xfa, 0x0, 0x7, + 0xff, 0xfb, 0x87, 0x7a, 0xff, 0xf8, 0x0, 0xdf, + 0xf4, 0x0, 0x0, 0x3, 0xff, 0xf0, 0xf, 0xfd, + 0x0, 0x0, 0x0, 0x6, 0x99, 0x10, 0xff, 0xd0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xd, 0xff, 0x60, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x6f, 0xff, 0xfd, + 0xb8, 0x63, 0x0, 0x0, 0x0, 0x9f, 0xff, 0xff, + 0xff, 0xfe, 0x70, 0x0, 0x0, 0x38, 0xbd, 0xff, + 0xff, 0xff, 0x80, 0x0, 0x0, 0x0, 0x0, 0x24, + 0xaf, 0xff, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xaf, 0xf5, 0x1, 0x10, 0x0, 0x0, 0x0, 0x6, + 0xff, 0x73, 0xff, 0xb0, 0x0, 0x0, 0x0, 0x7f, + 0xf6, 0x1f, 0xff, 0x30, 0x0, 0x0, 0x1e, 0xff, + 0x30, 0xaf, 0xff, 0xb8, 0x88, 0xaf, 0xff, 0xc0, + 0x0, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xd1, 0x0, + 0x0, 0x5b, 0xef, 0xff, 0xec, 0x60, 0x0, + + /* U+0074 "t" */ + 0x0, 0x0, 0x3, 0x88, 0x30, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x7, 0xff, 0x70, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x7, 0xff, 0x70, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x7, 0xff, 0x70, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x7, 0xff, 0x70, 0x0, 0x0, 0x0, + 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfa, + 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfa, + 0x5a, 0xaa, 0xac, 0xff, 0xca, 0xaa, 0xaa, 0xa6, + 0x0, 0x0, 0x7, 0xff, 0x70, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x7, 0xff, 0x70, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x7, 0xff, 0x70, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x7, 0xff, 0x70, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x7, 0xff, 0x70, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x7, 0xff, 0x70, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x7, 0xff, 0x70, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x7, 0xff, 0x70, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x7, 0xff, 0x70, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x7, 0xff, 0x70, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x6, 0xff, 0x70, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x4, 0xff, 0xc0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xef, 0xfd, 0xaa, 0xaa, 0xa4, + 0x0, 0x0, 0x0, 0x4f, 0xff, 0xff, 0xff, 0xf7, + 0x0, 0x0, 0x0, 0x3, 0xae, 0xff, 0xff, 0xf7, + + /* U+0075 "u" */ + 0x2f, 0xfc, 0x0, 0x0, 0x0, 0x9, 0xff, 0x52, + 0xff, 0xc0, 0x0, 0x0, 0x0, 0x9f, 0xf5, 0x2f, + 0xfc, 0x0, 0x0, 0x0, 0x9, 0xff, 0x52, 0xff, + 0xc0, 0x0, 0x0, 0x0, 0x9f, 0xf5, 0x2f, 0xfc, + 0x0, 0x0, 0x0, 0x9, 0xff, 0x52, 0xff, 0xc0, + 0x0, 0x0, 0x0, 0x9f, 0xf5, 0x2f, 0xfc, 0x0, + 0x0, 0x0, 0x9, 0xff, 0x52, 0xff, 0xc0, 0x0, + 0x0, 0x0, 0x9f, 0xf5, 0x2f, 0xfc, 0x0, 0x0, + 0x0, 0x9, 0xff, 0x52, 0xff, 0xc0, 0x0, 0x0, + 0x0, 0x9f, 0xf5, 0x2f, 0xfc, 0x0, 0x0, 0x0, + 0x9, 0xff, 0x51, 0xff, 0xc0, 0x0, 0x0, 0x0, + 0x9f, 0xf4, 0xf, 0xfe, 0x0, 0x0, 0x0, 0xb, + 0xff, 0x30, 0xcf, 0xf4, 0x0, 0x0, 0x1, 0xff, + 0xf0, 0x7, 0xff, 0xd2, 0x0, 0x1, 0xcf, 0xf9, + 0x0, 0xc, 0xff, 0xfb, 0x9a, 0xff, 0xfe, 0x10, + 0x0, 0x1c, 0xff, 0xff, 0xff, 0xfd, 0x20, 0x0, + 0x0, 0x6, 0xbe, 0xfe, 0xc7, 0x0, 0x0, + + /* U+0076 "v" */ + 0x1f, 0xff, 0x0, 0x0, 0x0, 0x0, 0xb, 0xff, + 0x40, 0xcf, 0xf4, 0x0, 0x0, 0x0, 0x0, 0xff, + 0xf0, 0x6, 0xff, 0x90, 0x0, 0x0, 0x0, 0x5f, + 0xfa, 0x0, 0x1f, 0xfe, 0x0, 0x0, 0x0, 0xa, + 0xff, 0x40, 0x0, 0xcf, 0xf4, 0x0, 0x0, 0x0, + 0xff, 0xf0, 0x0, 0x7, 0xff, 0x90, 0x0, 0x0, + 0x4f, 0xfa, 0x0, 0x0, 0x1f, 0xfe, 0x0, 0x0, + 0xa, 0xff, 0x40, 0x0, 0x0, 0xcf, 0xf3, 0x0, + 0x0, 0xef, 0xf0, 0x0, 0x0, 0x7, 0xff, 0x80, + 0x0, 0x4f, 0xfa, 0x0, 0x0, 0x0, 0x1f, 0xfd, + 0x0, 0x9, 0xff, 0x40, 0x0, 0x0, 0x0, 0xcf, + 0xf2, 0x0, 0xef, 0xf0, 0x0, 0x0, 0x0, 0x7, + 0xff, 0x70, 0x3f, 0xfa, 0x0, 0x0, 0x0, 0x0, + 0x1f, 0xfc, 0x8, 0xff, 0x40, 0x0, 0x0, 0x0, + 0x0, 0xcf, 0xf1, 0xcf, 0xf0, 0x0, 0x0, 0x0, + 0x0, 0x7, 0xff, 0x6f, 0xfa, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x1f, 0xfd, 0xff, 0x50, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xcf, 0xff, 0xf0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x7, 0xff, 0xfa, 0x0, 0x0, + 0x0, + + /* U+0077 "w" */ + 0xe, 0xf8, 0x0, 0x0, 0xef, 0xf2, 0x0, 0x3, + 0xff, 0x10, 0xcf, 0xb0, 0x0, 0x1f, 0xff, 0x40, + 0x0, 0x6f, 0xf0, 0x9, 0xfd, 0x0, 0x4, 0xfe, + 0xf7, 0x0, 0x8, 0xfc, 0x0, 0x7f, 0xf0, 0x0, + 0x7f, 0xbf, 0xa0, 0x0, 0xaf, 0x90, 0x4, 0xff, + 0x10, 0xa, 0xf6, 0xfd, 0x0, 0xd, 0xf7, 0x0, + 0x2f, 0xf4, 0x0, 0xcf, 0x2f, 0xf0, 0x0, 0xff, + 0x40, 0x0, 0xff, 0x60, 0xf, 0xf0, 0xdf, 0x20, + 0x1f, 0xf1, 0x0, 0xd, 0xf8, 0x2, 0xfd, 0xa, + 0xf5, 0x4, 0xff, 0x0, 0x0, 0xaf, 0xa0, 0x5f, + 0xa0, 0x8f, 0x80, 0x6f, 0xc0, 0x0, 0x7, 0xfd, + 0x7, 0xf7, 0x5, 0xfb, 0x8, 0xf9, 0x0, 0x0, + 0x5f, 0xf0, 0xaf, 0x50, 0x2f, 0xd0, 0xbf, 0x70, + 0x0, 0x2, 0xff, 0x1d, 0xf2, 0x0, 0xff, 0xd, + 0xf4, 0x0, 0x0, 0xf, 0xf4, 0xff, 0x0, 0xd, + 0xf3, 0xff, 0x10, 0x0, 0x0, 0xdf, 0x8f, 0xc0, + 0x0, 0xbf, 0x7f, 0xf0, 0x0, 0x0, 0xb, 0xfc, + 0xfa, 0x0, 0x8, 0xfb, 0xfc, 0x0, 0x0, 0x0, + 0x8f, 0xff, 0x70, 0x0, 0x6f, 0xff, 0x90, 0x0, + 0x0, 0x5, 0xff, 0xf4, 0x0, 0x3, 0xff, 0xf7, + 0x0, 0x0, 0x0, 0x3f, 0xff, 0x20, 0x0, 0xf, + 0xff, 0x40, 0x0, + + /* U+0078 "x" */ + 0xa, 0xff, 0xa0, 0x0, 0x0, 0x0, 0x7f, 0xfd, + 0x0, 0x1e, 0xff, 0x50, 0x0, 0x0, 0x2f, 0xff, + 0x40, 0x0, 0x5f, 0xfe, 0x0, 0x0, 0xb, 0xff, + 0x90, 0x0, 0x0, 0xaf, 0xf9, 0x0, 0x5, 0xff, + 0xd0, 0x0, 0x0, 0x1, 0xef, 0xf3, 0x1, 0xef, + 0xf3, 0x0, 0x0, 0x0, 0x5, 0xff, 0xc0, 0x9f, + 0xf9, 0x0, 0x0, 0x0, 0x0, 0xa, 0xff, 0x8f, + 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1e, 0xff, + 0xff, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5f, + 0xff, 0x90, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa, + 0xff, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5, + 0xff, 0xef, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x1, + 0xef, 0xf2, 0xdf, 0xf3, 0x0, 0x0, 0x0, 0x0, + 0xbf, 0xf8, 0x5, 0xff, 0xd0, 0x0, 0x0, 0x0, + 0x5f, 0xfd, 0x0, 0xa, 0xff, 0x90, 0x0, 0x0, + 0x1e, 0xff, 0x30, 0x0, 0x1e, 0xff, 0x30, 0x0, + 0xb, 0xff, 0x90, 0x0, 0x0, 0x6f, 0xfd, 0x0, + 0x6, 0xff, 0xe0, 0x0, 0x0, 0x0, 0xcf, 0xf9, + 0x1, 0xff, 0xf4, 0x0, 0x0, 0x0, 0x2, 0xff, + 0xf4, + + /* U+0079 "y" */ + 0x1f, 0xff, 0x0, 0x0, 0x0, 0x0, 0xb, 0xff, + 0x40, 0xbf, 0xf6, 0x0, 0x0, 0x0, 0x1, 0xff, + 0xe0, 0x4, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x6f, + 0xf8, 0x0, 0xe, 0xff, 0x20, 0x0, 0x0, 0xc, + 0xff, 0x30, 0x0, 0x8f, 0xf8, 0x0, 0x0, 0x2, + 0xff, 0xd0, 0x0, 0x2, 0xff, 0xd0, 0x0, 0x0, + 0x7f, 0xf7, 0x0, 0x0, 0xc, 0xff, 0x30, 0x0, + 0xd, 0xff, 0x10, 0x0, 0x0, 0x5f, 0xf9, 0x0, + 0x2, 0xff, 0xb0, 0x0, 0x0, 0x0, 0xff, 0xf0, + 0x0, 0x8f, 0xf5, 0x0, 0x0, 0x0, 0x9, 0xff, + 0x50, 0xd, 0xff, 0x0, 0x0, 0x0, 0x0, 0x3f, + 0xfb, 0x3, 0xff, 0xa0, 0x0, 0x0, 0x0, 0x0, + 0xdf, 0xf1, 0x8f, 0xf4, 0x0, 0x0, 0x0, 0x0, + 0x7, 0xff, 0x7d, 0xfe, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x1f, 0xfd, 0xff, 0x80, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xaf, 0xff, 0xf2, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x4, 0xff, 0xfc, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xe, 0xff, 0x70, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xef, 0xf1, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x4f, 0xfb, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xa, 0xff, 0x50, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xf0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x6f, 0xf9, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xc, 0xff, 0x30, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xff, 0xe0, + 0x0, 0x0, 0x0, 0x0, + + /* U+007A "z" */ + 0xd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, + 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x8, + 0xaa, 0xaa, 0xaa, 0xaa, 0xcf, 0xff, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x1e, 0xff, 0x70, 0x0, 0x0, + 0x0, 0x0, 0xb, 0xff, 0xa0, 0x0, 0x0, 0x0, + 0x0, 0x8, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, + 0x5, 0xff, 0xe2, 0x0, 0x0, 0x0, 0x0, 0x2, + 0xff, 0xf4, 0x0, 0x0, 0x0, 0x0, 0x0, 0xdf, + 0xf7, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf, 0xfa, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xfc, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x4f, 0xfe, 0x10, 0x0, + 0x0, 0x0, 0x0, 0x2e, 0xff, 0x30, 0x0, 0x0, + 0x0, 0x0, 0xd, 0xff, 0x60, 0x0, 0x0, 0x0, + 0x0, 0xa, 0xff, 0x90, 0x0, 0x0, 0x0, 0x0, + 0x1, 0xff, 0xfa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa3, + 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x52, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf5, + + /* U+007B "{" */ + 0x0, 0x0, 0x0, 0x0, 0x6, 0xbe, 0xff, 0x20, + 0x0, 0x0, 0x0, 0x1c, 0xff, 0xff, 0xf2, 0x0, + 0x0, 0x0, 0xa, 0xff, 0xfb, 0x99, 0x10, 0x0, + 0x0, 0x1, 0xff, 0xf3, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x3f, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x2, 0xff, 0xb0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x1f, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe, + 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xcf, + 0xf1, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xff, + 0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0xcf, 0xf1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xfc, 0x0, + 0x0, 0x5, 0x99, 0x99, 0xbf, 0xfd, 0x20, 0x0, + 0x0, 0x9f, 0xff, 0xff, 0xc5, 0x0, 0x0, 0x0, + 0x9, 0xff, 0xff, 0xff, 0xf8, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x2, 0x9f, 0xf7, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xef, 0xf0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xb, 0xff, 0x20, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xbf, 0xf2, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xd, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xef, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xf, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, + 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, + 0xfb, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, + 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, + 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0xaf, 0xff, + 0xc9, 0x91, 0x0, 0x0, 0x0, 0x0, 0xcf, 0xff, + 0xff, 0x20, 0x0, 0x0, 0x0, 0x0, 0x5b, 0xef, + 0xf2, + + /* U+007C "|" */ + 0xdf, 0xf0, 0xdf, 0xf0, 0xdf, 0xf0, 0xdf, 0xf0, + 0xdf, 0xf0, 0xdf, 0xf0, 0xdf, 0xf0, 0xdf, 0xf0, + 0xdf, 0xf0, 0xdf, 0xf0, 0xdf, 0xf0, 0xdf, 0xf0, + 0xdf, 0xf0, 0xdf, 0xf0, 0xdf, 0xf0, 0xdf, 0xf0, + 0xdf, 0xf0, 0xdf, 0xf0, 0xdf, 0xf0, 0xdf, 0xf0, + 0xdf, 0xf0, 0xdf, 0xf0, 0xdf, 0xf0, 0xdf, 0xf0, + 0xdf, 0xf0, 0xdf, 0xf0, 0xdf, 0xf0, 0xdf, 0xf0, + 0xdf, 0xf0, 0xdf, 0xf0, + + /* U+007D "}" */ + 0xff, 0xec, 0x70, 0x0, 0x0, 0x0, 0x0, 0xff, + 0xff, 0xfe, 0x30, 0x0, 0x0, 0x0, 0x89, 0xbf, + 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xdf, + 0xf5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xf6, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x8f, 0xf5, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xaf, 0xf3, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xdf, 0xf0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, + 0x2, 0xff, 0xb0, 0x0, 0x0, 0x0, 0x0, 0x4, + 0xff, 0x90, 0x0, 0x0, 0x0, 0x0, 0x4, 0xff, + 0x90, 0x0, 0x0, 0x0, 0x0, 0x1, 0xff, 0xe1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x5f, 0xfe, 0xa9, + 0x99, 0x97, 0x0, 0x0, 0x1, 0xbf, 0xff, 0xff, + 0xfc, 0x0, 0x0, 0x1d, 0xff, 0xff, 0xff, 0xfc, + 0x0, 0x0, 0xdf, 0xf7, 0x10, 0x0, 0x0, 0x0, + 0x3, 0xff, 0xb0, 0x0, 0x0, 0x0, 0x0, 0x5, + 0xff, 0x90, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, + 0xa0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xff, 0xc0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xe0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xcf, 0xf1, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xaf, 0xf3, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x8f, 0xf6, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x7f, 0xf6, 0x0, 0x0, 0x0, 0x0, 0x1, + 0xdf, 0xf4, 0x0, 0x0, 0x0, 0x89, 0xbf, 0xff, + 0xd0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xfe, 0x20, + 0x0, 0x0, 0x0, 0xff, 0xec, 0x70, 0x0, 0x0, + 0x0, 0x0, + + /* U+007E "~" */ + 0x0, 0x4, 0x64, 0x0, 0x0, 0x0, 0x46, 0x60, + 0x5f, 0xff, 0xfe, 0x30, 0x0, 0xc, 0xff, 0x3f, + 0xff, 0xff, 0xff, 0x20, 0x0, 0xcf, 0xf9, 0xff, + 0x60, 0x6f, 0xfe, 0x10, 0xe, 0xfe, 0xbf, 0xf0, + 0x0, 0x7f, 0xfd, 0x7a, 0xff, 0xac, 0xff, 0x0, + 0x0, 0x9f, 0xff, 0xff, 0xf2, 0xcf, 0xf0, 0x0, + 0x0, 0x5d, 0xfe, 0xa2, 0x0 +}; + + +/*--------------------- + * GLYPH DESCRIPTION + *--------------------*/ + +static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = { + {.bitmap_index = 0, .adv_w = 0, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0} /* id = 0 reserved */, + {.bitmap_index = 0, .adv_w = 307, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 0, .adv_w = 307, .box_w = 5, .box_h = 23, .ofs_x = 7, .ofs_y = 0}, + {.bitmap_index = 58, .adv_w = 307, .box_w = 11, .box_h = 10, .ofs_x = 4, .ofs_y = 13}, + {.bitmap_index = 113, .adv_w = 307, .box_w = 18, .box_h = 23, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 320, .adv_w = 307, .box_w = 15, .box_h = 33, .ofs_x = 2, .ofs_y = -4}, + {.bitmap_index = 568, .adv_w = 307, .box_w = 19, .box_h = 23, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 787, .adv_w = 307, .box_w = 20, .box_h = 23, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1017, .adv_w = 307, .box_w = 5, .box_h = 10, .ofs_x = 7, .ofs_y = 13}, + {.bitmap_index = 1042, .adv_w = 307, .box_w = 11, .box_h = 31, .ofs_x = 5, .ofs_y = -4}, + {.bitmap_index = 1213, .adv_w = 307, .box_w = 11, .box_h = 31, .ofs_x = 3, .ofs_y = -4}, + {.bitmap_index = 1384, .adv_w = 307, .box_w = 18, .box_h = 17, .ofs_x = 1, .ofs_y = 3}, + {.bitmap_index = 1537, .adv_w = 307, .box_w = 16, .box_h = 16, .ofs_x = 2, .ofs_y = 2}, + {.bitmap_index = 1665, .adv_w = 307, .box_w = 6, .box_h = 10, .ofs_x = 6, .ofs_y = -5}, + {.bitmap_index = 1695, .adv_w = 307, .box_w = 11, .box_h = 3, .ofs_x = 4, .ofs_y = 9}, + {.bitmap_index = 1712, .adv_w = 307, .box_w = 7, .box_h = 6, .ofs_x = 6, .ofs_y = 0}, + {.bitmap_index = 1733, .adv_w = 307, .box_w = 15, .box_h = 30, .ofs_x = 2, .ofs_y = -4}, + {.bitmap_index = 1958, .adv_w = 307, .box_w = 15, .box_h = 23, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 2131, .adv_w = 307, .box_w = 16, .box_h = 23, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 2315, .adv_w = 307, .box_w = 15, .box_h = 23, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 2488, .adv_w = 307, .box_w = 15, .box_h = 23, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 2661, .adv_w = 307, .box_w = 14, .box_h = 23, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 2822, .adv_w = 307, .box_w = 15, .box_h = 23, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 2995, .adv_w = 307, .box_w = 16, .box_h = 23, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 3179, .adv_w = 307, .box_w = 16, .box_h = 23, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 3363, .adv_w = 307, .box_w = 16, .box_h = 23, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 3547, .adv_w = 307, .box_w = 16, .box_h = 23, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 3731, .adv_w = 307, .box_w = 7, .box_h = 18, .ofs_x = 6, .ofs_y = 0}, + {.bitmap_index = 3794, .adv_w = 307, .box_w = 7, .box_h = 23, .ofs_x = 6, .ofs_y = -5}, + {.bitmap_index = 3875, .adv_w = 307, .box_w = 15, .box_h = 18, .ofs_x = 2, .ofs_y = 2}, + {.bitmap_index = 4010, .adv_w = 307, .box_w = 15, .box_h = 10, .ofs_x = 2, .ofs_y = 5}, + {.bitmap_index = 4085, .adv_w = 307, .box_w = 15, .box_h = 18, .ofs_x = 2, .ofs_y = 2}, + {.bitmap_index = 4220, .adv_w = 307, .box_w = 12, .box_h = 23, .ofs_x = 4, .ofs_y = 0}, + {.bitmap_index = 4358, .adv_w = 307, .box_w = 17, .box_h = 29, .ofs_x = 1, .ofs_y = -6}, + {.bitmap_index = 4605, .adv_w = 307, .box_w = 17, .box_h = 23, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 4801, .adv_w = 307, .box_w = 15, .box_h = 23, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 4974, .adv_w = 307, .box_w = 15, .box_h = 23, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 5147, .adv_w = 307, .box_w = 15, .box_h = 23, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 5320, .adv_w = 307, .box_w = 14, .box_h = 23, .ofs_x = 3, .ofs_y = 0}, + {.bitmap_index = 5481, .adv_w = 307, .box_w = 14, .box_h = 23, .ofs_x = 3, .ofs_y = 0}, + {.bitmap_index = 5642, .adv_w = 307, .box_w = 15, .box_h = 23, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 5815, .adv_w = 307, .box_w = 15, .box_h = 23, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 5988, .adv_w = 307, .box_w = 13, .box_h = 23, .ofs_x = 3, .ofs_y = 0}, + {.bitmap_index = 6138, .adv_w = 307, .box_w = 15, .box_h = 23, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 6311, .adv_w = 307, .box_w = 16, .box_h = 23, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 6495, .adv_w = 307, .box_w = 14, .box_h = 23, .ofs_x = 4, .ofs_y = 0}, + {.bitmap_index = 6656, .adv_w = 307, .box_w = 15, .box_h = 23, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 6829, .adv_w = 307, .box_w = 15, .box_h = 23, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 7002, .adv_w = 307, .box_w = 15, .box_h = 23, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 7175, .adv_w = 307, .box_w = 16, .box_h = 23, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 7359, .adv_w = 307, .box_w = 15, .box_h = 29, .ofs_x = 2, .ofs_y = -6}, + {.bitmap_index = 7577, .adv_w = 307, .box_w = 16, .box_h = 23, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 7761, .adv_w = 307, .box_w = 15, .box_h = 23, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 7934, .adv_w = 307, .box_w = 17, .box_h = 23, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 8130, .adv_w = 307, .box_w = 15, .box_h = 23, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 8303, .adv_w = 307, .box_w = 17, .box_h = 23, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 8499, .adv_w = 307, .box_w = 19, .box_h = 23, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 8718, .adv_w = 307, .box_w = 17, .box_h = 23, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 8914, .adv_w = 307, .box_w = 18, .box_h = 23, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 9121, .adv_w = 307, .box_w = 15, .box_h = 23, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 9294, .adv_w = 307, .box_w = 9, .box_h = 30, .ofs_x = 6, .ofs_y = -4}, + {.bitmap_index = 9429, .adv_w = 307, .box_w = 15, .box_h = 30, .ofs_x = 2, .ofs_y = -4}, + {.bitmap_index = 9654, .adv_w = 307, .box_w = 9, .box_h = 30, .ofs_x = 4, .ofs_y = -4}, + {.bitmap_index = 9789, .adv_w = 307, .box_w = 15, .box_h = 13, .ofs_x = 2, .ofs_y = 11}, + {.bitmap_index = 9887, .adv_w = 307, .box_w = 17, .box_h = 3, .ofs_x = 1, .ofs_y = -3}, + {.bitmap_index = 9913, .adv_w = 307, .box_w = 7, .box_h = 5, .ofs_x = 5, .ofs_y = 21}, + {.bitmap_index = 9931, .adv_w = 307, .box_w = 15, .box_h = 18, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 10066, .adv_w = 307, .box_w = 15, .box_h = 23, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 10239, .adv_w = 307, .box_w = 15, .box_h = 18, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 10374, .adv_w = 307, .box_w = 15, .box_h = 23, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 10547, .adv_w = 307, .box_w = 15, .box_h = 18, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 10682, .adv_w = 307, .box_w = 16, .box_h = 23, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 10866, .adv_w = 307, .box_w = 15, .box_h = 24, .ofs_x = 2, .ofs_y = -6}, + {.bitmap_index = 11046, .adv_w = 307, .box_w = 15, .box_h = 23, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 11219, .adv_w = 307, .box_w = 16, .box_h = 25, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 11419, .adv_w = 307, .box_w = 13, .box_h = 31, .ofs_x = 2, .ofs_y = -6}, + {.bitmap_index = 11621, .adv_w = 307, .box_w = 15, .box_h = 23, .ofs_x = 3, .ofs_y = 0}, + {.bitmap_index = 11794, .adv_w = 307, .box_w = 18, .box_h = 23, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 12001, .adv_w = 307, .box_w = 17, .box_h = 18, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 12154, .adv_w = 307, .box_w = 15, .box_h = 18, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 12289, .adv_w = 307, .box_w = 15, .box_h = 18, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 12424, .adv_w = 307, .box_w = 15, .box_h = 24, .ofs_x = 2, .ofs_y = -6}, + {.bitmap_index = 12604, .adv_w = 307, .box_w = 15, .box_h = 24, .ofs_x = 2, .ofs_y = -6}, + {.bitmap_index = 12784, .adv_w = 307, .box_w = 14, .box_h = 18, .ofs_x = 3, .ofs_y = 0}, + {.bitmap_index = 12910, .adv_w = 307, .box_w = 15, .box_h = 18, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 13045, .adv_w = 307, .box_w = 16, .box_h = 23, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 13229, .adv_w = 307, .box_w = 15, .box_h = 18, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 13364, .adv_w = 307, .box_w = 17, .box_h = 18, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 13517, .adv_w = 307, .box_w = 19, .box_h = 18, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 13688, .adv_w = 307, .box_w = 17, .box_h = 18, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 13841, .adv_w = 307, .box_w = 17, .box_h = 24, .ofs_x = 1, .ofs_y = -6}, + {.bitmap_index = 14045, .adv_w = 307, .box_w = 15, .box_h = 18, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 14180, .adv_w = 307, .box_w = 15, .box_h = 30, .ofs_x = 2, .ofs_y = -4}, + {.bitmap_index = 14405, .adv_w = 307, .box_w = 4, .box_h = 30, .ofs_x = 8, .ofs_y = -4}, + {.bitmap_index = 14465, .adv_w = 307, .box_w = 14, .box_h = 30, .ofs_x = 3, .ofs_y = -4}, + {.bitmap_index = 14675, .adv_w = 307, .box_w = 15, .box_h = 7, .ofs_x = 2, .ofs_y = 8} +}; + +/*--------------------- + * CHARACTER MAPPING + *--------------------*/ + + + +/*Collect the unicode lists and glyph_id offsets*/ +static const lv_font_fmt_txt_cmap_t cmaps[] = +{ + { + .range_start = 32, .range_length = 95, .glyph_id_start = 1, + .unicode_list = NULL, .glyph_id_ofs_list = NULL, .list_length = 0, .type = LV_FONT_FMT_TXT_CMAP_FORMAT0_TINY + } +}; + + + +/*-------------------- + * ALL CUSTOM DATA + *--------------------*/ + +#if LVGL_VERSION_MAJOR == 8 +/*Store all the custom data of the font*/ +static lv_font_fmt_txt_glyph_cache_t cache; +#endif + +#if LVGL_VERSION_MAJOR >= 8 +static const lv_font_fmt_txt_dsc_t font_dsc = { +#else +static lv_font_fmt_txt_dsc_t font_dsc = { +#endif + .glyph_bitmap = glyph_bitmap, + .glyph_dsc = glyph_dsc, + .cmaps = cmaps, + .kern_dsc = NULL, + .kern_scale = 0, + .cmap_num = 1, + .bpp = 4, + .kern_classes = 0, + .bitmap_format = 0, +#if LVGL_VERSION_MAJOR == 8 + .cache = &cache +#endif +}; + + +/*----------------- + * PUBLIC FONT + *----------------*/ + +/*Initialize a public general font descriptor*/ +#if LVGL_VERSION_MAJOR >= 8 +const lv_font_t JetBrainsMono32 = { +#else +lv_font_t JetBrainsMono32 = { +#endif + .get_glyph_dsc = lv_font_get_glyph_dsc_fmt_txt, /*Function pointer to get glyph's data*/ + .get_glyph_bitmap = lv_font_get_bitmap_fmt_txt, /*Function pointer to get glyph's bitmap*/ + .line_height = 35, /*The maximum line height required by the font*/ + .base_line = 6, /*Baseline measured from the bottom of the line*/ +#if !(LVGL_VERSION_MAJOR == 6 && LVGL_VERSION_MINOR == 0) + .subpx = LV_FONT_SUBPX_NONE, +#endif +#if LV_VERSION_CHECK(7, 4, 0) || LVGL_VERSION_MAJOR >= 8 + .underline_position = -5, + .underline_thickness = 2, +#endif + .dsc = &font_dsc, /*The custom font data. Will be accessed by `get_glyph_bitmap/dsc` */ + .fallback = NULL, + .user_data = NULL +}; + + + +#endif /*#if JETBRAINSMONO32*/ + diff --git a/device/src/keyboard/oled/fonts/jet_brains_mono_8.c b/device/src/keyboard/oled/fonts/jet_brains_mono_8.c new file mode 100644 index 000000000..6601f7473 --- /dev/null +++ b/device/src/keyboard/oled/fonts/jet_brains_mono_8.c @@ -0,0 +1,626 @@ +/******************************************************************************* + * Size: 8 px + * Bpp: 4 + * Opts: + ******************************************************************************/ + +#ifdef LV_LVGL_H_INCLUDE_SIMPLE +#include "lvgl.h" +#else +#include "lvgl/lvgl.h" +#endif + +#ifndef JETBRAINSMONO8 +#define JETBRAINSMONO8 1 +#endif + +#if JETBRAINSMONO8 + +/*----------------- + * BITMAPS + *----------------*/ + +/*Store the image of the glyphs*/ +static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { + /* U+0020 " " */ + + /* U+0021 "!" */ + 0xd, 0xc, 0xb, 0xb, 0x6, 0x0, 0x1d, + + /* U+0022 "\"" */ + 0xc2, 0xac, 0x29, 0x71, 0x60, + + /* U+0023 "#" */ + 0x5, 0x37, 0x10, 0x71, 0x90, 0x3c, 0x9c, 0x40, + 0x80, 0x80, 0x6c, 0x9b, 0x22, 0x64, 0x40, 0x44, + 0x62, 0x0, + + /* U+0024 "$" */ + 0x0, 0x70, 0x0, 0x7d, 0x60, 0x39, 0x8b, 0x12, + 0xb8, 0x0, 0x6, 0xe6, 0x0, 0x7, 0xb1, 0x58, + 0x7a, 0x20, 0x9d, 0x70, 0x0, 0x70, 0x0, + + /* U+0025 "%" */ + 0x8b, 0x13, 0x69, 0x45, 0x90, 0x94, 0xa4, 0x6, + 0xa9, 0x0, 0x7, 0x5a, 0x41, 0x88, 0x19, 0x81, + 0x5a, 0x60, + + /* U+0026 "&" */ + 0xa, 0xb4, 0x1, 0xa1, 0x80, 0xc, 0x10, 0x4, + 0xc9, 0x3, 0xb0, 0x8b, 0x4b, 0x4, 0xe0, 0x5c, + 0xa3, 0x90, + + /* U+0027 "'" */ + 0xc, 0xc, 0x7, + + /* U+0028 "(" */ + 0x0, 0x40, 0xa7, 0x39, 0x7, 0x40, 0x83, 0x8, + 0x30, 0x65, 0x1, 0xc0, 0x4, 0xb0, 0x0, + + /* U+0029 ")" */ + 0x3, 0x0, 0xa, 0x70, 0x0, 0xb1, 0x0, 0x74, + 0x0, 0x65, 0x0, 0x64, 0x0, 0x83, 0x1, 0xc0, + 0xc, 0x20, 0x0, 0x0, + + /* U+002A "*" */ + 0x0, 0xa0, 0x6, 0x5a, 0x64, 0x17, 0xf5, 0x0, + 0xa6, 0x80, 0x4, 0x5, 0x0, + + /* U+002B "+" */ + 0x0, 0xb0, 0x0, 0xb, 0x0, 0x5b, 0xeb, 0x30, + 0xb, 0x0, 0x0, 0x20, 0x0, + + /* U+002C "," */ + 0x9, 0x1b, 0x38, + + /* U+002D "-" */ + 0x9b, 0x70, + + /* U+002E "." */ + 0x5, 0x2, 0xe0, + + /* U+002F "/" */ + 0x0, 0x5, 0x0, 0x0, 0xc0, 0x0, 0x38, 0x0, + 0x9, 0x30, 0x0, 0xc0, 0x0, 0x38, 0x0, 0x9, + 0x30, 0x0, 0xc0, 0x0, 0x38, 0x0, 0x0, + + /* U+0030 "0" */ + 0xa, 0xb8, 0x4, 0x70, 0xa1, 0x55, 0x8, 0x25, + 0x5a, 0x82, 0x55, 0x8, 0x24, 0x70, 0xa0, 0xa, + 0xa7, 0x0, + + /* U+0031 "1" */ + 0x8, 0xf0, 0x4, 0x7b, 0x0, 0x0, 0xb0, 0x0, + 0xb, 0x0, 0x0, 0xb0, 0x0, 0xb, 0x0, 0x3b, + 0xeb, 0x30, + + /* U+0032 "2" */ + 0xa, 0xb8, 0x4, 0x70, 0xb1, 0x0, 0xb, 0x0, + 0x3, 0xa0, 0x1, 0xc1, 0x0, 0xb3, 0x0, 0x4e, + 0xbb, 0x20, + + /* U+0033 "3" */ + 0x3b, 0xbe, 0x0, 0x7, 0x50, 0x3, 0xd1, 0x0, + 0x15, 0xc0, 0x0, 0xa, 0x5, 0x60, 0xb0, 0xb, + 0xb7, 0x0, + + /* U+0034 "4" */ + 0x0, 0x84, 0x1, 0xb0, 0x7, 0x50, 0xc, 0x8, + 0x66, 0xb, 0x6c, 0xbd, 0x0, 0xb, + + /* U+0035 "5" */ + 0x3d, 0xba, 0x3, 0x70, 0x0, 0x37, 0x0, 0x2, + 0xcb, 0x70, 0x0, 0xb, 0x14, 0x40, 0xa1, 0xb, + 0xb8, 0x0, + + /* U+0036 "6" */ + 0x0, 0xc0, 0x0, 0x49, 0x0, 0xc, 0x20, 0x3, + 0xe9, 0x60, 0x66, 0x9, 0x25, 0x50, 0x82, 0xa, + 0xb9, 0x0, + + /* U+0037 "7" */ + 0x5d, 0xbd, 0x54, 0x40, 0xa2, 0x0, 0xb, 0x0, + 0x5, 0x70, 0x0, 0xa2, 0x0, 0xb, 0x0, 0x5, + 0x70, 0x0, + + /* U+0038 "8" */ + 0x9, 0xb7, 0x3, 0x80, 0xb0, 0x29, 0xb, 0x0, + 0xbd, 0x80, 0x56, 0xa, 0x25, 0x50, 0x92, 0xa, + 0xb9, 0x0, + + /* U+0039 "9" */ + 0xa, 0xb8, 0x4, 0x60, 0xa2, 0x74, 0x7, 0x34, + 0x70, 0xa0, 0x8, 0xa9, 0x0, 0x8, 0x10, 0x2, + 0x90, 0x0, + + /* U+003A ":" */ + 0x2e, 0x0, 0x30, 0x0, 0x0, 0x30, 0x2e, 0x0, + + /* U+003B ";" */ + 0x2e, 0x0, 0x40, 0x0, 0x0, 0x0, 0x9, 0x1, + 0xb0, 0x47, 0x0, + + /* U+003C "<" */ + 0x0, 0x0, 0x0, 0x6, 0xb1, 0x2b, 0x50, 0x2, + 0xb4, 0x0, 0x0, 0x8a, 0x0, 0x0, 0x10, + + /* U+003D "=" */ + 0x3b, 0xbb, 0x10, 0x0, 0x0, 0x3b, 0xbb, 0x10, + + /* U+003E ">" */ + 0x10, 0x0, 0x2, 0xb4, 0x0, 0x0, 0x8b, 0x0, + 0x5, 0xb1, 0x2b, 0x60, 0x1, 0x0, 0x0, + + /* U+003F "?" */ + 0xbc, 0x40, 0xb, 0x0, 0xb4, 0xc3, 0x34, 0x0, + 0x0, 0x77, 0x0, + + /* U+0040 "@" */ + 0x9, 0xaa, 0x6, 0x40, 0x65, 0x90, 0x3, 0x7a, + 0x8, 0x97, 0xa0, 0x93, 0x7a, 0x9, 0x36, 0x90, + 0x89, 0x16, 0x50, 0x0, 0xa, 0xa5, 0x0, + + /* U+0041 "A" */ + 0x3, 0xf0, 0x0, 0x6a, 0x30, 0x9, 0x46, 0x0, + 0xa0, 0x90, 0xd, 0xac, 0x4, 0x60, 0x91, 0x73, + 0x6, 0x40, + + /* U+0042 "B" */ + 0x4d, 0xb8, 0x4, 0x70, 0xb0, 0x47, 0xb, 0x4, + 0xdc, 0x70, 0x47, 0xa, 0x14, 0x70, 0x92, 0x4d, + 0xba, 0x0, + + /* U+0043 "C" */ + 0xa, 0xb9, 0x3, 0x80, 0x91, 0x47, 0x0, 0x4, + 0x70, 0x0, 0x47, 0x0, 0x3, 0x80, 0x91, 0xa, + 0xb9, 0x0, + + /* U+0044 "D" */ + 0x4d, 0xc6, 0x4, 0x70, 0xb0, 0x47, 0xa, 0x14, + 0x70, 0xa1, 0x47, 0xa, 0x14, 0x70, 0xb0, 0x4d, + 0xb6, 0x0, + + /* U+0045 "E" */ + 0x3d, 0xbb, 0x13, 0x80, 0x0, 0x38, 0x0, 0x3, + 0xdb, 0xa0, 0x38, 0x0, 0x3, 0x80, 0x0, 0x3d, + 0xbb, 0x10, + + /* U+0046 "F" */ + 0x3d, 0xbb, 0x23, 0x70, 0x0, 0x37, 0x0, 0x3, + 0xdb, 0xb0, 0x37, 0x0, 0x3, 0x70, 0x0, 0x37, + 0x0, 0x0, + + /* U+0047 "G" */ + 0xa, 0xb8, 0x3, 0x80, 0x91, 0x46, 0x0, 0x4, + 0x68, 0xc1, 0x46, 0x9, 0x23, 0x80, 0xa0, 0xa, + 0xb8, 0x0, + + /* U+0048 "H" */ + 0x47, 0xa, 0x14, 0x70, 0xa1, 0x47, 0xa, 0x14, + 0xdb, 0xe1, 0x47, 0xa, 0x14, 0x70, 0xa1, 0x47, + 0xa, 0x10, + + /* U+0049 "I" */ + 0x1b, 0xeb, 0x0, 0xb0, 0x0, 0xb0, 0x0, 0xb0, + 0x0, 0xb0, 0x0, 0xb0, 0x1b, 0xeb, + + /* U+004A "J" */ + 0x0, 0xb, 0x0, 0xb, 0x0, 0xb, 0x0, 0xb, + 0x0, 0xb, 0x83, 0xb, 0x2b, 0xc5, + + /* U+004B "K" */ + 0x47, 0x9, 0x34, 0x70, 0xb0, 0x47, 0x65, 0x4, + 0xde, 0x10, 0x47, 0x66, 0x4, 0x70, 0xc0, 0x47, + 0x8, 0x40, + + /* U+004C "L" */ + 0xb0, 0x0, 0xb0, 0x0, 0xb0, 0x0, 0xb0, 0x0, + 0xb0, 0x0, 0xb0, 0x0, 0xeb, 0xb4, + + /* U+004D "M" */ + 0x6b, 0xe, 0x36, 0xb4, 0xb3, 0x68, 0xb8, 0x36, + 0x4b, 0x73, 0x64, 0x7, 0x36, 0x40, 0x73, 0x64, + 0x7, 0x30, + + /* U+004E "N" */ + 0x4d, 0x9, 0x14, 0xe2, 0x91, 0x49, 0x69, 0x14, + 0x6a, 0x91, 0x46, 0x9a, 0x14, 0x65, 0xe1, 0x46, + 0xf, 0x10, + + /* U+004F "O" */ + 0xa, 0xb8, 0x3, 0x80, 0xb0, 0x46, 0xa, 0x14, + 0x60, 0xa1, 0x46, 0xa, 0x13, 0x80, 0xb0, 0xa, + 0xb8, 0x0, + + /* U+0050 "P" */ + 0x4d, 0xbb, 0x4, 0x70, 0x75, 0x47, 0x8, 0x44, + 0xdb, 0x90, 0x47, 0x0, 0x4, 0x70, 0x0, 0x47, + 0x0, 0x0, + + /* U+0051 "Q" */ + 0xa, 0xb8, 0x4, 0x70, 0xa1, 0x55, 0x9, 0x25, + 0x50, 0x92, 0x55, 0x9, 0x24, 0x70, 0xa0, 0xa, + 0xc9, 0x0, 0x3, 0x90, 0x0, 0xc, 0x0, + + /* U+0052 "R" */ + 0x4d, 0xb9, 0x4, 0x70, 0x92, 0x47, 0xa, 0x24, + 0xdd, 0x90, 0x47, 0x56, 0x4, 0x70, 0xc0, 0x47, + 0x9, 0x20, + + /* U+0053 "S" */ + 0x9, 0xb7, 0x3, 0x70, 0x80, 0x2b, 0x10, 0x0, + 0x6d, 0x90, 0x0, 0xb, 0x25, 0x60, 0x92, 0xb, + 0xb9, 0x0, + + /* U+0054 "T" */ + 0x6b, 0xeb, 0x40, 0xb, 0x0, 0x0, 0xb0, 0x0, + 0xb, 0x0, 0x0, 0xb0, 0x0, 0xb, 0x0, 0x0, + 0xb0, 0x0, + + /* U+0055 "U" */ + 0x47, 0xa, 0x14, 0x70, 0xa1, 0x47, 0xa, 0x14, + 0x70, 0xa1, 0x47, 0xa, 0x13, 0x80, 0xc0, 0xa, + 0xb8, 0x0, + + /* U+0056 "V" */ + 0x73, 0x7, 0x44, 0x70, 0xa1, 0x1a, 0xb, 0x0, + 0xb0, 0xa0, 0xa, 0x56, 0x0, 0x6b, 0x30, 0x3, + 0xf0, 0x0, + + /* U+0057 "W" */ + 0xa0, 0xd0, 0x9a, 0x2d, 0x27, 0x94, 0xa4, 0x67, + 0x77, 0x74, 0x6b, 0x4a, 0x24, 0xc1, 0xd1, 0x3c, + 0xf, 0x0, + + /* U+0058 "X" */ + 0x57, 0x9, 0x20, 0xc1, 0xa0, 0x7, 0xc3, 0x0, + 0x1e, 0x0, 0x8, 0xb5, 0x0, 0xb1, 0xb0, 0x75, + 0x9, 0x40, + + /* U+0059 "Y" */ + 0x83, 0x6, 0x51, 0xa0, 0xb0, 0xa, 0x48, 0x0, + 0x4e, 0x10, 0x0, 0xc0, 0x0, 0xb, 0x0, 0x0, + 0xb0, 0x0, + + /* U+005A "Z" */ + 0x3b, 0xbe, 0x0, 0x1, 0xa0, 0x0, 0x83, 0x0, + 0x1b, 0x0, 0x8, 0x40, 0x0, 0xb0, 0x0, 0x4d, + 0xbb, 0x10, + + /* U+005B "[" */ + 0x4c, 0x65, 0x50, 0x55, 0x5, 0x50, 0x55, 0x5, + 0x50, 0x55, 0x5, 0x50, 0x4c, 0x60, + + /* U+005C "\\" */ + 0x23, 0x0, 0x1, 0xa0, 0x0, 0xb, 0x0, 0x0, + 0x65, 0x0, 0x1, 0xa0, 0x0, 0xb, 0x0, 0x0, + 0x65, 0x0, 0x1, 0xa0, 0x0, 0xb, 0x0, + + /* U+005D "]" */ + 0x9c, 0x20, 0x92, 0x9, 0x20, 0x92, 0x9, 0x20, + 0x92, 0x9, 0x20, 0x92, 0x9c, 0x20, + + /* U+005E "^" */ + 0x0, 0x60, 0x0, 0x5b, 0x20, 0x9, 0x18, 0x2, + 0x70, 0x90, + + /* U+005F "_" */ + 0x5a, 0xaa, 0x30, + + /* U+0060 "`" */ + 0x41, 0x2a, + + /* U+0061 "a" */ + 0xa, 0xb9, 0x1, 0x30, 0xb0, 0x1a, 0xad, 0x16, + 0x60, 0xb1, 0x2c, 0xac, 0x10, + + /* U+0062 "b" */ + 0x47, 0x0, 0x4, 0x70, 0x0, 0x4a, 0xb9, 0x4, + 0x80, 0xa1, 0x47, 0x9, 0x14, 0x80, 0xa1, 0x4b, + 0xb9, 0x0, + + /* U+0063 "c" */ + 0xa, 0xb9, 0x3, 0x80, 0x71, 0x46, 0x0, 0x3, + 0x80, 0x71, 0xa, 0xb9, 0x0, + + /* U+0064 "d" */ + 0x0, 0xa, 0x10, 0x0, 0xa1, 0xb, 0xac, 0x14, + 0x70, 0xb1, 0x46, 0xa, 0x14, 0x70, 0xb1, 0xb, + 0xac, 0x10, + + /* U+0065 "e" */ + 0xa, 0xa7, 0x4, 0x70, 0xa0, 0x5c, 0xab, 0x14, + 0x70, 0x30, 0xa, 0xb9, 0x0, + + /* U+0066 "f" */ + 0x0, 0xcb, 0x20, 0x47, 0x0, 0x4, 0x70, 0x6, + 0xcd, 0xb2, 0x4, 0x70, 0x0, 0x47, 0x0, 0x4, + 0x70, 0x0, + + /* U+0067 "g" */ + 0xb, 0xac, 0x13, 0x80, 0xb1, 0x46, 0xa, 0x13, + 0x90, 0xc1, 0x9, 0x9b, 0x10, 0x0, 0xb0, 0x8, + 0xc8, 0x0, + + /* U+0068 "h" */ + 0x47, 0x0, 0x4, 0x70, 0x0, 0x4a, 0xb9, 0x4, + 0x80, 0xb0, 0x47, 0xa, 0x14, 0x70, 0xa1, 0x47, + 0xa, 0x10, + + /* U+0069 "i" */ + 0x0, 0xd0, 0x0, 0x1, 0x0, 0x1b, 0xe0, 0x0, + 0xb, 0x0, 0x0, 0xb0, 0x0, 0xb, 0x0, 0x3b, + 0xeb, 0x50, + + /* U+006A "j" */ + 0x0, 0x67, 0x0, 0x0, 0x3b, 0xc7, 0x0, 0x37, + 0x0, 0x37, 0x0, 0x37, 0x0, 0x37, 0x0, 0x56, + 0x3b, 0xb0, + + /* U+006B "k" */ + 0x38, 0x0, 0x3, 0x80, 0x0, 0x38, 0xb, 0x23, + 0x84, 0x80, 0x3d, 0xd1, 0x3, 0x84, 0x90, 0x38, + 0xa, 0x20, + + /* U+006C "l" */ + 0x8c, 0x70, 0x0, 0x37, 0x0, 0x3, 0x70, 0x0, + 0x37, 0x0, 0x3, 0x70, 0x0, 0x38, 0x0, 0x0, + 0xcb, 0x40, + + /* U+006D "m" */ + 0x89, 0xab, 0x18, 0x29, 0x54, 0x82, 0x95, 0x58, + 0x29, 0x55, 0x82, 0x95, 0x50, + + /* U+006E "n" */ + 0x4a, 0x99, 0x4, 0x80, 0xb0, 0x47, 0xa, 0x14, + 0x70, 0xa1, 0x47, 0xa, 0x10, + + /* U+006F "o" */ + 0xa, 0xb8, 0x4, 0x70, 0xa0, 0x56, 0x9, 0x24, + 0x70, 0xa0, 0xa, 0xb8, 0x0, + + /* U+0070 "p" */ + 0x4b, 0x99, 0x4, 0x80, 0xa1, 0x47, 0x9, 0x14, + 0x90, 0xa1, 0x4b, 0xb9, 0x4, 0x70, 0x0, 0x47, + 0x0, 0x0, + + /* U+0071 "q" */ + 0xb, 0xac, 0x14, 0x70, 0xb1, 0x46, 0xa, 0x14, + 0x70, 0xb1, 0xb, 0xac, 0x10, 0x0, 0xa1, 0x0, + 0xa, 0x10, + + /* U+0072 "r" */ + 0x1b, 0x9b, 0x1, 0xa0, 0x83, 0x19, 0x0, 0x1, + 0x90, 0x0, 0x19, 0x0, 0x0, + + /* U+0073 "s" */ + 0xb, 0xba, 0x3, 0x80, 0x30, 0x9, 0xba, 0x1, + 0x30, 0xa1, 0x1c, 0xba, 0x0, + + /* U+0074 "t" */ + 0x2, 0x20, 0x0, 0x55, 0x0, 0x7d, 0xdb, 0x10, + 0x55, 0x0, 0x5, 0x50, 0x0, 0x55, 0x0, 0x2, + 0xcb, 0x10, + + /* U+0075 "u" */ + 0x47, 0xa, 0x14, 0x70, 0xa1, 0x47, 0xa, 0x13, + 0x80, 0xb0, 0xa, 0xb8, 0x0, + + /* U+0076 "v" */ + 0x65, 0x8, 0x31, 0xa0, 0xb0, 0xb, 0x19, 0x0, + 0x89, 0x50, 0x3, 0xf0, 0x0, + + /* U+0077 "w" */ + 0x90, 0xd1, 0x78, 0x4c, 0x45, 0x68, 0x78, 0x23, + 0xc3, 0xc0, 0x1d, 0xd, 0x0, + + /* U+0078 "x" */ + 0x39, 0xb, 0x10, 0x98, 0x60, 0x3, 0xf0, 0x0, + 0xa7, 0x70, 0x48, 0xb, 0x20, + + /* U+0079 "y" */ + 0x65, 0x8, 0x31, 0xa0, 0xb0, 0xb, 0x29, 0x0, + 0x6b, 0x40, 0x1, 0xe0, 0x0, 0x1a, 0x0, 0x6, + 0x50, 0x0, + + /* U+007A "z" */ + 0x2b, 0xbf, 0x0, 0x5, 0x70, 0x2, 0xb0, 0x0, + 0xb1, 0x0, 0x4e, 0xbb, 0x0, + + /* U+007B "{" */ + 0x0, 0x5b, 0x0, 0xb, 0x0, 0x0, 0xb0, 0x0, + 0xb, 0x0, 0x4b, 0x80, 0x0, 0xb, 0x0, 0x0, + 0xb0, 0x0, 0xb, 0x0, 0x0, 0x5b, 0x0, + + /* U+007C "|" */ + 0x5b, 0xbb, 0xbb, 0xbb, 0xb0, + + /* U+007D "}" */ + 0x2b, 0x20, 0x0, 0x28, 0x0, 0x3, 0x70, 0x0, + 0x46, 0x0, 0x0, 0xcb, 0x20, 0x46, 0x0, 0x3, + 0x70, 0x0, 0x28, 0x0, 0x2b, 0x20, 0x0, + + /* U+007E "~" */ + 0x2b, 0x55, 0x35, 0x38, 0xa0 +}; + + +/*--------------------- + * GLYPH DESCRIPTION + *--------------------*/ + +static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = { + {.bitmap_index = 0, .adv_w = 0, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0} /* id = 0 reserved */, + {.bitmap_index = 0, .adv_w = 77, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 0, .adv_w = 77, .box_w = 2, .box_h = 7, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 7, .adv_w = 77, .box_w = 3, .box_h = 3, .ofs_x = 1, .ofs_y = 4}, + {.bitmap_index = 12, .adv_w = 77, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 30, .adv_w = 77, .box_w = 5, .box_h = 9, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 53, .adv_w = 77, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 71, .adv_w = 77, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 89, .adv_w = 77, .box_w = 2, .box_h = 3, .ofs_x = 1, .ofs_y = 4}, + {.bitmap_index = 92, .adv_w = 77, .box_w = 3, .box_h = 10, .ofs_x = 1, .ofs_y = -2}, + {.bitmap_index = 107, .adv_w = 77, .box_w = 4, .box_h = 10, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 127, .adv_w = 77, .box_w = 5, .box_h = 5, .ofs_x = 0, .ofs_y = 1}, + {.bitmap_index = 140, .adv_w = 77, .box_w = 5, .box_h = 5, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 153, .adv_w = 77, .box_w = 2, .box_h = 3, .ofs_x = 1, .ofs_y = -2}, + {.bitmap_index = 156, .adv_w = 77, .box_w = 3, .box_h = 1, .ofs_x = 1, .ofs_y = 2}, + {.bitmap_index = 158, .adv_w = 77, .box_w = 3, .box_h = 2, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 161, .adv_w = 77, .box_w = 5, .box_h = 9, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 184, .adv_w = 77, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 202, .adv_w = 77, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 220, .adv_w = 77, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 238, .adv_w = 77, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 256, .adv_w = 77, .box_w = 4, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 270, .adv_w = 77, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 288, .adv_w = 77, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 306, .adv_w = 77, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 324, .adv_w = 77, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 342, .adv_w = 77, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 360, .adv_w = 77, .box_w = 3, .box_h = 5, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 368, .adv_w = 77, .box_w = 3, .box_h = 7, .ofs_x = 1, .ofs_y = -2}, + {.bitmap_index = 379, .adv_w = 77, .box_w = 5, .box_h = 6, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 394, .adv_w = 77, .box_w = 5, .box_h = 3, .ofs_x = 0, .ofs_y = 1}, + {.bitmap_index = 402, .adv_w = 77, .box_w = 5, .box_h = 6, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 417, .adv_w = 77, .box_w = 3, .box_h = 7, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 428, .adv_w = 77, .box_w = 5, .box_h = 9, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 451, .adv_w = 77, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 469, .adv_w = 77, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 487, .adv_w = 77, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 505, .adv_w = 77, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 523, .adv_w = 77, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 541, .adv_w = 77, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 559, .adv_w = 77, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 577, .adv_w = 77, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 595, .adv_w = 77, .box_w = 4, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 609, .adv_w = 77, .box_w = 4, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 623, .adv_w = 77, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 641, .adv_w = 77, .box_w = 4, .box_h = 7, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 655, .adv_w = 77, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 673, .adv_w = 77, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 691, .adv_w = 77, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 709, .adv_w = 77, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 727, .adv_w = 77, .box_w = 5, .box_h = 9, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 750, .adv_w = 77, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 768, .adv_w = 77, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 786, .adv_w = 77, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 804, .adv_w = 77, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 822, .adv_w = 77, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 840, .adv_w = 77, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 858, .adv_w = 77, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 876, .adv_w = 77, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 894, .adv_w = 77, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 912, .adv_w = 77, .box_w = 3, .box_h = 9, .ofs_x = 1, .ofs_y = -1}, + {.bitmap_index = 926, .adv_w = 77, .box_w = 5, .box_h = 9, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 949, .adv_w = 77, .box_w = 3, .box_h = 9, .ofs_x = 1, .ofs_y = -1}, + {.bitmap_index = 963, .adv_w = 77, .box_w = 5, .box_h = 4, .ofs_x = 0, .ofs_y = 3}, + {.bitmap_index = 973, .adv_w = 77, .box_w = 5, .box_h = 1, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 976, .adv_w = 77, .box_w = 2, .box_h = 2, .ofs_x = 1, .ofs_y = 6}, + {.bitmap_index = 978, .adv_w = 77, .box_w = 5, .box_h = 5, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 991, .adv_w = 77, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1009, .adv_w = 77, .box_w = 5, .box_h = 5, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1022, .adv_w = 77, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1040, .adv_w = 77, .box_w = 5, .box_h = 5, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1053, .adv_w = 77, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1071, .adv_w = 77, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 1089, .adv_w = 77, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1107, .adv_w = 77, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1125, .adv_w = 77, .box_w = 4, .box_h = 9, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 1143, .adv_w = 77, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1161, .adv_w = 77, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1179, .adv_w = 77, .box_w = 5, .box_h = 5, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1192, .adv_w = 77, .box_w = 5, .box_h = 5, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1205, .adv_w = 77, .box_w = 5, .box_h = 5, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1218, .adv_w = 77, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 1236, .adv_w = 77, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 1254, .adv_w = 77, .box_w = 5, .box_h = 5, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1267, .adv_w = 77, .box_w = 5, .box_h = 5, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1280, .adv_w = 77, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1298, .adv_w = 77, .box_w = 5, .box_h = 5, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1311, .adv_w = 77, .box_w = 5, .box_h = 5, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1324, .adv_w = 77, .box_w = 5, .box_h = 5, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1337, .adv_w = 77, .box_w = 5, .box_h = 5, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1350, .adv_w = 77, .box_w = 5, .box_h = 7, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 1368, .adv_w = 77, .box_w = 5, .box_h = 5, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1381, .adv_w = 77, .box_w = 5, .box_h = 9, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 1404, .adv_w = 77, .box_w = 1, .box_h = 9, .ofs_x = 2, .ofs_y = -1}, + {.bitmap_index = 1409, .adv_w = 77, .box_w = 5, .box_h = 9, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 1432, .adv_w = 77, .box_w = 5, .box_h = 2, .ofs_x = 0, .ofs_y = 2} +}; + +/*--------------------- + * CHARACTER MAPPING + *--------------------*/ + + + +/*Collect the unicode lists and glyph_id offsets*/ +static const lv_font_fmt_txt_cmap_t cmaps[] = +{ + { + .range_start = 32, .range_length = 95, .glyph_id_start = 1, + .unicode_list = NULL, .glyph_id_ofs_list = NULL, .list_length = 0, .type = LV_FONT_FMT_TXT_CMAP_FORMAT0_TINY + } +}; + + + +/*-------------------- + * ALL CUSTOM DATA + *--------------------*/ + +#if LVGL_VERSION_MAJOR == 8 +/*Store all the custom data of the font*/ +static lv_font_fmt_txt_glyph_cache_t cache; +#endif + +#if LVGL_VERSION_MAJOR >= 8 +static const lv_font_fmt_txt_dsc_t font_dsc = { +#else +static lv_font_fmt_txt_dsc_t font_dsc = { +#endif + .glyph_bitmap = glyph_bitmap, + .glyph_dsc = glyph_dsc, + .cmaps = cmaps, + .kern_dsc = NULL, + .kern_scale = 0, + .cmap_num = 1, + .bpp = 4, + .kern_classes = 0, + .bitmap_format = 0, +#if LVGL_VERSION_MAJOR == 8 + .cache = &cache +#endif +}; + + +/*----------------- + * PUBLIC FONT + *----------------*/ + +/*Initialize a public general font descriptor*/ +#if LVGL_VERSION_MAJOR >= 8 +const lv_font_t JetBrainsMono8 = { +#else +lv_font_t JetBrainsMono8 = { +#endif + .get_glyph_dsc = lv_font_get_glyph_dsc_fmt_txt, /*Function pointer to get glyph's data*/ + .get_glyph_bitmap = lv_font_get_bitmap_fmt_txt, /*Function pointer to get glyph's bitmap*/ + .line_height = 10, /*The maximum line height required by the font*/ + .base_line = 2, /*Baseline measured from the bottom of the line*/ +#if !(LVGL_VERSION_MAJOR == 6 && LVGL_VERSION_MINOR == 0) + .subpx = LV_FONT_SUBPX_NONE, +#endif +#if LV_VERSION_CHECK(7, 4, 0) || LVGL_VERSION_MAJOR >= 8 + .underline_position = -1, + .underline_thickness = 0, +#endif + .dsc = &font_dsc, /*The custom font data. Will be accessed by `get_glyph_bitmap/dsc` */ + .fallback = NULL, + .user_data = NULL +}; + + + +#endif /*#if JETBRAINSMONO8*/ + diff --git a/device/src/keyboard/oled/framebuffer.c b/device/src/keyboard/oled/framebuffer.c new file mode 100644 index 000000000..e84139441 --- /dev/null +++ b/device/src/keyboard/oled/framebuffer.c @@ -0,0 +1,69 @@ +#include "framebuffer.h" +#include "widgets/console_widget.h" +#include "widgets/widget.h" +#include +#include +#include + +void Framebuffer_Clear(widget_t* canvas, framebuffer_t* buffer) +{ + uint16_t canvasOffsetX = canvas == NULL ? 0 : canvas->x; + uint16_t canvasOffsetY = canvas == NULL ? 0 : canvas->y; + uint16_t canvasWidth = canvas == NULL ? DISPLAY_WIDTH : canvas->w; + uint16_t canvasHeight = canvas == NULL ? DISPLAY_HEIGHT : canvas->h; + + + // TODO: optimize this + for (uint16_t y = 0; y < canvasHeight; y++) { + for (uint16_t x = 0; x < canvasWidth; x++) { + Framebuffer_SetPixel(buffer, canvasOffsetX+x, canvasOffsetY+y, 0); + } + buffer->dirtyRanges[canvasOffsetY+y].min = MIN(buffer->dirtyRanges[y].min, canvasOffsetX); + buffer->dirtyRanges[canvasOffsetY+y].max = MAX(buffer->dirtyRanges[y].max, canvasOffsetX+canvasWidth-1); + } +} + +void Framebuffer_DrawHLine(widget_t* canvas, framebuffer_t* buffer, uint8_t x1, uint8_t x2, uint8_t y) +{ + uint16_t canvasOffsetX = canvas == NULL ? 0 : canvas->x; + uint16_t canvasOffsetY = canvas == NULL ? 0 : canvas->y; + uint16_t canvasWidth = canvas == NULL ? DISPLAY_WIDTH : canvas->w; + uint16_t canvasHeight = canvas == NULL ? DISPLAY_HEIGHT : canvas->h; + + if (x1 > x2) { + uint8_t tmp = x1; + x1 = x2; + x2 = tmp; + } + + if (y < canvasHeight) { + for (uint16_t x = x1; x < x2 && x < canvasWidth; x++) { + Framebuffer_SetPixel(buffer, canvasOffsetX+x, canvasOffsetY+y, 0xff); + } + buffer->dirtyRanges[canvasOffsetY+y].min = MIN(buffer->dirtyRanges[y].min, canvasOffsetX+x1); + buffer->dirtyRanges[canvasOffsetY+y].max = MAX(buffer->dirtyRanges[y].max, canvasOffsetX+x2); + } +} + +void Framebuffer_DrawVLine(widget_t* canvas, framebuffer_t* buffer, uint8_t x, uint8_t y1, uint8_t y2) +{ + uint16_t canvasOffsetX = canvas == NULL ? 0 : canvas->x; + uint16_t canvasOffsetY = canvas == NULL ? 0 : canvas->y; + uint16_t canvasWidth = canvas == NULL ? DISPLAY_WIDTH : canvas->w; + uint16_t canvasHeight = canvas == NULL ? DISPLAY_HEIGHT : canvas->h; + + if (y1 > y2) { + uint8_t tmp = y1; + y1 = y2; + y2 = tmp; + } + + if (x < canvasWidth) { + for (uint16_t y = y1; y < y2 && y < canvasHeight; y++) { + Framebuffer_SetPixel(buffer, canvasOffsetX+x, canvasOffsetY+y, 0xff); + buffer->dirtyRanges[canvasOffsetY+y].min = MIN(buffer->dirtyRanges[y].min, canvasOffsetX+x); + buffer->dirtyRanges[canvasOffsetY+y].max = MAX(buffer->dirtyRanges[y].max, canvasOffsetX+x); + } + } +} + diff --git a/device/src/keyboard/oled/framebuffer.h b/device/src/keyboard/oled/framebuffer.h new file mode 100644 index 000000000..660c5ca60 --- /dev/null +++ b/device/src/keyboard/oled/framebuffer.h @@ -0,0 +1,69 @@ +#ifndef __FRAMEBUFFER_H__ +#define __FRAMEBUFFER_H__ + +// Includes: + + #include "oled_display.h" + #include + #include + #include "legacy/led_display.h" + #include + +// Macros: + +// Typedefs: + + typedef enum { + AlignmentType_Begin_ = 1, + AlignmentType_Center_ = 2, + AlignmentType_End_ = 3, + + AlignmentType_Begin = -((AlignmentType_Begin_ << 9) + 256), + AlignmentType_Center = -((AlignmentType_Center_ << 9) + 256), + AlignmentType_End = -((AlignmentType_End_ << 9) + 256), + } alignment_type_t; + + typedef struct { + uint8_t value; + uint8_t oldValue; + } pixel_t; + + typedef struct { + uint8_t min; + uint8_t max; + } range_t; + + typedef struct { + pixel_t buffer[DISPLAY_WIDTH*DISPLAY_HEIGHT/2]; + range_t dirtyRanges[DISPLAY_HEIGHT]; + } framebuffer_t; + + typedef struct widget_t widget_t; + +// Variables: + +// Functions: + + void Framebuffer_Clear(widget_t* canvas, framebuffer_t* buffer); + void Framebuffer_DrawHLine(widget_t* canvas, framebuffer_t* buffer, uint8_t x1, uint8_t x2, uint8_t y); + void Framebuffer_DrawVLine(widget_t* canvas, framebuffer_t* buffer, uint8_t x, uint8_t y1, uint8_t y2); + + // todo: currently we use 8 bit colors; refactor it to 4 bits. + static inline void Framebuffer_SetPixel(framebuffer_t* buffer, uint16_t x, uint16_t y, uint8_t value) + { + uint16_t index = (y*DISPLAY_WIDTH+x)/2; + uint8_t shadedValue = value >> 4; + if (x%2 == 1) { + buffer->buffer[index].value = (buffer->buffer[index].value & 0x0f) | (shadedValue << 4); + } else { + buffer->buffer[index].value = (buffer->buffer[index].value & 0xf0) | (shadedValue & 0x0f); + } + }; + + static inline pixel_t* Framebuffer_GetPixel(framebuffer_t* buffer, uint16_t x, uint16_t y) + { + uint16_t index = (y*DISPLAY_WIDTH+x)/2; + return &buffer->buffer[index]; + }; + +#endif diff --git a/device/src/keyboard/oled/oled.c b/device/src/keyboard/oled/oled.c new file mode 100644 index 000000000..66c6c276f --- /dev/null +++ b/device/src/keyboard/oled/oled.c @@ -0,0 +1,339 @@ +#include "device.h" +#include "framebuffer.h" +#include "oled.h" +#include "oled_display.h" +#include "oled_buffer.h" +#include "screens/screen_manager.h" +#include "legacy/event_scheduler.h" +#include "legacy/timer.h" +#include "legacy/led_manager.h" +#include "keyboard/oled/screens/screens.h" + +#if DEVICE_HAS_OLED + +#include +#include +#include "keyboard/oled/oled.h" +#include "keyboard/spi.h" + +// Thread definitions + +#define THREAD_STACK_SIZE 1000 +#define THREAD_PRIORITY 5 +#define OLED_FADE_TIME 2*255 +#define OLED_FADE_STEP 1 + +static K_THREAD_STACK_DEFINE(stack_area, THREAD_STACK_SIZE); +static struct k_thread thread_data; + +// OLED GPIOs + +const struct gpio_dt_spec oledEn = GPIO_DT_SPEC_GET(DT_ALIAS(oled_en), gpios); +const struct gpio_dt_spec oledResetDt = GPIO_DT_SPEC_GET(DT_ALIAS(oled_reset), gpios); +const struct gpio_dt_spec oledCsDt = GPIO_DT_SPEC_GET(DT_ALIAS(oled_cs), gpios); +const struct gpio_dt_spec oledA0Dt = GPIO_DT_SPEC_GET(DT_ALIAS(oled_a0), gpios); + +static uint8_t lastBrightness = 0xff; + +static void setOledCs(bool state) { + gpio_pin_set_dt(&oledCsDt, state); +} + +static void setA0(bool state) { + gpio_pin_set_dt(&oledA0Dt, state); +} + +static void oledCommand1(bool A0, uint8_t b1) { + setA0(A0); + setOledCs(true); + writeSpi(b1); + setOledCs(false); +} + +static void oledCommand2(bool A0, uint8_t b1, uint8_t b2) { + setA0(A0); + setOledCs(true); + writeSpi(b1); + writeSpi(b2); + setOledCs(false); +} + +static void setPositionTo(uint16_t x, uint16_t y, uint16_t lastWrittenPixelX, uint16_t lastWrittenPixelY) { + uint8_t columnAddress = (DISPLAY_WIDTH-1-x)/2; + + if (lastWrittenPixelX != x+2 || lastWrittenPixelY != y) { + setA0(0); + + uint8_t buf[4]; + uint8_t len; + + if (y != lastWrittenPixelY) { + buf[0] = OledCommand_SetRowAddress; + buf[1] = y; + buf[2] = OledCommand_SetColumnLow | (columnAddress & 0x0f); + buf[3] = OledCommand_SetColumnHigh | (columnAddress >> 4); + len = 4; + } else { + buf[0] = OledCommand_SetColumnLow | (columnAddress & 0x0f); + buf[1] = OledCommand_SetColumnHigh | (columnAddress >> 4); + len = 2; + } + + writeSpi2(buf, len); + setA0(1); + } +} + +static bool oledNeedsRedraw = false; +static k_tid_t oledThreadId = 0; + +static widget_t* currentScreen = NULL; +static uint16_t currentXShift = 0; +static uint16_t currentYShift = 0; +static bool wantScreenShift; + +static uint8_t computeBrightness() { + if (ActiveScreen == ScreenId_Debug && DisplayBrightness == 0) { + return 255; + } else { + return DisplayBrightness; + } +} + +static void forceRedraw() { + for (uint16_t x = 0; x < DISPLAY_WIDTH; x+=2) { + for (uint16_t y = 0; y < DISPLAY_HEIGHT; y++) { + pixel_t* p = Framebuffer_GetPixel(OledBuffer, x, y); + p->oldValue = p->value + 1; + } + } +} + +void Oled_ActivateScreen(widget_t* screen, bool forceRedraw) { + if (currentScreen != screen || forceRedraw) { + currentScreen = screen; + Framebuffer_Clear(NULL, OledBuffer); + currentScreen->layOut(currentScreen, currentXShift, currentYShift, DISPLAY_WIDTH - DISPLAY_SHIFTING_MARGIN, DISPLAY_HEIGHT - DISPLAY_SHIFTING_MARGIN); + } +} + +void Oled_UpdateBrightness() { + Oled_RequestRedraw(); +} + +void Oled_ShiftScreen() { + wantScreenShift = true; + Oled_RequestRedraw(); +} + +static void performScreenShift() { + static uint16_t shiftCounter = 0; + static bool initialized = false; + wantScreenShift = false; + + if (!initialized) { + shiftCounter = k_cycle_get_32() % (DISPLAY_SHIFTING_MARGIN*DISPLAY_SHIFTING_MARGIN); + initialized = true; + } + + shiftCounter = (shiftCounter + 7) % (DISPLAY_SHIFTING_MARGIN*DISPLAY_SHIFTING_MARGIN); + + currentXShift = shiftCounter / (DISPLAY_SHIFTING_MARGIN); + currentYShift = shiftCounter % (DISPLAY_SHIFTING_MARGIN); + + EventScheduler_Schedule(CurrentTime + DISPLAY_SHIFTING_PERIOD, EventSchedulerEvent_ShiftScreen, "Oled - shift screen"); + Oled_ActivateScreen(currentScreen, true); +} + +#define PIXEL(x, y) (OledBuffer->buffer[(y*DISPLAY_WIDTH+x)/2]) + +static bool shouldContinueWithoutPositionChange(uint16_t x, uint16_t y) { + static uint8_t lastX = 255, lastY = 255; + if (y == lastY && lastX < x) { + return true; + } + uint16_t max = MIN(DISPLAY_MIN_GAP_TO_SKIP*2, x); + for (uint8_t i = 2; i <= max; i += 2) { + if (PIXEL(x-i, y).value != PIXEL(x-i, y).oldValue) { + lastX = x-i; + lastY = y; + return true; + } + } + return false; +} + +static uint16_t roundToEven(uint16_t a) { + return a & ~1; +} + +static void adjustBrightness() { + uint8_t targetBrightness = computeBrightness(); + + uint8_t nextBrightness = lastBrightness; + + if (nextBrightness != targetBrightness) { + if (nextBrightness - OLED_FADE_STEP > targetBrightness) { + nextBrightness -= OLED_FADE_STEP; + } else if (nextBrightness + OLED_FADE_STEP < targetBrightness) { + nextBrightness += OLED_FADE_STEP; + } else { + nextBrightness = targetBrightness; + } + } + + if (nextBrightness == 0) { + oledCommand1(0, OledCommand_SetDisplayOff); + } else { + oledCommand1(0, OledCommand_SetDisplayOn); + oledCommand2(0, OledCommand_SetContrast, nextBrightness); + } + + lastBrightness = nextBrightness; +} + +static void diffUpdate() { + setA0(true); + setOledCs(true); + + // uint32_t time = k_uptime_get_32(); + + uint8_t buf[DISPLAY_WIDTH / 2]; + uint8_t buf_pos = 0; + + for (uint16_t y = 0; y < DISPLAY_HEIGHT; y++) { + uint16_t min = roundToEven(OledBuffer->dirtyRanges[y].min); + uint16_t max = roundToEven(OledBuffer->dirtyRanges[y].max); + for (uint16_t x = max; min <= x && x < DISPLAY_WIDTH; x -= 2) { + if (oledNeedsRedraw) { + setOledCs(false); + k_mutex_unlock(&SpiMutex); + return; + } + + static uint16_t lastWrittenPixelX = 0; + static uint16_t lastWrittenPixelY = 0; + + pixel_t* pixel = &PIXEL(x, y); + + if (pixel->value != pixel->oldValue) { + buf_pos = 0; + + setPositionTo(x, y, lastWrittenPixelX, lastWrittenPixelY); + + buf[buf_pos++] = pixel->value; + pixel->oldValue = pixel->value; + + while (shouldContinueWithoutPositionChange(x, y)) { + x -= 2; + buf[buf_pos++] = PIXEL(x, y).value; + PIXEL(x, y).oldValue = PIXEL(x, y).value; + } + + writeSpi2(buf, buf_pos); + + lastWrittenPixelX = x; + lastWrittenPixelY = y; + } + } + OledBuffer->dirtyRanges[y].min = 255; + OledBuffer->dirtyRanges[y].max = 0; + } + setOledCs(false); + // printk("update took %ims\n", k_uptime_get_32() - time); +} + +void sleepDisplay() { + while (computeBrightness() == 0 && lastBrightness == 0) { + k_sleep(K_FOREVER); + } +} + +void oledUpdater() { + k_mutex_lock(&SpiMutex, K_FOREVER); + oledCommand1(0, OledCommand_SetDisplayOn); + oledCommand2(0, OledCommand_SetContrast, 0xff); + oledCommand1(0, OledCommand_SetScanDirectionDown); + k_mutex_unlock(&SpiMutex); + + performScreenShift(); + currentScreen->draw(currentScreen, OledBuffer); + forceRedraw(); + + bool lastOledNeedsRedraw = true; + + while (true) { + { + k_mutex_lock(&SpiMutex, K_FOREVER); + + if (lastBrightness != computeBrightness()) { + adjustBrightness(); + } + + if (lastOledNeedsRedraw) { + lastOledNeedsRedraw = false; + diffUpdate(); + } + + k_mutex_unlock(&SpiMutex); + } + + if (!oledNeedsRedraw && lastBrightness == computeBrightness()) { + k_sleep(K_FOREVER); + } else { + k_sleep(K_MSEC(OLED_FADE_TIME / (255/OLED_FADE_STEP))); + } + + if (lastBrightness == 0) { + sleepDisplay(); + } + + lastOledNeedsRedraw = oledNeedsRedraw; + oledNeedsRedraw = false; + + if (wantScreenShift) { + performScreenShift(); + } + + currentScreen->draw(currentScreen, OledBuffer); + } +} + +void Oled_RequestRedraw() { + oledNeedsRedraw = true; + k_wakeup(oledThreadId); +} + +void InitOled(void) { + gpio_pin_configure_dt(&oledEn, GPIO_OUTPUT); + gpio_pin_set_dt(&oledEn, true); + + gpio_pin_configure_dt(&oledResetDt, GPIO_OUTPUT); + gpio_pin_set_dt(&oledResetDt, false); + k_msleep(1); + gpio_pin_set_dt(&oledResetDt, true); + + gpio_pin_configure_dt(&oledCsDt, GPIO_OUTPUT); + gpio_pin_configure_dt(&oledA0Dt, GPIO_OUTPUT); + + OledBuffer_Init(); + ScreenManager_Init(); + currentScreen = MainScreen; + + oledThreadId = k_thread_create( + &thread_data, stack_area, + K_THREAD_STACK_SIZEOF(stack_area), + oledUpdater, + NULL, NULL, NULL, + THREAD_PRIORITY, 0, K_NO_WAIT + ); + k_thread_name_set(&thread_data, "oled_updater"); +} + +#else // DEVICE_HAS_OLED + +void Oled_ActivateScreen(widget_t* screen, bool forceRedraw){}; +void Oled_RequestRedraw(){}; +void Oled_ShiftScreen(){}; + +#endif // DEVICE_HAS_OLED diff --git a/device/src/keyboard/oled/oled.h b/device/src/keyboard/oled/oled.h new file mode 100644 index 000000000..b54d40d8d --- /dev/null +++ b/device/src/keyboard/oled/oled.h @@ -0,0 +1,23 @@ +#ifndef __OLED_H__ +#define __OLED_H__ + +// Includes: + + #include "widgets/widget.h" + +// Variables: + + extern const struct gpio_dt_spec oledEn; + extern const struct gpio_dt_spec oledResetDt; + extern const struct gpio_dt_spec oledCsDt; + extern const struct gpio_dt_spec oledA0Dt; + +// Functions: + + void InitOled(void); + void Oled_ActivateScreen(widget_t* screen, bool forceRedraw); + void Oled_RequestRedraw(void); + void Oled_ShiftScreen(); + void Oled_UpdateBrightness(); + +#endif // __OLED_H__ diff --git a/device/src/keyboard/oled/oled_buffer.c b/device/src/keyboard/oled/oled_buffer.c new file mode 100644 index 000000000..734dc8984 --- /dev/null +++ b/device/src/keyboard/oled/oled_buffer.c @@ -0,0 +1,19 @@ +#include "oled_buffer.h" +#include +#include +#include +#include +#include "fonts/fonts.h" +#include "framebuffer.h" +#include "oled_text_renderer.h" +#include "oled.h" + +framebuffer_t oledBuffer; + +framebuffer_t* OledBuffer = (framebuffer_t*)&oledBuffer; + +void OledBuffer_Init() +{ + Framebuffer_DrawText(NULL, OledBuffer, AlignmentType_Center, AlignmentType_Center, &JetBrainsMono32, "Hello world!", NULL); +} + diff --git a/device/src/keyboard/oled/oled_buffer.h b/device/src/keyboard/oled/oled_buffer.h new file mode 100644 index 000000000..171bf1f50 --- /dev/null +++ b/device/src/keyboard/oled/oled_buffer.h @@ -0,0 +1,23 @@ +#ifndef __OLED_BUFFER_H__ +#define __OLED_BUFFER_H__ + +// Includes: + + #include + #include + #include "framebuffer.h" + +// Macros: + + +// Typedefs: + +// Variables: + + extern framebuffer_t* OledBuffer; + +// Functions: + + void OledBuffer_Init(); + +#endif diff --git a/device/src/keyboard/oled/oled_display.h b/device/src/keyboard/oled/oled_display.h new file mode 100644 index 000000000..82a11c58d --- /dev/null +++ b/device/src/keyboard/oled/oled_display.h @@ -0,0 +1,29 @@ +#ifndef __OLED_DISPLAY_H__ +#define __OLED_DISPLAY_H__ + +// Macros: + + #define DISPLAY_WIDTH 256 + #define DISPLAY_HEIGHT 64 + + #define DISPLAY_SHIFTING_MARGIN 4 + #define DISPLAY_SHIFTING_PERIOD 180000 + + #define DISPLAY_MIN_GAP_TO_SKIP 8 + + #define DISPLAY_USABLE_WIDTH (DISPLAY_WIDTH-DISPLAY_SHIFTING_MARGIN) + #define DISPLAY_USABLE_HEIGHT (DISPLAY_HEIGHT-DISPLAY_SHIFTING_MARGIN) + +// Typedefs: + +typedef enum { + OledCommand_SetDisplayOn = 0xaf, + OledCommand_SetDisplayOff = 0xae, + OledCommand_SetContrast = 0x81, + OledCommand_SetRowAddress = 0xb0, + OledCommand_SetColumnLow = 0x00, + OledCommand_SetColumnHigh = 0x10, + OledCommand_SetScanDirectionDown = 0xc8, +} oled_commands_t; + +#endif // __OLED_DISPLAY_H__ diff --git a/device/src/keyboard/oled/oled_text_renderer.c b/device/src/keyboard/oled/oled_text_renderer.c new file mode 100644 index 000000000..773a4f02f --- /dev/null +++ b/device/src/keyboard/oled/oled_text_renderer.c @@ -0,0 +1,233 @@ +#include "oled_text_renderer.h" +#include "framebuffer.h" +#include "lvgl/lvgl.h" +#include "fonts/fonts.h" +#include "oled_buffer.h" +#include +#include +#include +#include +#include "widgets/widget.h" +#include +#include +#include "legacy/str_utils.h" + +static int16_t computeAlignment(int16_t width, int16_t objectWidth, int16_t alignment) +{ + int16_t offset = -((-alignment & ((1 << 9) - 1)) - 256); + + switch ((-alignment) >> 9) { + default: + case AlignmentType_Begin_: + return offset; + case AlignmentType_Center_: + return width/2 - objectWidth/2 + offset; + case AlignmentType_End_: + return width - objectWidth + offset; + } +} + + +static uint8_t drawGlyph(widget_t* canvas, framebuffer_t* buffer, int16_t x, int16_t y, const lv_font_t* font, uint8_t glyphIdx, uint8_t color) +{ + int16_t canvasOffsetX = canvas == NULL ? 0 : canvas->x; + int16_t canvasOffsetY = canvas == NULL ? 0 : canvas->y; + int16_t canvasWidth = canvas == NULL ? DISPLAY_WIDTH : canvas->w; + int16_t canvasHeight = canvas == NULL ? DISPLAY_HEIGHT : canvas->h; + + const uint8_t* bitmap = font->dsc->glyph_bitmap; + const lv_font_fmt_txt_glyph_dsc_t* glyph = &font->dsc->glyph_dsc[glyphIdx]; + + int16_t rw = glyph->adv_w/16; + int16_t rh = font->line_height; + + // clear the area. Glyph bitmaps generally code just the non-empty bounding box, so full clearing is necessary + for (uint16_t i = MAX(y,0); i < MIN(canvasHeight, y+rh); i++) { + for (uint16_t j = MAX(x,0); j < MIN(canvasWidth, x+rw); j++) { + Framebuffer_SetPixel(buffer, canvasOffsetX+j, canvasOffsetY+i, 0); + } + } + + int16_t w = glyph->box_w; + int16_t h = glyph->box_h; + int16_t top = font->line_height - font->base_line - h - glyph->ofs_y; + + // draw the glyph + for (uint16_t iy = 0; iy < h; iy++) { + int16_t dstY = top+y+iy; + if (dstY < 0 || dstY >= canvasHeight) { + continue; + } + for (uint16_t ix = 0; ix < w; ix++) { + int16_t dstX = glyph->ofs_x+x+ix; + + if (dstX < 0 || dstX >= canvasWidth) { + continue; + } + + uint16_t pixelIndex = iy * w + ix; + uint8_t byte = bitmap[glyph->bitmap_index + pixelIndex/2]; + uint8_t pixelValue; + if (pixelIndex % 2 == 0) { + pixelValue = byte & 0xf0; + } else { + pixelValue = byte << 4; + } + + if (color == FontControl_NextCharGray) { + pixelValue /= 8; + } + if (color == FontControl_NextCharBlack) { + pixelValue = 0; + } + + Framebuffer_SetPixel(buffer, canvasOffsetX + dstX, canvasOffsetY + dstY, pixelValue); + } + } + + return rw; +} + +static uint8_t getUtf8Length(uint8_t firstByte) { + if ((firstByte & 0xe0) == 0xc0) { + return 2; + } else if ((firstByte & 0xf0) == 0xe0) { + return 3; + } else if ((firstByte & 0xf8) == 0xf0) { + return 4; + } else { + return 1; + } +} + +// TODO: return resulting bounds rectangle? +void Framebuffer_DrawText(widget_t* canvas, framebuffer_t* buffer, int16_t x, int16_t y, const lv_font_t* font, const char* text, const char* textEnd) +{ + bool truncated; + if (x < 0 || y < 0) { + int16_t canvasWidth = canvas == NULL ? DISPLAY_WIDTH : canvas->w; + int16_t canvasHeight = canvas == NULL ? DISPLAY_HEIGHT : canvas->h; + const char* truncatedEnd; + int16_t textWidth = Framebuffer_TextWidth(font, text, textEnd, canvasWidth, &truncated, &truncatedEnd); + int16_t textHeight = font->line_height; + + if (truncated) { + textEnd = truncatedEnd; + } + + if (x < 0) { + x = computeAlignment(canvasWidth, textWidth, x); + } + + if (y < 0) { + y = computeAlignment(canvasHeight, textHeight, y); + } + } + + uint8_t color = FontControl_NextCharWhite; + bool icon12 = false; + + uint16_t consumed = 0; + while (*text != '\0' && (textEnd == NULL || text < textEnd)) { + if (*text > 127) { + consumed += drawGlyph(canvas, buffer, x+consumed, y, font, '*'-31, color); + icon12 = false; + color = FontControl_NextCharWhite; + text+= getUtf8Length(*text); + } else if (*text >= 32) { + consumed += drawGlyph(canvas, buffer, x+consumed, y, icon12 ? &FontAwesome12 : font, (*text)-31, color); + icon12 = false; + color = FontControl_NextCharWhite; + text++; + } else if (*text < 32) { + switch (*text) { + case FontControl_NextCharBlack: + case FontControl_NextCharGray: + case FontControl_NextCharWhite: + color = *text; + break; + case FontControl_NextCharIcon12: + icon12 = true; + break; + } + text++; + } + } + + if (truncated) { + for (uint8_t i = 0; i < 3; i++) { + consumed += drawGlyph(canvas, buffer, x+consumed, y, font, '.'-31, color); + } + } +} + +static uint16_t getGlyphWidth(const lv_font_t* font, uint8_t glyphIdx) +{ + const lv_font_fmt_txt_glyph_dsc_t* someGlyph = &font->dsc->glyph_dsc[glyphIdx]; + return someGlyph->adv_w/16; +} + +uint16_t Framebuffer_GetGlyphWidth(const lv_font_t* font, uint8_t glyphIdx) +{ + return getGlyphWidth(font, glyphIdx-31); +} + +uint16_t Framebuffer_TextWidth(const lv_font_t* font, const char* text, const char* textEnd, uint16_t maxWidth, bool* truncated, const char** truncatedText) +{ + bool dummyBool; + const char* dummyChar; + + if (truncated == NULL) { + truncated = &dummyBool; + } + + if (truncatedText == NULL) { + truncatedText = &dummyChar; + } + + uint16_t dotsWidth = getGlyphWidth(font, '.'-31)*3; + + uint8_t color = FontControl_NextCharWhite; + bool icon12 = false; + + *truncatedText = text; + + uint16_t previousConsumed = 0; + uint16_t consumed = 0; + while (*text != '\0' && (textEnd == NULL || text < textEnd)) { + previousConsumed = consumed; + if (*text > 127) { + consumed += getGlyphWidth(font, '*'-31); + icon12 = false; + color = FontControl_NextCharWhite; + text+= getUtf8Length(*text); + } else if (*text >= 32) { + consumed += getGlyphWidth(icon12 ? &FontAwesome12 : font, (*text)-31); + icon12 = false; + color = FontControl_NextCharWhite; + text++; + } else if (*text < 32) { + switch (*text) { + case FontControl_NextCharBlack: + case FontControl_NextCharGray: + case FontControl_NextCharWhite: + color = *text; + break; + case FontControl_NextCharIcon12: + icon12 = true; + break; + } + text++; + } + + if ( consumed + dotsWidth < maxWidth ) { + *truncatedText = text; + } else { + *truncated = true; + return previousConsumed + dotsWidth; + } + } + + *truncated = false; + return consumed; +} diff --git a/device/src/keyboard/oled/oled_text_renderer.h b/device/src/keyboard/oled/oled_text_renderer.h new file mode 100644 index 000000000..5e9f00828 --- /dev/null +++ b/device/src/keyboard/oled/oled_text_renderer.h @@ -0,0 +1,32 @@ +#ifndef __OLED_TEXT_RENDERER_H__ +#define __OLED_TEXT_RENDERER_H__ + +// Includes: + + #include + #include "lvgl/lvgl.h" + #include "framebuffer.h" + #include "keyboard/oled/fonts/font_awesome_12.h" + +// Macros: + +// Variables: + +// Typedefs: + + typedef enum { + FontControl_NextCharGray = 1, + FontControl_NextCharWhite, + FontControl_NextCharBlack, + FontControl_NextCharIcon12, + } font_control_t; + + typedef struct widget_t widget_t; + +// Functions: + + void Framebuffer_DrawText(widget_t* canvas, framebuffer_t* buffer, int16_t x, int16_t y, const lv_font_t* font, const char* text, const char* textEnd); + uint16_t Framebuffer_GetGlyphWidth(const lv_font_t* font, uint8_t glyphIdx); + uint16_t Framebuffer_TextWidth(const lv_font_t* font, const char* text, const char* textEnd, uint16_t maxWidth, bool* truncated, const char** truncatedText); + +#endif diff --git a/device/src/keyboard/oled/screens/canvas_screen.c b/device/src/keyboard/oled/screens/canvas_screen.c new file mode 100644 index 000000000..67e68afb1 --- /dev/null +++ b/device/src/keyboard/oled/screens/canvas_screen.c @@ -0,0 +1,32 @@ +#include "canvas_screen.h" +#include "keyboard/oled/oled_buffer.h" +#include "keyboard/oled/oled.h" +#include "keyboard/oled/widgets/widgets.h" +#include "keyboard/oled/screens/screen_manager.h" +#include + +widget_t* CanvasScreen; + +void CanvasScreen_Draw(uint16_t x, uint16_t y, uint8_t* data, uint16_t len) { + ScreenManager_ActivateScreen(ScreenId_Canvas); + widget_t canvas = (widget_t) { + .x = x, + .y = y, + .w = MIN(DISPLAY_WIDTH-x, len), + .h = 1, + }; + // this is neccesary to mark the buffer region as dirty. + Framebuffer_Clear(&canvas, OledBuffer); + for (uint16_t i = 0; i < len; i++) { + if (x >= DISPLAY_WIDTH) { + printk("Usb attempting to draw outside of display range!\n"); + } + Framebuffer_SetPixel(OledBuffer, x, y, data[i]); + x++; + } + Oled_RequestRedraw(); +} + +void CanvasScreen_Init() { + CanvasScreen = &CanvasWidget; +} diff --git a/device/src/keyboard/oled/screens/canvas_screen.h b/device/src/keyboard/oled/screens/canvas_screen.h new file mode 100644 index 000000000..e18022874 --- /dev/null +++ b/device/src/keyboard/oled/screens/canvas_screen.h @@ -0,0 +1,25 @@ +#ifndef __CANVAS_SCREEN_H__ +#define __CANVAS_SCREEN_H__ + +// Includes: + + #include + #include + #include "../widgets/widget.h" + +// Macros: + + #define CANVAS_TIMEOUT 60000 + +// Typedefs: + +// Variables: + + extern widget_t* CanvasScreen; + +// Functions: + + void CanvasScreen_Init(); + void CanvasScreen_Draw(uint16_t x, uint16_t y, uint8_t* data, uint16_t len); + +#endif diff --git a/device/src/keyboard/oled/screens/debug_screen.c b/device/src/keyboard/oled/screens/debug_screen.c new file mode 100644 index 000000000..20d6b4747 --- /dev/null +++ b/device/src/keyboard/oled/screens/debug_screen.c @@ -0,0 +1,8 @@ +#include "debug_screen.h" +#include "keyboard/oled/widgets/widgets.h" + +widget_t* DebugScreen; + +void DebugScreen_Init() { + DebugScreen = &ConsoleWidget; +} diff --git a/device/src/keyboard/oled/screens/debug_screen.h b/device/src/keyboard/oled/screens/debug_screen.h new file mode 100644 index 000000000..a705ff2e3 --- /dev/null +++ b/device/src/keyboard/oled/screens/debug_screen.h @@ -0,0 +1,24 @@ +#ifndef __DEBUG_SCREEN_H__ +#define __DEBUG_SCREEN_H__ + +// Includes: + + #include + #include + #include "keyboard/oled/widgets/widget.h" + +// Macros: + +// Typedefs: + + #define DEBUG_SCREEN_NOTIFICATION_TIMEOUT 10000 + +// Variables: + + extern widget_t* DebugScreen; + +// Functions: + + void DebugScreen_Init(); + +#endif diff --git a/device/src/keyboard/oled/screens/main_screen.c b/device/src/keyboard/oled/screens/main_screen.c new file mode 100644 index 000000000..daa13d8b2 --- /dev/null +++ b/device/src/keyboard/oled/screens/main_screen.c @@ -0,0 +1,21 @@ +#include "main_screen.h" +#include "keyboard/oled/widgets/widgets.h" + + +static widget_t statusSplitter; +static widget_t keymapSplitter; +static widget_t keymapLayerSplitter; + +widget_t* MainScreen; + +void MainScreen_Init() +{ + const uint8_t statusHeight = 18; + const uint8_t keymapHeight = 28; + + keymapLayerSplitter = SplitterWidget_BuildHorizontal(&KeymapWidget, &LayerWidget, 128, false); + keymapSplitter = SplitterWidget_BuildVertical(&KeymapLayerWidget, &TargetWidget, keymapHeight, false); + statusSplitter = SplitterWidget_BuildVertical(&StatusWidget, &keymapSplitter, statusHeight, false); + + MainScreen = &statusSplitter; +} diff --git a/device/src/keyboard/oled/screens/main_screen.h b/device/src/keyboard/oled/screens/main_screen.h new file mode 100644 index 000000000..9f29f231d --- /dev/null +++ b/device/src/keyboard/oled/screens/main_screen.h @@ -0,0 +1,22 @@ +#ifndef __MAIN_SCREEN_H__ +#define __MAIN_SCREEN_H__ + +// Includes: + + #include + #include + #include "keyboard/oled/widgets/widget.h" + +// Macros: + +// Typedefs: + +// Variables: + + extern widget_t* MainScreen; + +// Functions: + + void MainScreen_Init(); + +#endif diff --git a/device/src/keyboard/oled/screens/pairing_screen.c b/device/src/keyboard/oled/screens/pairing_screen.c new file mode 100644 index 000000000..f4c2bf809 --- /dev/null +++ b/device/src/keyboard/oled/screens/pairing_screen.c @@ -0,0 +1,148 @@ +#include "pairing_screen.h" +#include "keyboard/oled/widgets/widgets.h" +#include "keyboard/oled/screens/screen_manager.h" +#include "keyboard/oled/oled.h" +#include "keyboard/oled/oled_buffer.h" +#include "logger.h" +#include "legacy/lufa/HIDClassCommon.h" +#include "bt_conn.h" +#include "screen_manager.h" +#include "legacy/key_action.h" + +static widget_t splitterWidget; +static widget_t questionLine; +static widget_t answerLine; + +static widget_t pairingFailed; +static widget_t pairingSucceeded; + +widget_t* PairingScreen; +widget_t* PairingSucceededScreen; +widget_t* PairingFailedScreen; + +static uint8_t passwordCharCount = 0; +static uint8_t password[PASSWORD_LENGTH]; +static char passwordTextBuffer[2*PASSWORD_LENGTH] = { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '\0'}; +static unsigned int correctPassword; + +static void updatePasswordText() +{ + for (uint8_t i = 0; i < PASSWORD_LENGTH; i++) { + if (i < passwordCharCount) { + passwordTextBuffer[i*2] = '0'+password[i]; + } else { + passwordTextBuffer[i*2] = '_'; + } + } + + TextWidget_SetText(&answerLine, passwordTextBuffer); + Oled_RequestRedraw(); +} + +unsigned int computePassword() +{ + unsigned int res = 0; + for (uint8_t i = 0; i < PASSWORD_LENGTH; i++) { + res = res*10 + password[i]; + } + return res; +} + +static void registerPasswordDigit(uint8_t digit) +{ + if (passwordCharCount < PASSWORD_LENGTH) { + password[passwordCharCount++] = digit; + } + + updatePasswordText(); + + if (passwordCharCount == PASSWORD_LENGTH) { + if (computePassword() == correctPassword) { + num_comp_reply(1); + ScreenManager_ActivateScreen(ScreenId_PairingSucceeded); + } else { + num_comp_reply(0); + ScreenManager_ActivateScreen(ScreenId_PairingFailed); + } + } +} + +const rgb_t* PairingScreen_ActionColor(key_action_t* action) { + static const rgb_t black = { 0, 0, 0 }; + static const rgb_t green = { 0, 0xff, 0 }; + static const rgb_t red = { 0xff, 0, 0 }; + static const rgb_t blue = { 0, 0, 0xff }; + + if ( + action->type != KeyActionType_Keystroke + || action->keystroke.keystrokeType != KeystrokeType_Basic + || action->keystroke.modifiers != 0 + ) { + return &black; + } + + switch (action->keystroke.scancode) { + case HID_KEYBOARD_SC_ESCAPE: + return &red; + case HID_KEYBOARD_SC_DELETE: + case HID_KEYBOARD_SC_BACKSPACE: + return &blue; + case HID_KEYBOARD_SC_1_AND_EXCLAMATION ... HID_KEYBOARD_SC_9_AND_OPENING_PARENTHESIS: + case HID_KEYBOARD_SC_0_AND_CLOSING_PARENTHESIS: + case HID_KEYBOARD_SC_KEYPAD_1_AND_END ... HID_KEYBOARD_SC_KEYPAD_9_AND_PAGE_UP: + case HID_KEYBOARD_SC_KEYPAD_0_AND_INSERT: + return &green; + default: + return &black; + } +} + +void PairingScreen_RegisterScancode(uint8_t scancode) +{ + switch (scancode) + { + case HID_KEYBOARD_SC_ESCAPE: + num_comp_reply(0); + ScreenManager_ActivateScreen(ScreenId_PairingFailed); + break; + case HID_KEYBOARD_SC_DELETE: + case HID_KEYBOARD_SC_BACKSPACE: + passwordCharCount--; + updatePasswordText(); + break; + case HID_KEYBOARD_SC_1_AND_EXCLAMATION ... HID_KEYBOARD_SC_9_AND_OPENING_PARENTHESIS: + registerPasswordDigit(scancode - HID_KEYBOARD_SC_1_AND_EXCLAMATION+1); + break; + case HID_KEYBOARD_SC_0_AND_CLOSING_PARENTHESIS: + registerPasswordDigit(0); + break; + case HID_KEYBOARD_SC_KEYPAD_1_AND_END ... HID_KEYBOARD_SC_KEYPAD_9_AND_PAGE_UP: + registerPasswordDigit(scancode - HID_KEYBOARD_SC_KEYPAD_1_AND_END+1); + break; + case HID_KEYBOARD_SC_KEYPAD_0_AND_INSERT: + registerPasswordDigit(0); + break; + } +} + +void PairingScreen_AskForPassword(unsigned int pass) +{ + correctPassword = pass; + passwordCharCount = 0; + updatePasswordText(); + ScreenManager_ActivateScreen(ScreenId_Pairing); +} + +void PairingScreen_Init() +{ + questionLine = TextWidget_Build(&JetBrainsMono16, "Pairing code:"); + answerLine = TextWidget_Build(&JetBrainsMono16, passwordTextBuffer); + splitterWidget = SplitterWidget_BuildVertical(&questionLine, &answerLine, (DISPLAY_HEIGHT-DISPLAY_SHIFTING_MARGIN)/2, false); + PairingScreen = &splitterWidget; + + pairingFailed = TextWidget_Build(&JetBrainsMono16, "Pairing failed!"); + PairingFailedScreen = &pairingFailed; + + pairingSucceeded = TextWidget_Build(&JetBrainsMono16, "Pairing succeeded!"); + PairingSucceededScreen = &pairingSucceeded; +} diff --git a/device/src/keyboard/oled/screens/pairing_screen.h b/device/src/keyboard/oled/screens/pairing_screen.h new file mode 100644 index 000000000..2daaa5bb6 --- /dev/null +++ b/device/src/keyboard/oled/screens/pairing_screen.h @@ -0,0 +1,30 @@ +#ifndef __PAIRING_SCREEN_H__ +#define __PAIRING_SCREEN_H__ + +// Includes: + + #include + #include + #include "../widgets/widget.h" + #include "legacy/key_action.h" + +// Macros: + + #define PASSWORD_LENGTH 6 + +// Typedefs: + +// Variables: + + extern widget_t* PairingScreen; + extern widget_t* PairingSucceededScreen; + extern widget_t* PairingFailedScreen; + +// Functions: + + void PairingScreen_Init(); + void PairingScreen_RegisterScancode(uint8_t scancode); + void PairingScreen_AskForPassword(unsigned int pass); + const rgb_t* PairingScreen_ActionColor(key_action_t* action); + +#endif diff --git a/device/src/keyboard/oled/screens/screen_manager.c b/device/src/keyboard/oled/screens/screen_manager.c new file mode 100644 index 000000000..7b23abf4a --- /dev/null +++ b/device/src/keyboard/oled/screens/screen_manager.c @@ -0,0 +1,77 @@ +#include "screen_manager.h" +#include "canvas_screen.h" +#include "keyboard/oled/widgets/widgets.h" +#include "keyboard/oled/screens/screens.h" +#include "keyboard/oled/oled.h" +#include "legacy/timer.h" +#include "legacy/event_scheduler.h" +#include "legacy/timer.h" +#include "legacy/event_scheduler.h" +#include "legacy/ledmap.h" + +screen_id_t ActiveScreen = ScreenId_Main; + +static void onExit(screen_id_t screen) { + switch(screen) { + case ScreenId_Pairing: + Ledmap_ResetTemporaryLedBacklightingMode(); + Ledmap_UpdateBacklightLeds(); + break; + default: + break; + } +} + +void ScreenManager_ActivateScreen(screen_id_t screen) +{ + widget_t* screenPtr = NULL; + + onExit(ActiveScreen); + + switch(screen) { + case ScreenId_Pairing: + screenPtr = PairingScreen; + Ledmap_SetTemporaryLedBacklightingMode(BacklightingMode_Numpad); + Ledmap_UpdateBacklightLeds(); + break; + case ScreenId_Debug: + screenPtr = DebugScreen; + EventScheduler_Reschedule(CurrentTime + DEBUG_SCREEN_NOTIFICATION_TIMEOUT, EventSchedulerEvent_SwitchScreen, "ScreenManager - switch to main screen"); + break; + case ScreenId_Main: + screenPtr = MainScreen; + break; + case ScreenId_PairingSucceeded: + screenPtr = PairingSucceededScreen; + EventScheduler_Schedule(CurrentTime + SCREEN_NOTIFICATION_TIMEOUT, EventSchedulerEvent_SwitchScreen, "ScreenManager - switch to main screen"); + break; + case ScreenId_PairingFailed: + screenPtr = PairingFailedScreen; + EventScheduler_Schedule(CurrentTime + SCREEN_NOTIFICATION_TIMEOUT, EventSchedulerEvent_SwitchScreen, "ScreenManager - switch to main screen"); + break; + case ScreenId_Canvas: + EventScheduler_Reschedule(CurrentTime + CANVAS_TIMEOUT, EventSchedulerEvent_SwitchScreen, "ScreenManager - switch to main screen"); + screenPtr = CanvasScreen; + break; + default: + break; + } + + ActiveScreen = screen; + Oled_ActivateScreen(screenPtr, false); + Oled_RequestRedraw(); +} + +void ScreenManager_SwitchScreenEvent() +{ + ScreenManager_ActivateScreen(ScreenId_Main); +} + +void ScreenManager_Init() +{ + WidgetStore_Init(); + PairingScreen_Init(); + CanvasScreen_Init(); + MainScreen_Init(); + DebugScreen_Init(); +} diff --git a/device/src/keyboard/oled/screens/screen_manager.h b/device/src/keyboard/oled/screens/screen_manager.h new file mode 100644 index 000000000..4e8be73cd --- /dev/null +++ b/device/src/keyboard/oled/screens/screen_manager.h @@ -0,0 +1,36 @@ +#ifndef __SCREEN_MANAGER_H__ +#define __SCREEN_MANAGER_H__ + +// Includes: + + #include + #include + #include "../widgets/widget.h" + +// Macros: + +#define SCREEN_NOTIFICATION_TIMEOUT 3000 + +// Typedefs: + + typedef enum { + ScreenId_Main, + ScreenId_Debug, + ScreenId_Pairing, + ScreenId_PairingFailed, + ScreenId_PairingSucceeded, + ScreenId_Canvas, + } screen_id_t; + +// Variables: + + extern bool ScreenManager_AwaitsInput; + extern screen_id_t ActiveScreen; + +// Functions: + + void ScreenManager_ActivateScreen(screen_id_t screen); + void ScreenManager_SwitchScreenEvent(); + void ScreenManager_Init(); + +#endif diff --git a/device/src/keyboard/oled/screens/screens.h b/device/src/keyboard/oled/screens/screens.h new file mode 100644 index 000000000..abbafdb9f --- /dev/null +++ b/device/src/keyboard/oled/screens/screens.h @@ -0,0 +1,20 @@ +#ifndef __SCREENS_H__ +#define __SCREENS_H__ + +// Includes: + + #include + #include + #include "pairing_screen.h" + #include "main_screen.h" + #include "debug_screen.h" + +// Macros: + +// Typedefs: + +// Variables: + +// Functions: + +#endif diff --git a/device/src/keyboard/oled/widgets/console_widget.c b/device/src/keyboard/oled/widgets/console_widget.c new file mode 100644 index 000000000..50869683c --- /dev/null +++ b/device/src/keyboard/oled/widgets/console_widget.c @@ -0,0 +1,83 @@ +#include "console_widget.h" +#include "widget.h" +#include +#include +#include +#include +#include +#include "../fonts/fonts.h" +#include "../framebuffer.h" +#include "../oled_buffer.h" +#include "../oled_text_renderer.h" +#include "../oled.h" +#include "../screens/screen_manager.h" + +#define MIN_CHAR_WIDTH 5 +#define MIN_CHAR_HEIGHT 7 +#define CONSOLE_BUFFER_LINE_COUNT (DISPLAY_HEIGHT/MIN_CHAR_HEIGHT+1) +#define CONSOLE_BUFFER_LINE_LENGTH (DISPLAY_WIDTH/MIN_CHAR_WIDTH+2) + +static char consoleBuffer[CONSOLE_BUFFER_LINE_COUNT][CONSOLE_BUFFER_LINE_LENGTH] = {}; +static uint8_t consoleBufferStart = 0; +static bool consoleBufferIsDirty = true; + +void ConsoleWidget_LayOut(widget_t* self, uint8_t x, uint8_t y, uint8_t w, uint8_t h) +{ + self->x = x; + self->y = y; + self->w = w; + self->h = h; + self->dirty = true; +} + +void ConsoleWidget_Draw(widget_t* self, framebuffer_t* buffer) +{ + if (self->dirty || consoleBufferIsDirty) { + self->dirty = false; + consoleBufferIsDirty = false; + + const lv_font_t* logFont = &CustomMono8; + uint8_t line_height = logFont->line_height; + + Framebuffer_Clear(self, buffer); + + for (uint8_t line = 0; line < CONSOLE_BUFFER_LINE_COUNT; line++) { + const char* text = &consoleBuffer[(consoleBufferStart + CONSOLE_BUFFER_LINE_COUNT - line)%CONSOLE_BUFFER_LINE_COUNT][0]; + + Framebuffer_DrawText(self, buffer, 0, self->h - line_height*(line+1), logFont, text, NULL); + } + } +} + +widget_t ConsoleWidget_Build() +{ + return (widget_t){ + .type = WidgetType_Console, + .layOut = &ConsoleWidget_LayOut, + .draw = &ConsoleWidget_Draw, + .dirty = true, + }; +} + +void Oled_LogConstant(const char* text) +{ + consoleBufferStart = (consoleBufferStart+1) % CONSOLE_BUFFER_LINE_COUNT; + strncpy(&consoleBuffer[consoleBufferStart][0], text, CONSOLE_BUFFER_LINE_LENGTH); + consoleBuffer[consoleBufferStart][CONSOLE_BUFFER_LINE_LENGTH-1] = '\0'; + + consoleBufferIsDirty = true; + + ScreenManager_ActivateScreen(ScreenId_Debug); + // Widget_Refresh(NULL); +} + +void Oled_Log(const char *fmt, ...) +{ + va_list myargs; + va_start(myargs, fmt); + char buffer[256]; + vsprintf(buffer, fmt, myargs); + Oled_LogConstant(buffer); +} + + diff --git a/device/src/keyboard/oled/widgets/console_widget.h b/device/src/keyboard/oled/widgets/console_widget.h new file mode 100644 index 000000000..1ca23afe3 --- /dev/null +++ b/device/src/keyboard/oled/widgets/console_widget.h @@ -0,0 +1,23 @@ +#ifndef __CONSOLE_WIDGET_H__ +#define __CONSOLE_WIDGET_H__ + +// Includes: + + #include + #include + #include "widget.h" + +// Macros: + +// Typedefs: + +// Variables: + +// Functions: + + widget_t ConsoleWidget_Build(); + + void Oled_LogConstant(const char* text); + void Oled_Log(const char *fmt, ...); + +#endif diff --git a/device/src/keyboard/oled/widgets/custom_widget.c b/device/src/keyboard/oled/widgets/custom_widget.c new file mode 100644 index 000000000..7408f0e4f --- /dev/null +++ b/device/src/keyboard/oled/widgets/custom_widget.c @@ -0,0 +1,26 @@ +#include "custom_widget.h" +#include "widget.h" +#include + +void CustomWidget_LayOut(widget_t* self, uint8_t x, uint8_t y, uint8_t w, uint8_t h) +{ + self->x = x; + self->y = y; + self->w = w; + self->h = h; + self->dirty = true; +} + +void CustomWidget_Draw(widget_t* self, framebuffer_t* buffer) +{ +} + +widget_t CustomWidget_Build(void (*draw)(widget_t* self, framebuffer_t* buffer)) +{ + return (widget_t){ + .type = WidgetType_Custom, + .layOut = &CustomWidget_LayOut, + .draw = draw == NULL ? &CustomWidget_Draw : draw, + .dirty = true, + }; +} diff --git a/device/src/keyboard/oled/widgets/custom_widget.h b/device/src/keyboard/oled/widgets/custom_widget.h new file mode 100644 index 000000000..867c1b0bb --- /dev/null +++ b/device/src/keyboard/oled/widgets/custom_widget.h @@ -0,0 +1,21 @@ +#ifndef __CUSTOM_WIDGET_H__ +#define __CUSTOM_WIDGET_H__ + +// Includes: + + #include + #include + #include "widget.h" + +// Macros: + +// Typedefs: + +// Variables: + +// Functions: + + void CustomWidget_LayOut(widget_t* self, uint8_t x, uint8_t y, uint8_t w, uint8_t h); + widget_t CustomWidget_Build(void (*draw)(widget_t* self, framebuffer_t* buffer)); + +#endif diff --git a/device/src/keyboard/oled/widgets/frame_widget.c b/device/src/keyboard/oled/widgets/frame_widget.c new file mode 100644 index 000000000..2b543fb3a --- /dev/null +++ b/device/src/keyboard/oled/widgets/frame_widget.c @@ -0,0 +1,35 @@ +#include "frame_widget.h" +#include "widget.h" + +void FrameWidget_LayOut(widget_t* self, uint8_t x, uint8_t y, uint8_t w, uint8_t h) +{ + self->x = x; + self->y = y; + self->w = w; + self->h = h; + self->dirty = true; + self->simpleContentData.content->layOut(self->simpleContentData.content, x+1, y+1, w-2, h-2); +} + +void FrameWidget_Draw(widget_t* self, framebuffer_t* buffer) +{ + if (self->dirty) { + self->dirty = false; + Framebuffer_DrawHLine(self, buffer, 0, self->w, 0); + Framebuffer_DrawHLine(self, buffer, 0, self->w, self->h-1); + Framebuffer_DrawVLine(self, buffer, 0, 0, self->h); + Framebuffer_DrawVLine(self, buffer, self->w-1, 0, self->h-1); + } + self->simpleContentData.content->draw(self->simpleContentData.content, buffer); +} + +widget_t FrameWidget_Build(widget_t* content) +{ + return (widget_t){ + .type = WidgetType_Frame, + .simpleContentData.content = content, + .layOut = &FrameWidget_LayOut, + .draw = &FrameWidget_Draw, + .dirty = true, + }; +} diff --git a/device/src/keyboard/oled/widgets/frame_widget.h b/device/src/keyboard/oled/widgets/frame_widget.h new file mode 100644 index 000000000..c3ecaeab6 --- /dev/null +++ b/device/src/keyboard/oled/widgets/frame_widget.h @@ -0,0 +1,20 @@ +#ifndef __FRAME_WIDGET_H__ +#define __FRAME_WIDGET_H__ + +// Includes: + + #include + #include + #include "widget.h" + +// Macros: + +// Typedefs: + +// Variables: + +// Functions: + + widget_t FrameWidget_Build(widget_t* content); + +#endif diff --git a/device/src/keyboard/oled/widgets/splitter_widget.c b/device/src/keyboard/oled/widgets/splitter_widget.c new file mode 100644 index 000000000..25520bf4b --- /dev/null +++ b/device/src/keyboard/oled/widgets/splitter_widget.c @@ -0,0 +1,63 @@ +#include "splitter_widget.h" +#include "widget.h" + +void SplitterWidget_LayOut(widget_t* self, uint8_t x, uint8_t y, uint8_t w, uint8_t h) +{ + self->x = x; + self->y = y; + self->w = w; + self->h = h; + self->dirty = true; + uint8_t splitWidth = self->splitterData.splitLine ? 1 : 0; + if (self->type == WidgetType_VSplitter) { + self->splitterData.child1->layOut(self->splitterData.child1, x, y, w, self->splitterData.splitAt); + self->splitterData.child2->layOut(self->splitterData.child2, x, y+self->splitterData.splitAt+splitWidth, w, h-splitWidth-self->splitterData.splitAt); + } else { + self->splitterData.child1->layOut(self->splitterData.child1, x, y, self->splitterData.splitAt, h); + self->splitterData.child2->layOut(self->splitterData.child2, x+self->splitterData.splitAt+splitWidth, y, w-splitWidth-self->splitterData.splitAt, h); + } + +} + +void SplitterWidget_Draw(widget_t* self, framebuffer_t* buffer) +{ + if (self->dirty) { + self->dirty = false; + if (self->type == WidgetType_VSplitter) { + Framebuffer_DrawHLine(self, buffer, 0, self->w, self->splitterData.splitAt); + } else { + Framebuffer_DrawVLine(self, buffer, self->splitterData.splitAt, 0, self->h); + } + } + + self->splitterData.child1->draw(self->splitterData.child1, buffer); + self->splitterData.child2->draw(self->splitterData.child2, buffer); +} + +widget_t SplitterWidget_BuildVertical(widget_t* child1, widget_t* child2, uint8_t splitAt, bool splitLine) +{ + return (widget_t){ + .type = WidgetType_VSplitter, + .splitterData.child1 = child1, + .splitterData.child2 = child2, + .splitterData.splitAt = splitAt, + .splitterData.splitLine = splitLine, + .layOut = &SplitterWidget_LayOut, + .draw = &SplitterWidget_Draw, + .dirty = true, + }; +} + +widget_t SplitterWidget_BuildHorizontal(widget_t* child1, widget_t* child2, uint8_t splitAt, bool splitLine) +{ + return (widget_t){ + .type = WidgetType_HSplitter, + .splitterData.child1 = child1, + .splitterData.child2 = child2, + .splitterData.splitAt = splitAt, + .splitterData.splitLine = splitLine, + .layOut = &SplitterWidget_LayOut, + .draw = &SplitterWidget_Draw, + .dirty = true, + }; +} diff --git a/device/src/keyboard/oled/widgets/splitter_widget.h b/device/src/keyboard/oled/widgets/splitter_widget.h new file mode 100644 index 000000000..c929f2d33 --- /dev/null +++ b/device/src/keyboard/oled/widgets/splitter_widget.h @@ -0,0 +1,21 @@ +#ifndef __SPLITTER_WIDGET_H__ +#define __SPLITTER_WIDGET_H__ + +// Includes: + + #include + #include + #include "widget.h" + +// Macros: + +// Typedefs: + +// Variables: + +// Functions: + + widget_t SplitterWidget_BuildVertical(widget_t* child1, widget_t* child2, uint8_t splitAt, bool splitLine); + widget_t SplitterWidget_BuildHorizontal(widget_t* child1, widget_t* child2, uint8_t splitAt, bool splitLine); + +#endif diff --git a/device/src/keyboard/oled/widgets/text_widget.c b/device/src/keyboard/oled/widgets/text_widget.c new file mode 100644 index 000000000..e3e89e1d7 --- /dev/null +++ b/device/src/keyboard/oled/widgets/text_widget.c @@ -0,0 +1,57 @@ +#include "text_widget.h" +#include "keyboard/oled/widgets/widgets.h" +#include "keyboard/oled/oled.h" +#include +#include "legacy/str_utils.h" + +void TextWidget_Draw(widget_t* self, framebuffer_t* buffer) +{ + if (self->dirty) { + self->dirty = false; + Framebuffer_Clear(self, buffer); + if (self->textData.textProvider != NULL) { + self->textData.text = self->textData.textProvider(); + } + if (self->textData.text.start != NULL) { + Framebuffer_DrawText(self, buffer, AlignmentType_Center, AlignmentType_Center, self->textData.font, self->textData.text.start, self->textData.text.end); + } + } +} + +void TextWidget_SetText(widget_t* self, char* text) +{ + self->dirty = true; + self->textData.text.start = text; + Oled_RequestRedraw(); +} + +widget_t TextWidget_Build(const lv_font_t* font, char* text) +{ + return (widget_t){ + .type = WidgetType_Text, + .layOut = &CustomWidget_LayOut, + .draw = &TextWidget_Draw, + .dirty = true, + .textData = { + .font = font, + .text = { .start = text, .end = NULL }, + .textProvider = NULL, + } + }; +} + +widget_t TextWidget_BuildRefreshable(const lv_font_t* font, string_segment_t (*textProvider)()) { + return (widget_t){ + .type = WidgetType_Text, + .layOut = &CustomWidget_LayOut, + .draw = &TextWidget_Draw, + .dirty = true, + .textData = { + .font = font, + .text = { .start = NULL, .end = NULL }, + .textProvider = textProvider, + } + }; +} + + diff --git a/device/src/keyboard/oled/widgets/text_widget.h b/device/src/keyboard/oled/widgets/text_widget.h new file mode 100644 index 000000000..366d9579f --- /dev/null +++ b/device/src/keyboard/oled/widgets/text_widget.h @@ -0,0 +1,31 @@ +#ifndef __TEXT_WIDGET_H__ +#define __TEXT_WIDGET_H__ + +// Includes: + + #include + #include + #include "widget.h" + +// Macros: + +// Typedefs: + +typedef enum { + TextWidgetId_Layer, + TextWidgetId_Status, + TextWidgetId_Keymap, + TextWidgetId_Count, +} text_widget_id_t; + +// Variables: + +// Functions: + + void TextWidget_SetText(widget_t* self, char* text); + widget_t TextWidget_Build(const lv_font_t* font, char* text); + widget_t TextWidget_BuildRefreshable(const lv_font_t* font, string_segment_t (*textProvider)()); + + void InitTextWidgets(); + +#endif diff --git a/device/src/keyboard/oled/widgets/widget.c b/device/src/keyboard/oled/widgets/widget.c new file mode 100644 index 000000000..f1ba80b51 --- /dev/null +++ b/device/src/keyboard/oled/widgets/widget.c @@ -0,0 +1,14 @@ +#include "widget.h" +#include "../oled.h" +#include "device.h" +#include + +void Widget_Refresh(widget_t* widget) +{ +#if DEVICE_HAS_OLED + if (widget != NULL) { + widget->dirty = true; + } + Oled_RequestRedraw(); +#endif +} diff --git a/device/src/keyboard/oled/widgets/widget.h b/device/src/keyboard/oled/widgets/widget.h new file mode 100644 index 000000000..1a140d0c6 --- /dev/null +++ b/device/src/keyboard/oled/widgets/widget.h @@ -0,0 +1,63 @@ +#ifndef __WIDGET_H__ +#define __WIDGET_H__ + +// Includes: + + #include + #include + #include "../framebuffer.h" + #include "keyboard/oled/fonts/fonts.h" + #include "legacy/str_utils.h" + +// Macros: + +// Typedefs: + + typedef enum { + WidgetType_VSplitter, + WidgetType_HSplitter, + WidgetType_Frame, + WidgetType_Console, + WidgetType_Text, + WidgetType_Custom, + } widget_type_t; + + typedef struct widget_t widget_t; + + struct widget_t { + uint8_t x; + uint8_t y; + uint8_t w; + uint8_t h; + + void (*layOut)(widget_t* self, uint8_t x, uint8_t y, uint8_t w, uint8_t h); + void (*draw)(widget_t* self, framebuffer_t* buffer); + + widget_type_t type; + bool dirty; + + union { + struct { + widget_t* child1; + widget_t* child2; + uint8_t splitAt; + bool splitLine; + } splitterData; + struct { + widget_t* content; + } simpleContentData; + struct { + string_segment_t text; + const lv_font_t* font; + string_segment_t (*textProvider)(); + } textData; + }; + }; + +// Variables: + +// Functions: + + void Widget_Refresh(widget_t* widget); + +#endif diff --git a/device/src/keyboard/oled/widgets/widget_store.c b/device/src/keyboard/oled/widgets/widget_store.c new file mode 100644 index 000000000..2d682104a --- /dev/null +++ b/device/src/keyboard/oled/widgets/widget_store.c @@ -0,0 +1,210 @@ +#include "console_widget.h" +#include "custom_widget.h" +#include "keyboard/oled/widgets/custom_widget.h" +#include "keyboard/oled/oled.h" +#include "keyboard/oled/widgets/widgets.h" +#include "keyboard/oled/fonts/fonts.h" +#include "keyboard/oled/framebuffer.h" +#include "keyboard/oled/oled_text_renderer.h" +#include "text_widget.h" +#include "widget.h" +#include "legacy/keymap.h" +#include "legacy/layer.h" +#include "legacy/layer_switcher.h" +#include "legacy/str_utils.h" +#include "keyboard/uart.h" +#include "bt_conn.h" +#include "state_sync.h" +#include +#include +#include "device_state.h" +#include "usb/usb_compatibility.h" +#include "macros/status_buffer.h" + +widget_t KeymapWidget; +widget_t LayerWidget; +widget_t KeymapLayerWidget; +widget_t StatusWidget; +widget_t CanvasWidget; +widget_t ConsoleWidget; +widget_t TargetWidget; + +static string_segment_t getLayerText() { + return (string_segment_t){ .start = LayerNames[ActiveLayer], .end = NULL }; +} + +static string_segment_t getKeymapText() { + if (strcmp(AllKeymaps[CurrentKeymapIndex].abbreviation, "FTY") == 0) { + return (string_segment_t){ .start = "Factory default", .end = NULL }; + } else { + return GetKeymapName(CurrentKeymapIndex); + } +} + + +static string_segment_t getTargetText() { + if (DeviceState_IsConnected(ConnectionId_UsbHid)) { + return (string_segment_t){ .start = "USB Cable", .end = NULL }; + } else if (DeviceState_IsConnected(ConnectionId_Dongle)) { + return (string_segment_t){ .start = "UHK Dongle", .end = NULL }; + } else if (DeviceState_IsConnected(ConnectionId_BluetoothHid)) { + return (string_segment_t){ .start = "Bluetooth", .end = NULL }; + } else { + return (string_segment_t){ .start = "Disconnected", .end = NULL }; + } +} + + +ATTR_UNUSED static string_segment_t getKeymapLayerText() { +#define BUFFER_LENGTH 32 + static char buffer[BUFFER_LENGTH] = { [BUFFER_LENGTH-1] = 0 }; + string_segment_t layerText = getLayerText(); + string_segment_t keymapText = getKeymapText(); + if (ActiveLayer == LayerId_Base) { + snprintf(buffer, BUFFER_LENGTH-1, "%.*s", SegmentLen(keymapText), keymapText.start); + } else { + snprintf(buffer, BUFFER_LENGTH-1, "%.*s: %.*s", SegmentLen(keymapText), keymapText.start, SegmentLen(layerText), layerText.start); + } + return (string_segment_t){ .start = buffer, .end = NULL }; +#undef BUFFER_LENGTH +} + +static string_segment_t getLeftStatusText() { +#define BUFFER_LENGTH 10 + static char buffer [BUFFER_LENGTH] = { [BUFFER_LENGTH-1] = 0 }; + font_icons_t icon = FontIcon_CircleXmarkLarge; + if (DEVICE_ID == DeviceId_Uhk80_Right) { + if (Uart_IsConnected()) { + icon = FontIcon_PlugsConnected; + } else if (Bt_DeviceIsConnected(DeviceId_Uhk80_Left)) { + icon = FontIcon_SignalStream; + } + } + snprintf(buffer, BUFFER_LENGTH-1, "%c%c", (char)FontControl_NextCharIcon12, (char)icon); + return (string_segment_t){ .start = buffer, .end = NULL }; +#undef BUFFER_LENGTH +} + +static void getBatteryStatusText(device_id_t deviceId, battery_state_t* battery, char* buffer, bool fixed) { + char percSign = !battery->powered ? '-' : battery->batteryCharging ? '+' : '%'; + if (!DeviceState_IsDeviceConnected(deviceId)) { + sprintf(buffer, " "); + } else if (!battery->batteryPresent) { + sprintf(buffer, " "); + } else { + sprintf(buffer, fixed ? "%3i%c" : "%i%c", battery->batteryPercentage, percSign); + } +} + +static string_segment_t getRightStatusText() { +#define BUFFER_LENGTH 22 +#define BAT_BUFFER_LENGTH 10 + static char buffer [BUFFER_LENGTH] = { [BUFFER_LENGTH-1] = 0 }; + char leftBattery[BAT_BUFFER_LENGTH]; + char rightBattery[BAT_BUFFER_LENGTH]; + if (SyncLeftHalfState.battery.batteryPresent && SyncRightHalfState.battery.batteryPresent) { + getBatteryStatusText(DeviceId_Uhk80_Left, &SyncLeftHalfState.battery, leftBattery, true); + getBatteryStatusText(DeviceId_Uhk80_Right, &SyncRightHalfState.battery, rightBattery, true); + snprintf(buffer, BUFFER_LENGTH-1, "%s %s", leftBattery, rightBattery); + } else if (SyncLeftHalfState.battery.batteryPresent) { + getBatteryStatusText(DeviceId_Uhk80_Left, &SyncLeftHalfState.battery, leftBattery, false); + snprintf(buffer, BUFFER_LENGTH-1, "L%s", leftBattery); + } else if (SyncRightHalfState.battery.batteryPresent) { + getBatteryStatusText(DeviceId_Uhk80_Right, &SyncRightHalfState.battery, rightBattery, false); + snprintf(buffer, BUFFER_LENGTH-1, "R%s", rightBattery); + } else { + snprintf(buffer, BUFFER_LENGTH-1, ""); + } + return (string_segment_t){ .start = buffer, .end = NULL }; +#undef BAT_BUFFER_LENGTH +#undef BUFFER_LENGTH +} + +static string_segment_t getErrorIndicatorText() { + static char buffer [3] = {}; + sprintf(buffer, "%c%c", (char)FontControl_NextCharIcon12, (char)FontIcon_TriangleExclamation); + return (string_segment_t){ .start = buffer, .end = NULL }; +} + +static string_segment_t getKeyboardLedsStateText() { + static char buffer [8] = {}; + const uint8_t variant = 3; + switch (variant) { + case 0: + sprintf(buffer, "%cC %cN", + KeyboardLedsState.capsLock ? FontControl_NextCharWhite : FontControl_NextCharGray, + KeyboardLedsState.numLock ? FontControl_NextCharWhite : FontControl_NextCharGray + ); + break; + case 1: + sprintf(buffer, "%cA %c1", + KeyboardLedsState.capsLock ? FontControl_NextCharWhite : FontControl_NextCharGray, + KeyboardLedsState.numLock ? FontControl_NextCharWhite : FontControl_NextCharGray + ); + break; + case 2: + sprintf(buffer, "%c%c%c %c%c%c", + KeyboardLedsState.capsLock ? FontControl_NextCharWhite : FontControl_NextCharGray, + FontControl_NextCharIcon12, + FontIcon_LockA, + KeyboardLedsState.numLock ? FontControl_NextCharWhite : FontControl_NextCharGray, + FontControl_NextCharIcon12, + FontIcon_LockHashtag + ); + break; + case 3: + sprintf(buffer, "%c%c%c %c%c%c", + KeyboardLedsState.capsLock ? FontControl_NextCharWhite : FontControl_NextCharGray, + FontControl_NextCharIcon12, + FontIcon_LockSquareA, + KeyboardLedsState.numLock ? FontControl_NextCharWhite : FontControl_NextCharGray, + FontControl_NextCharIcon12, + FontIcon_LockSquareOne + ); + break; + } + return (string_segment_t){ .start = buffer, .end = NULL }; +} + + +static void drawStatus(widget_t* self, framebuffer_t* buffer) +{ + if (self->dirty) { + self->dirty = false; + Framebuffer_Clear(self, buffer); + Framebuffer_DrawText(self, buffer, AlignmentType_Begin + 5, AlignmentType_Center, &JetBrainsMono12, getLeftStatusText().start, NULL); + if (Macros_StatusBufferError) { + Framebuffer_DrawText(self, buffer, AlignmentType_Center - 30, AlignmentType_Center, &JetBrainsMono12, getErrorIndicatorText().start, NULL); + } + Framebuffer_DrawText(self, buffer, AlignmentType_Center, AlignmentType_Center, &JetBrainsMono12, getKeyboardLedsStateText().start, NULL); + Framebuffer_DrawText(self, buffer, AlignmentType_End, AlignmentType_Center, &JetBrainsMono12, getRightStatusText().start, NULL); + } +} + +static void drawKeymapLayer(widget_t* self, framebuffer_t* buffer) +{ + if (self->dirty) { + self->dirty = false; + Framebuffer_Clear(self, buffer); + const lv_font_t* keymapFont = &JetBrainsMono16; + const lv_font_t* layerFont = &JetBrainsMono12; + string_segment_t keymapText = getKeymapText(); + string_segment_t layerText = getLayerText(); + uint16_t keymapWidth = Framebuffer_TextWidth(keymapFont, keymapText.start, keymapText.end, self->w, NULL, NULL); + Framebuffer_DrawText(self, buffer, self->w/2 - keymapWidth/2, AlignmentType_Center, keymapFont, keymapText.start, keymapText.end); + if (ActiveLayer != LayerId_Base) { + Framebuffer_DrawText(self, buffer, self->w/2 + keymapWidth/2 + 10, AlignmentType_Center+(keymapFont->line_height - layerFont->line_height)/2, layerFont, layerText.start, layerText.end); + } + } +} + +void WidgetStore_Init() +{ + LayerWidget = TextWidget_BuildRefreshable(&JetBrainsMono16, &getLayerText); + KeymapWidget = TextWidget_BuildRefreshable(&JetBrainsMono24, &getKeymapText); + TargetWidget = TextWidget_BuildRefreshable(&JetBrainsMono12, &getTargetText); + KeymapLayerWidget = CustomWidget_Build(&drawKeymapLayer); + StatusWidget = CustomWidget_Build(&drawStatus); + CanvasWidget = CustomWidget_Build(NULL); + ConsoleWidget = ConsoleWidget_Build(); +} diff --git a/device/src/keyboard/oled/widgets/widget_store.h b/device/src/keyboard/oled/widgets/widget_store.h new file mode 100644 index 000000000..69dfae186 --- /dev/null +++ b/device/src/keyboard/oled/widgets/widget_store.h @@ -0,0 +1,30 @@ +#ifndef __WIDGET_STOR_H__ +#define __WIDGET_STOR_H__ + +// Includes: + + #include + #include + #include "widget.h" + +// Macros: + +// Typedefs: + +// Variables: + + extern widget_t KeymapWidget; + extern widget_t LayerWidget; + extern widget_t KeymapLayerWidget; + extern widget_t StatusWidget; + extern widget_t CanvasWidget; + extern widget_t ConsoleWidget; + extern widget_t TargetWidget; + +// Functions: + + void WidgetStore_Init(); + +#endif + + diff --git a/device/src/keyboard/oled/widgets/widgets.h b/device/src/keyboard/oled/widgets/widgets.h new file mode 100644 index 000000000..33ec185dd --- /dev/null +++ b/device/src/keyboard/oled/widgets/widgets.h @@ -0,0 +1,16 @@ +#ifndef __WIDGETS_H__ +#define __WIDGETS_H__ + +#include "keyboard/oled/widgets/widget.h" +#include "keyboard/oled/framebuffer.h" +#include "keyboard/oled/fonts/fonts.h" +#include "keyboard/oled/oled_text_renderer.h" +#include "keyboard/oled/widgets/widget.h" +#include "keyboard/oled/widgets/text_widget.h" +#include "keyboard/oled/widgets/custom_widget.h" +#include "keyboard/oled/widgets/frame_widget.h" +#include "keyboard/oled/widgets/console_widget.h" +#include "keyboard/oled/widgets/splitter_widget.h" +#include "keyboard/oled/widgets/widget_store.h" + +#endif diff --git a/device/src/keyboard/spi.c b/device/src/keyboard/spi.c new file mode 100644 index 000000000..77a45c413 --- /dev/null +++ b/device/src/keyboard/spi.c @@ -0,0 +1,44 @@ +#include "keyboard/spi.h" +#include + +struct k_mutex SpiMutex; + +const struct device *spi0_dev = DEVICE_DT_GET(DT_NODELABEL(spi1)); + +static struct spi_config spiConf = { + .frequency = 32000000U, + .operation = (SPI_OP_MODE_MASTER | SPI_WORD_SET(8) | SPI_TRANSFER_MSB) +}; + + +uint8_t buf[1] = {1}; +struct spi_buf spiBuf[] = { + { + .buf = &buf, + .len = 1, + } +}; + +const struct spi_buf_set spiBufSet = { + .buffers = spiBuf, + .count = 1, +}; + +void writeSpi(uint8_t data) +{ + buf[0] = data; + spiBuf[0].buf = buf; + spiBuf[0].len = 1; + spi_write(spi0_dev, &spiConf, &spiBufSet); +} + +void writeSpi2(uint8_t* data, uint8_t len) +{ + spiBuf[0].buf = data; + spiBuf[0].len = len; + spi_write(spi0_dev, &spiConf, &spiBufSet); +} + +void InitSpi(void) { + k_mutex_init(&SpiMutex); +} diff --git a/device/src/keyboard/spi.h b/device/src/keyboard/spi.h new file mode 100644 index 000000000..ffc270039 --- /dev/null +++ b/device/src/keyboard/spi.h @@ -0,0 +1,21 @@ +#ifndef __SPI_H__ +#define __SPI_H__ + +// Includes: + + #include + #include + +// Macros: + +// Variables: + + extern struct k_mutex SpiMutex; + +// Functions: + + extern void writeSpi(uint8_t data); + extern void writeSpi2(uint8_t* data, uint8_t len); + extern void InitSpi(void); + +#endif // __SPI_H__ diff --git a/device/src/keyboard/uart.c b/device/src/keyboard/uart.c new file mode 100644 index 000000000..a6a7f3621 --- /dev/null +++ b/device/src/keyboard/uart.c @@ -0,0 +1,277 @@ +#include +#include +#include "legacy/timer.h" +#include "uart.h" +#include "messenger.h" +#include "messenger_queue.h" +#include "device.h" +#include "device_state.h" +#include "legacy/debug.h" +#include "legacy/event_scheduler.h" + +// Thread definitions + +#define THREAD_STACK_SIZE 1000 +#define THREAD_PRIORITY 5 + +static K_THREAD_STACK_DEFINE(stack_area, THREAD_STACK_SIZE); +static struct k_thread thread_data; + +#define END_BYTE 0xFE +#define ESCAPE_BYTE 0xFD + +// UART definitions + +const struct device *uart_dev = DEVICE_DT_GET(DT_NODELABEL(uart1)); + +#define TX_BUF_SIZE UART_MAX_PACKET_LENGTH*2+1 +uint8_t txBuffer[TX_BUF_SIZE]; +uint16_t txPosition = 0; + +#define UART_SLOTS 1 +K_SEM_DEFINE(txBufferBusy, UART_SLOTS, UART_SLOTS); + +#define RX_BUF_SIZE UART_MAX_PACKET_LENGTH +uint8_t* rxBuffer = NULL; +uint16_t rxPosition = 0; + +#define BUF_SIZE TX_BUF_SIZE +uint8_t *rxbuf; +uint8_t rxbuf1[BUF_SIZE]; +uint8_t rxbuf2[BUF_SIZE]; + +uint32_t lastPingTime = -2*UART_TIMEOUT; + +bool isConnected = false; + +static void appendRxByte(uint8_t byte) { + if (rxPosition < RX_BUF_SIZE) { + rxBuffer[rxPosition++] = byte; + } else { + printk("Uart error: too long message in rx buffer, length: %i, begins with [%i, %i, ...]\n", rxPosition, rxBuffer[0], rxBuffer[1]); + } +} + +static void rxPacketReceived() { + lastPingTime = k_uptime_get(); + uint16_t len = rxPosition; + + if (len == 0) { + // we received ping + } else { + uint8_t* oldPacket = rxBuffer; + + rxBuffer = MessengerQueue_AllocateMemory(); + rxPosition = 0; + + if (DEVICE_IS_UHK80_RIGHT) { + Messenger_Enqueue(DeviceId_Uhk80_Left, oldPacket, len); + } else if (DEVICE_IS_UHK80_LEFT) { + Messenger_Enqueue(DeviceId_Uhk80_Right, oldPacket, len); + } + } +} + +static void processIncomingByte(uint8_t byte) { + static bool escaping = false; + switch (byte) { + case END_BYTE: + if (escaping) { + appendRxByte(byte); + escaping = false; + } else { + rxPacketReceived(); + } + break; + case ESCAPE_BYTE: + if (escaping) { + appendRxByte(byte); + escaping = false; + } else { + escaping = true; + } + break; + default: + appendRxByte(byte); + break; + } +} + +static void uart_callback(const struct device *dev, struct uart_event *evt, void *user_data) { + int err; + + switch (evt->type) { + case UART_TX_DONE: + k_sem_give(&txBufferBusy); + break; + + case UART_TX_ABORTED: + uart_tx(uart_dev, txBuffer, txPosition, UART_TIMEOUT); + printk("Tx aborted, retrying\n"); + break; + + case UART_RX_RDY: + for (uint16_t i = 0; i < evt->data.rx.len; i++) { + uint8_t byte = evt->data.rx.buf[evt->data.rx.offset+i]; + processIncomingByte(byte); + } + break; + + case UART_RX_BUF_REQUEST: + { + rxbuf = (rxbuf == rxbuf1) ? rxbuf2 : rxbuf1; + + err = uart_rx_buf_rsp(uart_dev, rxbuf, BUF_SIZE); + if (err != 0) { + printk("Could not provide new buffer because %i\n", err); + } + __ASSERT(err == 0, "Failed to provide new buffer"); + break; + } + + case UART_RX_BUF_RELEASED: + break; + + case UART_RX_DISABLED: + printk("UART_RX_DISABLED\n"); + CurrentTime = k_uptime_get(); + EventScheduler_Schedule(CurrentTime + 1000, EventSchedulerEvent_ReenableUart, "reenable uart"); + break; + + case UART_RX_STOPPED: + printk("UART_RX_STOPPED\n"); + CurrentTime = k_uptime_get(); + EventScheduler_Schedule(CurrentTime + 1000, EventSchedulerEvent_ReenableUart, "reenable uart"); + break; + } +} + + +static void appendTxByte(uint8_t byte) { + if (txPosition < TX_BUF_SIZE) { + txBuffer[txPosition++] = byte; + } else { + printk("Uart error: too long message in tx buffer\n"); + } +} + +static void processOutgoingByte(uint8_t byte) { + switch (byte) { + case END_BYTE: + appendTxByte(ESCAPE_BYTE); + appendTxByte(END_BYTE); + break; + case ESCAPE_BYTE: + appendTxByte(ESCAPE_BYTE); + appendTxByte(ESCAPE_BYTE); + break; + default: + appendTxByte(byte); + break; + } +} + +void Uart_SendPacket(const uint8_t* data, uint16_t len) { + SEM_TAKE(&txBufferBusy); + + txPosition = 0; + + if (len > 0) { + processOutgoingByte(DEVICE_ID); + processOutgoingByte(DEVICE_ID == DeviceId_Uhk80_Right ? DeviceId_Uhk80_Left : DeviceId_Uhk80_Right); + } + + for (uint16_t i = 0; i < len; i++) { + processOutgoingByte(data[i]); + } + + appendTxByte(END_BYTE); + + uart_tx(uart_dev, txBuffer, txPosition, UART_TIMEOUT); +} + +void Uart_SendMessage(message_t msg) { + SEM_TAKE(&txBufferBusy); + + txPosition = 0; + + processOutgoingByte(msg.src); + processOutgoingByte(msg.dst); + + for (uint8_t id = 0; id < msg.idsUsed; id++) { + processOutgoingByte(msg.messageId[id]); + } + + for (uint16_t i = 0; i < msg.len; i++) { + processOutgoingByte(msg.data[i]); + } + + appendTxByte(END_BYTE); + + uart_tx(uart_dev, txBuffer, txPosition, UART_TIMEOUT); +} + +static void ping() { + Uart_SendPacket(NULL, 0); +} + +bool Uart_IsConnected() { + return isConnected; +} + +static void updateConnectionState() { + uint32_t pingDiff = (k_uptime_get() - lastPingTime); + bool newIsConnected = pingDiff < UART_TIMEOUT; + if (isConnected != newIsConnected) { + isConnected = newIsConnected; + DeviceState_TriggerUpdate(); + if (!isConnected) { + k_sem_init(&txBufferBusy, UART_SLOTS, UART_SLOTS); + } + } +} + +void testUart() { + while (1) { + ping(); + updateConnectionState(); + k_sleep(K_MSEC(UART_TIMEOUT/2)); + } +} + +void InitUart(void) { + rxBuffer = MessengerQueue_AllocateMemory(); + + uart_callback_set(uart_dev, uart_callback, NULL); + rxbuf = rxbuf1; + Uart_Enable(); + + k_thread_create( + &thread_data, stack_area, + K_THREAD_STACK_SIZEOF(stack_area), + testUart, + NULL, NULL, NULL, + THREAD_PRIORITY, 0, K_NO_WAIT + ); + k_thread_name_set(&thread_data, "test_uart"); +} + +bool Uart_Availability(messenger_availability_op_t operation) { + switch (operation) { + case MessengerAvailabilityOp_InquireOneEmpty: + return k_sem_count_get(&txBufferBusy) > 0; + case MessengerAvailabilityOp_InquireAllEmpty: + return k_sem_count_get(&txBufferBusy) == UART_SLOTS; + case MessengerAvailabilityOp_BlockTillOneEmpty: + k_sem_take(&txBufferBusy, K_FOREVER); + k_sem_give(&txBufferBusy); + return true; + default: + return false; + } +} + +void Uart_Enable() { + printk("Enabling UART\n"); + uart_rx_enable(uart_dev, rxbuf, BUF_SIZE, UART_TIMEOUT); +} diff --git a/device/src/keyboard/uart.h b/device/src/keyboard/uart.h new file mode 100644 index 000000000..89fcd85a5 --- /dev/null +++ b/device/src/keyboard/uart.h @@ -0,0 +1,27 @@ +#ifndef __UART_H__ +#define __UART_H__ + +// Includes: + + #include "messenger.h" + #include "link_protocol.h" + +// Macros: + + #define UART_TIMEOUT 2000 + #define UART_MAX_PACKET_LENGTH MAX_LINK_PACKET_LENGTH + +// Variables: + + extern const struct device *uart_dev; + +// Functions: + + bool Uart_IsConnected(); + void Uart_SendPacket(const uint8_t* data, uint16_t len); + void Uart_SendMessage(message_t msg); + bool Uart_Availability(messenger_availability_op_t total); + void Uart_Enable(); + void InitUart(void); + +#endif // __UART_H__ diff --git a/device/src/legacy/arduino_hid/ConsumerAPI.h b/device/src/legacy/arduino_hid/ConsumerAPI.h new file mode 120000 index 000000000..81839e6f1 --- /dev/null +++ b/device/src/legacy/arduino_hid/ConsumerAPI.h @@ -0,0 +1 @@ +../../../../right/src/arduino_hid/ConsumerAPI.h \ No newline at end of file diff --git a/device/src/legacy/arduino_hid/SystemAPI.h b/device/src/legacy/arduino_hid/SystemAPI.h new file mode 120000 index 000000000..f6a065be8 --- /dev/null +++ b/device/src/legacy/arduino_hid/SystemAPI.h @@ -0,0 +1 @@ +../../../../right/src/arduino_hid/SystemAPI.h \ No newline at end of file diff --git a/device/src/legacy/caret_config.c b/device/src/legacy/caret_config.c new file mode 120000 index 000000000..c4eda29e4 --- /dev/null +++ b/device/src/legacy/caret_config.c @@ -0,0 +1 @@ +../../../right/src/caret_config.c \ No newline at end of file diff --git a/device/src/legacy/caret_config.h b/device/src/legacy/caret_config.h new file mode 120000 index 000000000..1b5fa2fb3 --- /dev/null +++ b/device/src/legacy/caret_config.h @@ -0,0 +1 @@ +../../../right/src/caret_config.h \ No newline at end of file diff --git a/device/src/legacy/config_manager.c b/device/src/legacy/config_manager.c new file mode 120000 index 000000000..454030746 --- /dev/null +++ b/device/src/legacy/config_manager.c @@ -0,0 +1 @@ +../../../right/src/config_manager.c \ No newline at end of file diff --git a/device/src/legacy/config_manager.h b/device/src/legacy/config_manager.h new file mode 120000 index 000000000..fa3bffa45 --- /dev/null +++ b/device/src/legacy/config_manager.h @@ -0,0 +1 @@ +../../../right/src/config_manager.h \ No newline at end of file diff --git a/device/src/legacy/config_parser/basic_types.c b/device/src/legacy/config_parser/basic_types.c new file mode 120000 index 000000000..af120a88d --- /dev/null +++ b/device/src/legacy/config_parser/basic_types.c @@ -0,0 +1 @@ +../../../../right/src/config_parser/basic_types.c \ No newline at end of file diff --git a/device/src/legacy/config_parser/basic_types.h b/device/src/legacy/config_parser/basic_types.h new file mode 120000 index 000000000..49c15dae4 --- /dev/null +++ b/device/src/legacy/config_parser/basic_types.h @@ -0,0 +1 @@ +../../../../right/src/config_parser/basic_types.h \ No newline at end of file diff --git a/device/src/legacy/config_parser/config_globals.c b/device/src/legacy/config_parser/config_globals.c new file mode 120000 index 000000000..a12d48b8a --- /dev/null +++ b/device/src/legacy/config_parser/config_globals.c @@ -0,0 +1 @@ +../../../../right/src/config_parser/config_globals.c \ No newline at end of file diff --git a/device/src/legacy/config_parser/config_globals.h b/device/src/legacy/config_parser/config_globals.h new file mode 120000 index 000000000..5dc84014b --- /dev/null +++ b/device/src/legacy/config_parser/config_globals.h @@ -0,0 +1 @@ +../../../../right/src/config_parser/config_globals.h \ No newline at end of file diff --git a/device/src/legacy/config_parser/error_reporting.c b/device/src/legacy/config_parser/error_reporting.c new file mode 120000 index 000000000..fefc49287 --- /dev/null +++ b/device/src/legacy/config_parser/error_reporting.c @@ -0,0 +1 @@ +../../../../right/src/config_parser/error_reporting.c \ No newline at end of file diff --git a/device/src/legacy/config_parser/error_reporting.h b/device/src/legacy/config_parser/error_reporting.h new file mode 120000 index 000000000..cad46a086 --- /dev/null +++ b/device/src/legacy/config_parser/error_reporting.h @@ -0,0 +1 @@ +../../../../right/src/config_parser/error_reporting.h \ No newline at end of file diff --git a/device/src/legacy/config_parser/parse_config.c b/device/src/legacy/config_parser/parse_config.c new file mode 120000 index 000000000..9f022856b --- /dev/null +++ b/device/src/legacy/config_parser/parse_config.c @@ -0,0 +1 @@ +../../../../right/src/config_parser/parse_config.c \ No newline at end of file diff --git a/device/src/legacy/config_parser/parse_config.h b/device/src/legacy/config_parser/parse_config.h new file mode 120000 index 000000000..a8aecc277 --- /dev/null +++ b/device/src/legacy/config_parser/parse_config.h @@ -0,0 +1 @@ +../../../../right/src/config_parser/parse_config.h \ No newline at end of file diff --git a/device/src/legacy/config_parser/parse_host_connection.c b/device/src/legacy/config_parser/parse_host_connection.c new file mode 120000 index 000000000..734ff0120 --- /dev/null +++ b/device/src/legacy/config_parser/parse_host_connection.c @@ -0,0 +1 @@ +../../../../right/src/config_parser/parse_host_connection.c \ No newline at end of file diff --git a/device/src/legacy/config_parser/parse_host_connection.h b/device/src/legacy/config_parser/parse_host_connection.h new file mode 120000 index 000000000..7155652c4 --- /dev/null +++ b/device/src/legacy/config_parser/parse_host_connection.h @@ -0,0 +1 @@ +../../../../right/src/config_parser/parse_host_connection.h \ No newline at end of file diff --git a/device/src/legacy/config_parser/parse_keymap.c b/device/src/legacy/config_parser/parse_keymap.c new file mode 120000 index 000000000..63cf99fff --- /dev/null +++ b/device/src/legacy/config_parser/parse_keymap.c @@ -0,0 +1 @@ +../../../../right/src/config_parser/parse_keymap.c \ No newline at end of file diff --git a/device/src/legacy/config_parser/parse_keymap.h b/device/src/legacy/config_parser/parse_keymap.h new file mode 120000 index 000000000..5a4447a10 --- /dev/null +++ b/device/src/legacy/config_parser/parse_keymap.h @@ -0,0 +1 @@ +../../../../right/src/config_parser/parse_keymap.h \ No newline at end of file diff --git a/device/src/legacy/config_parser/parse_macro.c b/device/src/legacy/config_parser/parse_macro.c new file mode 120000 index 000000000..bc869228f --- /dev/null +++ b/device/src/legacy/config_parser/parse_macro.c @@ -0,0 +1 @@ +../../../../right/src/config_parser/parse_macro.c \ No newline at end of file diff --git a/device/src/legacy/config_parser/parse_macro.h b/device/src/legacy/config_parser/parse_macro.h new file mode 120000 index 000000000..e37827061 --- /dev/null +++ b/device/src/legacy/config_parser/parse_macro.h @@ -0,0 +1 @@ +../../../../right/src/config_parser/parse_macro.h \ No newline at end of file diff --git a/device/src/legacy/config_parser/parse_module_config.c b/device/src/legacy/config_parser/parse_module_config.c new file mode 120000 index 000000000..2fd3971bb --- /dev/null +++ b/device/src/legacy/config_parser/parse_module_config.c @@ -0,0 +1 @@ +../../../../right/src/config_parser/parse_module_config.c \ No newline at end of file diff --git a/device/src/legacy/config_parser/parse_module_config.h b/device/src/legacy/config_parser/parse_module_config.h new file mode 120000 index 000000000..1abf9e4d6 --- /dev/null +++ b/device/src/legacy/config_parser/parse_module_config.h @@ -0,0 +1 @@ +../../../../right/src/config_parser/parse_module_config.h \ No newline at end of file diff --git a/device/src/legacy/debug.c b/device/src/legacy/debug.c new file mode 120000 index 000000000..6be27d501 --- /dev/null +++ b/device/src/legacy/debug.c @@ -0,0 +1 @@ +../../../right/src/debug.c \ No newline at end of file diff --git a/device/src/legacy/debug.h b/device/src/legacy/debug.h new file mode 120000 index 000000000..cb3eb62dc --- /dev/null +++ b/device/src/legacy/debug.h @@ -0,0 +1 @@ +../../../right/src/debug.h \ No newline at end of file diff --git a/device/src/legacy/eeprom.c b/device/src/legacy/eeprom.c new file mode 120000 index 000000000..1ea632f18 --- /dev/null +++ b/device/src/legacy/eeprom.c @@ -0,0 +1 @@ +../../../right/src/eeprom.c \ No newline at end of file diff --git a/device/src/legacy/eeprom.h b/device/src/legacy/eeprom.h new file mode 120000 index 000000000..7997074cb --- /dev/null +++ b/device/src/legacy/eeprom.h @@ -0,0 +1 @@ +../../../right/src/eeprom.h \ No newline at end of file diff --git a/device/src/legacy/event_scheduler.c b/device/src/legacy/event_scheduler.c new file mode 120000 index 000000000..5774cae3c --- /dev/null +++ b/device/src/legacy/event_scheduler.c @@ -0,0 +1 @@ +../../../right/src/event_scheduler.c \ No newline at end of file diff --git a/device/src/legacy/event_scheduler.h b/device/src/legacy/event_scheduler.h new file mode 120000 index 000000000..6f073e3a9 --- /dev/null +++ b/device/src/legacy/event_scheduler.h @@ -0,0 +1 @@ +../../../right/src/event_scheduler.h \ No newline at end of file diff --git a/device/src/legacy/host_connection.c b/device/src/legacy/host_connection.c new file mode 120000 index 000000000..946909088 --- /dev/null +++ b/device/src/legacy/host_connection.c @@ -0,0 +1 @@ +../../../right/src/host_connection.c \ No newline at end of file diff --git a/device/src/legacy/host_connection.h b/device/src/legacy/host_connection.h new file mode 120000 index 000000000..bf11f4788 --- /dev/null +++ b/device/src/legacy/host_connection.h @@ -0,0 +1 @@ +../../../right/src/host_connection.h \ No newline at end of file diff --git a/device/src/legacy/i2c.c b/device/src/legacy/i2c.c new file mode 120000 index 000000000..cf7045b2e --- /dev/null +++ b/device/src/legacy/i2c.c @@ -0,0 +1 @@ +../../../right/src/i2c.c \ No newline at end of file diff --git a/device/src/legacy/i2c.h b/device/src/legacy/i2c.h new file mode 120000 index 000000000..9044e8779 --- /dev/null +++ b/device/src/legacy/i2c.h @@ -0,0 +1 @@ +../../../right/src/i2c.h \ No newline at end of file diff --git a/device/src/legacy/i2c_error_logger.c b/device/src/legacy/i2c_error_logger.c new file mode 120000 index 000000000..c96f860b0 --- /dev/null +++ b/device/src/legacy/i2c_error_logger.c @@ -0,0 +1 @@ +../../../right/src/i2c_error_logger.c \ No newline at end of file diff --git a/device/src/legacy/i2c_error_logger.h b/device/src/legacy/i2c_error_logger.h new file mode 120000 index 000000000..f6ca55391 --- /dev/null +++ b/device/src/legacy/i2c_error_logger.h @@ -0,0 +1 @@ +../../../right/src/i2c_error_logger.h \ No newline at end of file diff --git a/device/src/legacy/key_action.h b/device/src/legacy/key_action.h new file mode 120000 index 000000000..bbd6a30d2 --- /dev/null +++ b/device/src/legacy/key_action.h @@ -0,0 +1 @@ +../../../right/src/key_action.h \ No newline at end of file diff --git a/device/src/legacy/key_states.c b/device/src/legacy/key_states.c new file mode 120000 index 000000000..7f380b228 --- /dev/null +++ b/device/src/legacy/key_states.c @@ -0,0 +1 @@ +../../../right/src/key_states.c \ No newline at end of file diff --git a/device/src/legacy/key_states.h b/device/src/legacy/key_states.h new file mode 120000 index 000000000..621f46b76 --- /dev/null +++ b/device/src/legacy/key_states.h @@ -0,0 +1 @@ +../../../right/src/key_states.h \ No newline at end of file diff --git a/device/src/legacy/keymap.c b/device/src/legacy/keymap.c new file mode 120000 index 000000000..d11056c26 --- /dev/null +++ b/device/src/legacy/keymap.c @@ -0,0 +1 @@ +../../../right/src/keymap.c \ No newline at end of file diff --git a/device/src/legacy/keymap.h b/device/src/legacy/keymap.h new file mode 120000 index 000000000..4166ab564 --- /dev/null +++ b/device/src/legacy/keymap.h @@ -0,0 +1 @@ +../../../right/src/keymap.h \ No newline at end of file diff --git a/device/src/legacy/layer.c b/device/src/legacy/layer.c new file mode 120000 index 000000000..2b70d7530 --- /dev/null +++ b/device/src/legacy/layer.c @@ -0,0 +1 @@ +../../../right/src/layer.c \ No newline at end of file diff --git a/device/src/legacy/layer.h b/device/src/legacy/layer.h new file mode 120000 index 000000000..d071a4f0f --- /dev/null +++ b/device/src/legacy/layer.h @@ -0,0 +1 @@ +../../../right/src/layer.h \ No newline at end of file diff --git a/device/src/legacy/layer_stack.c b/device/src/legacy/layer_stack.c new file mode 120000 index 000000000..e80288390 --- /dev/null +++ b/device/src/legacy/layer_stack.c @@ -0,0 +1 @@ +../../../right/src/layer_stack.c \ No newline at end of file diff --git a/device/src/legacy/layer_stack.h b/device/src/legacy/layer_stack.h new file mode 120000 index 000000000..ceedd56c8 --- /dev/null +++ b/device/src/legacy/layer_stack.h @@ -0,0 +1 @@ +../../../right/src/layer_stack.h \ No newline at end of file diff --git a/device/src/legacy/layer_switcher.c b/device/src/legacy/layer_switcher.c new file mode 120000 index 000000000..39cf6b2e0 --- /dev/null +++ b/device/src/legacy/layer_switcher.c @@ -0,0 +1 @@ +../../../right/src/layer_switcher.c \ No newline at end of file diff --git a/device/src/legacy/layer_switcher.h b/device/src/legacy/layer_switcher.h new file mode 120000 index 000000000..873becff4 --- /dev/null +++ b/device/src/legacy/layer_switcher.h @@ -0,0 +1 @@ +../../../right/src/layer_switcher.h \ No newline at end of file diff --git a/device/src/legacy/layouts/key_layout.c b/device/src/legacy/layouts/key_layout.c new file mode 120000 index 000000000..cebed70f0 --- /dev/null +++ b/device/src/legacy/layouts/key_layout.c @@ -0,0 +1 @@ +../../../../right/src/layouts/key_layout.c \ No newline at end of file diff --git a/device/src/legacy/layouts/key_layout.h b/device/src/legacy/layouts/key_layout.h new file mode 120000 index 000000000..4a2a0807a --- /dev/null +++ b/device/src/legacy/layouts/key_layout.h @@ -0,0 +1 @@ +../../../../right/src/layouts/key_layout.h \ No newline at end of file diff --git a/device/src/legacy/layouts/key_layout_60_to_universal.c b/device/src/legacy/layouts/key_layout_60_to_universal.c new file mode 120000 index 000000000..28f4b7df9 --- /dev/null +++ b/device/src/legacy/layouts/key_layout_60_to_universal.c @@ -0,0 +1 @@ +../../../../right/src/layouts/key_layout_60_to_universal.c \ No newline at end of file diff --git a/device/src/legacy/layouts/key_layout_60_to_universal.h b/device/src/legacy/layouts/key_layout_60_to_universal.h new file mode 120000 index 000000000..78f0fa4c2 --- /dev/null +++ b/device/src/legacy/layouts/key_layout_60_to_universal.h @@ -0,0 +1 @@ +../../../../right/src/layouts/key_layout_60_to_universal.h \ No newline at end of file diff --git a/device/src/legacy/layouts/key_layout_80_to_universal.c b/device/src/legacy/layouts/key_layout_80_to_universal.c new file mode 120000 index 000000000..745f8a106 --- /dev/null +++ b/device/src/legacy/layouts/key_layout_80_to_universal.c @@ -0,0 +1 @@ +../../../../right/src/layouts/key_layout_80_to_universal.c \ No newline at end of file diff --git a/device/src/legacy/layouts/key_layout_80_to_universal.h b/device/src/legacy/layouts/key_layout_80_to_universal.h new file mode 120000 index 000000000..0046c71e6 --- /dev/null +++ b/device/src/legacy/layouts/key_layout_80_to_universal.h @@ -0,0 +1 @@ +../../../../right/src/layouts/key_layout_80_to_universal.h \ No newline at end of file diff --git a/device/src/legacy/led_display.c b/device/src/legacy/led_display.c new file mode 120000 index 000000000..5d4d891f5 --- /dev/null +++ b/device/src/legacy/led_display.c @@ -0,0 +1 @@ +../../../right/src/led_display.c \ No newline at end of file diff --git a/device/src/legacy/led_display.h b/device/src/legacy/led_display.h new file mode 120000 index 000000000..b7bedb476 --- /dev/null +++ b/device/src/legacy/led_display.h @@ -0,0 +1 @@ +../../../right/src/led_display.h \ No newline at end of file diff --git a/device/src/legacy/led_manager.c b/device/src/legacy/led_manager.c new file mode 120000 index 000000000..6277120f7 --- /dev/null +++ b/device/src/legacy/led_manager.c @@ -0,0 +1 @@ +../../../right/src/led_manager.c \ No newline at end of file diff --git a/device/src/legacy/led_manager.h b/device/src/legacy/led_manager.h new file mode 120000 index 000000000..1de3c2d1a --- /dev/null +++ b/device/src/legacy/led_manager.h @@ -0,0 +1 @@ +../../../right/src/led_manager.h \ No newline at end of file diff --git a/device/src/legacy/ledmap.c b/device/src/legacy/ledmap.c new file mode 120000 index 000000000..2e911d84d --- /dev/null +++ b/device/src/legacy/ledmap.c @@ -0,0 +1 @@ +../../../right/src/ledmap.c \ No newline at end of file diff --git a/device/src/legacy/ledmap.h b/device/src/legacy/ledmap.h new file mode 120000 index 000000000..59c7548b6 --- /dev/null +++ b/device/src/legacy/ledmap.h @@ -0,0 +1 @@ +../../../right/src/ledmap.h \ No newline at end of file diff --git a/device/src/legacy/lufa/HIDClassCommon.h b/device/src/legacy/lufa/HIDClassCommon.h new file mode 120000 index 000000000..b268be5fd --- /dev/null +++ b/device/src/legacy/lufa/HIDClassCommon.h @@ -0,0 +1 @@ +../../../../right/src/lufa/HIDClassCommon.h \ No newline at end of file diff --git a/device/src/legacy/macro_events.c b/device/src/legacy/macro_events.c new file mode 120000 index 000000000..dacf1fc46 --- /dev/null +++ b/device/src/legacy/macro_events.c @@ -0,0 +1 @@ +../../../right/src/macro_events.c \ No newline at end of file diff --git a/device/src/legacy/macro_events.h b/device/src/legacy/macro_events.h new file mode 120000 index 000000000..4da8f0669 --- /dev/null +++ b/device/src/legacy/macro_events.h @@ -0,0 +1 @@ +../../../right/src/macro_events.h \ No newline at end of file diff --git a/device/src/legacy/macro_recorder.c b/device/src/legacy/macro_recorder.c new file mode 120000 index 000000000..9aaa6fdf0 --- /dev/null +++ b/device/src/legacy/macro_recorder.c @@ -0,0 +1 @@ +../../../right/src/macro_recorder.c \ No newline at end of file diff --git a/device/src/legacy/macro_recorder.h b/device/src/legacy/macro_recorder.h new file mode 120000 index 000000000..2979f89ab --- /dev/null +++ b/device/src/legacy/macro_recorder.h @@ -0,0 +1 @@ +../../../right/src/macro_recorder.h \ No newline at end of file diff --git a/device/src/legacy/macros/commands.c b/device/src/legacy/macros/commands.c new file mode 120000 index 000000000..5632ee0b6 --- /dev/null +++ b/device/src/legacy/macros/commands.c @@ -0,0 +1 @@ +../../../../right/src/macros/commands.c \ No newline at end of file diff --git a/device/src/legacy/macros/commands.h b/device/src/legacy/macros/commands.h new file mode 120000 index 000000000..84b66d3ea --- /dev/null +++ b/device/src/legacy/macros/commands.h @@ -0,0 +1 @@ +../../../../right/src/macros/commands.h \ No newline at end of file diff --git a/device/src/legacy/macros/core.c b/device/src/legacy/macros/core.c new file mode 120000 index 000000000..ced86e042 --- /dev/null +++ b/device/src/legacy/macros/core.c @@ -0,0 +1 @@ +../../../../right/src/macros/core.c \ No newline at end of file diff --git a/device/src/legacy/macros/core.h b/device/src/legacy/macros/core.h new file mode 120000 index 000000000..c4ec995ef --- /dev/null +++ b/device/src/legacy/macros/core.h @@ -0,0 +1 @@ +../../../../right/src/macros/core.h \ No newline at end of file diff --git a/device/src/legacy/macros/debug_commands.c b/device/src/legacy/macros/debug_commands.c new file mode 120000 index 000000000..51f3630d6 --- /dev/null +++ b/device/src/legacy/macros/debug_commands.c @@ -0,0 +1 @@ +../../../../right/src/macros/debug_commands.c \ No newline at end of file diff --git a/device/src/legacy/macros/debug_commands.h b/device/src/legacy/macros/debug_commands.h new file mode 120000 index 000000000..18963497a --- /dev/null +++ b/device/src/legacy/macros/debug_commands.h @@ -0,0 +1 @@ +../../../../right/src/macros/debug_commands.h \ No newline at end of file diff --git a/device/src/legacy/macros/key_timing.c b/device/src/legacy/macros/key_timing.c new file mode 120000 index 000000000..0bd987b55 --- /dev/null +++ b/device/src/legacy/macros/key_timing.c @@ -0,0 +1 @@ +../../../../right/src/macros/key_timing.c \ No newline at end of file diff --git a/device/src/legacy/macros/key_timing.h b/device/src/legacy/macros/key_timing.h new file mode 120000 index 000000000..f9ff340bd --- /dev/null +++ b/device/src/legacy/macros/key_timing.h @@ -0,0 +1 @@ +../../../../right/src/macros/key_timing.h \ No newline at end of file diff --git a/device/src/legacy/macros/keyid_parser.c b/device/src/legacy/macros/keyid_parser.c new file mode 120000 index 000000000..8257aef8b --- /dev/null +++ b/device/src/legacy/macros/keyid_parser.c @@ -0,0 +1 @@ +../../../../right/src/macros/keyid_parser.c \ No newline at end of file diff --git a/device/src/legacy/macros/keyid_parser.h b/device/src/legacy/macros/keyid_parser.h new file mode 120000 index 000000000..c0c6dc037 --- /dev/null +++ b/device/src/legacy/macros/keyid_parser.h @@ -0,0 +1 @@ +../../../../right/src/macros/keyid_parser.h \ No newline at end of file diff --git a/device/src/legacy/macros/scancode_commands.c b/device/src/legacy/macros/scancode_commands.c new file mode 120000 index 000000000..d5b2fe4f5 --- /dev/null +++ b/device/src/legacy/macros/scancode_commands.c @@ -0,0 +1 @@ +../../../../right/src/macros/scancode_commands.c \ No newline at end of file diff --git a/device/src/legacy/macros/scancode_commands.h b/device/src/legacy/macros/scancode_commands.h new file mode 120000 index 000000000..d7f2bc7a9 --- /dev/null +++ b/device/src/legacy/macros/scancode_commands.h @@ -0,0 +1 @@ +../../../../right/src/macros/scancode_commands.h \ No newline at end of file diff --git a/device/src/legacy/macros/set_command.c b/device/src/legacy/macros/set_command.c new file mode 120000 index 000000000..1de4b5b69 --- /dev/null +++ b/device/src/legacy/macros/set_command.c @@ -0,0 +1 @@ +../../../../right/src/macros/set_command.c \ No newline at end of file diff --git a/device/src/legacy/macros/set_command.h b/device/src/legacy/macros/set_command.h new file mode 120000 index 000000000..a27dede42 --- /dev/null +++ b/device/src/legacy/macros/set_command.h @@ -0,0 +1 @@ +../../../../right/src/macros/set_command.h \ No newline at end of file diff --git a/device/src/legacy/macros/shortcut_parser.c b/device/src/legacy/macros/shortcut_parser.c new file mode 120000 index 000000000..98374cde5 --- /dev/null +++ b/device/src/legacy/macros/shortcut_parser.c @@ -0,0 +1 @@ +../../../../right/src/macros/shortcut_parser.c \ No newline at end of file diff --git a/device/src/legacy/macros/shortcut_parser.h b/device/src/legacy/macros/shortcut_parser.h new file mode 120000 index 000000000..85c1a1f59 --- /dev/null +++ b/device/src/legacy/macros/shortcut_parser.h @@ -0,0 +1 @@ +../../../../right/src/macros/shortcut_parser.h \ No newline at end of file diff --git a/device/src/legacy/macros/status_buffer.c b/device/src/legacy/macros/status_buffer.c new file mode 120000 index 000000000..0d4ab7b3f --- /dev/null +++ b/device/src/legacy/macros/status_buffer.c @@ -0,0 +1 @@ +../../../../right/src/macros/status_buffer.c \ No newline at end of file diff --git a/device/src/legacy/macros/status_buffer.h b/device/src/legacy/macros/status_buffer.h new file mode 120000 index 000000000..43467817c --- /dev/null +++ b/device/src/legacy/macros/status_buffer.h @@ -0,0 +1 @@ +../../../../right/src/macros/status_buffer.h \ No newline at end of file diff --git a/device/src/legacy/macros/string_reader.c b/device/src/legacy/macros/string_reader.c new file mode 120000 index 000000000..63925fe21 --- /dev/null +++ b/device/src/legacy/macros/string_reader.c @@ -0,0 +1 @@ +../../../../right/src/macros/string_reader.c \ No newline at end of file diff --git a/device/src/legacy/macros/string_reader.h b/device/src/legacy/macros/string_reader.h new file mode 120000 index 000000000..42e34ce02 --- /dev/null +++ b/device/src/legacy/macros/string_reader.h @@ -0,0 +1 @@ +../../../../right/src/macros/string_reader.h \ No newline at end of file diff --git a/device/src/legacy/macros/typedefs.h b/device/src/legacy/macros/typedefs.h new file mode 120000 index 000000000..b22048007 --- /dev/null +++ b/device/src/legacy/macros/typedefs.h @@ -0,0 +1 @@ +../../../../right/src/macros/typedefs.h \ No newline at end of file diff --git a/device/src/legacy/macros/vars.c b/device/src/legacy/macros/vars.c new file mode 120000 index 000000000..2f8d5d222 --- /dev/null +++ b/device/src/legacy/macros/vars.c @@ -0,0 +1 @@ +../../../../right/src/macros/vars.c \ No newline at end of file diff --git a/device/src/legacy/macros/vars.h b/device/src/legacy/macros/vars.h new file mode 120000 index 000000000..995c88cee --- /dev/null +++ b/device/src/legacy/macros/vars.h @@ -0,0 +1 @@ +../../../../right/src/macros/vars.h \ No newline at end of file diff --git a/device/src/legacy/module.c b/device/src/legacy/module.c new file mode 120000 index 000000000..080022091 --- /dev/null +++ b/device/src/legacy/module.c @@ -0,0 +1 @@ +../../../right/src/module.c \ No newline at end of file diff --git a/device/src/legacy/module.h b/device/src/legacy/module.h new file mode 120000 index 000000000..904998ba5 --- /dev/null +++ b/device/src/legacy/module.h @@ -0,0 +1 @@ +../../../right/src/module.h \ No newline at end of file diff --git a/device/src/legacy/mouse_controller.c b/device/src/legacy/mouse_controller.c new file mode 120000 index 000000000..44d2a3e32 --- /dev/null +++ b/device/src/legacy/mouse_controller.c @@ -0,0 +1 @@ +../../../right/src/mouse_controller.c \ No newline at end of file diff --git a/device/src/legacy/mouse_controller.h b/device/src/legacy/mouse_controller.h new file mode 120000 index 000000000..f78e06abd --- /dev/null +++ b/device/src/legacy/mouse_controller.h @@ -0,0 +1 @@ +../../../right/src/mouse_controller.h \ No newline at end of file diff --git a/device/src/legacy/mouse_keys.c b/device/src/legacy/mouse_keys.c new file mode 120000 index 000000000..d469e3035 --- /dev/null +++ b/device/src/legacy/mouse_keys.c @@ -0,0 +1 @@ +../../../right/src/mouse_keys.c \ No newline at end of file diff --git a/device/src/legacy/mouse_keys.h b/device/src/legacy/mouse_keys.h new file mode 120000 index 000000000..6ce6a2ba5 --- /dev/null +++ b/device/src/legacy/mouse_keys.h @@ -0,0 +1 @@ +../../../right/src/mouse_keys.h \ No newline at end of file diff --git a/device/src/legacy/peripherals/led_driver.h b/device/src/legacy/peripherals/led_driver.h new file mode 120000 index 000000000..bd82f18eb --- /dev/null +++ b/device/src/legacy/peripherals/led_driver.h @@ -0,0 +1 @@ +../../../../right/src/peripherals/led_driver.h \ No newline at end of file diff --git a/device/src/legacy/peripherals/merge_sensor.c b/device/src/legacy/peripherals/merge_sensor.c new file mode 120000 index 000000000..307d15742 --- /dev/null +++ b/device/src/legacy/peripherals/merge_sensor.c @@ -0,0 +1 @@ +../../../../right/src/peripherals/merge_sensor.c \ No newline at end of file diff --git a/device/src/legacy/peripherals/merge_sensor.h b/device/src/legacy/peripherals/merge_sensor.h new file mode 120000 index 000000000..ee59348ab --- /dev/null +++ b/device/src/legacy/peripherals/merge_sensor.h @@ -0,0 +1 @@ +../../../../right/src/peripherals/merge_sensor.h \ No newline at end of file diff --git a/device/src/legacy/peripherals/reset_button.c b/device/src/legacy/peripherals/reset_button.c new file mode 120000 index 000000000..9b11b0275 --- /dev/null +++ b/device/src/legacy/peripherals/reset_button.c @@ -0,0 +1 @@ +../../../../right/src/peripherals/reset_button.c \ No newline at end of file diff --git a/device/src/legacy/peripherals/reset_button.h b/device/src/legacy/peripherals/reset_button.h new file mode 120000 index 000000000..1dc4091ce --- /dev/null +++ b/device/src/legacy/peripherals/reset_button.h @@ -0,0 +1 @@ +../../../../right/src/peripherals/reset_button.h \ No newline at end of file diff --git a/device/src/legacy/postponer.c b/device/src/legacy/postponer.c new file mode 120000 index 000000000..2cd8a6571 --- /dev/null +++ b/device/src/legacy/postponer.c @@ -0,0 +1 @@ +../../../right/src/postponer.c \ No newline at end of file diff --git a/device/src/legacy/postponer.h b/device/src/legacy/postponer.h new file mode 120000 index 000000000..6cee20cbb --- /dev/null +++ b/device/src/legacy/postponer.h @@ -0,0 +1 @@ +../../../right/src/postponer.h \ No newline at end of file diff --git a/device/src/legacy/power_mode.c b/device/src/legacy/power_mode.c new file mode 120000 index 000000000..50912722d --- /dev/null +++ b/device/src/legacy/power_mode.c @@ -0,0 +1 @@ +../../../right/src/power_mode.c \ No newline at end of file diff --git a/device/src/legacy/power_mode.h b/device/src/legacy/power_mode.h new file mode 120000 index 000000000..c16be5d95 --- /dev/null +++ b/device/src/legacy/power_mode.h @@ -0,0 +1 @@ +../../../right/src/power_mode.h \ No newline at end of file diff --git a/device/src/legacy/secondary_role_driver.c b/device/src/legacy/secondary_role_driver.c new file mode 120000 index 000000000..8224494e2 --- /dev/null +++ b/device/src/legacy/secondary_role_driver.c @@ -0,0 +1 @@ +../../../right/src/secondary_role_driver.c \ No newline at end of file diff --git a/device/src/legacy/secondary_role_driver.h b/device/src/legacy/secondary_role_driver.h new file mode 120000 index 000000000..7c0b4b0c9 --- /dev/null +++ b/device/src/legacy/secondary_role_driver.h @@ -0,0 +1 @@ +../../../right/src/secondary_role_driver.h \ No newline at end of file diff --git a/device/src/legacy/segment_display.c b/device/src/legacy/segment_display.c new file mode 120000 index 000000000..5aa96c1b3 --- /dev/null +++ b/device/src/legacy/segment_display.c @@ -0,0 +1 @@ +../../../right/src/segment_display.c \ No newline at end of file diff --git a/device/src/legacy/segment_display.h b/device/src/legacy/segment_display.h new file mode 120000 index 000000000..aadd3c4c9 --- /dev/null +++ b/device/src/legacy/segment_display.h @@ -0,0 +1 @@ +../../../right/src/segment_display.h \ No newline at end of file diff --git a/device/src/legacy/slave_drivers/is31fl3xxx_driver.c b/device/src/legacy/slave_drivers/is31fl3xxx_driver.c new file mode 120000 index 000000000..142e50152 --- /dev/null +++ b/device/src/legacy/slave_drivers/is31fl3xxx_driver.c @@ -0,0 +1 @@ +../../../../right/src/slave_drivers/is31fl3xxx_driver.c \ No newline at end of file diff --git a/device/src/legacy/slave_drivers/is31fl3xxx_driver.h b/device/src/legacy/slave_drivers/is31fl3xxx_driver.h new file mode 120000 index 000000000..a8695c548 --- /dev/null +++ b/device/src/legacy/slave_drivers/is31fl3xxx_driver.h @@ -0,0 +1 @@ +../../../../right/src/slave_drivers/is31fl3xxx_driver.h \ No newline at end of file diff --git a/device/src/legacy/slave_drivers/touchpad_driver.c b/device/src/legacy/slave_drivers/touchpad_driver.c new file mode 120000 index 000000000..c370498cc --- /dev/null +++ b/device/src/legacy/slave_drivers/touchpad_driver.c @@ -0,0 +1 @@ +../../../../right/src/slave_drivers/touchpad_driver.c \ No newline at end of file diff --git a/device/src/legacy/slave_drivers/touchpad_driver.h b/device/src/legacy/slave_drivers/touchpad_driver.h new file mode 120000 index 000000000..34d893029 --- /dev/null +++ b/device/src/legacy/slave_drivers/touchpad_driver.h @@ -0,0 +1 @@ +../../../../right/src/slave_drivers/touchpad_driver.h \ No newline at end of file diff --git a/device/src/legacy/slave_drivers/uhk_module_driver.c b/device/src/legacy/slave_drivers/uhk_module_driver.c new file mode 120000 index 000000000..166cb8769 --- /dev/null +++ b/device/src/legacy/slave_drivers/uhk_module_driver.c @@ -0,0 +1 @@ +../../../../right/src/slave_drivers/uhk_module_driver.c \ No newline at end of file diff --git a/device/src/legacy/slave_drivers/uhk_module_driver.h b/device/src/legacy/slave_drivers/uhk_module_driver.h new file mode 120000 index 000000000..998976223 --- /dev/null +++ b/device/src/legacy/slave_drivers/uhk_module_driver.h @@ -0,0 +1 @@ +../../../../right/src/slave_drivers/uhk_module_driver.h \ No newline at end of file diff --git a/device/src/legacy/slave_scheduler.c b/device/src/legacy/slave_scheduler.c new file mode 120000 index 000000000..012395c24 --- /dev/null +++ b/device/src/legacy/slave_scheduler.c @@ -0,0 +1 @@ +../../../right/src/slave_scheduler.c \ No newline at end of file diff --git a/device/src/legacy/slave_scheduler.h b/device/src/legacy/slave_scheduler.h new file mode 120000 index 000000000..d5ae59beb --- /dev/null +++ b/device/src/legacy/slave_scheduler.h @@ -0,0 +1 @@ +../../../right/src/slave_scheduler.h \ No newline at end of file diff --git a/device/src/legacy/slot.h b/device/src/legacy/slot.h new file mode 120000 index 000000000..c3d3583e8 --- /dev/null +++ b/device/src/legacy/slot.h @@ -0,0 +1 @@ +../../../right/src/slot.h \ No newline at end of file diff --git a/device/src/legacy/storage.c b/device/src/legacy/storage.c new file mode 120000 index 000000000..e803bfde6 --- /dev/null +++ b/device/src/legacy/storage.c @@ -0,0 +1 @@ +../../../right/src/storage.c \ No newline at end of file diff --git a/device/src/legacy/storage.h b/device/src/legacy/storage.h new file mode 120000 index 000000000..0e878e12a --- /dev/null +++ b/device/src/legacy/storage.h @@ -0,0 +1 @@ +../../../right/src/storage.h \ No newline at end of file diff --git a/device/src/legacy/str_utils.c b/device/src/legacy/str_utils.c new file mode 120000 index 000000000..064f0b950 --- /dev/null +++ b/device/src/legacy/str_utils.c @@ -0,0 +1 @@ +../../../right/src/str_utils.c \ No newline at end of file diff --git a/device/src/legacy/str_utils.h b/device/src/legacy/str_utils.h new file mode 120000 index 000000000..c3f841108 --- /dev/null +++ b/device/src/legacy/str_utils.h @@ -0,0 +1 @@ +../../../right/src/str_utils.h \ No newline at end of file diff --git a/device/src/legacy/stubs.c b/device/src/legacy/stubs.c new file mode 120000 index 000000000..6a20b7a4a --- /dev/null +++ b/device/src/legacy/stubs.c @@ -0,0 +1 @@ +../../../right/src/stubs.c \ No newline at end of file diff --git a/device/src/legacy/stubs.h b/device/src/legacy/stubs.h new file mode 120000 index 000000000..631f203a7 --- /dev/null +++ b/device/src/legacy/stubs.h @@ -0,0 +1 @@ +../../../right/src/stubs.h \ No newline at end of file diff --git a/device/src/legacy/test_switches.c b/device/src/legacy/test_switches.c new file mode 120000 index 000000000..73ce46265 --- /dev/null +++ b/device/src/legacy/test_switches.c @@ -0,0 +1 @@ +../../../right/src/test_switches.c \ No newline at end of file diff --git a/device/src/legacy/test_switches.h b/device/src/legacy/test_switches.h new file mode 120000 index 000000000..f3bed02b2 --- /dev/null +++ b/device/src/legacy/test_switches.h @@ -0,0 +1 @@ +../../../right/src/test_switches.h \ No newline at end of file diff --git a/device/src/legacy/timer.c b/device/src/legacy/timer.c new file mode 120000 index 000000000..568d3b278 --- /dev/null +++ b/device/src/legacy/timer.c @@ -0,0 +1 @@ +../../../right/src/timer.c \ No newline at end of file diff --git a/device/src/legacy/timer.h b/device/src/legacy/timer.h new file mode 120000 index 000000000..a8f8b9dc3 --- /dev/null +++ b/device/src/legacy/timer.h @@ -0,0 +1 @@ +../../../right/src/timer.h \ No newline at end of file diff --git a/device/src/legacy/usb_api.h b/device/src/legacy/usb_api.h new file mode 120000 index 000000000..7b7715fa2 --- /dev/null +++ b/device/src/legacy/usb_api.h @@ -0,0 +1 @@ +../../../right/src/usb_api.h \ No newline at end of file diff --git a/device/src/legacy/usb_commands/usb_command_apply_config.c b/device/src/legacy/usb_commands/usb_command_apply_config.c new file mode 120000 index 000000000..783756a77 --- /dev/null +++ b/device/src/legacy/usb_commands/usb_command_apply_config.c @@ -0,0 +1 @@ +../../../../right/src/usb_commands/usb_command_apply_config.c \ No newline at end of file diff --git a/device/src/legacy/usb_commands/usb_command_apply_config.h b/device/src/legacy/usb_commands/usb_command_apply_config.h new file mode 120000 index 000000000..07ee5e339 --- /dev/null +++ b/device/src/legacy/usb_commands/usb_command_apply_config.h @@ -0,0 +1 @@ +../../../../right/src/usb_commands/usb_command_apply_config.h \ No newline at end of file diff --git a/device/src/legacy/usb_commands/usb_command_draw_oled.c b/device/src/legacy/usb_commands/usb_command_draw_oled.c new file mode 120000 index 000000000..33383383f --- /dev/null +++ b/device/src/legacy/usb_commands/usb_command_draw_oled.c @@ -0,0 +1 @@ +../../../../right/src/usb_commands/usb_command_draw_oled.c \ No newline at end of file diff --git a/device/src/legacy/usb_commands/usb_command_draw_oled.h b/device/src/legacy/usb_commands/usb_command_draw_oled.h new file mode 120000 index 000000000..f1c15b43e --- /dev/null +++ b/device/src/legacy/usb_commands/usb_command_draw_oled.h @@ -0,0 +1 @@ +../../../../right/src/usb_commands/usb_command_draw_oled.h \ No newline at end of file diff --git a/device/src/legacy/usb_commands/usb_command_exec_macro_command.c b/device/src/legacy/usb_commands/usb_command_exec_macro_command.c new file mode 120000 index 000000000..487f2146e --- /dev/null +++ b/device/src/legacy/usb_commands/usb_command_exec_macro_command.c @@ -0,0 +1 @@ +../../../../right/src/usb_commands/usb_command_exec_macro_command.c \ No newline at end of file diff --git a/device/src/legacy/usb_commands/usb_command_exec_macro_command.h b/device/src/legacy/usb_commands/usb_command_exec_macro_command.h new file mode 120000 index 000000000..e2316a365 --- /dev/null +++ b/device/src/legacy/usb_commands/usb_command_exec_macro_command.h @@ -0,0 +1 @@ +../../../../right/src/usb_commands/usb_command_exec_macro_command.h \ No newline at end of file diff --git a/device/src/legacy/usb_commands/usb_command_get_debug_buffer.c b/device/src/legacy/usb_commands/usb_command_get_debug_buffer.c new file mode 120000 index 000000000..31e1236a5 --- /dev/null +++ b/device/src/legacy/usb_commands/usb_command_get_debug_buffer.c @@ -0,0 +1 @@ +../../../../right/src/usb_commands/usb_command_get_debug_buffer.c \ No newline at end of file diff --git a/device/src/legacy/usb_commands/usb_command_get_debug_buffer.h b/device/src/legacy/usb_commands/usb_command_get_debug_buffer.h new file mode 120000 index 000000000..a993ff99d --- /dev/null +++ b/device/src/legacy/usb_commands/usb_command_get_debug_buffer.h @@ -0,0 +1 @@ +../../../../right/src/usb_commands/usb_command_get_debug_buffer.h \ No newline at end of file diff --git a/device/src/legacy/usb_commands/usb_command_get_device_property.c b/device/src/legacy/usb_commands/usb_command_get_device_property.c new file mode 120000 index 000000000..1f8cb5368 --- /dev/null +++ b/device/src/legacy/usb_commands/usb_command_get_device_property.c @@ -0,0 +1 @@ +../../../../right/src/usb_commands/usb_command_get_device_property.c \ No newline at end of file diff --git a/device/src/legacy/usb_commands/usb_command_get_device_property.h b/device/src/legacy/usb_commands/usb_command_get_device_property.h new file mode 120000 index 000000000..b7539958f --- /dev/null +++ b/device/src/legacy/usb_commands/usb_command_get_device_property.h @@ -0,0 +1 @@ +../../../../right/src/usb_commands/usb_command_get_device_property.h \ No newline at end of file diff --git a/device/src/legacy/usb_commands/usb_command_get_device_state.c b/device/src/legacy/usb_commands/usb_command_get_device_state.c new file mode 120000 index 000000000..949590371 --- /dev/null +++ b/device/src/legacy/usb_commands/usb_command_get_device_state.c @@ -0,0 +1 @@ +../../../../right/src/usb_commands/usb_command_get_device_state.c \ No newline at end of file diff --git a/device/src/legacy/usb_commands/usb_command_get_device_state.h b/device/src/legacy/usb_commands/usb_command_get_device_state.h new file mode 120000 index 000000000..3da9110d3 --- /dev/null +++ b/device/src/legacy/usb_commands/usb_command_get_device_state.h @@ -0,0 +1 @@ +../../../../right/src/usb_commands/usb_command_get_device_state.h \ No newline at end of file diff --git a/device/src/legacy/usb_commands/usb_command_get_module_property.c b/device/src/legacy/usb_commands/usb_command_get_module_property.c new file mode 120000 index 000000000..9551110f6 --- /dev/null +++ b/device/src/legacy/usb_commands/usb_command_get_module_property.c @@ -0,0 +1 @@ +../../../../right/src/usb_commands/usb_command_get_module_property.c \ No newline at end of file diff --git a/device/src/legacy/usb_commands/usb_command_get_module_property.h b/device/src/legacy/usb_commands/usb_command_get_module_property.h new file mode 120000 index 000000000..f4bc42d01 --- /dev/null +++ b/device/src/legacy/usb_commands/usb_command_get_module_property.h @@ -0,0 +1 @@ +../../../../right/src/usb_commands/usb_command_get_module_property.h \ No newline at end of file diff --git a/device/src/legacy/usb_commands/usb_command_get_new_pairings.c b/device/src/legacy/usb_commands/usb_command_get_new_pairings.c new file mode 120000 index 000000000..6fa515616 --- /dev/null +++ b/device/src/legacy/usb_commands/usb_command_get_new_pairings.c @@ -0,0 +1 @@ +../../../../right/src/usb_commands/usb_command_get_new_pairings.c \ No newline at end of file diff --git a/device/src/legacy/usb_commands/usb_command_get_new_pairings.h b/device/src/legacy/usb_commands/usb_command_get_new_pairings.h new file mode 120000 index 000000000..f2611136a --- /dev/null +++ b/device/src/legacy/usb_commands/usb_command_get_new_pairings.h @@ -0,0 +1 @@ +../../../../right/src/usb_commands/usb_command_get_new_pairings.h \ No newline at end of file diff --git a/device/src/legacy/usb_commands/usb_command_get_variable.c b/device/src/legacy/usb_commands/usb_command_get_variable.c new file mode 120000 index 000000000..e55651151 --- /dev/null +++ b/device/src/legacy/usb_commands/usb_command_get_variable.c @@ -0,0 +1 @@ +../../../../right/src/usb_commands/usb_command_get_variable.c \ No newline at end of file diff --git a/device/src/legacy/usb_commands/usb_command_get_variable.h b/device/src/legacy/usb_commands/usb_command_get_variable.h new file mode 120000 index 000000000..9a2315488 --- /dev/null +++ b/device/src/legacy/usb_commands/usb_command_get_variable.h @@ -0,0 +1 @@ +../../../../right/src/usb_commands/usb_command_get_variable.h \ No newline at end of file diff --git a/device/src/legacy/usb_commands/usb_command_launch_storage_transfer.c b/device/src/legacy/usb_commands/usb_command_launch_storage_transfer.c new file mode 120000 index 000000000..1d463b5be --- /dev/null +++ b/device/src/legacy/usb_commands/usb_command_launch_storage_transfer.c @@ -0,0 +1 @@ +../../../../right/src/usb_commands/usb_command_launch_storage_transfer.c \ No newline at end of file diff --git a/device/src/legacy/usb_commands/usb_command_launch_storage_transfer.h b/device/src/legacy/usb_commands/usb_command_launch_storage_transfer.h new file mode 120000 index 000000000..ca2de2063 --- /dev/null +++ b/device/src/legacy/usb_commands/usb_command_launch_storage_transfer.h @@ -0,0 +1 @@ +../../../../right/src/usb_commands/usb_command_launch_storage_transfer.h \ No newline at end of file diff --git a/device/src/legacy/usb_commands/usb_command_pairing.c b/device/src/legacy/usb_commands/usb_command_pairing.c new file mode 120000 index 000000000..15aceaa26 --- /dev/null +++ b/device/src/legacy/usb_commands/usb_command_pairing.c @@ -0,0 +1 @@ +../../../../right/src/usb_commands/usb_command_pairing.c \ No newline at end of file diff --git a/device/src/legacy/usb_commands/usb_command_pairing.h b/device/src/legacy/usb_commands/usb_command_pairing.h new file mode 120000 index 000000000..d87599a79 --- /dev/null +++ b/device/src/legacy/usb_commands/usb_command_pairing.h @@ -0,0 +1 @@ +../../../../right/src/usb_commands/usb_command_pairing.h \ No newline at end of file diff --git a/device/src/legacy/usb_commands/usb_command_read_config.c b/device/src/legacy/usb_commands/usb_command_read_config.c new file mode 120000 index 000000000..3395bdbaa --- /dev/null +++ b/device/src/legacy/usb_commands/usb_command_read_config.c @@ -0,0 +1 @@ +../../../../right/src/usb_commands/usb_command_read_config.c \ No newline at end of file diff --git a/device/src/legacy/usb_commands/usb_command_read_config.h b/device/src/legacy/usb_commands/usb_command_read_config.h new file mode 120000 index 000000000..e4149de33 --- /dev/null +++ b/device/src/legacy/usb_commands/usb_command_read_config.h @@ -0,0 +1 @@ +../../../../right/src/usb_commands/usb_command_read_config.h \ No newline at end of file diff --git a/device/src/legacy/usb_commands/usb_command_reenumerate.c b/device/src/legacy/usb_commands/usb_command_reenumerate.c new file mode 120000 index 000000000..36935f457 --- /dev/null +++ b/device/src/legacy/usb_commands/usb_command_reenumerate.c @@ -0,0 +1 @@ +../../../../right/src/usb_commands/usb_command_reenumerate.c \ No newline at end of file diff --git a/device/src/legacy/usb_commands/usb_command_reenumerate.h b/device/src/legacy/usb_commands/usb_command_reenumerate.h new file mode 120000 index 000000000..79cb2b793 --- /dev/null +++ b/device/src/legacy/usb_commands/usb_command_reenumerate.h @@ -0,0 +1 @@ +../../../../right/src/usb_commands/usb_command_reenumerate.h \ No newline at end of file diff --git a/device/src/legacy/usb_commands/usb_command_set_variable.c b/device/src/legacy/usb_commands/usb_command_set_variable.c new file mode 120000 index 000000000..35afb5da6 --- /dev/null +++ b/device/src/legacy/usb_commands/usb_command_set_variable.c @@ -0,0 +1 @@ +../../../../right/src/usb_commands/usb_command_set_variable.c \ No newline at end of file diff --git a/device/src/legacy/usb_commands/usb_command_set_variable.h b/device/src/legacy/usb_commands/usb_command_set_variable.h new file mode 120000 index 000000000..24ebbbc8c --- /dev/null +++ b/device/src/legacy/usb_commands/usb_command_set_variable.h @@ -0,0 +1 @@ +../../../../right/src/usb_commands/usb_command_set_variable.h \ No newline at end of file diff --git a/device/src/legacy/usb_commands/usb_command_switch_keymap.c b/device/src/legacy/usb_commands/usb_command_switch_keymap.c new file mode 120000 index 000000000..c5b01a813 --- /dev/null +++ b/device/src/legacy/usb_commands/usb_command_switch_keymap.c @@ -0,0 +1 @@ +../../../../right/src/usb_commands/usb_command_switch_keymap.c \ No newline at end of file diff --git a/device/src/legacy/usb_commands/usb_command_switch_keymap.h b/device/src/legacy/usb_commands/usb_command_switch_keymap.h new file mode 120000 index 000000000..48f75932c --- /dev/null +++ b/device/src/legacy/usb_commands/usb_command_switch_keymap.h @@ -0,0 +1 @@ +../../../../right/src/usb_commands/usb_command_switch_keymap.h \ No newline at end of file diff --git a/device/src/legacy/usb_commands/usb_command_write_config.c b/device/src/legacy/usb_commands/usb_command_write_config.c new file mode 120000 index 000000000..d21fda651 --- /dev/null +++ b/device/src/legacy/usb_commands/usb_command_write_config.c @@ -0,0 +1 @@ +../../../../right/src/usb_commands/usb_command_write_config.c \ No newline at end of file diff --git a/device/src/legacy/usb_commands/usb_command_write_config.h b/device/src/legacy/usb_commands/usb_command_write_config.h new file mode 120000 index 000000000..0da04dc1a --- /dev/null +++ b/device/src/legacy/usb_commands/usb_command_write_config.h @@ -0,0 +1 @@ +../../../../right/src/usb_commands/usb_command_write_config.h \ No newline at end of file diff --git a/device/src/legacy/usb_composite_device.h b/device/src/legacy/usb_composite_device.h new file mode 120000 index 000000000..84bdb4b85 --- /dev/null +++ b/device/src/legacy/usb_composite_device.h @@ -0,0 +1 @@ +../../../right/src/usb_composite_device.h \ No newline at end of file diff --git a/device/src/legacy/usb_descriptors/usb_descriptor_basic_keyboard_report.h b/device/src/legacy/usb_descriptors/usb_descriptor_basic_keyboard_report.h new file mode 120000 index 000000000..0cdb73347 --- /dev/null +++ b/device/src/legacy/usb_descriptors/usb_descriptor_basic_keyboard_report.h @@ -0,0 +1 @@ +../../../../right/src/usb_descriptors/usb_descriptor_basic_keyboard_report.h \ No newline at end of file diff --git a/device/src/legacy/usb_descriptors/usb_descriptor_configuration.h b/device/src/legacy/usb_descriptors/usb_descriptor_configuration.h new file mode 120000 index 000000000..cc99c7788 --- /dev/null +++ b/device/src/legacy/usb_descriptors/usb_descriptor_configuration.h @@ -0,0 +1 @@ +../../../../right/src/usb_descriptors/usb_descriptor_configuration.h \ No newline at end of file diff --git a/device/src/legacy/usb_descriptors/usb_descriptor_media_keyboard_report.h b/device/src/legacy/usb_descriptors/usb_descriptor_media_keyboard_report.h new file mode 120000 index 000000000..2d344e121 --- /dev/null +++ b/device/src/legacy/usb_descriptors/usb_descriptor_media_keyboard_report.h @@ -0,0 +1 @@ +../../../../right/src/usb_descriptors/usb_descriptor_media_keyboard_report.h \ No newline at end of file diff --git a/device/src/legacy/usb_descriptors/usb_descriptor_mouse_report.h b/device/src/legacy/usb_descriptors/usb_descriptor_mouse_report.h new file mode 120000 index 000000000..f5df01abd --- /dev/null +++ b/device/src/legacy/usb_descriptors/usb_descriptor_mouse_report.h @@ -0,0 +1 @@ +../../../../right/src/usb_descriptors/usb_descriptor_mouse_report.h \ No newline at end of file diff --git a/device/src/legacy/usb_descriptors/usb_descriptor_system_keyboard_report.h b/device/src/legacy/usb_descriptors/usb_descriptor_system_keyboard_report.h new file mode 120000 index 000000000..ef95c0b8d --- /dev/null +++ b/device/src/legacy/usb_descriptors/usb_descriptor_system_keyboard_report.h @@ -0,0 +1 @@ +../../../../right/src/usb_descriptors/usb_descriptor_system_keyboard_report.h \ No newline at end of file diff --git a/device/src/legacy/usb_device_config.h b/device/src/legacy/usb_device_config.h new file mode 120000 index 000000000..9b3840b6c --- /dev/null +++ b/device/src/legacy/usb_device_config.h @@ -0,0 +1 @@ +../../../right/src/usb_device_config.h \ No newline at end of file diff --git a/device/src/legacy/usb_interfaces/usb_interface_basic_keyboard.c b/device/src/legacy/usb_interfaces/usb_interface_basic_keyboard.c new file mode 120000 index 000000000..2d229ba12 --- /dev/null +++ b/device/src/legacy/usb_interfaces/usb_interface_basic_keyboard.c @@ -0,0 +1 @@ +../../../../right/src/usb_interfaces/usb_interface_basic_keyboard.c \ No newline at end of file diff --git a/device/src/legacy/usb_interfaces/usb_interface_basic_keyboard.h b/device/src/legacy/usb_interfaces/usb_interface_basic_keyboard.h new file mode 120000 index 000000000..1e3dc9426 --- /dev/null +++ b/device/src/legacy/usb_interfaces/usb_interface_basic_keyboard.h @@ -0,0 +1 @@ +../../../../right/src/usb_interfaces/usb_interface_basic_keyboard.h \ No newline at end of file diff --git a/device/src/legacy/usb_interfaces/usb_interface_gamepad.c b/device/src/legacy/usb_interfaces/usb_interface_gamepad.c new file mode 120000 index 000000000..c8ab04756 --- /dev/null +++ b/device/src/legacy/usb_interfaces/usb_interface_gamepad.c @@ -0,0 +1 @@ +../../../../right/src/usb_interfaces/usb_interface_gamepad.c \ No newline at end of file diff --git a/device/src/legacy/usb_interfaces/usb_interface_gamepad.h b/device/src/legacy/usb_interfaces/usb_interface_gamepad.h new file mode 120000 index 000000000..c966b7cab --- /dev/null +++ b/device/src/legacy/usb_interfaces/usb_interface_gamepad.h @@ -0,0 +1 @@ +../../../../right/src/usb_interfaces/usb_interface_gamepad.h \ No newline at end of file diff --git a/device/src/legacy/usb_interfaces/usb_interface_generic_hid.c b/device/src/legacy/usb_interfaces/usb_interface_generic_hid.c new file mode 120000 index 000000000..5b3188c55 --- /dev/null +++ b/device/src/legacy/usb_interfaces/usb_interface_generic_hid.c @@ -0,0 +1 @@ +../../../../right/src/usb_interfaces/usb_interface_generic_hid.c \ No newline at end of file diff --git a/device/src/legacy/usb_interfaces/usb_interface_generic_hid.h b/device/src/legacy/usb_interfaces/usb_interface_generic_hid.h new file mode 120000 index 000000000..cd0da0296 --- /dev/null +++ b/device/src/legacy/usb_interfaces/usb_interface_generic_hid.h @@ -0,0 +1 @@ +../../../../right/src/usb_interfaces/usb_interface_generic_hid.h \ No newline at end of file diff --git a/device/src/legacy/usb_interfaces/usb_interface_media_keyboard.c b/device/src/legacy/usb_interfaces/usb_interface_media_keyboard.c new file mode 120000 index 000000000..d11d00b30 --- /dev/null +++ b/device/src/legacy/usb_interfaces/usb_interface_media_keyboard.c @@ -0,0 +1 @@ +../../../../right/src/usb_interfaces/usb_interface_media_keyboard.c \ No newline at end of file diff --git a/device/src/legacy/usb_interfaces/usb_interface_media_keyboard.h b/device/src/legacy/usb_interfaces/usb_interface_media_keyboard.h new file mode 120000 index 000000000..7eabcce2f --- /dev/null +++ b/device/src/legacy/usb_interfaces/usb_interface_media_keyboard.h @@ -0,0 +1 @@ +../../../../right/src/usb_interfaces/usb_interface_media_keyboard.h \ No newline at end of file diff --git a/device/src/legacy/usb_interfaces/usb_interface_mouse.c b/device/src/legacy/usb_interfaces/usb_interface_mouse.c new file mode 120000 index 000000000..2c88cbe30 --- /dev/null +++ b/device/src/legacy/usb_interfaces/usb_interface_mouse.c @@ -0,0 +1 @@ +../../../../right/src/usb_interfaces/usb_interface_mouse.c \ No newline at end of file diff --git a/device/src/legacy/usb_interfaces/usb_interface_mouse.h b/device/src/legacy/usb_interfaces/usb_interface_mouse.h new file mode 120000 index 000000000..1b75c27c4 --- /dev/null +++ b/device/src/legacy/usb_interfaces/usb_interface_mouse.h @@ -0,0 +1 @@ +../../../../right/src/usb_interfaces/usb_interface_mouse.h \ No newline at end of file diff --git a/device/src/legacy/usb_interfaces/usb_interface_system_keyboard.c b/device/src/legacy/usb_interfaces/usb_interface_system_keyboard.c new file mode 120000 index 000000000..6f410eef1 --- /dev/null +++ b/device/src/legacy/usb_interfaces/usb_interface_system_keyboard.c @@ -0,0 +1 @@ +../../../../right/src/usb_interfaces/usb_interface_system_keyboard.c \ No newline at end of file diff --git a/device/src/legacy/usb_interfaces/usb_interface_system_keyboard.h b/device/src/legacy/usb_interfaces/usb_interface_system_keyboard.h new file mode 120000 index 000000000..0704407e0 --- /dev/null +++ b/device/src/legacy/usb_interfaces/usb_interface_system_keyboard.h @@ -0,0 +1 @@ +../../../../right/src/usb_interfaces/usb_interface_system_keyboard.h \ No newline at end of file diff --git a/device/src/legacy/usb_protocol_handler.c b/device/src/legacy/usb_protocol_handler.c new file mode 120000 index 000000000..74022275a --- /dev/null +++ b/device/src/legacy/usb_protocol_handler.c @@ -0,0 +1 @@ +../../../right/src/usb_protocol_handler.c \ No newline at end of file diff --git a/device/src/legacy/usb_protocol_handler.h b/device/src/legacy/usb_protocol_handler.h new file mode 120000 index 000000000..54c870237 --- /dev/null +++ b/device/src/legacy/usb_protocol_handler.h @@ -0,0 +1 @@ +../../../right/src/usb_protocol_handler.h \ No newline at end of file diff --git a/device/src/legacy/usb_report_updater.c b/device/src/legacy/usb_report_updater.c new file mode 120000 index 000000000..5f398dd9b --- /dev/null +++ b/device/src/legacy/usb_report_updater.c @@ -0,0 +1 @@ +../../../right/src/usb_report_updater.c \ No newline at end of file diff --git a/device/src/legacy/usb_report_updater.h b/device/src/legacy/usb_report_updater.h new file mode 120000 index 000000000..9a5e6bfdd --- /dev/null +++ b/device/src/legacy/usb_report_updater.h @@ -0,0 +1 @@ +../../../right/src/usb_report_updater.h \ No newline at end of file diff --git a/device/src/legacy/user_logic.c b/device/src/legacy/user_logic.c new file mode 120000 index 000000000..eac1ed206 --- /dev/null +++ b/device/src/legacy/user_logic.c @@ -0,0 +1 @@ +../../../right/src/user_logic.c \ No newline at end of file diff --git a/device/src/legacy/user_logic.h b/device/src/legacy/user_logic.h new file mode 120000 index 000000000..135248d0f --- /dev/null +++ b/device/src/legacy/user_logic.h @@ -0,0 +1 @@ +../../../right/src/user_logic.h \ No newline at end of file diff --git a/device/src/legacy/utils.c b/device/src/legacy/utils.c new file mode 120000 index 000000000..da84c19bf --- /dev/null +++ b/device/src/legacy/utils.c @@ -0,0 +1 @@ +../../../right/src/utils.c \ No newline at end of file diff --git a/device/src/legacy/utils.h b/device/src/legacy/utils.h new file mode 120000 index 000000000..30a018054 --- /dev/null +++ b/device/src/legacy/utils.h @@ -0,0 +1 @@ +../../../right/src/utils.h \ No newline at end of file diff --git a/device/src/link_protocol.h b/device/src/link_protocol.h new file mode 100644 index 000000000..a7d4264fd --- /dev/null +++ b/device/src/link_protocol.h @@ -0,0 +1,40 @@ +#ifndef __LINK_PROTOCOL_H__ +#define __LINK_PROTOCOL_H__ + +// Includes: + +#include +#include + +// Macros: + +// 251 = maximum BLE packet length with data length extension +// 4 bytes reserved for L2CAP header +// 3 bytes reserved for ATT header +// https://devzone.nordicsemi.com/f/nordic-q-a/111900/maximum-nus-packet-payload-with-ble-data-length-extensio +// Should equal `CONFIG_BT_BUF_ACL_RX_SIZE - L2CAP_HEADER_SIZE - ATT_HEADER_SIZE`, otherwise something is wrong +#define MAX_LINK_PACKET_LENGTH 244 + +// Typedefs: + +typedef enum { + SyncablePropertyId_UserConfiguration, + SyncablePropertyId_CurrentKeymapId, + SyncablePropertyId_CurrentLayerId, + SyncablePropertyId_KeyboardReport, + SyncablePropertyId_MouseReport, + SyncablePropertyId_GamepadReport, + SyncablePropertyId_LeftHalfKeyStates, + SyncablePropertyId_LeftModuleKeyStates, + SyncablePropertyId_LeftBatteryPercentage, + SyncablePropertyId_LeftBatteryChargingState, + SyncablePropertyId_ControlsReport, +} syncable_property_id_t; + +typedef struct { + syncable_property_id_t id; + bool dirty; +} syncable_property_t; + + +#endif // __LINK_PROTOCOL_H__ diff --git a/device/src/logger.c b/device/src/logger.c new file mode 100644 index 000000000..01dc4d22b --- /dev/null +++ b/device/src/logger.c @@ -0,0 +1,66 @@ +#include +#include +#include +#include "logger.h" +#include "shell.h" +#include "keyboard/uart.h" +#include "nus_client.h" +#include "nus_server.h" +#include "device.h" +#include "messenger.h" +#include "legacy/macros/status_buffer.h" +#include "zephyr/device.h" + +#ifdef DEVICE_HAS_OLED +#include "keyboard/oled/widgets/console_widget.h" +#endif + +#define MAX_LOG_LENGTH 64 + +#define EXPAND_STRING(BUFFER) \ +char BUFFER[MAX_LOG_LENGTH]; \ +{ \ + va_list myargs; \ + va_start(myargs, fmt); \ + BUFFER[MAX_LOG_LENGTH-1] = '\0'; \ + vsnprintf(BUFFER, MAX_LOG_LENGTH-1, fmt, myargs); \ +} + +void Uart_LogConstant(const char* buffer) { + printk("%s", buffer); +} + +void Uart_Log(const char *fmt, ...) { + EXPAND_STRING(buffer); + + Uart_LogConstant(buffer); +} + +void Log(const char *fmt, ...) { + EXPAND_STRING(buffer); + + LogConstantTo(DeviceId_Uhk_Dongle, LogTarget_Uart, buffer); +} + +void LogConstantTo(device_id_t deviceId, log_target_t logMask, const char* buffer) { + if (DEVICE_ID == deviceId) { + if (logMask & LogTarget_Oled) { + Oled_LogConstant(buffer); + } + if (logMask & LogTarget_Uart) { + Uart_LogConstant(buffer); + } + if (logMask & LogTarget_ErrorBuffer) { + Macros_ReportPrintf(NULL, "%s", buffer); + } + } else { + Messenger_Send2(deviceId, MessageId_Log, logMask, buffer, strlen(buffer)+1); + } +} + +void LogTo(device_id_t deviceId, log_target_t logMask, const char *fmt, ...) { + EXPAND_STRING(buffer); + + LogConstantTo(deviceId, logMask, buffer); +} + diff --git a/device/src/logger.h b/device/src/logger.h new file mode 100644 index 000000000..681d4d190 --- /dev/null +++ b/device/src/logger.h @@ -0,0 +1,27 @@ +#ifndef __LOGGER_H__ +#define __LOGGER_H__ + +// Includes: + + #include "device.h" + #include "stdint.h" + +// Variables: + +typedef enum { + LogTarget_Oled = 1, + LogTarget_Uart = 2, + LogTarget_ErrorBuffer = 4, +} log_target_t; + +// Functions: + + void Oled_LogConstant(const char* text); + void Oled_Log(const char *fmt, ...); + void Uart_LogConstant(const char* buffer); + void Uart_Log(const char *fmt, ...); + void Log(const char *fmt, ...); + void LogTo(device_id_t deviceId, log_target_t logMask, const char *fmt, ...); + void LogConstantTo(device_id_t deviceId, log_target_t logMask, const char* buffer); + +#endif // __LOGGER_H__ diff --git a/device/src/lvgl/lvgl.c b/device/src/lvgl/lvgl.c new file mode 100644 index 000000000..4d73f861c --- /dev/null +++ b/device/src/lvgl/lvgl.c @@ -0,0 +1,12 @@ +#include "lvgl.h" + +bool lv_font_get_glyph_dsc_fmt_txt(const lv_font_t * font, lv_font_glyph_dsc_t * dsc_out, uint32_t unicode_letter, uint32_t unicode_letter_next) +{ + return true; +} + +const void * lv_font_get_bitmap_fmt_txt(lv_font_glyph_dsc_t * g_dsc, uint32_t unicode_letter, + lv_draw_buf_t * draw_buf) +{ + return NULL; +} diff --git a/device/src/lvgl/lvgl.h b/device/src/lvgl/lvgl.h new file mode 100644 index 000000000..1c0fd93f1 --- /dev/null +++ b/device/src/lvgl/lvgl.h @@ -0,0 +1,235 @@ +#ifndef __LVGL_DUMMY_H__ +#define __LVGL_DUMMY_H__ + +// This file contains excerpts from the LVGL project needed to use LVGL-unpacked fonts. + +/** + * The original source codes are available under following license: + * + * MIT license + * Copyright (c) 2021 LVGL Kft + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +// Includes: + +#include +#include +#include + +// Macros: + +#define LV_ATTRIBUTE_LARGE_CONST +#define LVGL_VERSION_MAJOR 8 +#define LV_VERSION_CHECK(A, B, C) (A >= 8) + +// Variables: + +// Typedefs: + +typedef struct { + uint32_t bitmap_index; /**< Start index of the bitmap. A font can be max 4 GB.*/ + uint32_t adv_w; /**< Draw the next glyph after this width. 28.4 format (real_value * 16 is stored).*/ + uint16_t box_w; /**< Width of the glyph's bounding box*/ + uint16_t box_h; /**< Height of the glyph's bounding box*/ + int16_t ofs_x; /**< x offset of the bounding box*/ + int16_t ofs_y; /**< y offset of the bounding box. Measured from the top of the line*/ +} lv_font_fmt_txt_glyph_dsc_t; + +/** Format of font character map.*/ +typedef enum { + LV_FONT_FMT_TXT_CMAP_FORMAT0_FULL, + LV_FONT_FMT_TXT_CMAP_SPARSE_FULL, + LV_FONT_FMT_TXT_CMAP_FORMAT0_TINY, + LV_FONT_FMT_TXT_CMAP_SPARSE_TINY, +} lv_font_fmt_txt_cmap_type_t; + + + +/** + * Map codepoints to a `glyph_dsc`s + * Several formats are supported to optimize memory usage + * See https://github.com/lvgl/lv_font_conv/blob/master/doc/font_spec.md + */ +typedef struct { + /** First Unicode character for this range*/ + uint32_t range_start; + + /** Number of Unicode characters related to this range. + * Last Unicode character = range_start + range_length - 1*/ + uint16_t range_length; + + /** First glyph ID (array index of `glyph_dsc`) for this range*/ + uint16_t glyph_id_start; + + /* + According the specification there are 4 formats: + https://github.com/lvgl/lv_font_conv/blob/master/doc/font_spec.md + + For simplicity introduce "relative code point": + rcp = codepoint - range_start + + and a search function: + search a "value" in an "array" and returns the index of "value". + + Format 0 tiny + unicode_list == NULL && glyph_id_ofs_list == NULL + glyph_id = glyph_id_start + rcp + + Format 0 full + unicode_list == NULL && glyph_id_ofs_list != NULL + glyph_id = glyph_id_start + glyph_id_ofs_list[rcp] + + Sparse tiny + unicode_list != NULL && glyph_id_ofs_list == NULL + glyph_id = glyph_id_start + search(unicode_list, rcp) + + Sparse full + unicode_list != NULL && glyph_id_ofs_list != NULL + glyph_id = glyph_id_start + glyph_id_ofs_list[search(unicode_list, rcp)] + */ + + const uint16_t * unicode_list; + + /** if(type == LV_FONT_FMT_TXT_CMAP_FORMAT0_...) it's `uint8_t *` + * if(type == LV_FONT_FMT_TXT_CMAP_SPARSE_...) it's `uint16_t *` + */ + const void * glyph_id_ofs_list; + + /** Length of `unicode_list` and/or `glyph_id_ofs_list`*/ + uint16_t list_length; + + /** Type of this character map*/ + lv_font_fmt_txt_cmap_type_t type; +} lv_font_fmt_txt_cmap_t; + + +typedef struct _lv_font_t lv_font_t;/** Describes the properties of a glyph.*/ + +typedef struct { + const void * cache; + int32_t ref_cnt; + uint32_t node_size; + + bool is_invalid; +} lv_cache_entry_t; + +typedef enum { + LV_FONT_SUBPX_NONE, + LV_FONT_SUBPX_HOR, + LV_FONT_SUBPX_VER, + LV_FONT_SUBPX_BOTH, +} lv_font_subpx_t; + +/** The font format.*/ +typedef enum { + LV_FONT_GLYPH_FORMAT_NONE = 0, /**< Maybe not visible*/ + + /**< Legacy simple formats*/ + LV_FONT_GLYPH_FORMAT_A1 = 0x01, /**< 1 bit per pixel*/ + LV_FONT_GLYPH_FORMAT_A2 = 0x02, /**< 2 bit per pixel*/ + LV_FONT_GLYPH_FORMAT_A4 = 0x04, /**< 4 bit per pixel*/ + LV_FONT_GLYPH_FORMAT_A8 = 0x08, /**< 8 bit per pixel*/ + + LV_FONT_GLYPH_FORMAT_IMAGE = 0x09, /**< Image format*/ + + /**< Advanced formats*/ + LV_FONT_GLYPH_FORMAT_VECTOR = 0x0A, /**< Vectorial format*/ + LV_FONT_GLYPH_FORMAT_SVG = 0x0B, /**< SVG format*/ + LV_FONT_GLYPH_FORMAT_CUSTOM = 0xFF, /**< Custom format*/ +} lv_font_glyph_format_t; + +typedef struct { + const lv_font_t * + resolved_font; /**< Pointer to a font where the glyph was actually found after handling fallbacks*/ + uint16_t adv_w; /**< The glyph needs this space. Draw the next glyph after this width.*/ + uint16_t box_w; /**< Width of the glyph's bounding box*/ + uint16_t box_h; /**< Height of the glyph's bounding box*/ + int16_t ofs_x; /**< x offset of the bounding box*/ + int16_t ofs_y; /**< y offset of the bounding box*/ + lv_font_glyph_format_t format; /**< Font format of the glyph see @lv_font_glyph_format_t*/ + uint8_t is_placeholder: 1; /**< Glyph is missing. But placeholder will still be displayed*/ + + uint32_t glyph_index; /**< The index of the glyph in the font file. Used by the font cache*/ + lv_cache_entry_t * entry; /**< The cache entry of the glyph draw data. Used by the font cache*/ +} lv_font_glyph_dsc_t; + +typedef struct lv_draw_buf_t lv_draw_buf_t; + +typedef uint8_t lv_font_fmt_txt_glyph_cache_t; + +/*Describe store additional data for fonts*/ +typedef struct { + /*The bitmaps of all glyphs*/ + const uint8_t * glyph_bitmap; + + /*Describe the glyphs*/ + const lv_font_fmt_txt_glyph_dsc_t * glyph_dsc; + + /*Map the glyphs to Unicode characters. + *Array of `lv_font_cmap_fmt_txt_t` variables*/ + const lv_font_fmt_txt_cmap_t * cmaps; + + /** + * Store kerning values. + * Can be `lv_font_fmt_txt_kern_pair_t * or `lv_font_kern_classes_fmt_txt_t *` + * depending on `kern_classes` + */ + const void * kern_dsc; + + /*Scale kern values in 12.4 format*/ + uint16_t kern_scale; + + /*Number of cmap tables*/ + uint16_t cmap_num : 9; + + /*Bit per pixel: 1, 2, 3, 4, 8*/ + uint16_t bpp : 4; + + /*Type of `kern_dsc`*/ + uint16_t kern_classes : 1; + + /* + * storage format of the bitmap + * from `lv_font_fmt_txt_bitmap_format_t` + */ + uint16_t bitmap_format : 2; + void* cache; +} lv_font_fmt_txt_dsc_t; + +struct _lv_font_t { + /** Get a glyph's descriptor from a font*/ + bool (*get_glyph_dsc)(const lv_font_t *, lv_font_glyph_dsc_t *, uint32_t letter, uint32_t letter_next); + + /** Get a glyph's bitmap from a font*/ + const void * (*get_glyph_bitmap)(lv_font_glyph_dsc_t *, uint32_t, lv_draw_buf_t *); + + /** Release a glyph*/ + void (*release_glyph)(const lv_font_t *, lv_font_glyph_dsc_t *); + + /*Pointer to the font in a font pack (must have the same line height)*/ + int32_t line_height; /**< The real line height where any text fits*/ + int32_t base_line; /**< Base line measured from the top of the line_height*/ + uint8_t subpx : 2; /**< An element of `lv_font_subpx_t`*/ + uint8_t kerning : 1; /**< An element of `lv_font_kerning_t`*/ + + int8_t underline_position; /**< Distance between the top of the underline and base line (< 0 means below the base line)*/ + int8_t underline_thickness; /**< Thickness of the underline*/ + + const lv_font_fmt_txt_dsc_t* dsc; /**< Store implementation specific or run_time data or caching here*/ + const lv_font_t * fallback; /**< Fallback font for missing glyph. Resolved recursively */ + void * user_data; /**< Custom user data for font.*/ +}; + +// Functions: + + +bool lv_font_get_glyph_dsc_fmt_txt(const lv_font_t * font, lv_font_glyph_dsc_t * dsc_out, uint32_t unicode_letter, uint32_t unicode_letter_next); +const void * lv_font_get_bitmap_fmt_txt(lv_font_glyph_dsc_t * g_dsc, uint32_t unicode_letter, lv_draw_buf_t * draw_buf); + +#endif diff --git a/device/src/main.c b/device/src/main.c new file mode 100644 index 000000000..5a35ca837 --- /dev/null +++ b/device/src/main.c @@ -0,0 +1,191 @@ +#include "main.h" +#include "bt_advertise.h" +#include "nus_client.h" +#include "nus_server.h" +#include "bt_manager.h" +#include "legacy/config_parser/config_globals.h" +#include "legacy/ledmap.h" +#include "shared/attributes.h" +#include "zephyr/kernel.h" +#include "zephyr/storage/flash_map.h" +#include "keyboard/key_scanner.h" +#include "keyboard/leds.h" +#include "keyboard/oled/oled.h" +#include "keyboard/charger.h" +#include "keyboard/spi.h" +#include "keyboard/uart.h" +#include "keyboard/i2c.h" +#include "peripherals/merge_sensor.h" +#include "shell.h" +#include "device.h" +#include "usb/usb.h" +#include "bt_conn.h" +#include "settings.h" +#include "flash.h" +#include "usb_commands/usb_command_apply_config.h" +#include "macros/shortcut_parser.h" +#include "macros/keyid_parser.h" +#include "macros/core.h" +#include "legacy/timer.h" +#include "legacy/user_logic.h" +#include "legacy/config_manager.h" +#include "messenger.h" +#include "legacy/led_manager.h" +#include "legacy/debug.h" +#include "state_sync.h" +#include "keyboard/charger.h" +#include +#include "dongle_leds.h" +#include "debug_eventloop_timing.h" +#include +#include "dongle_leds.h" +#include "legacy/usb_protocol_handler.h" + +k_tid_t Main_ThreadId = 0; + +static void sleepTillNextMs() { + static uint64_t wakeupTimeUs = 0; + const uint64_t minSleepTime = 100; + uint64_t currentTimeUs = k_cyc_to_us_near64(k_cycle_get_32()); + + wakeupTimeUs = wakeupTimeUs+1000; + + if (currentTimeUs < wakeupTimeUs) { + k_usleep(MAX(wakeupTimeUs-currentTimeUs, minSleepTime)); + } else { + k_usleep(minSleepTime); + wakeupTimeUs = currentTimeUs; + } +} + + +static K_SEM_DEFINE(mainWakeupSemaphore, 1, 1); + +static void scheduleNextRun() { + uint32_t nextEventTime = 0; + bool eventIsValid = false; + if (EventScheduler_Vector & EventVector_EventScheduler) { + nextEventTime = EventScheduler_Process(); + eventIsValid = true; + } + CurrentTime = k_uptime_get(); + int32_t diff = nextEventTime - CurrentTime; + + k_sem_take(&mainWakeupSemaphore, K_NO_WAIT); + bool haveMoreWork = (EventScheduler_Vector & EventVector_UserLogicUpdateMask); + if (haveMoreWork) { + LOG_SCHEDULE( EventVector_ReportMask("Continuing immediately because of: ", EventScheduler_Vector & EventVector_UserLogicUpdateMask);); + EVENTLOOP_TIMING(printk("Continuing immediately\n")); + // Mouse keys don't like being called twice in one second for some reason + k_sem_give(&mainWakeupSemaphore); + sleepTillNextMs(); + return; + } else if (eventIsValid) { + EVENTLOOP_TIMING(printk("Sleeping for %d\n", diff)); + k_sem_take(&mainWakeupSemaphore, K_MSEC(diff)); + // k_sleep(K_MSEC(diff)); + } else { + EVENTLOOP_TIMING(printk("Sleeping forever\n")); + k_sem_take(&mainWakeupSemaphore, K_FOREVER); + // k_sleep(K_FOREVER); + } +} + +//TODO: inline this +void Main_Wake() { + k_sem_give(&mainWakeupSemaphore); + // k_wakeup(Main_ThreadId); +} + +int main(void) { + Main_ThreadId = k_current_get(); + printk("----------\n" DEVICE_NAME " started\n"); + + if (DEVICE_IS_UHK80_RIGHT) { + flash_area_open(FLASH_AREA_ID(hardware_config_partition), &hardwareConfigArea); + flash_area_open(FLASH_AREA_ID(user_config_partition), &userConfigArea); + } + + if (!DEVICE_IS_UHK_DONGLE) { + InitUart(); + InitZephyrI2c(); + InitSpi(); + +#if DEVICE_HAS_OLED + InitOled(); +#endif // DEVICE_HAS_OLED + + InitLeds(); + +#if DEVICE_HAS_MERGE_SENSOR + MergeSensor_Init(); +#endif // DEVICE_HAS_MERGE_SENSOR + + InitKeyScanner(); + + } + + if (DEVICE_IS_UHK80_LEFT || DEVICE_IS_UHK80_RIGHT) { + ConfigManager_ResetConfiguration(false); + Ledmap_InitLedLayout(); + } + + if (DEVICE_IS_UHK80_RIGHT) { + InitFlash(); + printk("Reading hardware config\n"); + Flash_ReadAreaSync(hardwareConfigArea, 0, HardwareConfigBuffer.buffer, HARDWARE_CONFIG_SIZE); + printk("Reading user config\n"); + Flash_ReadAreaSync(userConfigArea, 0, StagingUserConfigBuffer.buffer, USER_CONFIG_SIZE); + USB_SetSerialNumber(HardwareConfig->uniqueId); + printk("Applying user config\n"); + bool factoryMode = false; + if (factoryMode || UsbCommand_ApplyConfig() != UsbStatusCode_Success) { + UsbCommand_ApplyFactory(); + } + printk("User config applied\n"); + ShortcutParser_initialize(); + KeyIdParser_initialize(); + Macros_Initialize(); + } + + USB_EnableHid(); // has to be after USB_SetSerialNumber + + bt_enable(NULL); + + // has to be after bt_enable + InitSettings(); + + // has to be after InitSettings + BtManager_InitBt(); + BtManager_StartBt(); + + if (!DEVICE_IS_UHK_DONGLE) { + InitCharger(); // has to be after usb initialization + } + + Messenger_Init(); + + StateSync_Init(); + +#if DEVICE_IS_UHK80_RIGHT + while (true) + { + CurrentTime = k_uptime_get(); + Messenger_ProcessQueue(); + if (EventScheduler_Vector & EventVector_UserLogicUpdateMask) { + EVENTLOOP_TIMING(EVENTLOOP_TIMING(EventloopTiming_Start())); + RunUserLogic(); + EVENTLOOP_TIMING(EventloopTiming_End()); + } + scheduleNextRun(); + } +#else + while (true) + { + CurrentTime = k_uptime_get(); + Messenger_ProcessQueue(); + RunUhk80LeftHalfLogic(); + scheduleNextRun(); + } +#endif +} diff --git a/device/src/main.h b/device/src/main.h new file mode 100644 index 000000000..e0284efa5 --- /dev/null +++ b/device/src/main.h @@ -0,0 +1,23 @@ +#ifndef __MAIN_H__ +#define __MAIN_H__ + +// Includes: + + #include + #include + #include + +// Macros: + +// Typedefs: + +// Variables: + + extern k_tid_t Main_ThreadId; + +// Functions: + + void Main_Wake(); + +#endif // __MAIN_H__ + diff --git a/device/src/messenger.c b/device/src/messenger.c new file mode 100644 index 000000000..60f04460c --- /dev/null +++ b/device/src/messenger.c @@ -0,0 +1,377 @@ +#include "messenger.h" +#include "bt_conn.h" +#include "device.h" +#include "autoconf.h" +#include "link_protocol.h" +#include "logger.h" +#include "main.h" +#include "messenger_queue.h" +#include "shared/slave_protocol.h" +#include "state_sync.h" +#include "usb/usb_compatibility.h" +#include "nus_server.h" +#include "nus_client.h" +#include "legacy/module.h" +#include "legacy/key_states.h" +#include "shared/attributes.h" +#include "legacy/str_utils.h" +#include "legacy/event_scheduler.h" +#include "legacy/slave_drivers/uhk_module_driver.h" + +#if DEVICE_IS_KEYBOARD +#include "keyboard/uart.h" +#endif + +static k_tid_t mainThreadId = 0; + +typedef enum { + MessengerChannel_NusServer, + MessengerChannel_NusClient, + MessengerChannel_Uart, + MessengerChannel_None, +} messenger_channel_t; + +static messenger_channel_t determineChannel(device_id_t dst) { +#if DEVICE_IS_KEYBOARD + if (Uart_IsConnected()) { + if (DEVICE_IS_UHK80_LEFT) { + switch (dst) { + case DeviceId_Uhk_Dongle: + case DeviceId_Uhk80_Right: + return MessengerChannel_Uart; + default: + break; + } + } + + if (DEVICE_IS_UHK80_RIGHT) { + switch (dst) { + case DeviceId_Uhk_Dongle: + break; + case DeviceId_Uhk80_Left: + return MessengerChannel_Uart; + default: + break; + } + } + } +#endif + + if (DEVICE_IS_UHK80_LEFT && Bt_DeviceIsConnected(DeviceId_Uhk80_Right)) { + switch (dst) { + case DeviceId_Uhk_Dongle: + case DeviceId_Uhk80_Right: + if (Bt_DeviceIsConnected(DeviceId_Uhk80_Right)) { + return MessengerChannel_NusServer; + } + default: + return MessengerChannel_None; + } + } + + if (DEVICE_IS_UHK80_RIGHT) { + switch (dst) { + case DeviceId_Uhk_Dongle: + if (Bt_DeviceIsConnected(DeviceId_Uhk_Dongle)) { + return MessengerChannel_NusServer; + } + break; + case DeviceId_Uhk80_Left: + if (Bt_DeviceIsConnected(DeviceId_Uhk80_Left)) { + return MessengerChannel_NusClient; + } + break; + default: + return MessengerChannel_None; + } + } + + if (DEVICE_IS_UHK_DONGLE) { + switch (dst) { + case DeviceId_Uhk80_Right: + case DeviceId_Uhk80_Left: + if (Bt_DeviceIsConnected(DeviceId_Uhk80_Right)) { + return MessengerChannel_NusClient; + } + break; + default: + return MessengerChannel_None; + } + } + + return MessengerChannel_None; +} + +static char getDeviceAbbrev(device_id_t src) { + switch (src) { + case DeviceId_Uhk80_Left: + return 'L'; + case DeviceId_Uhk80_Right: + return 'R'; + case DeviceId_Uhk_Dongle: + return 'D'; + default: + return '?'; + } +} + +static void receiveLog(device_id_t src, const uint8_t* data, uint16_t len) { + uint8_t ATTR_UNUSED messageId = *(data++); + uint8_t logmask = *(data++); + LogTo(DEVICE_ID, logmask, "%c>>> %s", getDeviceAbbrev(src), data); +} + + +static void receiveLeft(device_id_t src, const uint8_t* data, uint16_t len) { + switch (data[0]) { + case MessageId_StateSync: + StateSync_ReceiveStateUpdate(src, data, len); + break; + case MessageId_Log: + receiveLog(src, data, len); + break; + default: + printk("Didn't expect to receive message %i %i\n", data[0], data[1]); + break; + } +} + +static void processSyncablePropertyRight(device_id_t src, const uint8_t* data, uint16_t len) { + + uint8_t ATTR_UNUSED messageId = *(data++); + uint8_t propertyId = *(data++); + const uint8_t* message = data; + switch (propertyId) { + case SyncablePropertyId_LeftHalfKeyStates: + for (uint8_t keyId = 0; keyId < MAX_KEY_COUNT_PER_MODULE; keyId++) { + KeyStates[SlotId_LeftKeyboardHalf][keyId].hardwareSwitchState = !!(message[keyId/8] & (1 << (keyId % 8))); + } + EventVector_Set(EventVector_StateMatrix); + break; + case SyncablePropertyId_LeftModuleKeyStates: + { + uint8_t driverId = UhkModuleDriverId_LeftModule; + uhk_module_state_t *moduleState = UhkModuleStates + driverId; + UhkModuleSlaveDriver_ProcessKeystates(driverId, moduleState, data); + } + break; + default: + printk("Unrecognized or unexpected message [%i, %i, ...]\n", data[0], data[1]); + break; + } +} + +static void receiveRight(device_id_t src, const uint8_t* data, uint16_t len) { + switch (data[0]) { + case MessageId_StateSync: + StateSync_ReceiveStateUpdate(src, data, len); + break; + case MessageId_SyncableProperty: + processSyncablePropertyRight(src, data, len); + break; + case MessageId_Log: + receiveLog(src, data, len); + break; + default: + printk("Unrecognized or unexpected message [%i, %i, ...]\n", data[0], data[1]); + break; + } +} + +static void processSyncablePropertyDongle(device_id_t src, const uint8_t* data, uint16_t len) { + uint8_t ATTR_UNUSED messageId = *(data++); + uint8_t propertyId = *(data++); + const uint8_t* message = data; + switch (propertyId) { + case SyncablePropertyId_KeyboardReport: + UsbCompatibility_SendKeyboardReport((usb_basic_keyboard_report_t*)message); + break; + case SyncablePropertyId_MouseReport: + UsbCompatibility_SendMouseReport((usb_mouse_report_t*)message); + break; + case SyncablePropertyId_ControlsReport: + UsbCompatibility_SendConsumerReport2(message); + break; + default: + printk("Unrecognized or unexpected message [%i, %i, ...]\n", data[0], data[1]); + break; + } +} + +static void receiveDongle(device_id_t src, const uint8_t* data, uint16_t len) { + switch (data[0]) { + case MessageId_SyncableProperty: + processSyncablePropertyDongle(src, data, len); + break; + case MessageId_StateSync: + StateSync_ReceiveStateUpdate(src, data, len); + break; + case MessageId_Log: + receiveLog(src, data, len); + break; + default: + printk("Unrecognized or unexpected message [%i, %i, ...]\n", data[0], data[1]); + break; + } +} + +static void receive(const uint8_t* data, uint16_t len) { + device_id_t src = *data++; + device_id_t dst = *data++; + len-= 2; + + if (dst != DEVICE_ID) { + message_t msg = { + .data = data, + .len = len, + .idsUsed = 0, + .src = src, + .dst = dst, + }; + printk("Forwarding message from %d to %d\n", msg.src, msg.dst); + Messenger_SendMessage(msg); + } else { + switch (DEVICE_ID) { + case DeviceId_Uhk80_Left: + receiveLeft(src, data, len); + break; + case DeviceId_Uhk80_Right: + receiveRight(src, data, len); + break; + case DeviceId_Uhk_Dongle: + receiveDongle(src, data, len); + break; + } + } +} + +static bool isSpam(const uint8_t* data) { + if (data[MessageOffset_MsgId1] == MessageId_Ping) { + return true; + } + if (data[MessageOffset_MsgId1] == MessageId_StateSync && data[MessageOffset_MsgId1+1] == StateSyncPropertyId_Battery) { + return DEBUG_EVENTLOOP_SCHEDULE; + } + return false; +} + +ATTR_UNUSED static void getMessageDescription(const uint8_t* data, const char** out1, const char** out2) { + switch (data[MessageOffset_MsgId1]) { + case MessageId_StateSync: + *out1 = "StateSync"; + *out2 = StateSync_PropertyIdToString(data[MessageOffset_MsgId1+1]); + return; + case MessageId_SyncableProperty: + *out1 = "SyncableProperty"; + *out2 = NULL; + return; + case MessageId_Log: + *out1 = "Log"; + *out2 = NULL; + return; + case MessageId_Ping: + *out1 = "Ping"; + *out2 = NULL; + return; + default: + *out1 = "Unknown"; + *out2 = NULL; + return; + } +} + +void Messenger_Enqueue(uint8_t src, const uint8_t* data, uint16_t len) { + if (!isSpam(data)) { + MessengerQueue_Put(src, data, len); + EventVector_Set(EventVector_NewMessage); + LOG_SCHEDULE( + const char* desc1; + const char* desc2; + getMessageDescription(data, &desc1, &desc2); + printk(" (%c %s %s)\n", getDeviceAbbrev(data[MessageOffset_Src]), desc1, desc2 == NULL ? "" : desc2); + ); + Main_Wake(); + } +} + +void Messenger_ProcessQueue() { + EventVector_Unset(EventVector_NewMessage); + messenger_queue_record_t rec = MessengerQueue_Take(); + while (rec.data != NULL) { + receive(rec.data, rec.len); + MessengerQueue_FreeMemory(rec.data); + + rec = MessengerQueue_Take(); + } +} + +bool Messenger_Availability(device_id_t dst, messenger_availability_op_t operation) { + messenger_channel_t channel = determineChannel(dst); + + switch (channel) { + case MessengerChannel_Uart: +#if DEVICE_IS_KEYBOARD + return Uart_Availability(operation); +#endif + return false; + case MessengerChannel_NusServer: + return NusServer_Availability(operation); + case MessengerChannel_NusClient: + return NusClient_Availability(operation); + default: + return false; + } +} + +void Messenger_SendMessage(message_t message) { + messenger_channel_t channel = determineChannel(message.dst); + device_id_t dst = message.dst; + + switch (channel) { + case MessengerChannel_Uart: +#if DEVICE_IS_KEYBOARD + Uart_SendMessage(message); +#endif + break; + case MessengerChannel_NusServer: + NusServer_SendMessage(message); + break; + case MessengerChannel_NusClient: + NusClient_SendMessage(message); + break; + default: + printk("Failed to send message from %s to %s\n", Utils_DeviceIdToString(DEVICE_ID), Utils_DeviceIdToString(dst)); + break; + } +} + +void Messenger_Send(device_id_t dst, uint8_t messageId, const uint8_t* data, uint16_t len) { + message_t msg = { + .data = data, + .len = len, + .messageId[0] = messageId, + .idsUsed = 1, + .src = DEVICE_ID, + .dst = dst, + }; + Messenger_SendMessage(msg); +} + +void Messenger_Send2(device_id_t dst, uint8_t messageId, uint8_t messageId2, const uint8_t* data, uint16_t len) { + message_t msg = { + .data = data, + .len = len, + .messageId[0] = messageId, + .messageId[1] = messageId2, + .idsUsed = 2, + .src = DEVICE_ID, + .dst = dst, + }; + Messenger_SendMessage(msg); +} + +void Messenger_Init() { + MessengerQueue_Init(); + mainThreadId = k_current_get(); +} + diff --git a/device/src/messenger.h b/device/src/messenger.h new file mode 100644 index 000000000..cf7007a36 --- /dev/null +++ b/device/src/messenger.h @@ -0,0 +1,54 @@ +#ifndef __MESSENGER_H__ +#define __MESSENGER_H__ + +// Includes: + + #include "shared/attributes.h" +#include + #include + +// Typedefs: + + typedef enum { + MessengerAvailabilityOp_InquireOneEmpty, + MessengerAvailabilityOp_InquireAllEmpty, + MessengerAvailabilityOp_BlockTillOneEmpty, + } messenger_availability_op_t; + + typedef enum { + MessageId_StateSync = 1, + MessageId_SyncableProperty, + MessageId_Log, + MessageId_Ping, + } message_id_t; + +typedef enum { + MessageOffset_Src = 0, + MessageOffset_Dst = 1, + MessageOffset_MsgId1 = 2, +} message_offset_t; + + // the point of message_t is to reduce the number of times we need to copy the message. + typedef struct { + const uint8_t* data; + uint16_t len; + uint8_t messageId[2]; + uint8_t idsUsed; + uint8_t src; + uint8_t dst; + } ATTR_PACKED message_t; + +// Functions: + + void Messenger_Receive(uint8_t src, const uint8_t* data, uint16_t len); + void Messenger_SendMessage(message_t message); + void Messenger_Send(uint8_t dst, uint8_t messageId, const uint8_t* data, uint16_t len); + void Messenger_Send2(uint8_t dst, uint8_t messageId, uint8_t messageId2, const uint8_t* data, uint16_t len); + bool Messenger_Availability(uint8_t dst, messenger_availability_op_t operation); + + void Messenger_Enqueue(uint8_t src, const uint8_t* data, uint16_t len); + void Messenger_ProcessQueue(); + + void Messenger_Init(); + +#endif // __MESSENGER_H__ diff --git a/device/src/messenger_queue.c b/device/src/messenger_queue.c new file mode 100644 index 000000000..f78f1aa85 --- /dev/null +++ b/device/src/messenger_queue.c @@ -0,0 +1,157 @@ +#include "messenger_queue.h" +#include "shared/attributes.h" +#include "device.h" +#include "link_protocol.h" +#include +#include +#include + +// define pool helpers +#define POOL(NAME, POOL_SIZE, SEGMENT_SIZE) \ + struct { \ + ATTR_ALIGNED uint8_t segments[POOL_SIZE][SEGMENT_SIZE]; \ + ATTR_ALIGNED bool segmentTaken[POOL_SIZE]; \ + uint8_t idx; \ + } NAME; + +#define POOL_ALLOCATE(NAME, POOL_SIZE, SEGMENT_SIZE) \ + uint8_t consumedIdx = NAME.idx; \ + NAME.idx = (NAME.idx+1) % POOL_SIZE; \ + if (__sync_bool_compare_and_swap(&NAME.segmentTaken[consumedIdx], false, true)) { \ + return &NAME.segments[consumedIdx][0]; \ + } + +#define POOL_FREE(ARG1, NAME, POOL_SIZE, SEGMENT_SIZE) \ + uint8_t idx = (ARG1 - &NAME.segments[0][0]) / SEGMENT_SIZE; \ + NAME.segmentTaken[idx] = false; + +#define POOL_STATE(NAME, POOL_SIZE, SEGMENT_SIZE) \ +{ \ + uint8_t count = 0; \ + for (uint8_t i = 0; i < POOL_SIZE; i++) { \ + if (NAME.segmentTaken[i]) { \ + count++; \ + } \ + } \ + printk("%i/%i segments taken\n", count, POOL_SIZE); \ +} \ + +// Define the structures + +#define POOL_SIZE 16 +#define POOL_REGION_SIZE MAX_LINK_PACKET_LENGTH +#define QUEUE_REGION_SIZE sizeof(messenger_queue_record_t) + +POOL(regionPool, POOL_SIZE, POOL_REGION_SIZE); +POOL(queuePool, POOL_SIZE, QUEUE_REGION_SIZE); + +#define FIFO_RETRIES 10 +struct k_fifo messageQueue; + +struct { + messenger_queue_record_t* first; + messenger_queue_record_t* last; +} fifo = { .first = NULL, .last = NULL } ; + + +static void panic(const char* reason) { + printk("%s", reason); + k_panic(); +} + +static void fifoPut(messenger_queue_record_t* node) { + for (uint8_t tries = 0; tries < FIFO_RETRIES; tries++) { + if (fifo.first == NULL) { + node->fifo_reserved = NULL; + if (!__sync_bool_compare_and_swap((intptr_t*)&fifo.first, NULL, node)) { + continue; + } + fifo.last = fifo.first; + return; + } else { + node->fifo_reserved = NULL; + if (!__sync_bool_compare_and_swap((intptr_t*)&fifo.last->fifo_reserved, NULL, (intptr_t)node)) { + continue; + } + while ( fifo.last->fifo_reserved != NULL ) { + fifo.last = fifo.last->fifo_reserved; + } + return; + } + } + panic("failed to insert message into fifo\n"); +} + +static messenger_queue_record_t* fifoTake() { + for (uint8_t tries = 0; tries < FIFO_RETRIES; tries++) { + if (fifo.first == NULL) { + return NULL; + } else { + messenger_queue_record_t* node = fifo.first; + messenger_queue_record_t* next = node->fifo_reserved; + if (!__sync_bool_compare_and_swap((intptr_t*)&fifo.first, (intptr_t)node, (intptr_t)next)) { + continue; + } + return node; + } + } + panic("failed to retrieve next message from fifo\n"); + return NULL; +} + + +// handle region pool + +uint8_t* MessengerQueue_AllocateMemory() { + for (uint8_t tries = 0; tries < POOL_SIZE; tries++) { + POOL_ALLOCATE(regionPool, POOL_SIZE, POOL_REGION_SIZE); + } + panic("Message segment queue space ran out!\n"); + return NULL; +} + +void MessengerQueue_FreeMemory(const uint8_t* segment) { + POOL_FREE(segment, regionPool, POOL_SIZE, POOL_REGION_SIZE); +} + +// handle queues + +uint8_t* allocateQueueSegment() { + for (uint8_t tries = 0; tries < POOL_SIZE; tries++) { + POOL_ALLOCATE(queuePool, POOL_SIZE, QUEUE_REGION_SIZE); + } + panic("Message segment queue space ran out!\n"); + return NULL; +} + +void freeQueueSegment(const uint8_t* segment) { + POOL_FREE(segment, queuePool, POOL_SIZE, QUEUE_REGION_SIZE); +} + +void MessengerQueue_Put(device_id_t src, const uint8_t* data, uint16_t len) { + messenger_queue_record_t* record = (messenger_queue_record_t*)allocateQueueSegment(); + record->src = src; + record->len = len; + record->data = data; + fifoPut(record); +} + +messenger_queue_record_t MessengerQueue_Take() { + messenger_queue_record_t* record = fifoTake(); + + if (record != NULL) { + messenger_queue_record_t res = *record; + freeQueueSegment((const uint8_t*)record); + return res; + } else { + messenger_queue_record_t res = { + .data = NULL, + .len = 0, + }; + return res; + } +} + +void MessengerQueue_Init() { + k_fifo_init(&messageQueue); +} diff --git a/device/src/messenger_queue.h b/device/src/messenger_queue.h new file mode 100644 index 000000000..b8fbff2b3 --- /dev/null +++ b/device/src/messenger_queue.h @@ -0,0 +1,29 @@ +#ifndef __MESSENGER_QUEUE_H__ +#define __MESSENGER_QUEUE_H__ + +// Includes: + + #include "shared/attributes.h" + #include + #include "device.h" + +// Typedefs: + + typedef struct { + __attribute__((aligned)) void *fifo_reserved; /* 1st word reserved for use by FIFO */ + uint16_t len; + device_id_t src; + const uint8_t* data; + } messenger_queue_record_t; + + +// Functions: + void MessengerQueue_Init(); + + uint8_t* MessengerQueue_AllocateMemory(); + void MessengerQueue_FreeMemory(const uint8_t* segment); + + void MessengerQueue_Put(device_id_t src, const uint8_t* data, uint16_t len); + messenger_queue_record_t MessengerQueue_Take(); + +#endif // __MESSENGER_QUEUE_H__ diff --git a/device/src/nus_client.c b/device/src/nus_client.c new file mode 100644 index 000000000..7f438928d --- /dev/null +++ b/device/src/nus_client.c @@ -0,0 +1,204 @@ +#include +#include +#include +#include "bt_scan.h" +#include "bt_conn.h" +#include "device.h" +#include "legacy/usb_interfaces/usb_interface_basic_keyboard.h" +#include "legacy/usb_interfaces/usb_interface_mouse.h" +#include "messenger.h" +#include "nus_client.h" +#include "bool_array_converter.h" +#include "legacy/slot.h" +#include "shared/bool_array_converter.h" +#include "legacy/module.h" +#include "legacy/key_states.h" +#include "keyboard/oled/widgets/console_widget.h" +#include "state_sync.h" +#include "usb/usb_compatibility.h" +#include "link_protocol.h" +#include "messenger_queue.h" +#include "legacy/debug.h" +#include + +static struct bt_nus_client nus_client; + +#define NUS_SLOTS 1 +static K_SEM_DEFINE(nusBusy, NUS_SLOTS, NUS_SLOTS); + +static void ble_data_sent(struct bt_nus_client *nus, uint8_t err, const uint8_t *const data, uint16_t len) { + k_sem_give(&nusBusy); + if (err) { + printk("ATT error code: 0x%02X\n", err); + } +} + +static uint8_t ble_data_received(struct bt_nus_client *nus, const uint8_t *data, uint16_t len) { + uint8_t* copy = MessengerQueue_AllocateMemory(); + memcpy(copy, data, len); + + switch (DEVICE_ID) { + case DeviceId_Uhk80_Right: + Messenger_Enqueue(DeviceId_Uhk80_Left, copy, len); + break; + case DeviceId_Uhk_Dongle: + Messenger_Enqueue(DeviceId_Uhk80_Right, copy, len); + break; + default: + printk("Ble received message from unknown source."); + break; + } + return BT_GATT_ITER_CONTINUE; +} + +static void discovery_complete(struct bt_gatt_dm *dm, void *context) { + struct bt_nus_client *nus = context; + int err = 0; + + bt_gatt_dm_data_print(dm); + + err = bt_nus_handles_assign(dm, nus); + + if (err) { + printk("Could not assign NUS handles (err %d)\n", err); + return; + } + + err = bt_nus_subscribe_receive(nus); + + if (err) { + printk("Could not subscribe to NUS notifications (err %d)\n", err); + return; + } + + err = bt_gatt_dm_data_release(dm); + + if (err) { + printk("Could not release the discovery data (err %d)\n", err); + return; + } + + printk("NUS connection with %s successfully established\n", GetPeerStringByConn(nus->conn)); + + if (DEVICE_ID == DeviceId_Uhk80_Right) { + Bt_SetDeviceConnected(DeviceId_Uhk80_Left); + } + if (DEVICE_ID == DeviceId_Uhk_Dongle) { + Bt_SetDeviceConnected(DeviceId_Uhk80_Right); + } +} + +static void discovery_service_not_found(struct bt_conn *conn, void *context) { + printk("Service not found\n"); +} + +static void discovery_error(struct bt_conn *conn, int err, void *context) { + printk("Error while discovering GATT database: (%d)\n", err); +} + +struct bt_gatt_dm_cb discovery_cb = { + .completed = discovery_complete, + .service_not_found = discovery_service_not_found, + .error_found = discovery_error, +}; + +static void gatt_discover(struct bt_conn *conn) { + int err = bt_gatt_dm_start(conn, BT_UUID_NUS_SERVICE, &discovery_cb, &nus_client); + if (err) { + printk("could not start the discovery procedure, error code: %d\n", err); + } +} + +static void exchange_func(struct bt_conn *conn, uint8_t err, struct bt_gatt_exchange_params *params) { + if (err) { + printk("MTU exchange failed with %s (err %u)\n", GetPeerStringByConn(conn), err); + } else { + printk("MTU exchange done with %s\n", GetPeerStringByConn(conn)); + } +} + +void NusClient_Connect(struct bt_conn *conn) { + static struct bt_gatt_exchange_params exchange_params; + + exchange_params.func = exchange_func; + int err = bt_gatt_exchange_mtu(conn, &exchange_params); + if (err) { + printk("MTU exchange failed with %s, err %d\n", GetPeerStringByConn(conn), err); + } + + gatt_discover(conn); + + err = bt_scan_stop(); + if (err && (err != -EALREADY)) { + printk("Stop LE scan failed (err %d)\n", err); + } +} + +void NusClient_Disconnected() { + // I argue that when bt is not connected, freeing the semaphore causes no trouble. + k_sem_init(&nusBusy, NUS_SLOTS, NUS_SLOTS); +} + +void NusClient_Init(void) { + int err; + + struct bt_nus_client_init_param init = { + .cb = { + .received = ble_data_received, + .sent = ble_data_sent, + } + }; + + err = bt_nus_client_init(&nus_client, &init); + if (err) { + printk("NUS Client initialization failed (err %d)\n", err); + return; + } + + printk("NUS Client module initialized\n"); +} + +bool NusClient_Availability(messenger_availability_op_t operation) { + switch (operation) { + case MessengerAvailabilityOp_InquireOneEmpty: + return k_sem_count_get(&nusBusy) > 0; + case MessengerAvailabilityOp_InquireAllEmpty: + return k_sem_count_get(&nusBusy) == NUS_SLOTS; + case MessengerAvailabilityOp_BlockTillOneEmpty: + k_sem_take(&nusBusy, K_FOREVER); + k_sem_give(&nusBusy); + return true; + default: + return false; + } +} + +static void send_raw_buffer(const uint8_t *data, uint16_t len) { + SEM_TAKE(&nusBusy); + int err = bt_nus_client_send(&nus_client, data, len); + if (err) { + k_sem_give(&nusBusy); + printk("Client failed to send data over BLE connection (err %d)\n", err); + } +} + +void NusClient_SendMessage(message_t msg) { + uint8_t buffer[MAX_LINK_PACKET_LENGTH]; + uint8_t bufferIdx = 0; + + buffer[bufferIdx++] = msg.src; + buffer[bufferIdx++] = msg.dst; + + for (uint8_t id = 0; id < msg.idsUsed; id++) { + buffer[bufferIdx++] = msg.messageId[id]; + } + + if (msg.len + msg.idsUsed + 2 > MAX_LINK_PACKET_LENGTH) { + printk("Message is too long for NUS packets! [%i, %i, ...]\n", buffer[0], buffer[1]); + return; + } + + memcpy(&buffer[bufferIdx], msg.data, msg.len); + + send_raw_buffer(buffer, msg.len+msg.idsUsed+2); +} diff --git a/device/src/nus_client.h b/device/src/nus_client.h new file mode 100644 index 000000000..7d0d71b59 --- /dev/null +++ b/device/src/nus_client.h @@ -0,0 +1,17 @@ +#ifndef __NUS_CLIENT_H__ +#define __NUS_CLIENT_H__ + +// Includes + + #include + #include "messenger.h" + +// Functions: + + void NusClient_Init(void); + void NusClient_Disconnected(); + void NusClient_Connect(struct bt_conn *conn); + void NusClient_SendMessage(message_t msg); + bool NusClient_Availability(messenger_availability_op_t operation); + +#endif // __NUS_CLIENT_H__ diff --git a/device/src/nus_server.c b/device/src/nus_server.c new file mode 100644 index 000000000..19f9485c5 --- /dev/null +++ b/device/src/nus_server.c @@ -0,0 +1,129 @@ +#include "nus_server.h" +#include +#include "bt_conn.h" +#include "bt_advertise.h" +#include "bt_conn.h" +#include "messenger.h" +#include "device.h" +#include "messenger_queue.h" +#include "legacy/debug.h" +#include "zephyr/bluetooth/addr.h" + +#define NUS_SLOTS 2 + +static K_SEM_DEFINE(nusBusy, NUS_SLOTS, NUS_SLOTS); + +static void setPeerConnected(uint8_t peerId, device_id_t peerDeviceId, struct bt_conn *conn) { + const bt_addr_le_t *addr = bt_conn_get_dst(conn); + if (!Peers[peerId].isConnected || bt_addr_le_eq(&Peers[peerId].addr, addr) != 0) { + Peers[peerId].addr = *addr; + Bt_SetDeviceConnected(peerDeviceId); + } +} + +static void received(struct bt_conn *conn, const uint8_t *const data, uint16_t len) { + uint8_t* copy = MessengerQueue_AllocateMemory(); + memcpy(copy, data, len); + + if (DEVICE_ID == DeviceId_Uhk80_Left) { + setPeerConnected(PeerIdRight, DeviceId_Uhk80_Right, conn); + } + + if (DEVICE_ID == DeviceId_Uhk80_Right) { + setPeerConnected(PeerIdDongle, DeviceId_Uhk_Dongle, conn); + } + + switch (DEVICE_ID) { + case DeviceId_Uhk80_Left: + Messenger_Enqueue(DeviceId_Uhk80_Right, copy, len); + break; + case DeviceId_Uhk80_Right: + Messenger_Enqueue(DeviceId_Uhk_Dongle, copy, len); + break; + default: + printk("Ble received message from unknown source."); + break; + } +} + +static void sent(struct bt_conn *conn) { + k_sem_give(&nusBusy); + char addr[BT_ADDR_LE_STR_LEN] = {0}; + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, ARRAY_SIZE(addr)); +} + +static void send_enabled(enum bt_nus_send_status status) +{ + if (status == BT_NUS_SEND_STATUS_ENABLED) { + // in theory, NUS is ready. In practice, it is once we receive a message from the client. + printk("NUS peripheral connection is ready.\n"); + } +} + +static struct bt_nus_cb nus_cb = { + .received = received, + .sent = sent, + .send_enabled = send_enabled, +}; + +int NusServer_Init(void) { + int err = bt_nus_init(&nus_cb); + if (err) { + printk("Failed to initialize UART service (err: %d)\n", err); + return err; + } + + printk("NUS Server module initialized.\n"); + + return 0; +} + +void NusServer_Disconnected() { + // I argue that when bt is not connected, freeing the semaphore causes no trouble. + k_sem_init(&nusBusy, NUS_SLOTS, NUS_SLOTS); +} + +static void send_raw_buffer(const uint8_t *data, uint16_t len) { + SEM_TAKE(&nusBusy); + int err = bt_nus_send(NULL, data, len); + if (err) { + k_sem_give(&nusBusy); + printk("Failed to send data over BLE connection (err: %d)\n", err); + } +} + +bool NusServer_Availability(messenger_availability_op_t operation) { + switch (operation) { + case MessengerAvailabilityOp_InquireOneEmpty: + return k_sem_count_get(&nusBusy) > 0; + case MessengerAvailabilityOp_InquireAllEmpty: + return k_sem_count_get(&nusBusy) == NUS_SLOTS; + case MessengerAvailabilityOp_BlockTillOneEmpty: + k_sem_take(&nusBusy, K_FOREVER); + k_sem_give(&nusBusy); + return true; + default: + return false; + } +} + +void NusServer_SendMessage(message_t msg) { + uint8_t buffer[MAX_LINK_PACKET_LENGTH]; + uint8_t bufferIdx = 0; + + buffer[bufferIdx++] = msg.src; + buffer[bufferIdx++] = msg.dst; + + for (uint8_t id = 0; id < msg.idsUsed; id++) { + buffer[bufferIdx++] = msg.messageId[id]; + } + + if (msg.len + msg.idsUsed + 2 > MAX_LINK_PACKET_LENGTH) { + printk("Message is too long for NUS packets! [%i, %i, ...]\n", buffer[0], buffer[1]); + return; + } + + memcpy(&buffer[bufferIdx], msg.data, msg.len); + + send_raw_buffer(buffer, msg.len+msg.idsUsed+2); +} diff --git a/device/src/nus_server.h b/device/src/nus_server.h new file mode 100644 index 000000000..8e2cc45f8 --- /dev/null +++ b/device/src/nus_server.h @@ -0,0 +1,16 @@ +#ifndef __NUS_SERVER_H__ +#define __NUS_SERVER_H__ + +// Includes: +// + #include "link_protocol.h" + #include "messenger.h" + +// Functions: + + extern int NusServer_Init(void); + extern void NusServer_Disconnected(); + extern void NusServer_SendMessage(message_t msg); + extern bool NusServer_Availability(messenger_availability_op_t operation); + +#endif // __NUS_SERVER_H__ diff --git a/device/src/settings.c b/device/src/settings.c new file mode 100644 index 000000000..18e3f5e75 --- /dev/null +++ b/device/src/settings.c @@ -0,0 +1,59 @@ +#include +#include +#include "bt_conn.h" +#include "dongle_leds.h" +#include "stubs.h" + +bool RightAddressIsSet = false; + +static void setRightAddressIsSet(bool isSet) +{ + if (RightAddressIsSet != isSet) { + RightAddressIsSet = isSet; + DongleLeds_Update(); + } +} + +// (This isn't getting called at all when there is no "uhk/addr" settings present.) +static int peerAddressSet(const char *name, size_t len, settings_read_cb read_cb, void *cb_arg) +{ + static char foo_val[BT_ADDR_SIZE]; + read_cb(cb_arg, &foo_val, len); + + for (uint8_t i=0; itype = BT_ADDR_LE_RANDOM; + for (uint8_t j=0; ja.val[j] = foo_val[BT_ADDR_SIZE-1-j]; + printk("%02x", addr->a.val[j]); + } + printk("\n"); + if (i == PeerIdRight) { + setRightAddressIsSet(true); + } + break; + } + } + + return 0; +} + +struct settings_handler settingsHandler = { + .name = "uhk/addr", + .h_set = peerAddressSet, +}; + +void InitSettings(void) +{ + settings_subsys_init(); + settings_register(&settingsHandler); + settings_load(); +} + +void Settings_Reload(void) +{ + setRightAddressIsSet(false); + settings_load(); +} diff --git a/device/src/settings.h b/device/src/settings.h new file mode 100644 index 000000000..228f0a1fd --- /dev/null +++ b/device/src/settings.h @@ -0,0 +1,18 @@ +#ifndef __SETTINGS_H__ +#define __SETTINGS_H__ + +// Includes + + #include + #include + +// Functions: + + void InitSettings(void); + void Settings_Reload(void); + +// Variables: + + extern bool RightAddressIsSet; + +#endif // __SETTINGS_H__ diff --git a/device/src/shared/atomicity.h b/device/src/shared/atomicity.h new file mode 120000 index 000000000..6e6f4c116 --- /dev/null +++ b/device/src/shared/atomicity.h @@ -0,0 +1 @@ +../../../shared/atomicity.h \ No newline at end of file diff --git a/device/src/shared/attributes.h b/device/src/shared/attributes.h new file mode 120000 index 000000000..df86e53a2 --- /dev/null +++ b/device/src/shared/attributes.h @@ -0,0 +1 @@ +../../../shared/attributes.h \ No newline at end of file diff --git a/device/src/shared/bool_array_converter.c b/device/src/shared/bool_array_converter.c new file mode 120000 index 000000000..77f5ca0f5 --- /dev/null +++ b/device/src/shared/bool_array_converter.c @@ -0,0 +1 @@ +../../../shared/bool_array_converter.c \ No newline at end of file diff --git a/device/src/shared/bool_array_converter.h b/device/src/shared/bool_array_converter.h new file mode 120000 index 000000000..7e8aabd13 --- /dev/null +++ b/device/src/shared/bool_array_converter.h @@ -0,0 +1 @@ +../../../shared/bool_array_converter.h \ No newline at end of file diff --git a/device/src/shared/buffer.c b/device/src/shared/buffer.c new file mode 120000 index 000000000..87b66f8ae --- /dev/null +++ b/device/src/shared/buffer.c @@ -0,0 +1 @@ +../../../shared/buffer.c \ No newline at end of file diff --git a/device/src/shared/buffer.h b/device/src/shared/buffer.h new file mode 120000 index 000000000..68c7f5889 --- /dev/null +++ b/device/src/shared/buffer.h @@ -0,0 +1 @@ +../../../shared/buffer.h \ No newline at end of file diff --git a/device/src/shared/crc16.c b/device/src/shared/crc16.c new file mode 120000 index 000000000..b4ddbf8d1 --- /dev/null +++ b/device/src/shared/crc16.c @@ -0,0 +1 @@ +../../../shared/crc16.c \ No newline at end of file diff --git a/device/src/shared/crc16.h b/device/src/shared/crc16.h new file mode 120000 index 000000000..a73d7cacc --- /dev/null +++ b/device/src/shared/crc16.h @@ -0,0 +1 @@ +../../../shared/crc16.h \ No newline at end of file diff --git a/device/src/shared/fallback_versions.c b/device/src/shared/fallback_versions.c new file mode 120000 index 000000000..d4f54d7f1 --- /dev/null +++ b/device/src/shared/fallback_versions.c @@ -0,0 +1 @@ +../../../shared/fallback_versions.c \ No newline at end of file diff --git a/device/src/shared/i2c_addresses.h b/device/src/shared/i2c_addresses.h new file mode 120000 index 000000000..3c544991d --- /dev/null +++ b/device/src/shared/i2c_addresses.h @@ -0,0 +1 @@ +../../../shared/i2c_addresses.h \ No newline at end of file diff --git a/device/src/shared/key_matrix.c b/device/src/shared/key_matrix.c new file mode 120000 index 000000000..966921f38 --- /dev/null +++ b/device/src/shared/key_matrix.c @@ -0,0 +1 @@ +../../../shared/key_matrix.c \ No newline at end of file diff --git a/device/src/shared/key_matrix.h b/device/src/shared/key_matrix.h new file mode 120000 index 000000000..1fd7e18da --- /dev/null +++ b/device/src/shared/key_matrix.h @@ -0,0 +1 @@ +../../../shared/key_matrix.h \ No newline at end of file diff --git a/device/src/shared/slave_protocol.c b/device/src/shared/slave_protocol.c new file mode 120000 index 000000000..9f808ac9d --- /dev/null +++ b/device/src/shared/slave_protocol.c @@ -0,0 +1 @@ +../../../shared/slave_protocol.c \ No newline at end of file diff --git a/device/src/shared/slave_protocol.h b/device/src/shared/slave_protocol.h new file mode 120000 index 000000000..0ed1b5785 --- /dev/null +++ b/device/src/shared/slave_protocol.h @@ -0,0 +1 @@ +../../../shared/slave_protocol.h \ No newline at end of file diff --git a/device/src/shared/versioning.h b/device/src/shared/versioning.h new file mode 120000 index 000000000..7a1d374ff --- /dev/null +++ b/device/src/shared/versioning.h @@ -0,0 +1 @@ +../../../shared/versioning.h \ No newline at end of file diff --git a/device/src/shell.c b/device/src/shell.c new file mode 100644 index 000000000..dc5b5904c --- /dev/null +++ b/device/src/shell.c @@ -0,0 +1,183 @@ +#include "shell.h" +#include "bt_conn.h" +#include "device.h" +#include "keyboard/charger.h" +#include "keyboard/leds.h" +#include "keyboard/oled/oled.h" +#include "usb/usb.h" +#include +#include +#include +#include "bt_conn.h" +#include "keyboard/charger.h" +#include "legacy/ledmap.h" +#include "legacy/event_scheduler.h" + +shell_t Shell = { + .keyLog = 0, + .statLog = 0, + .ledsAlwaysOn = 0, + .oledEn = 1, + .sdbState = 1, + .chargerState = 1, +}; + + +static int cmd_uhk_keylog(const struct shell *shell, size_t argc, char *argv[]) +{ + if (argc == 1) { + shell_fprintf(shell, SHELL_NORMAL, "%i\n", Shell.keyLog); + } else { + Shell.keyLog = argv[1][0] == '1'; + } + return 0; +} +#if !DEVICE_IS_UHK_DONGLE +static int cmd_uhk_statlog(const struct shell *shell, size_t argc, char *argv[]) +{ + if (argc == 1) { + shell_fprintf(shell, SHELL_NORMAL, "%i\n", Shell.statLog); + } else { + Shell.statLog = argv[1][0] == '1'; + } + return 0; +} + +static int cmd_uhk_leds(const struct shell *shell, size_t argc, char *argv[]) +{ + if (argc == 1) { + shell_fprintf(shell, SHELL_NORMAL, "%i\n", Shell.ledsAlwaysOn); + } else { + Shell.ledsAlwaysOn = argv[1][0] == '1'; + } + return 0; +} + +static int cmd_uhk_sdb(const struct shell *shell, size_t argc, char *argv[]) +{ + if (argc == 1) { + shell_fprintf(shell, SHELL_NORMAL, "%i\n", Shell.sdbState ? 1 : 0); + } else { + Shell.sdbState = argv[1][0] == '1'; + gpio_pin_set_dt(&ledsSdbDt, Shell.sdbState); + } + return 0; +} + +// Charger behavior: +// - If CHARGER_EN=0 or USB is disconnected, then TS reads 6552[0-9] raw value and sometimes drops to 0. +// - If CHARGER_EN=1, USB is connected, and the battery is disconnected, then STAT alternates between 0 and 1 per second + +static int cmd_uhk_charger(const struct shell *shell, size_t argc, char *argv[]) +{ + if (argc == 1) { + shell_fprintf(shell, SHELL_NORMAL, "CHARGER_EN: %i | ", Shell.chargerState ? 1 : 0); + shell_fprintf(shell, SHELL_NORMAL, "STAT: %i ", gpio_pin_get_dt(&chargerStatDt) ? 1 : 0); + + Charger_PrintState(); + } else { + Shell.chargerState = argv[1][0] == '1'; + gpio_pin_set_dt(&chargerEnDt, Shell.chargerState); + } + return 0; +} +#endif // !DEVICE_IS_UHK_DONGLE + +#if DEVICE_IS_UHK80_RIGHT +static int cmd_uhk_testled(const struct shell *shell, size_t argc, char *argv[]) +{ + if (argc == 1 || argv[1][0] == '1') { + Ledmap_ActivateTestLedMode(true); + } else { + Ledmap_ActivateTestLedMode(false); + } + return 0; +} +#endif + +#if DEVICE_HAS_OLED +static int cmd_uhk_oled(const struct shell *shell, size_t argc, char *argv[]) +{ + if (argc == 1) { + shell_fprintf(shell, SHELL_NORMAL, "%i\n", Shell.oledEn ? 1 : 0); + } else { + Shell.oledEn = argv[1][0] == '1'; + gpio_pin_set_dt(&oledEn, Shell.oledEn); + } + return 0; +} +#endif + +#if DEVICE_HAS_MERGE_SENSOR +static const struct gpio_dt_spec mergeSenseDt = GPIO_DT_SPEC_GET(DT_ALIAS(merge_sense), gpios); + +static int cmd_uhk_merge(const struct shell *shell, size_t argc, char *argv[]) +{ + shell_fprintf(shell, SHELL_NORMAL, "%i\n", gpio_pin_get_dt(&mergeSenseDt) ? 1 : 0); + return 0; +} +#endif + +static int cmd_uhk_rollover(const struct shell *shell, size_t argc, char *argv[]) +{ + if (argc == 1) { + shell_fprintf( + shell, SHELL_NORMAL, "%c\n", (HID_GetKeyboardRollover() == Rollover_NKey) ? 'n' : '6'); + } else { + HID_SetKeyboardRollover((argv[1][0] == '6') ? Rollover_6Key : Rollover_NKey); + } + return 0; +} + +static int cmd_uhk_gamepad(const struct shell *shell, size_t argc, char *argv[]) +{ + if (argc == 1) { + shell_fprintf(shell, SHELL_NORMAL, "%c\n", HID_GetGamepadActive() ? 'y' : 'n'); + } else { + HID_SetGamepadActive(argv[1][0] != '0'); + } + return 0; +} + +static int cmd_uhk_btacc(const struct shell *shell, size_t argc, char *argv[]) +{ + num_comp_reply(argv[1][0]); + return 0; +} + +static int cmd_uhk_btunpair(const struct shell *shell, size_t argc, char *argv[]) +{ + int err = bt_unpair(BT_ID_DEFAULT, NULL); + printk("unpair operation result: %d\n", err); + return 0; +} + +void InitShell(void) +{ + SHELL_STATIC_SUBCMD_SET_CREATE(uhk_cmds, + SHELL_CMD_ARG(keylog, NULL, "get/set key logging", cmd_uhk_keylog, 1, 1), +#if !DEVICE_IS_UHK_DONGLE + SHELL_CMD_ARG(statlog, NULL, "get/set stat logging", cmd_uhk_statlog, 1, 1), + SHELL_CMD_ARG(leds, NULL, "get/set LEDs always on state", cmd_uhk_leds, 1, 1), + SHELL_CMD_ARG(sdb, NULL, "get/set LED driver SDB pin", cmd_uhk_sdb, 1, 1), + SHELL_CMD_ARG(charger, NULL, "get/set CHARGER_EN pin", cmd_uhk_charger, 1, 1), +#endif // !DEVICE_IS_UHK_DONGLE +#if DEVICE_IS_UHK80_RIGHT + SHELL_CMD_ARG(testled, NULL, "enable led test mode", cmd_uhk_testled, 0, 1), + SHELL_CMD_ARG(ledtest, NULL, "enable led test mode", cmd_uhk_testled, 0, 1), +#endif +#if DEVICE_HAS_OLED + SHELL_CMD_ARG(oled, NULL, "get/set OLED_EN pin", cmd_uhk_oled, 1, 1), +#endif +#if DEVICE_HAS_MERGE_SENSOR + SHELL_CMD_ARG(merge, NULL, "get the merged state of UHK halves", cmd_uhk_merge, 1, 0), +#endif + SHELL_CMD_ARG( + rollover, NULL, "get/set keyboard rollover mode (n/6)", cmd_uhk_rollover, 1, 1), + SHELL_CMD_ARG(gamepad, NULL, "switch gamepad on/off", cmd_uhk_gamepad, 1, 1), + SHELL_CMD_ARG(btacc, NULL, "accept bluetooth pairing", cmd_uhk_btacc, 1, 1), + SHELL_CMD_ARG(btunpair, NULL, "unpair bluetooth devices", cmd_uhk_btunpair, 1, 1), + SHELL_SUBCMD_SET_END); + + SHELL_CMD_REGISTER(uhk, &uhk_cmds, "UHK commands", NULL); +} diff --git a/device/src/shell.h b/device/src/shell.h new file mode 100644 index 000000000..85599f2f5 --- /dev/null +++ b/device/src/shell.h @@ -0,0 +1,25 @@ +#ifndef __SHELL_H__ +#define __SHELL_H__ + +#include + +// Typedefs: + +typedef struct { + uint8_t keyLog; + uint8_t statLog; + uint8_t ledsAlwaysOn; + uint8_t oledEn; + uint8_t sdbState; + uint8_t chargerState; +} shell_t; + +// Variables: + +extern shell_t Shell; + +// Functions: + +extern void InitShell(void); + +#endif // SHELL_H__ diff --git a/device/src/stack_trace.c b/device/src/stack_trace.c new file mode 100644 index 000000000..d58c78833 --- /dev/null +++ b/device/src/stack_trace.c @@ -0,0 +1,65 @@ +#include "stack_trace.h" +#include "shared/attributes.h" +#include "shared/atomicity.h" +#include +#include +#include +#include + +// With this config, zephyr defines its own handler, leading to multiple definition error +#ifndef CONFIG_RESET_ON_FATAL_ERROR + +#define MAX_STACK_DEPTH 32 +#define RAW_STACK_DUMP_SIZE 64 + +static bool is_valid_code_address(uint32_t addr) { + return (addr >= (uint32_t)__rom_region_start && addr < (uint32_t)__rom_region_end); +} + +static bool is_valid_ram_address(uint32_t addr) { + extern char _image_ram_start[]; + extern char _image_ram_end[]; + return (addr >= (uint32_t)_image_ram_start && addr < (uint32_t)_image_ram_end); +} + +void print_stack_trace(const z_arch_esf_t *esf) { + uint32_t *sp = (uint32_t *)esf; + uint32_t lr = esf->basic.lr; + uint32_t pc = esf->basic.pc; + + printk("Stack trace:\n"); + printk(" 0x%08x (PC)\n", pc); + + if (is_valid_code_address(lr & ~1)) { + printk(" 0x%08x (LR)\n", lr & ~1); + } + + // Walk up the stack + for (int i = 0; i < MAX_STACK_DEPTH && is_valid_ram_address((uint32_t)sp); i++) { + uint32_t value = *sp; + if (is_valid_code_address(value & ~1)) { + printk(" 0x%08x\n", value & ~1); + } + sp++; + } + printk("To translate to code, you can use:\n ./build.sh right addrline 0x1234\n arm-none-eabi-addr2line -e device/build/$device/zephyr/zephyr.elf $ADDR\n"); +} + +void k_sys_fatal_error_handler(unsigned int reason, const z_arch_esf_t *esf) +{ + // Disable interrupts to prevent re-entrance + ATTR_UNUSED DISABLE_IRQ(); + + printk("*** Kernel Fatal Error %d ***\n", reason); + printk("Current thread: %p\n", k_current_get()); + + print_stack_trace(esf); + + // Halt the system + printk("System halted\n"); + while (1) { + k_cpu_idle(); + } +} + +#endif diff --git a/device/src/stack_trace.h b/device/src/stack_trace.h new file mode 100644 index 000000000..f9c62bd11 --- /dev/null +++ b/device/src/stack_trace.h @@ -0,0 +1,18 @@ +#ifndef __STACK_TRACE_H__ +#define __STACK_TRACE_H__ + +// Following kconfig is needed for the custom handler: +// CONFIG_RESET_ON_FATAL_ERROR=n + +// Includes: + +// Macros: + +// Typedefs: + +// Variables: + +// Functions: + +#endif // __MAIN_H__ + diff --git a/device/src/state_sync.c b/device/src/state_sync.c new file mode 100644 index 000000000..bac8bf47e --- /dev/null +++ b/device/src/state_sync.c @@ -0,0 +1,697 @@ +#include "state_sync.h" +#include "device.h" +#include "device_state.h" +#include "event_scheduler.h" +#include "keyboard/charger.h" +#include "keyboard/oled/widgets/widgets.h" +#include "legacy/config_manager.h" +#include "legacy/config_parser/config_globals.h" +#include "legacy/debug.h" +#include "legacy/event_scheduler.h" +#include "legacy/keymap.h" +#include "legacy/led_manager.h" +#include "legacy/ledmap.h" +#include "legacy/module.h" +#include "legacy/slave_drivers/uhk_module_driver.h" +#include "legacy/slot.h" +#include "legacy/str_utils.h" +#include "legacy/stubs.h" +#include "legacy/utils.h" +#include "messenger.h" +#include "state_sync.h" +#include "usb/usb_compatibility.h" +#include +#include +#include "legacy/peripherals/merge_sensor.h" +#include "power_mode.h" + +#define STATE_SYNC_SEND_DELAY 2 + +#define THREAD_STACK_SIZE 2000 +#define THREAD_PRIORITY 5 +static K_THREAD_STACK_DEFINE(stack_area_left, THREAD_STACK_SIZE); +static struct k_thread thread_data_left; +static k_tid_t stateSyncThreadLeftId = 0; + +static K_THREAD_STACK_DEFINE(stack_area_dongle, THREAD_STACK_SIZE); +static struct k_thread thread_data_dongle; +static k_tid_t stateSyncThreadDongleId = 0; + +sync_generic_half_state_t SyncLeftHalfState; +sync_generic_half_state_t SyncRightHalfState; + +static void receiveProperty(device_id_t src, state_sync_prop_id_t property, const uint8_t *data, uint8_t len); + +#define DEFAULT_LAYER_PROP(NAME) \ + [StateSyncPropertyId_##NAME] = {.leftData = NULL, \ + .rightData = NULL, \ + .dongleData = NULL, \ + .len = 0, \ + .direction = SyncDirection_RightToLeft, \ + .dirtyState = DirtyState_Clean, \ + .defaultDirty = DirtyState_Clean, \ + .name = #NAME} + +#define SIMPLE(NAME, DIRECTION, DEFAULT_DIRTY, DATA) \ + [StateSyncPropertyId_##NAME] = {.leftData = DATA, \ + .rightData = DATA, \ + .dongleData = DATA, \ + .len = sizeof(*DATA), \ + .direction = DIRECTION, \ + .dirtyState = DEFAULT_DIRTY, \ + .defaultDirty = DEFAULT_DIRTY, \ + .name = #NAME} + +#define SIMPLE_CUSTOM(NAME, DIRECTION, DEFAULT_DIRTY) \ + [StateSyncPropertyId_##NAME] = {.leftData = NULL, \ + .rightData = NULL, \ + .dongleData = NULL, \ + .len = 0, \ + .direction = SyncDirection_RightToLeft, \ + .dirtyState = DEFAULT_DIRTY, \ + .defaultDirty = DEFAULT_DIRTY, \ + .name = #NAME} + +#define DUAL_LR(NAME, DIRECTION, DEFAULT_DIRTY, LEFT, RIGHT) \ + [StateSyncPropertyId_##NAME] = {.leftData = LEFT, \ + .rightData = RIGHT, \ + .dongleData = NULL, \ + .len = sizeof(*LEFT), \ + .direction = SyncDirection_LeftToRight, \ + .dirtyState = DEFAULT_DIRTY, \ + .defaultDirty = DEFAULT_DIRTY, \ + .name = #NAME} + +#ifdef EMPTY + #undef EMPTY +#endif + +#define EMPTY(NAME, DIRECTION, DEFAULT_DIRTY) \ + [StateSyncPropertyId_##NAME] = {.leftData = NULL, \ + .rightData = NULL, \ + .dongleData = NULL, \ + .len = 0, \ + .direction = DIRECTION, \ + .dirtyState = DEFAULT_DIRTY, \ + .defaultDirty = DEFAULT_DIRTY, \ + .name = #NAME} + +#define CUSTOM(...) EMPTY(__VA_ARGS__) + +static state_sync_prop_t stateSyncProps[StateSyncPropertyId_Count] = { + DEFAULT_LAYER_PROP(LayerActionsLayer1), + DEFAULT_LAYER_PROP(LayerActionsLayer2), + DEFAULT_LAYER_PROP(LayerActionsLayer3), + DEFAULT_LAYER_PROP(LayerActionsLayer4), + DEFAULT_LAYER_PROP(LayerActionsLayer5), + DEFAULT_LAYER_PROP(LayerActionsLayer6), + DEFAULT_LAYER_PROP(LayerActionsLayer7), + DEFAULT_LAYER_PROP(LayerActionsLayer8), + DEFAULT_LAYER_PROP(LayerActionsLayer9), + DEFAULT_LAYER_PROP(LayerActionsLayer10), + DEFAULT_LAYER_PROP(LayerActionsLayer11), + DEFAULT_LAYER_PROP(LayerActionsLayer12), + DEFAULT_LAYER_PROP(LayerActionsClear), + SIMPLE(ActiveLayer, SyncDirection_RightToLeft, DirtyState_Clean, &ActiveLayer), + CUSTOM(Backlight, SyncDirection_RightToLeft, DirtyState_Clean), + SIMPLE(ActiveKeymap, SyncDirection_RightToLeft, DirtyState_Clean, &CurrentKeymapIndex), + SIMPLE(KeyboardLedsState, SyncDirection_DongleToRight, DirtyState_Clean, &KeyboardLedsState), + DUAL_LR(Battery, SyncDirection_LeftToRight, DirtyState_Clean, &SyncLeftHalfState.battery, &SyncRightHalfState.battery), + EMPTY(ResetRightLeftLink, SyncDirection_RightLeftBidir, DirtyState_Clean), + EMPTY(ResetRightDongleLink, SyncDirection_RightDongleBidir, DirtyState_Clean), + CUSTOM(ModuleStateLeftHalf, SyncDirection_LeftToRight, DirtyState_Clean), + CUSTOM(ModuleStateLeftModule, SyncDirection_LeftToRight, DirtyState_Clean), + EMPTY(LeftModuleDisconnected, SyncDirection_LeftToRight, DirtyState_Clean), + SIMPLE(MergeSensor, SyncDirection_LeftToRight, DirtyState_Clean, &MergeSensor_HalvesAreMerged), + SIMPLE(FunctionalColors, SyncDirection_RightToLeft, DirtyState_Clean, &Cfg.KeyActionColors), + SIMPLE(PowerMode, SyncDirection_RightToLeft, DirtyState_Clean, &CurrentPowerMode), + CUSTOM(Config, SyncDirection_RightToLeft, DirtyState_Clean), +}; + +static void invalidateProperty(state_sync_prop_id_t propId) { + STATE_SYNC_LOG("<<< Invalidating property %s\n", stateSyncProps[propId].name); + if (StateSyncPropertyId_LayerActionFirst <= propId && + propId <= StateSyncPropertyId_LayerActionLast) { + stateSyncProps[propId].dirtyState = stateSyncProps[propId].defaultDirty; + } else { + stateSyncProps[propId].dirtyState = DirtyState_NeedsUpdate; + } + bool isRightLeftDevice = + (DEVICE_ID == DeviceId_Uhk80_Left || DEVICE_ID == DeviceId_Uhk80_Right); + bool isRightLeftLink = (stateSyncProps[propId].direction & + (SyncDirection_RightToLeft | SyncDirection_LeftToRight)); + if (isRightLeftLink && isRightLeftDevice) { + k_wakeup(stateSyncThreadLeftId); + } + bool isRightDongleDevice = + (DEVICE_ID == DeviceId_Uhk80_Right || DEVICE_ID == DeviceId_Uhk_Dongle); + bool isRightDongleLink = (stateSyncProps[propId].direction & + (SyncDirection_DongleToRight | SyncDirection_RightToDongle)); + if (isRightDongleLink && isRightDongleDevice) { + k_wakeup(stateSyncThreadDongleId); + } +} + +void StateSync_UpdateProperty(state_sync_prop_id_t propId, void *data) { + state_sync_prop_t *prop = &stateSyncProps[propId]; + + if (DEVICE_ID == DeviceId_Uhk80_Left && prop->leftData && data) { + memcpy(prop->leftData, data, prop->len); + } + + if (DEVICE_ID == DeviceId_Uhk80_Right && prop->rightData && data) { + memcpy(prop->rightData, data, prop->len); + } + + if (DEVICE_ID == DeviceId_Uhk_Dongle && prop->dongleData && data) { + memcpy(prop->dongleData, data, prop->len); + } + + sync_direction_t srcMask, dstMask; + switch (DEVICE_ID) { + case DeviceId_Uhk80_Left: + srcMask = SyncDirection_LeftToRight; + dstMask = SyncDirection_RightToLeft; + break; + case DeviceId_Uhk80_Right: + srcMask = SyncDirection_RightToLeft | SyncDirection_RightToDongle; + dstMask = SyncDirection_LeftToRight | SyncDirection_DongleToRight; + break; + case DeviceId_Uhk_Dongle: + srcMask = SyncDirection_DongleToRight; + dstMask = SyncDirection_RightToDongle; + break; + } + + if (prop->direction & srcMask) { + invalidateProperty(propId); + } + if (prop->direction & (srcMask | dstMask)) { + receiveProperty(DEVICE_ID, propId, NULL, 0); + } +} + +void receiveLayerActionsClear(layer_id_t layerId) { + memset(&CurrentKeymap[layerId][SlotId_LeftKeyboardHalf][0], 0, + sizeof(key_action_t) * MAX_KEY_COUNT_PER_MODULE); +} + +void receiveLayerModuleActions(sync_command_action_t* actions, uint8_t layerId, uint8_t slotId, uint8_t bufferOffset, uint8_t actionOffset, uint8_t count) { + for (uint8_t i = 0; i < count; i++) { + uint8_t actionIdx = actionOffset + i; + uint8_t bufferIdx = bufferOffset + i; + key_action_t *dstAction = &CurrentKeymap[layerId][slotId][actionIdx]; + dstAction->color = actions[bufferIdx].color; + dstAction->colorOverridden = actions[bufferIdx].colorOverriden; + dstAction->type = actions[bufferIdx].type; + dstAction->keystroke.modifiers = actions[bufferIdx].modifierPresent ? 0xff : 0; + dstAction->keystroke.scancode = actions[bufferIdx].scancode; + } +} + +void receiveLayerActions(sync_command_layer_t *buffer) +{ + if (buffer->actionCount) { + receiveLayerModuleActions(buffer->actions, buffer->layerId, SlotId_LeftKeyboardHalf, 0, buffer->startOffset, buffer->actionCount); + } + if (buffer->moduleActionCount) { + receiveLayerModuleActions(buffer->actions, buffer->layerId, SlotId_LeftModule, buffer->actionCount, 0, buffer->moduleActionCount); + } +} + +void receiveBacklight(sync_command_backlight_t *buffer) { + Cfg.BacklightingMode = buffer->BacklightingMode; + KeyBacklightBrightness = buffer->KeyBacklightBrightness; + DisplayBrightness = buffer->DisplayBacklightBrightness; + Cfg.LedMap_ConstantRGB = buffer->LedMap_ConstantRGB; + if (HardwareConfig->isIso != buffer->isIso) { + HardwareConfig->isIso = buffer->isIso; + Ledmap_InitLedLayout(); + Ledmap_UpdateBacklightLeds(); + } +} + +static void receiveModuleStateData(sync_command_module_state_t *buffer) { + uint8_t driverId = UhkModuleSlaveDriver_SlotIdToDriverId(buffer->slotId); + uhk_module_state_t *moduleState = &UhkModuleStates[driverId]; + module_connection_state_t *moduleConnectionState = &ModuleConnectionStates[driverId]; + + moduleConnectionState->moduleId = buffer->moduleId; + moduleState->moduleId = buffer->moduleId; + moduleState->moduleProtocolVersion = buffer->moduleProtocolVersion; + moduleState->firmwareVersion = buffer->firmwareVersion; + moduleState->keyCount = buffer->keyCount; + moduleState->pointerCount = buffer->pointerCount; + Utils_SafeStrCopy(moduleState->gitRepo, buffer->gitRepo, MAX_STRING_PROPERTY_LENGTH); + Utils_SafeStrCopy(moduleState->gitTag, buffer->gitTag, MAX_STRING_PROPERTY_LENGTH); + memcpy(moduleState->firmwareChecksum, buffer->firmwareChecksum, MD5_CHECKSUM_LENGTH); +} + +static void receiveProperty(device_id_t src, state_sync_prop_id_t propId, const uint8_t *data, uint8_t len) { + state_sync_prop_t *prop = &stateSyncProps[propId]; + bool isLocalUpdate = src == DEVICE_ID; + + if (isLocalUpdate) { + STATE_SYNC_LOG("=== Updating local property %s\n", prop->name); + } else { + STATE_SYNC_LOG(">>> Received remote property %s from %s\n", prop->name, Utils_DeviceIdToString(src)); + } + + if (src == DeviceId_Uhk80_Left && prop->leftData && data) { + memcpy(prop->leftData, data, prop->len); + } + + if (src == DeviceId_Uhk80_Right && prop->rightData && data) { + memcpy(prop->rightData, data, prop->len); + } + + if (src == DeviceId_Uhk_Dongle && prop->dongleData && data) { + memcpy(prop->dongleData, data, prop->len); + } + + switch (propId) { + case StateSyncPropertyId_LayerActionsClear: + receiveLayerActionsClear(*((layer_id_t *)data)); + if (*((layer_id_t *)data) == ActiveLayer) { + Ledmap_UpdateBacklightLeds(); + } + break; + case StateSyncPropertyId_LayerActionFirst ... StateSyncPropertyId_LayerActionLast: + receiveLayerActions((sync_command_layer_t *)data); + if ((propId - StateSyncPropertyId_LayerActionFirst) == ActiveLayer) { + EventVector_Set(EventVector_LedMapUpdateNeeded); + } + break; + case StateSyncPropertyId_ActiveLayer: + if (!isLocalUpdate) { + EventVector_Set(EventVector_LedMapUpdateNeeded); + } + break; + case StateSyncPropertyId_Backlight: + if (!isLocalUpdate) { + receiveBacklight((sync_command_backlight_t *)data); + } + EventVector_Set(EventVector_LedMapUpdateNeeded); + break; + case StateSyncPropertyId_Battery: + WIDGET_REFRESH(&StatusWidget); + { + bool newRunningOnBattery = !SyncLeftHalfState.battery.powered || !SyncRightHalfState.battery.powered; + bool newRightRunningOnBattery = !SyncRightHalfState.battery.powered; + if (RunningOnBattery != newRunningOnBattery) { + RunningOnBattery = newRunningOnBattery; + RightRunningOnBattery = newRightRunningOnBattery; + EventVector_Set(EventVector_LedManagerFullUpdateNeeded); + } else if (RightRunningOnBattery != newRightRunningOnBattery) { + RightRunningOnBattery = newRightRunningOnBattery; + LedManager_UpdateSleepModes(); + } + } + break; + case StateSyncPropertyId_ActiveKeymap: + // TODO + break; + case StateSyncPropertyId_KeyboardLedsState: + WIDGET_REFRESH(&StatusWidget); + break; + case StateSyncPropertyId_ResetRightLeftLink: + StateSync_ResetRightLeftLink(false); + break; + case StateSyncPropertyId_ResetRightDongleLink: + StateSync_ResetRightDongleLink(false); + break; + case StateSyncPropertyId_LeftModuleDisconnected: + module_connection_state_t *moduleConnectionState = &ModuleConnectionStates[UhkModuleDriverId_LeftModule]; + moduleConnectionState->moduleId = 0; + break; + case StateSyncPropertyId_ModuleStateLeftHalf: + case StateSyncPropertyId_ModuleStateLeftModule: + if (!isLocalUpdate) { + receiveModuleStateData((sync_command_module_state_t *)data); + } + break; + case StateSyncPropertyId_FunctionalColors: + if (!isLocalUpdate) { + EventVector_Set(EventVector_LedMapUpdateNeeded); + } + break; + case StateSyncPropertyId_Config: + if (!isLocalUpdate) { + sync_command_config_t* buffer = (sync_command_config_t*)data; + DataModelVersion = buffer->dataModelVersion; + } + break; + case StateSyncPropertyId_MergeSensor: + break; + default: + printk("Property %i ('%s') has no receive handler. If this is correct, please add a " + "separate empty case...\n", + propId, prop->name); + break; + } +} + +void StateSync_ReceiveStateUpdate(device_id_t src, const uint8_t *data, uint8_t len) { + ATTR_UNUSED message_id_t messageId = *(data++); + ATTR_UNUSED state_sync_prop_id_t propId = *(data++); + + receiveProperty(src, propId, data, len - 2); +} + +static void submitPreparedData(device_id_t dst, state_sync_prop_id_t propId, const uint8_t *data, uint8_t len) { + STATE_SYNC_LOG(" Sending %s data to %s\n", stateSyncProps[propId].name, Utils_DeviceIdToString(dst)); + Messenger_Send2(dst, MessageId_StateSync, propId, data, len); +} + +static void prepareLayerActions(layer_id_t layerId, uint8_t slotId, uint8_t bufferOffset, uint8_t actionOffset, uint8_t count, sync_command_layer_t *buffer) { + for (uint8_t i = 0; i < count; i++) { + uint8_t actionIdx = actionOffset + i; + uint8_t bufferIdx = bufferOffset + i; + key_action_t *action = &CurrentKeymap[layerId][slotId][actionIdx]; + buffer->actions[bufferIdx].type = action->type; + buffer->actions[bufferIdx].scancode = action->keystroke.scancode; + buffer->actions[bufferIdx].color = action->color; + buffer->actions[bufferIdx].colorOverriden = action->colorOverridden; + buffer->actions[bufferIdx].modifierPresent = action->keystroke.modifiers != 0; + } +} + +static void prepareAndSubmitLayer(device_id_t dst, state_sync_prop_id_t propId, layer_id_t layerId) { + sync_command_layer_t buffer; + + const uint8_t firstPacketLeftHalfActionCount = KEY_COUNT_PER_UPDATE; + const uint8_t secondPacketLeftHalfActionCount = MAX_KEY_COUNT_PER_MODULE - KEY_COUNT_PER_UPDATE; + const uint8_t secondPacketLeftModuleActionCount = MAX_BACKLIT_KEY_COUNT_PER_LEFT_MODULE; + + buffer.layerId = layerId; + buffer.startOffset = 0; + buffer.actionCount = firstPacketLeftHalfActionCount; + buffer.moduleActionCount = 0; + + prepareLayerActions(layerId, SlotId_LeftKeyboardHalf, 0, 0, firstPacketLeftHalfActionCount, &buffer); + submitPreparedData(dst, propId, (const uint8_t *)&buffer, sizeof(buffer)); + + buffer.layerId = layerId; + buffer.startOffset = firstPacketLeftHalfActionCount; + buffer.actionCount = secondPacketLeftHalfActionCount; + buffer.moduleActionCount = secondPacketLeftModuleActionCount; + + prepareLayerActions(layerId, SlotId_LeftKeyboardHalf, 0, firstPacketLeftHalfActionCount, secondPacketLeftHalfActionCount, &buffer); + prepareLayerActions(layerId, SlotId_LeftModule, secondPacketLeftHalfActionCount, 0, secondPacketLeftModuleActionCount, &buffer); + submitPreparedData(dst, propId, (const uint8_t *)&buffer, sizeof(buffer)); +} + +static void prepareBacklight(sync_command_backlight_t *buffer) { + buffer->BacklightingMode = Ledmap_GetEffectiveBacklightMode(); + buffer->KeyBacklightBrightness = KeyBacklightBrightness; + buffer->DisplayBacklightBrightness = DisplayBrightness; + buffer->LedMap_ConstantRGB = Cfg.LedMap_ConstantRGB; + buffer->isIso = HardwareConfig->isIso; +} + +static void prepareLeftHalfStateData(sync_command_module_state_t *buffer) { +#if DEVICE_IS_UHK80_LEFT + buffer->slotId = SlotId_LeftKeyboardHalf; + buffer->moduleId = MODULE_ID; + buffer->moduleProtocolVersion = moduleProtocolVersion; + buffer->firmwareVersion = firmwareVersion; + buffer->keyCount = MODULE_KEY_COUNT; + buffer->pointerCount = MODULE_POINTER_COUNT; + Utils_SafeStrCopy(buffer->gitRepo, gitRepo, MAX_STRING_PROPERTY_LENGTH); + Utils_SafeStrCopy(buffer->gitTag, gitTag, MAX_STRING_PROPERTY_LENGTH); + memcpy(buffer->firmwareChecksum, ModuleMD5Checksums[MODULE_ID], MD5_CHECKSUM_LENGTH); +#endif +} + +static void prepareLeftModuleStateData(sync_command_module_state_t *buffer) { + uhk_module_state_t *moduleState = UhkModuleStates + UhkModuleSlaveDriver_SlotIdToDriverId(SlotId_LeftModule);; + + buffer->slotId = SlotId_LeftModule; + buffer->moduleId = moduleState->moduleId; + buffer->moduleProtocolVersion = moduleState->moduleProtocolVersion; + buffer->firmwareVersion = moduleState->firmwareVersion; + buffer->keyCount = moduleState->keyCount; + buffer->pointerCount = moduleState->pointerCount; + memcpy(buffer->gitRepo, moduleState->gitRepo, MAX_STRING_PROPERTY_LENGTH); + memcpy(buffer->gitTag, moduleState->gitTag, MAX_STRING_PROPERTY_LENGTH); + memcpy(buffer->firmwareChecksum, moduleState->firmwareChecksum, MD5_CHECKSUM_LENGTH); +} + +static void prepareData(device_id_t dst, const uint8_t *propDataPtr, state_sync_prop_id_t propId) { + state_sync_prop_t *prop = &stateSyncProps[propId]; + const uint8_t *data = propDataPtr; + + uint8_t len = prop->len; + + STATE_SYNC_LOG("<<< Preparing %s data for %s\n", prop->name, Utils_DeviceIdToString(dst)); + + prop->dirtyState = DirtyState_Clean; + + switch (propId) { + case StateSyncPropertyId_LayerActionFirst ... StateSyncPropertyId_LayerActionLast: { + layer_id_t layerId = propId - StateSyncPropertyId_LayerActionFirst + LayerId_First; + + if (prop->dirtyState == DirtyState_NeedsClearing) { + submitPreparedData(dst, StateSyncPropertyId_LayerActionsClear, &layerId, sizeof(layerId)); + return; + } else { + // 2 packets! + prepareAndSubmitLayer(dst, propId, layerId); + return; + } + } break; + case StateSyncPropertyId_ModuleStateLeftHalf: { + sync_command_module_state_t buffer = {}; + prepareLeftHalfStateData(&buffer); + submitPreparedData(dst, propId, (const uint8_t *)&buffer, sizeof(buffer)); + return; + } break; + case StateSyncPropertyId_ModuleStateLeftModule: { + sync_command_module_state_t buffer = {}; + prepareLeftModuleStateData(&buffer); + submitPreparedData(dst, propId, (const uint8_t *)&buffer, sizeof(buffer)); + return; + } break; + case StateSyncPropertyId_Backlight: { + sync_command_backlight_t buffer; + prepareBacklight(&buffer); + submitPreparedData(dst, propId, (const uint8_t *)&buffer, sizeof(buffer)); + return; + } break; + case StateSyncPropertyId_Config: { + sync_command_config_t buffer; + buffer.dataModelVersion = DataModelVersion; + submitPreparedData(dst, propId, (const uint8_t *)&buffer, sizeof(buffer)); + return; + } break; + default: + break; + } + + submitPreparedData(dst, propId, data, len); +} + +static void updateProperty(state_sync_prop_id_t propId) { + device_id_t dst; + const uint8_t *dataPtr; + state_sync_prop_t *prop = &stateSyncProps[propId]; + + if (DEVICE_ID == DeviceId_Uhk80_Left && (prop->direction & SyncDirection_LeftToRight)) { + dst = DeviceId_Uhk80_Right; + dataPtr = prop->leftData; + prepareData(dst, dataPtr, propId); + } + if (DEVICE_ID == DeviceId_Uhk80_Right && (prop->direction & SyncDirection_RightToLeft)) { + dst = DeviceId_Uhk80_Left; + dataPtr = prop->rightData; + prepareData(dst, dataPtr, propId); + } + if (DEVICE_ID == DeviceId_Uhk80_Right && (prop->direction & SyncDirection_RightToDongle)) { + dst = DeviceId_Uhk_Dongle; + dataPtr = prop->rightData; + prepareData(dst, dataPtr, propId); + } + if (DEVICE_ID == DeviceId_Uhk_Dongle && (prop->direction & SyncDirection_DongleToRight)) { + dst = DeviceId_Uhk80_Right; + dataPtr = prop->dongleData; + prepareData(dst, dataPtr, propId); + } +} + +#define UPDATE_AND_RETURN_IF_DIRTY(propId) \ + if (stateSyncProps[propId].dirtyState != DirtyState_Clean) { \ + updateProperty(propId); \ + return false; \ + } + +static bool handlePropertyUpdateRightToLeft() { + UPDATE_AND_RETURN_IF_DIRTY(StateSyncPropertyId_ResetRightLeftLink); + UPDATE_AND_RETURN_IF_DIRTY(StateSyncPropertyId_Config); + + if (KeyBacklightBrightness != 0) { + // Update relevant data + UPDATE_AND_RETURN_IF_DIRTY(StateSyncPropertyId_PowerMode); + UPDATE_AND_RETURN_IF_DIRTY(StateSyncPropertyId_FunctionalColors); + UPDATE_AND_RETURN_IF_DIRTY(StateSyncPropertyId_LayerActionFirst + ActiveLayer); + UPDATE_AND_RETURN_IF_DIRTY(StateSyncPropertyId_ActiveKeymap); + UPDATE_AND_RETURN_IF_DIRTY(StateSyncPropertyId_ActiveLayer); + UPDATE_AND_RETURN_IF_DIRTY(StateSyncPropertyId_Backlight); + + // Update rest of layers + state_sync_prop_id_t first = StateSyncPropertyId_LayerActionFirst; + state_sync_prop_id_t last = StateSyncPropertyId_LayerActionLast; + for (state_sync_prop_id_t propId = first; propId <= last; propId++) { + UPDATE_AND_RETURN_IF_DIRTY(propId); + } + } + UPDATE_AND_RETURN_IF_DIRTY(StateSyncPropertyId_Backlight); + + return true; +} + +static bool handlePropertyUpdateLeftToRight() { + UPDATE_AND_RETURN_IF_DIRTY(StateSyncPropertyId_ResetRightLeftLink); + + UPDATE_AND_RETURN_IF_DIRTY(StateSyncPropertyId_ModuleStateLeftHalf); + UPDATE_AND_RETURN_IF_DIRTY(StateSyncPropertyId_ModuleStateLeftModule); + UPDATE_AND_RETURN_IF_DIRTY(StateSyncPropertyId_LeftModuleDisconnected); + UPDATE_AND_RETURN_IF_DIRTY(StateSyncPropertyId_MergeSensor); + UPDATE_AND_RETURN_IF_DIRTY(StateSyncPropertyId_Battery); + + return true; +} + +static bool handlePropertyUpdateDongleToRight() { + UPDATE_AND_RETURN_IF_DIRTY(StateSyncPropertyId_ResetRightDongleLink); + + UPDATE_AND_RETURN_IF_DIRTY(StateSyncPropertyId_KeyboardLedsState); + + return true; +} + +static bool handlePropertyUpdateRightToDongle() { + UPDATE_AND_RETURN_IF_DIRTY(StateSyncPropertyId_ResetRightDongleLink); + + return true; +} + +static void updateLoopRightLeft() { + if (DEVICE_ID == DeviceId_Uhk80_Left) { + while (true) { + bool isConnected = DeviceState_IsDeviceConnected(DeviceId_Uhk80_Right); + STATE_SYNC_LOG("--- Left to right update loop, connected: %i\n", isConnected); + if (!isConnected || handlePropertyUpdateLeftToRight()) { + k_sleep(K_FOREVER); + } else { + k_sleep(K_MSEC(STATE_SYNC_SEND_DELAY)); + } + } + } + + if (DEVICE_ID == DeviceId_Uhk80_Right) { + while (true) { + bool isConnected = DeviceState_IsDeviceConnected(DeviceId_Uhk80_Left); + STATE_SYNC_LOG("--- Right to left update loop, connected: %i\n", isConnected); + if (!isConnected || handlePropertyUpdateRightToLeft()) { + k_sleep(K_FOREVER); + } else { + k_sleep(K_MSEC(STATE_SYNC_SEND_DELAY)); + } + } + } +} + +static void updateLoopRightDongle() { + if (DEVICE_ID == DeviceId_Uhk80_Right) { + while (true) { + bool isConnected = DeviceState_IsDeviceConnected(DeviceId_Uhk_Dongle); + STATE_SYNC_LOG("--- Right to dongle update loop, connected: %i\n", isConnected); + if (!isConnected || handlePropertyUpdateRightToDongle()) { + k_sleep(K_FOREVER); + } else { + k_sleep(K_MSEC(STATE_SYNC_SEND_DELAY)); + } + } + } + + if (DEVICE_ID == DeviceId_Uhk_Dongle) { + while (true) { + bool isConnected = DeviceState_IsDeviceConnected(DeviceId_Uhk80_Right); + STATE_SYNC_LOG("--- Dongle update loop, connected: %i\n", isConnected); + if (!isConnected || handlePropertyUpdateDongleToRight()) { + k_sleep(K_FOREVER); + } else { + k_sleep(K_MSEC(STATE_SYNC_SEND_DELAY)); + } + } + } +} + +void StateSync_UpdateLayer(layer_id_t layerId, bool fullUpdate) { + state_sync_prop_id_t propId = StateSyncPropertyId_LayerActionFirst + layerId - LayerId_First; + + stateSyncProps[propId].dirtyState = fullUpdate ? DirtyState_NeedsUpdate : DirtyState_NeedsClearing; + stateSyncProps[propId].defaultDirty = stateSyncProps[propId].dirtyState; + + k_wakeup(stateSyncThreadLeftId); +} + +void StateSync_Init() { + if (DEVICE_ID == DeviceId_Uhk80_Left || DEVICE_ID == DeviceId_Uhk80_Right) { + stateSyncThreadLeftId = k_thread_create(&thread_data_left, stack_area_left, + K_THREAD_STACK_SIZEOF(stack_area_left), updateLoopRightLeft, NULL, NULL, NULL, + THREAD_PRIORITY, 0, K_NO_WAIT); + k_thread_name_set(&thread_data_left, "state_sync_left_right"); + } + + if (DEVICE_ID == DeviceId_Uhk80_Right || DEVICE_ID == DeviceId_Uhk_Dongle) { + stateSyncThreadDongleId = k_thread_create(&thread_data_dongle, stack_area_dongle, + K_THREAD_STACK_SIZEOF(stack_area_dongle), updateLoopRightDongle, NULL, NULL, NULL, + THREAD_PRIORITY, 0, K_NO_WAIT); + k_thread_name_set(&thread_data_dongle, "state_sync_dongle_right"); + } +} + +void StateSync_ResetRightLeftLink(bool bidirectional) { + printk("Resetting left right link! %s\n", bidirectional ? "Bidirectional" : "Unidirectional"); + if (bidirectional) { + invalidateProperty(StateSyncPropertyId_ResetRightLeftLink); + } + if (DEVICE_ID == DeviceId_Uhk80_Right) { + invalidateProperty(StateSyncPropertyId_Config); + state_sync_prop_id_t first = StateSyncPropertyId_LayerActionFirst; + state_sync_prop_id_t last = StateSyncPropertyId_LayerActionLast; + for (state_sync_prop_id_t propId = first; propId <= last; propId++) { + invalidateProperty(propId); + } + invalidateProperty(StateSyncPropertyId_ActiveLayer); + invalidateProperty(StateSyncPropertyId_Backlight); + invalidateProperty(StateSyncPropertyId_FunctionalColors); + invalidateProperty(StateSyncPropertyId_PowerMode); + } + if (DEVICE_ID == DeviceId_Uhk80_Left) { + invalidateProperty(StateSyncPropertyId_Battery); + invalidateProperty(StateSyncPropertyId_ModuleStateLeftHalf); + invalidateProperty(StateSyncPropertyId_ModuleStateLeftModule); + invalidateProperty(StateSyncPropertyId_MergeSensor); + } +} + +void StateSync_ResetRightDongleLink(bool bidirectional) { + printk("Resetting dongle right link! %s\n", bidirectional ? "Bidirectional" : "Unidirectional"); + if (bidirectional) { + invalidateProperty(StateSyncPropertyId_ResetRightDongleLink); + } + if (DEVICE_ID == DeviceId_Uhk_Dongle) { + invalidateProperty(StateSyncPropertyId_KeyboardLedsState); + } +} + +void StateSync_ResetConfig() { + // For simplicity, update all for now + StateSync_ResetRightLeftLink(false); +} + +const char* StateSync_PropertyIdToString(state_sync_prop_id_t propId) { + return stateSyncProps[propId].name; +} diff --git a/device/src/state_sync.h b/device/src/state_sync.h new file mode 100644 index 000000000..f38554df6 --- /dev/null +++ b/device/src/state_sync.h @@ -0,0 +1,144 @@ +#ifndef __STATE_SYNC_H__ +#define __STATE_SYNC_H__ + +// Includes: + + #include + #include + #include "legacy/layer_switcher.h" + #include "legacy/key_action.h" + #include "legacy/module.h" + #include "keyboard/charger.h" + #include "shared/attributes.h" + #include "legacy/slave_drivers/uhk_module_driver.h" + #include "versioning.h" + +// Macros: + + #define KEY_COUNT_PER_UPDATE ((MAX_KEY_COUNT_PER_MODULE+MAX_BACKLIT_KEY_COUNT_PER_LEFT_MODULE)/2+1) + +// Typedefs: + + typedef struct { + battery_state_t battery; + } sync_generic_half_state_t; + + typedef struct { + uint8_t type : 6; + uint8_t modifierPresent : 1; + uint8_t colorOverriden : 1; + uint8_t scancode; + rgb_t color; + } ATTR_PACKED sync_command_action_t; + + typedef struct { + layer_id_t layerId; + uint8_t startOffset; + uint8_t actionCount; + uint8_t moduleActionCount; + sync_command_action_t actions[KEY_COUNT_PER_UPDATE]; + } sync_command_layer_t; + + typedef struct { + uint8_t BacklightingMode; + uint8_t KeyBacklightBrightness; + uint8_t DisplayBacklightBrightness; + rgb_t LedMap_ConstantRGB; + bool isIso; + } ATTR_PACKED sync_command_backlight_t; + + typedef struct { + uint8_t slotId; + uint8_t moduleId; + version_t moduleProtocolVersion; + version_t firmwareVersion; + uint8_t keyCount; + uint8_t pointerCount; + char gitRepo[MAX_STRING_PROPERTY_LENGTH]; + char gitTag[MAX_STRING_PROPERTY_LENGTH]; + char firmwareChecksum[MD5_CHECKSUM_LENGTH]; + } ATTR_PACKED sync_command_module_state_t; + + typedef struct { + version_t dataModelVersion; + } sync_command_config_t; + + // Draft for generic properties + typedef enum { + StateSyncPropertyId_LayerActionsLayer1 = 1, + StateSyncPropertyId_LayerActionsLayer2 = 2, + StateSyncPropertyId_LayerActionsLayer3 = 3, + StateSyncPropertyId_LayerActionsLayer4 = 4, + StateSyncPropertyId_LayerActionsLayer5 = 5, + StateSyncPropertyId_LayerActionsLayer6 = 6, + StateSyncPropertyId_LayerActionsLayer7 = 7, + StateSyncPropertyId_LayerActionsLayer8 = 8, + StateSyncPropertyId_LayerActionsLayer9 = 9, + StateSyncPropertyId_LayerActionsLayer10 = 10, + StateSyncPropertyId_LayerActionsLayer11 = 11, + StateSyncPropertyId_LayerActionsLayer12 = 12, + StateSyncPropertyId_LayerActionFirst = StateSyncPropertyId_LayerActionsLayer1, + StateSyncPropertyId_LayerActionLast = StateSyncPropertyId_LayerActionsLayer12, + StateSyncPropertyId_LayerActionsClear = 13, + StateSyncPropertyId_ActiveLayer = 14, + StateSyncPropertyId_Backlight = 15, + StateSyncPropertyId_ActiveKeymap = 16, + StateSyncPropertyId_Battery = 17, + StateSyncPropertyId_KeyboardLedsState = 18, + StateSyncPropertyId_ResetRightLeftLink = 19, + StateSyncPropertyId_ResetRightDongleLink = 20, + StateSyncPropertyId_ModuleStateLeftHalf = 21, + StateSyncPropertyId_ModuleStateLeftModule = 22, + StateSyncPropertyId_LeftModuleDisconnected = 23, + StateSyncPropertyId_MergeSensor = 24, + StateSyncPropertyId_FunctionalColors = 25, + StateSyncPropertyId_PowerMode = 26, + StateSyncPropertyId_Config = 27, + StateSyncPropertyId_Count, + } state_sync_prop_id_t; + + typedef enum { + SyncDirection_LeftToRight = 1 << 0, + SyncDirection_RightToLeft = 1 << 1, + SyncDirection_DongleToRight = 1 << 2, + SyncDirection_RightToDongle = 1 << 3, + SyncDirection_RightDongleBidir = SyncDirection_RightToDongle | SyncDirection_DongleToRight, + SyncDirection_RightLeftBidir = SyncDirection_LeftToRight | SyncDirection_RightToLeft, + } sync_direction_t; + + typedef enum { + DirtyState_Clean, + DirtyState_NeedsUpdate, + DirtyState_NeedsClearing, + } dirty_state_t; + + typedef struct { + const char* name; + void* leftData; + void* rightData; + void* dongleData; + uint8_t len; + sync_direction_t direction; + dirty_state_t dirtyState; + dirty_state_t defaultDirty; + } ATTR_PACKED state_sync_prop_t; + +// Variables: + + extern sync_generic_half_state_t SyncLeftHalfState; + extern sync_generic_half_state_t SyncRightHalfState; + +// Functions: + + void StateSync_UpdateLayer(layer_id_t layerId, bool fullUpdate); + void StateSync_Init(); + void StateSync_ReceiveProperty(device_id_t src, state_sync_prop_id_t property, void* data, uint8_t len); + void StateSync_UpdateProperty(state_sync_prop_id_t propId, void* data); + void StateSync_ReceiveStateUpdate(device_id_t src, const uint8_t* data, uint8_t len); + const char* StateSync_PropertyIdToString(state_sync_prop_id_t propId); + + void StateSync_ResetRightLeftLink(bool bidirectional); + void StateSync_ResetRightDongleLink(bool bidirectional); + void StateSync_ResetConfig(); + +#endif diff --git a/device/src/uhk60/main.c b/device/src/uhk60/main.c new file mode 100644 index 000000000..d781eab5f --- /dev/null +++ b/device/src/uhk60/main.c @@ -0,0 +1,14 @@ +#include +#include + +const struct gpio_dt_spec testLed = GPIO_DT_SPEC_GET(DT_ALIAS(test_led), gpios); + +int main(void) { + // printk("----------\n" DEVICE_NAME " started\n"); + + while (true) { + gpio_pin_configure_dt(&testLed, GPIO_OUTPUT); + gpio_pin_toggle_dt(&testLed); + k_msleep(1000); + } +} diff --git a/device/src/usb/command_app.cpp b/device/src/usb/command_app.cpp new file mode 100644 index 000000000..74bd3bb6a --- /dev/null +++ b/device/src/usb/command_app.cpp @@ -0,0 +1,81 @@ +#include "command_app.hpp" +#include "hid/rdf/descriptor.hpp" +#include "hid/report_protocol.hpp" +#include "zephyr/sys/printk.h" + +extern "C" bool CommandProtocolTx(const uint8_t *data, size_t size) +{ + return command_app::handle().send(std::span(data, size)); +} + +extern "C" void CommandProtocolRxHandler(const uint8_t *data, size_t size); + +void __attribute__((weak)) CommandProtocolRxHandler(const uint8_t *data, size_t size) +{ + printk("CommandProtocolRxHandler: data[0]:%u size:%d\n", data[0], size); + CommandProtocolTx(data, size); +} + +command_app &command_app::handle() +{ + static command_app app{}; + return app; +} + +void command_app::start(hid::protocol prot) +{ + // start receiving reports + receive_report(&out_buffer_[out_buffer_.active_side()]); +} + +void command_app::set_report(hid::report::type type, const std::span &data) +{ + if (((type != hid::report::type::OUTPUT) || (data.front() != report_ids::OUT_COMMAND))) { + return; + } + auto &out = *reinterpret_cast(data.data()); + CommandProtocolRxHandler(out.payload.data(), data.size() - (report_out::has_id() ? 1 : 0)); + + // always keep receiving new reports + out_buffer_.swap_sides(); + receive_report(&out_buffer_[out_buffer_.active_side()]); +} + +void command_app::get_report(hid::report::selector select, const std::span &buffer) +{ + if (select != report_in::selector()) { + return; + } + // copy to buffer to avoid overwriting data in transit + auto &report = in_buffer_[in_buffer_.inactive_side()]; + assert(buffer.size() >= sizeof(report)); + memcpy(buffer.data(), report.data(), sizeof(report)); + send_report(buffer.subspan(0, sizeof(report))); +} + +bool command_app::send(std::span buffer) +{ + auto buf_idx = in_buffer_.active_side(); + auto &report = in_buffer_[buf_idx]; + if (buffer.size() > report.payload.max_size()) { + printk("Usb payload exceeded maximum size!\n"); + return false; + } + std::copy(buffer.begin(), buffer.end(), report.payload.begin()); + c2usb::result err = send_report(&in_buffer_[buf_idx]); + if (err == hid::result::OK) { + in_buffer_.compare_swap(buf_idx); + return true; + } + printk("Command app failed to send report with: %i\n", (int)err); + return false; +} + +void command_app::in_report_sent(const std::span &data) +{ + if (data.front() != report_ids::IN_COMMAND) { + return; + } + auto buf_idx = in_buffer_.indexof(data.data()); + in_buffer_.compare_swap(buf_idx); +} diff --git a/device/src/usb/command_app.hpp b/device/src/usb/command_app.hpp new file mode 100644 index 000000000..e9166a0e4 --- /dev/null +++ b/device/src/usb/command_app.hpp @@ -0,0 +1,85 @@ +#ifndef __COMMAND_APP_HEADER__ +#define __COMMAND_APP_HEADER__ + +#include "double_buffer.hpp" +#include "hid/application.hpp" +#include "hid/rdf/descriptor.hpp" +#include "hid/report_protocol.hpp" +#include "report_ids.h" + +namespace hid::page { +enum class ugl : uint8_t; +template <> +struct info { + constexpr static page_id_t page_id = 0xFF00; + constexpr static usage_id_t max_usage_id = 0x0003; + constexpr static const char *name = "UGL"; +}; +enum class ugl : uint8_t { + COMMAND_APP = 0x0001, + COMMAND_DATA_IN = 0x0002, + COMMAND_DATA_OUT = 0x0003, +}; + +} // namespace hid::page + +class command_app : public hid::application { + command_app() : application(report_protocol()) {} + + public: + static constexpr size_t MESSAGE_SIZE = 63; + + static constexpr auto report_desc() + { + using namespace hid::page; + using namespace hid::rdf; + + // clang-format off + return descriptor( + usage_page(), + usage(ugl::COMMAND_APP), + collection::application( + conditional_report_id(), + report_size(8), + report_count(MESSAGE_SIZE), + logical_limits<1, 1>(0, 0xff), + usage(ugl::COMMAND_DATA_IN), + input::buffered_variable(), + conditional_report_id(), + usage(ugl::COMMAND_DATA_OUT), + output::buffered_variable() + ) + ); + // clang-format off + } + + template + struct report_base : public hid::report::base + { + std::array payload{}; + }; + using report_in = report_base; + using report_out = report_base; + + static command_app& handle(); + + bool send(std::span buffer); + + void start(hid::protocol prot) override; + void set_report(hid::report::type type, const std::span& data) override; + void get_report(hid::report::selector select, const std::span& buffer) override; + void in_report_sent(const std::span& data) override; + + private: + static hid::report_protocol report_protocol() + { + static constexpr const auto rd{report_desc()}; + constexpr hid::report_protocol rp{rd}; + return rp; + } + + double_buffer in_buffer_{}; + double_buffer out_buffer_{}; +}; + +#endif // __COMMAND_APP_HEADER__ diff --git a/device/src/usb/controls_app.cpp b/device/src/usb/controls_app.cpp new file mode 100644 index 000000000..17452c08d --- /dev/null +++ b/device/src/usb/controls_app.cpp @@ -0,0 +1,72 @@ +#include "controls_app.hpp" + +extern "C" +{ +#include "usb/usb.h" +#include +} + +static K_SEM_DEFINE(reportSending, 1, 1); + +controls_app& controls_app::handle() +{ + static controls_app app{}; + return app; +} + +void controls_app::start(hid::protocol prot) +{ + // TODO start handling controls events + report_buffer_.reset(); +} + +void controls_app::stop() +{ + // TODO stop handling controls events +} + +void controls_app::set_report_state(const controls_report_base<0> &data) +{ + k_sem_take(&reportSending, K_MSEC(SEMAPHORE_RESET_TIMEOUT)); + auto buf_idx = report_buffer_.active_side(); + auto &report = report_buffer_[buf_idx]; + report.consumer_codes = data.consumer_codes; + report.system_codes = data.system_codes; + report.telephony_codes = data.telephony_codes; + send_buffer(buf_idx); +} + +void controls_app::send_buffer(uint8_t buf_idx) +{ + if (!report_buffer_.differs()) { + k_sem_give(&reportSending); + return; + } + if (send_report(&report_buffer_[buf_idx]) == hid::result::OK) { + report_buffer_.compare_swap_copy(buf_idx); + k_sem_give(&reportSending); + } +} + +void controls_app::in_report_sent(const std::span &data) +{ + if (data.front() != report_ids::IN_CONTROLS) { + return; + } + auto buf_idx = report_buffer_.indexof(data.data()); + if (!report_buffer_.compare_swap_copy(buf_idx)) { + send_buffer(1 - buf_idx); + } +} + +void controls_app::get_report(hid::report::selector select, const std::span &buffer) +{ + if (select != controls_report::selector()) { + return; + } + // copy to buffer to avoid overwriting data in transit + auto &report = report_buffer_[report_buffer_.inactive_side()]; + assert(buffer.size() >= sizeof(report)); + memcpy(buffer.data(), report.data(), sizeof(report)); + send_report(buffer.subspan(0, sizeof(report))); +} diff --git a/device/src/usb/controls_app.hpp b/device/src/usb/controls_app.hpp new file mode 100644 index 000000000..f9f2d4e62 --- /dev/null +++ b/device/src/usb/controls_app.hpp @@ -0,0 +1,108 @@ +#ifndef __CONTROLS_APP_HEADER__ +#define __CONTROLS_APP_HEADER__ + +#include "double_buffer.hpp" +#include "hid/application.hpp" +#include "hid/page/consumer.hpp" +#include "hid/page/generic_desktop.hpp" +#include "hid/page/telephony.hpp" +#include "hid/rdf/descriptor.hpp" +#include "hid/report_array.hpp" +#include "hid/report_protocol.hpp" +#include "report_ids.h" + +using system_code = hid::page::generic_desktop; +using consumer_code = hid::page::consumer; +using telephony_code = hid::page::telephony; + +class controls_app : public hid::application { + static constexpr size_t CONSUMER_CODE_COUNT = 2; + static constexpr size_t SYSTEM_CODE_COUNT = 2; + static constexpr size_t TELEPHONY_CODE_COUNT = 2; + + controls_app() : application(report_protocol()) {} + + public: + template + struct controls_report_base : public hid::report::base { + hid::report_array consumer_codes{}; + hid::report_array system_codes{}; + hid::report_array telephony_codes{}; + + constexpr controls_report_base() = default; + + bool operator==(const controls_report_base &other) const = default; + bool operator!=(const controls_report_base &other) const = default; + + bool set_code(system_code c, bool value = true) { return system_codes.set(c, value); } + bool test(system_code c) const { return system_codes.test(c); } + bool set_code(consumer_code c, bool value = true) { return consumer_codes.set(c, value); } + bool test(consumer_code c) const { return consumer_codes.test(c); } + bool set_code(telephony_code c, bool value = true) { return telephony_codes.set(c, value); } + bool test(telephony_code c) const { return telephony_codes.test(c); } + }; + + static constexpr auto report_desc() + { + using namespace hid; + using namespace hid::page; + using namespace hid::rdf; + + // clang-format off + return descriptor( + usage_page(), + usage(consumer::CONSUMER_CONTROL), + collection::application( + conditional_report_id(), + + report_size(sizeof(hid::le_uint16_t) * 8), + report_count(CONSUMER_CODE_COUNT), + logical_limits<1, 2>(0, info::max_usage_id), + usage_extended_limits(nullusage, static_cast(info::max_usage_id)), + input::array(), + + report_size(sizeof(hid::le_uint16_t) * 8), + report_count(SYSTEM_CODE_COUNT), + logical_limits<1, 2>(0, info::max_usage_id), + usage_extended_limits(nullusage, static_cast(info::max_usage_id)), + input::array(), + + report_size(sizeof(hid::le_uint16_t) * 8), + report_count(TELEPHONY_CODE_COUNT), + logical_limits<1, 2>(0, info::max_usage_id), + usage_extended_limits(nullusage, static_cast(info::max_usage_id)), + input::array() + ) + ); + // clang-format on + } + + static controls_app &handle(); + + void set_report_state(const controls_report_base<0> &data); + + private: + static hid::report_protocol report_protocol() + { + static constexpr const auto rd{report_desc()}; + constexpr hid::report_protocol rp{rd}; + return rp; + } + + void start(hid::protocol prot) override; + void stop() override; + void set_report(hid::report::type type, const std::span &data) override + { + // no FEATURE or OUTPUT reports + } + void in_report_sent(const std::span &data) override; + void get_report(hid::report::selector select, const std::span &buffer) override; + void send_buffer(uint8_t buf_idx); + + using controls_report = controls_report_base; + double_buffer report_buffer_{}; +}; + +using controls_buffer = controls_app::controls_report_base<0>; + +#endif // __CONTROLS_APP_HEADER__ diff --git a/device/src/usb/double_buffer.hpp b/device/src/usb/double_buffer.hpp new file mode 100644 index 000000000..d13ae6467 --- /dev/null +++ b/device/src/usb/double_buffer.hpp @@ -0,0 +1,68 @@ +#ifndef _DOUBLE_BUFFER_HPP_ +#define _DOUBLE_BUFFER_HPP_ + +#include +#include +#include +#include + +template +class double_buffer +{ + struct aligned_storage + { + C2USB_USB_TRANSFER_ALIGN(T, m_){}; + }; + + public: + constexpr double_buffer() {} + + T& operator[](uint8_t i) { return buffers_[i].m_; } + + const T& operator[](uint8_t i) const { return buffers_[i].m_; } + + uint8_t active_side(std::memory_order mo = std::memory_order::seq_cst) const + { + return select_.load(mo); + } + + uint8_t inactive_side(std::memory_order mo = std::memory_order::seq_cst) const + { + return 1 - select_.load(mo); + } + + template + uint8_t indexof(TArg* ptr) const + { + auto oneptr = reinterpret_cast(&buffers_[1]); + auto dataptr = reinterpret_cast(ptr); + return (dataptr < oneptr) ? 0 : 1; + } + + void swap_sides(std::memory_order mo = std::memory_order::seq_cst) { select_.fetch_xor(1, mo); } + + bool compare_swap(uint8_t i, std::memory_order mo = std::memory_order::seq_cst) + { + return select_.compare_exchange_strong(i, 1 - i, mo); + } + + bool compare_swap_copy(uint8_t i, std::memory_order mo = std::memory_order::seq_cst) + { + if (compare_swap(i, mo)) + { + buffers_[1 - i] = buffers_[i]; + return true; + } + return false; + } + + void reset() { buffers_ = {}; } + + bool differs() const { return std::memcmp(&buffers_[0], &buffers_[1], sizeof(T)) != 0; } + + private: + std::array buffers_{}; + std::atomic_uint8_t select_{}; +}; + +#endif // _DOUBLE_BUFFER_HPP_ \ No newline at end of file diff --git a/device/src/usb/gamepad_app.cpp b/device/src/usb/gamepad_app.cpp new file mode 100644 index 000000000..b76ebf23f --- /dev/null +++ b/device/src/usb/gamepad_app.cpp @@ -0,0 +1,78 @@ +#include "gamepad_app.hpp" + +extern "C" +{ +#include "usb/usb.h" +#include +} + +static K_SEM_DEFINE(reportSending, 1, 1); + +gamepad_app& gamepad_app::handle() +{ + static gamepad_app app{}; + return app; +} + +void gamepad_app::start(hid::protocol prot) +{ + // TODO start handling gamepad events + report_buffer_.reset(); + if (prot != hid::protocol::REPORT) { + report_buffer_[0].id = 0; + report_buffer_[1].id = 0; + } +} + +void gamepad_app::stop() +{ + // TODO stop handling gamepad events +} + +void gamepad_app::set_report_state(const gamepad_report &data) +{ + k_sem_take(&reportSending, K_MSEC(SEMAPHORE_RESET_TIMEOUT)); + auto buf_idx = report_buffer_.active_side(); + auto &report = report_buffer_[buf_idx]; + report.buttons = data.buttons; + report.left = data.left; + report.right = data.right; + report.left_trigger = data.left_trigger; + report.right_trigger = data.right_trigger; + send_buffer(buf_idx); +} + +void gamepad_app::send_buffer(uint8_t buf_idx) +{ + if (!report_buffer_.differs()) { + k_sem_give(&reportSending); + return; + } + if (send_report(&report_buffer_[buf_idx]) == hid::result::OK) { + report_buffer_.compare_swap_copy(buf_idx); + k_sem_give(&reportSending); + } +} + +void gamepad_app::in_report_sent(const std::span &data) +{ + if (data.front() != report_ids::IN_GAMEPAD) { + return; + } + auto buf_idx = report_buffer_.indexof(data.data()); + if (!report_buffer_.compare_swap_copy(buf_idx)) { + send_buffer(1 - buf_idx); + } +} + +void gamepad_app::get_report(hid::report::selector select, const std::span &buffer) +{ + if (select != gamepad_report::selector()) { + return; + } + // copy to buffer to avoid overwriting data in transit + auto &report = report_buffer_[report_buffer_.inactive_side()]; + assert(buffer.size() >= sizeof(report)); + memcpy(buffer.data(), report.data(), sizeof(report)); + send_report(buffer.subspan(0, sizeof(report))); +} diff --git a/device/src/usb/gamepad_app.hpp b/device/src/usb/gamepad_app.hpp new file mode 100644 index 000000000..bf1d24407 --- /dev/null +++ b/device/src/usb/gamepad_app.hpp @@ -0,0 +1,199 @@ +#ifndef __GAMEPAD_APP_HEADER__ +#define __GAMEPAD_APP_HEADER__ + +#include "double_buffer.hpp" +#include "hid/application.hpp" +#include "hid/page/button.hpp" +#include "hid/page/generic_desktop.hpp" +#include "hid/rdf/descriptor.hpp" +#include "hid/report_protocol.hpp" +#include "report_ids.h" + +enum class gamepad_button { + UP = 0, + DOWN = 1, + LEFT = 2, + RIGHT = 3, + START = 4, + BACK = 5, + LS = 6, + RS = 7, + LB = 8, + RB = 9, + HOME = 10, + A = 12, + B = 13, + X = 14, + Y = 15 +}; + +class gamepad_app : public hid::application { + gamepad_app() : application(report_protocol()) {} + + public: + static constexpr auto report_desc() + { + using namespace hid::page; + using namespace hid::rdf; + + // clang-format off + // translate XBOX360 report mapping to HID as much as possible + return descriptor( + usage_page(), + usage(generic_desktop::GAMEPAD), + collection::application( + // Report ID (0, which isn't valid, mark it as reserved) + report_id(report_ids::IN_GAMEPAD), + // Report size + input::padding(8), + + // Buttons p1 + usage_page