From ed0e8221f17a635c08cc89ed9b5c61715549bd52 Mon Sep 17 00:00:00 2001 From: Jeroen Schweitzer Date: Tue, 14 Jul 2026 21:42:51 +0200 Subject: [PATCH] Phase 2: full LVGL face + Wi-Fi + gateway WebSocket + touch-to-talk The device now runs the complete face contract on glass: seven states with glyph expressions (custom 140px face font), matrix rain as pooled label streams (22px DejaVu+Noto katakana font), rage kaomoji frames (64px), orbit arc + elapsed counter wait cues, blink/talk/thought animations, idle clock (SNTP, Europe/Amsterdam), and the power ladder (active/ambient 35%/dormant 5% with rain parked). Voice path: ES7210 mic capture task streams 16k PCM over esp_websocket_client to the gateway; reply PCM buffers to PSRAM and plays via the audio task; touch-to-talk (tap to speak, tap to send). Protocol mapping per docs: thinking->effort, audio->speaking, error event->rage (auto-composes after 2 loops), WS loss->error face. Bring-up fixes: 8MB factory partition (fonts overflowed 1.5M), bsp_display_lock(0) is try-lock in this adapter (use UINT32_MAX), gong synth yields to feed IDLE0, wifi scan diagnostics (found SSID case mismatch), esp_websocket_client pinned ~1.3 (1.4 needs IDF>5.5). Verified on hardware: boots, connects to Wi-Fi and holds an open WebSocket to the gateway. Sauron (iMac TTY endpoint + ops console) planned in architecture.md. Co-Authored-By: Claude Fable 5 --- .gitignore | 2 +- README.md | 4 +- docs/architecture.md | 19 + firmware/main/CMakeLists.txt | 13 +- firmware/main/audio.c | 208 ++++++ firmware/main/desklock.h | 46 ++ firmware/main/desklock_main.c | 172 +---- firmware/main/face.c | 461 ++++++++++++ firmware/main/fonts/font_face_140.c | 1062 +++++++++++++++++++++++++++ firmware/main/fonts/font_rage_64.c | 425 +++++++++++ firmware/main/fonts/font_rain_22.c | 578 +++++++++++++++ firmware/main/gw_client.c | 124 ++++ firmware/main/idf_component.yml | 3 + firmware/main/net.c | 83 +++ firmware/main/secrets.h.example | 5 + firmware/partitions.csv | 4 + firmware/sdkconfig.defaults | 9 +- 17 files changed, 3073 insertions(+), 145 deletions(-) create mode 100644 firmware/main/audio.c create mode 100644 firmware/main/desklock.h create mode 100644 firmware/main/face.c create mode 100644 firmware/main/fonts/font_face_140.c create mode 100644 firmware/main/fonts/font_rage_64.c create mode 100644 firmware/main/fonts/font_rain_22.c create mode 100644 firmware/main/gw_client.c create mode 100644 firmware/main/net.c create mode 100644 firmware/main/secrets.h.example create mode 100644 firmware/partitions.csv diff --git a/.gitignore b/.gitignore index b996706..4583e2e 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,7 @@ firmware/managed_components/ firmware/sdkconfig firmware/sdkconfig.old firmware/dependencies.lock -firmware/secrets.h +firmware/main/secrets.h # Python __pycache__/ diff --git a/README.md b/README.md index 7bc7388..60b35a6 100644 --- a/README.md +++ b/README.md @@ -61,8 +61,8 @@ See [docs/architecture.md](docs/architecture.md) for the full design. ## Roadmap -1. **Bring-up** — ESP-IDF toolchain, build/flash, BSP display + Wi-Fi working -2. **Face** — LVGL face with idle/listening/thinking/speaking states, clock while idle +1. ~~**Bring-up**~~ ✅ — display, touch, audio, 200 MHz PSRAM, cathedral gong +2. **Face + voice loop** (in hardware test) — full LVGL face (7 states, rain, orbit, power ladder), Wi-Fi, WebSocket, touch-to-talk 3. **Voice (touch-to-talk)** — tap to talk → gateway → Tatlock → spoken reply 4. **Wake word** — esp-sr WakeNet on-device, echo cancellation, barge-in 5. **Polish** — Tatlock-initiated notifications, presence, OTA updates diff --git a/docs/architecture.md b/docs/architecture.md index e6d9354..07d2082 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -301,6 +301,25 @@ it is the one contract between the two halves of the repo. - **Monorepo**: the WS protocol couples firmware and gateway; versioning them together avoids contract drift. +## Additional endpoints — sauron (planned) + +**sauron** is an old iMac (Linux, text-only console) that will run the same UX as a +second butler endpoint plus an ops console. Because the gateway protocol is +endpoint-agnostic and each WS connection gets its own conversation, extra endpoints +are architecturally free. + +- **Client**: a terminal UI (`clients/sauron/`, Python + curses/textual) — the face + design is already ASCII, so a TTY renders it natively: glyph face states, + character-cell matrix rain, green-on-black. Audio via ALSA (arecord/aplay-level, + 16 kHz mono PCM), same WebSocket protocol, same state machine. +- **Screensaver model** (user-confirmed): the face+voice layer is the *idle mode* — + full-screen butler when nobody's working. The *workspace mode* is an SSH ops console: + live stats and remote control of tower-of-joy and forge. Any keypress drops from face + to console; idle timeout (and wake word later) raises the face again. Voice stays + available in both modes. +- **Not started** — planned after the device reaches phase 4/5. No browser/kiosk stack + needed unless we later want the glow. + ## CI & deployment Gitea Actions (`.gitea/workflows/build.yml`), following the tatlock/tatlock-ui pattern: diff --git a/firmware/main/CMakeLists.txt b/firmware/main/CMakeLists.txt index 84f7f27..2b31ab8 100644 --- a/firmware/main/CMakeLists.txt +++ b/firmware/main/CMakeLists.txt @@ -1,4 +1,15 @@ idf_component_register( - SRCS "desklock_main.c" + SRCS + "desklock_main.c" + "face.c" + "audio.c" + "net.c" + "gw_client.c" + "fonts/font_face_140.c" + "fonts/font_rain_22.c" + "fonts/font_rage_64.c" INCLUDE_DIRS "." + PRIV_REQUIRES nvs_flash esp_wifi esp_event esp_netif json esp_timer ) + +target_compile_definitions(${COMPONENT_LIB} PRIVATE LV_LVGL_H_INCLUDE_SIMPLE) diff --git a/firmware/main/audio.c b/firmware/main/audio.c new file mode 100644 index 0000000..200e16a --- /dev/null +++ b/firmware/main/audio.c @@ -0,0 +1,208 @@ +/* Audio: gong synthesis, mic capture -> gateway, gateway PCM -> speaker. */ + +#include +#include + +#include "esp_heap_caps.h" +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/queue.h" +#include "freertos/task.h" +#include "bsp/esp-bsp.h" +#include "esp_codec_dev.h" + +#include "desklock.h" + +static const char *TAG = "audio"; + +#define RATE 16000 +#define CAPTURE_CHUNK 3200 /* 100 ms */ +#define REPLY_MAX (RATE * 2 * 60) /* 60 s of reply audio */ + +#define GONG_SECONDS 5 +#define GONG_SAMPLES (RATE * GONG_SECONDS) +#define GONG_VOLUME 75 +#define GONG_PEAK 14000.0f + +static esp_codec_dev_handle_t s_spk; +static esp_codec_dev_handle_t s_mic; +static int16_t *s_gong; + +static uint8_t *s_reply; +static volatile size_t s_reply_len; +static volatile bool s_playing; +static volatile bool s_capturing; + +typedef enum { JOB_GONG, JOB_REPLY } job_t; +static QueueHandle_t s_jobs; + +/* --- gong: see docs/architecture.md "Sound signature" --- */ + +static const struct { + float ratio, amp, tau; +} PARTIALS[] = { + { 1.000f, 0.30f, 2.6f }, + { 1.004f, 0.22f, 2.2f }, + { 1.590f, 0.22f, 1.4f }, + { 2.140f, 0.16f, 0.9f }, + { 2.760f, 0.10f, 0.55f }, + { 3.570f, 0.05f, 0.35f }, + { 4.800f, 0.03f, 0.22f }, +}; +static const struct { + int delay_ms; + float gain; +} ECHOES[] = { { 95, 0.45f }, { 210, 0.30f }, { 370, 0.18f } }; + +static void synth_gong(void) +{ + float *dry = heap_caps_calloc(GONG_SAMPLES, sizeof(float), MALLOC_CAP_SPIRAM); + s_gong = heap_caps_malloc(GONG_SAMPLES * sizeof(int16_t), MALLOC_CAP_SPIRAM); + if (dry == NULL || s_gong == NULL) { + free(dry); + return; + } + for (size_t p = 0; p < sizeof(PARTIALS) / sizeof(PARTIALS[0]); p++) { + float step = 2.0f * (float)M_PI * 220.0f * PARTIALS[p].ratio / RATE; + float decay = expf(-1.0f / (PARTIALS[p].tau * RATE)); + float env = PARTIALS[p].amp, phase = 0.0f; + for (int i = 0; i < GONG_SAMPLES; i++) { + phase += step; + env *= decay; + dry[i] += sinf(phase) * env; + if ((i & 0x3FFF) == 0) { + vTaskDelay(1); /* keep IDLE0 fed; synth is not latency-critical */ + } + } + } + const int attack = RATE * 45 / 1000; + for (int i = 0; i < attack; i++) { + dry[i] *= (float)i / attack; + } + float peak = 1e-6f; + for (int i = 0; i < GONG_SAMPLES; i++) { + float s = dry[i]; + for (size_t e = 0; e < sizeof(ECHOES) / sizeof(ECHOES[0]); e++) { + int j = i - RATE * ECHOES[e].delay_ms / 1000; + if (j >= 0) { + s += dry[j] * ECHOES[e].gain; + } + } + const int fade = RATE * 2 / 5; + if (i > GONG_SAMPLES - fade) { + s *= (float)(GONG_SAMPLES - i) / fade; + } + dry[i] = s; + if (fabsf(s) > peak) { + peak = fabsf(s); + } + if ((i & 0x3FFF) == 0) { + vTaskDelay(1); + } + } + for (int i = 0; i < GONG_SAMPLES; i++) { + s_gong[i] = (int16_t)(dry[i] * (GONG_PEAK / peak)); + } + free(dry); +} + +/* --- playback worker --- */ + +static void audio_task(void *arg) +{ + (void)arg; + synth_gong(); + ESP_LOGI(TAG, "gong ready"); + job_t job; + while (xQueueReceive(s_jobs, &job, portMAX_DELAY) == pdTRUE) { + if (job == JOB_GONG && s_gong != NULL) { + esp_codec_dev_write(s_spk, s_gong, GONG_SAMPLES * sizeof(int16_t)); + } else if (job == JOB_REPLY) { + s_playing = true; + esp_codec_dev_write(s_spk, s_reply, s_reply_len); + s_playing = false; + app_on_playback_done(); + } + } +} + +static void capture_task(void *arg) +{ + (void)arg; + uint8_t *chunk = heap_caps_malloc(CAPTURE_CHUNK, MALLOC_CAP_DEFAULT); + while (s_capturing) { + if (esp_codec_dev_read(s_mic, chunk, CAPTURE_CHUNK) == ESP_CODEC_DEV_OK) { + gw_send_bin(chunk, CAPTURE_CHUNK); + } + } + free(chunk); + vTaskDelete(NULL); +} + +void audio_init(void) +{ + esp_codec_dev_sample_info_t fs = { + .sample_rate = RATE, + .channel = 1, + .bits_per_sample = 16, + }; + s_spk = bsp_audio_codec_speaker_init(); + if (s_spk != NULL) { + esp_codec_dev_set_out_vol(s_spk, GONG_VOLUME); + esp_codec_dev_open(s_spk, &fs); + } + s_mic = bsp_audio_codec_microphone_init(); + if (s_mic != NULL) { + esp_codec_dev_set_in_gain(s_mic, 30.0f); + esp_codec_dev_open(s_mic, &fs); + } + s_reply = heap_caps_malloc(REPLY_MAX, MALLOC_CAP_SPIRAM); + s_jobs = xQueueCreate(4, sizeof(job_t)); + xTaskCreate(audio_task, "audio", 4096, NULL, 5, NULL); + ESP_LOGI(TAG, "audio up (spk=%d mic=%d)", s_spk != NULL, s_mic != NULL); +} + +void audio_play_gong(void) +{ + job_t job = JOB_GONG; + xQueueSend(s_jobs, &job, 0); +} + +void audio_capture_start(void) +{ + if (s_mic == NULL || s_capturing) { + return; + } + s_capturing = true; + xTaskCreate(capture_task, "capture", 4096, NULL, 6, NULL); +} + +void audio_capture_stop(void) +{ + s_capturing = false; +} + +void audio_playback_begin(void) +{ + s_reply_len = 0; +} + +void audio_playback_feed(const uint8_t *data, size_t len) +{ + if (s_reply == NULL || s_reply_len + len > REPLY_MAX) { + return; + } + memcpy(s_reply + s_reply_len, data, len); + s_reply_len += len; +} + +void audio_playback_end(void) +{ + job_t job = JOB_REPLY; + xQueueSend(s_jobs, &job, 0); +} + +bool audio_is_playing(void) +{ + return s_playing; +} diff --git a/firmware/main/desklock.h b/firmware/main/desklock.h new file mode 100644 index 0000000..ea936d4 --- /dev/null +++ b/firmware/main/desklock.h @@ -0,0 +1,46 @@ +/* Shared app types and cross-module hooks. */ +#pragma once + +#include +#include +#include + +typedef enum { + FACE_BOOT, /* connecting — idle glyphs + status tag */ + FACE_IDLE, /* clock, rare drips */ + FACE_LISTENING, /* mic hot */ + FACE_PENSIVE, /* transcribing / short waits */ + FACE_EFFORT, /* Tatlock working: max rain + orbit + elapsed */ + FACE_SPEAKING, /* mouth sync */ + FACE_RAGE, /* request failed: table flip, auto-returns to idle */ + FACE_ERROR, /* gateway unreachable */ +} face_state_t; + +/* face.c */ +void face_init(void); +void face_set(face_state_t state); /* safe from any task */ +face_state_t face_get(void); +void face_activity(void); /* reset the power ladder to active */ + +/* audio.c */ +void audio_init(void); +void audio_play_gong(void); +void audio_capture_start(void); +void audio_capture_stop(void); +void audio_playback_begin(void); +void audio_playback_feed(const uint8_t *data, size_t len); +void audio_playback_end(void); +bool audio_is_playing(void); + +/* net.c */ +void net_start(void); + +/* gw_client.c */ +void gw_start(void); +bool gw_connected(void); +void gw_send_text(const char *json); +void gw_send_bin(const uint8_t *data, size_t len); + +/* desklock_main.c */ +void app_on_touch(void); +void app_on_playback_done(void); diff --git a/firmware/main/desklock_main.c b/firmware/main/desklock_main.c index 441a388..04c6fb2 100644 --- a/firmware/main/desklock_main.c +++ b/firmware/main/desklock_main.c @@ -1,153 +1,46 @@ -/* - * DeskLock — living-room face and voice for the Tatlock butler. +/* DeskLock — living-room face and voice for the Tatlock butler. * - * Boot sequence (planned): - * 1. BSP init: display + LVGL, touch, audio codec (ES8311/ES7210) - * 2. Wi-Fi up via ESP32-C6 (ESP-Hosted over SDIO) - * 3. WebSocket connection to the DeskLock gateway - * 4. Face state machine: idle / listening / thinking / speaking - * - * Current stage: bring-up — display + a placeholder face. + * Boot: display + face -> audio (gong) -> Wi-Fi (C6/ESP-Hosted) -> gateway WS. + * Interaction (phase 2): touch-to-talk — tap to speak, tap again to finish. */ -#include -#include - #include "esp_log.h" #include "bsp/esp-bsp.h" -#include "esp_codec_dev.h" -#include "lvgl.h" + +#include "desklock.h" static const char *TAG = "desklock"; -#define GONG_RATE 16000 -#define GONG_SECONDS 5 -#define GONG_SAMPLES (GONG_RATE * GONG_SECONDS) -#define GONG_VOLUME 75 /* codec volume: discreet, not loud */ -#define GONG_PEAK 14000.0f /* ~-7 dBFS headroom */ +static bool s_talking; -/* A distant temple gong in a stone space. - * - * Inharmonic partials with per-partial decay (lows ring for seconds, highs - * die fast), a detuned fundamental pair for slow shimmer, a soft 45 ms - * attack so the strike reads as far away, and three early reflections that - * stand in for cathedral walls. Fundamental sits at 220 Hz — low enough to - * feel voluminous, high enough for the bare 2 W speaker to reproduce. - */ -static const struct { - float ratio; - float amp; - float tau; /* seconds to 1/e */ -} gong_partials[] = { - { 1.000f, 0.30f, 2.6f }, - { 1.004f, 0.22f, 2.2f }, /* beating partner -> shimmer */ - { 1.590f, 0.22f, 1.4f }, - { 2.140f, 0.16f, 0.9f }, - { 2.760f, 0.10f, 0.55f }, - { 3.570f, 0.05f, 0.35f }, - { 4.800f, 0.03f, 0.22f }, -}; - -static const struct { - int delay_ms; - float gain; -} gong_echoes[] = { { 95, 0.45f }, { 210, 0.30f }, { 370, 0.18f } }; - -static void play_boot_gong(void) +void app_on_touch(void) { - esp_codec_dev_handle_t spk = bsp_audio_codec_speaker_init(); - if (spk == NULL) { - ESP_LOGW(TAG, "speaker init failed — no gong"); + face_activity(); + + if (!gw_connected()) { return; } - esp_codec_dev_sample_info_t fs = { - .sample_rate = GONG_RATE, - .channel = 1, - .bits_per_sample = 16, - }; - esp_codec_dev_set_out_vol(spk, GONG_VOLUME); - esp_codec_dev_open(spk, &fs); - - float *dry = heap_caps_calloc(GONG_SAMPLES, sizeof(float), MALLOC_CAP_SPIRAM); - int16_t *pcm = heap_caps_malloc(GONG_SAMPLES * sizeof(int16_t), MALLOC_CAP_SPIRAM); - if (dry == NULL || pcm == NULL) { - ESP_LOGW(TAG, "no memory for gong"); - goto out; - } - - for (size_t p = 0; p < sizeof(gong_partials) / sizeof(gong_partials[0]); p++) { - float step = 2.0f * (float)M_PI * 220.0f * gong_partials[p].ratio / GONG_RATE; - float decay = expf(-1.0f / (gong_partials[p].tau * GONG_RATE)); - float env = gong_partials[p].amp; - float phase = 0.0f; - for (int i = 0; i < GONG_SAMPLES; i++) { - phase += step; - env *= decay; - dry[i] += sinf(phase) * env; + if (!s_talking) { + if (audio_is_playing() || face_get() == FACE_EFFORT) { + return; /* barge-in is phase 4 */ } + s_talking = true; + gw_send_text("{\"type\":\"utterance_start\"}"); + audio_capture_start(); + face_set(FACE_LISTENING); + ESP_LOGI(TAG, "listening…"); + } else { + s_talking = false; + audio_capture_stop(); + gw_send_text("{\"type\":\"utterance_end\"}"); + face_set(FACE_PENSIVE); + ESP_LOGI(TAG, "utterance sent"); } - - const int attack = GONG_RATE * 45 / 1000; /* distant, not percussive */ - for (int i = 0; i < attack; i++) { - dry[i] *= (float)i / attack; - } - - float peak = 1e-6f; - for (int i = 0; i < GONG_SAMPLES; i++) { - float s = dry[i]; - for (size_t e = 0; e < sizeof(gong_echoes) / sizeof(gong_echoes[0]); e++) { - int j = i - GONG_RATE * gong_echoes[e].delay_ms / 1000; - if (j >= 0) { - s += dry[j] * gong_echoes[e].gain; - } - } - const int fade = GONG_RATE * 2 / 5; /* last 400 ms to silence */ - if (i > GONG_SAMPLES - fade) { - s *= (float)(GONG_SAMPLES - i) / fade; - } - dry[i] = s; - if (fabsf(s) > peak) { - peak = fabsf(s); - } - } - for (int i = 0; i < GONG_SAMPLES; i++) { - pcm[i] = (int16_t)(dry[i] * (GONG_PEAK / peak)); - } - - esp_codec_dev_write(spk, pcm, GONG_SAMPLES * sizeof(int16_t)); - ESP_LOGI(TAG, "boot gong played"); - -out: - free(dry); - free(pcm); - esp_codec_dev_close(spk); } -static void show_placeholder_face(void) +void app_on_playback_done(void) { - bsp_display_lock(0); - - lv_obj_t *scr = lv_screen_active(); - lv_obj_set_style_bg_color(scr, lv_color_black(), 0); - - lv_obj_t *eyes = lv_label_create(scr); - lv_label_set_text(eyes, "- -"); - lv_obj_set_style_text_color(eyes, lv_color_hex(0xADFFC8), 0); - lv_obj_set_style_text_font(eyes, &lv_font_montserrat_48, 0); - lv_obj_align(eyes, LV_ALIGN_CENTER, 0, -80); - - lv_obj_t *mouth = lv_label_create(scr); - lv_label_set_text(mouth, "\\_/"); - lv_obj_set_style_text_color(mouth, lv_color_hex(0xADFFC8), 0); - lv_obj_set_style_text_font(mouth, &lv_font_montserrat_48, 0); - lv_obj_align(mouth, LV_ALIGN_CENTER, 0, 40); - - lv_obj_t *tag = lv_label_create(scr); - lv_label_set_text(tag, "DESKLOCK"); - lv_obj_set_style_text_color(tag, lv_color_hex(0x2F7A4B), 0); - lv_obj_align(tag, LV_ALIGN_CENTER, 0, 160); - - bsp_display_unlock(); + face_set(FACE_IDLE); } void app_main(void) @@ -156,13 +49,12 @@ void app_main(void) bsp_display_start(); bsp_display_backlight_on(); - show_placeholder_face(); - play_boot_gong(); + face_init(); - ESP_LOGI(TAG, "DeskLock up (placeholder face)"); + audio_init(); + audio_play_gong(); - /* TODO(face): full LVGL face state machine per docs/architecture.md - * TODO(net): Wi-Fi via ESP-Hosted (C6), WebSocket to gateway - * TODO(voice): ES7210 capture upstream, ES8311 playback downstream - */ + net_start(); + + ESP_LOGI(TAG, "DeskLock up"); } diff --git a/firmware/main/face.c b/firmware/main/face.c new file mode 100644 index 0000000..3f4ee0f --- /dev/null +++ b/firmware/main/face.c @@ -0,0 +1,461 @@ +/* The DeskLock face: black screen, glyph expressions, matrix rain. + * Contract: sim/face/index.html + docs/architecture.md "Face design". + * All lv_timer callbacks run in the LVGL task; face_set() locks for other tasks. + */ + +#include +#include +#include + +#include "esp_random.h" +#include "bsp/esp-bsp.h" +#include "lvgl.h" + +#include "desklock.h" + +LV_FONT_DECLARE(font_face_140); +LV_FONT_DECLARE(font_rain_22); +LV_FONT_DECLARE(font_rage_64); + +#define SCREEN 800 +#define RAIN_MAX 40 +#define RAIN_CELL 20 +#define RAIN_COLS (SCREEN / RAIN_CELL) +#define TICK_MS 33 + +/* power ladder (docs/architecture.md "Power management") */ +#define AMBIENT_AFTER_MS (2 * 60 * 1000) +#define DORMANT_AFTER_MS (10 * 60 * 1000) + +typedef struct { + const char *eyes; + const char *mouth; + bool blink; + bool thought; + bool talk; + int rain_streams; + int rain_speed; /* px per tick, before per-stream jitter */ +} face_def_t; + +static const face_def_t DEFS[] = { + [FACE_BOOT] = { "- -", "\\_/", false, false, false, 6, 3 }, + [FACE_IDLE] = { "- -", "\\_/", true, false, false, 2, 2 }, + [FACE_LISTENING] = { "O O", "o", true, false, false, 16, 4 }, + [FACE_PENSIVE] = { "\xC2\xB7 \xC2\xB7", "~", false, true, false, 7, 3 }, + [FACE_EFFORT] = { "> <", "~", false, false, false, 40, 9 }, + [FACE_SPEAKING] = { "^ ^", "o", true, false, true, 14, 5 }, + [FACE_RAGE] = { NULL, "", false, false, false, 34, 12 }, + [FACE_ERROR] = { "x x", "-", false, false, false, 0, 0 }, +}; + +static const char *TALK[] = { "o", "O", "-", "O", "=", "o" }; + +static const struct { + const char *text; + int ms; +} RAGE_FRAMES[] = { + { "(\xC2\xB0\xE2\x96\xA1\xC2\xB0) \xE2\x94\xAC\xE2\x94\x80\xE2\x94\xAC", 900 }, + { "(\xE2\x95\xAF\xC2\xB0\xE2\x96\xA1\xC2\xB0)\xE2\x95\xAF\xEF\xB8\xB5 \xE2\x94\xBB\xE2\x94\x81\xE2\x94\xBB", 1300 }, + { "\xE2\x94\xAC\xE2\x94\x80\xE2\x94\xAC \xE3\x83\x8E( \xC2\xBA_\xC2\xBA \xE3\x83\x8E)", 1400 }, +}; +#define RAGE_LOOP_MS (900 + 1300 + 1400) +#define RAGE_AUTO_EXIT_LOOPS 2 + +/* rain glyph pool: ASCII + katakana (must exist in font_rain_22) */ +static const char *GLYPHS[] = { + "0","1","2","3","4","5","6","7","8","9","A","C","E","F","H","K","Z", + "$","#","%","*","+","=","<",">", + "\xE3\x82\xA2","\xE3\x82\xA4","\xE3\x82\xA6","\xE3\x82\xA8","\xE3\x82\xAA", + "\xE3\x82\xAB","\xE3\x82\xAD","\xE3\x82\xAF","\xE3\x82\xB1","\xE3\x82\xB3", + "\xE3\x82\xB5","\xE3\x82\xB7","\xE3\x82\xB9","\xE3\x82\xBB","\xE3\x82\xBD", + "\xE3\x82\xBF","\xE3\x83\x81","\xE3\x83\x84","\xE3\x83\x86","\xE3\x83\x88", + "\xE3\x83\x8A","\xE3\x83\x8B","\xE3\x83\x8C","\xE3\x83\x8D","\xE3\x83\x8E", +}; +#define NGLYPHS (sizeof(GLYPHS) / sizeof(GLYPHS[0])) + +typedef struct { + lv_obj_t *tail; + lv_obj_t *head; + int x, y, len, speed; + bool alive; +} stream_t; + +static struct { + face_state_t state; + lv_obj_t *rain_layer; + lv_obj_t *shade; + lv_obj_t *eyes; + lv_obj_t *mouth; + lv_obj_t *thought; + lv_obj_t *clock_lbl; + lv_obj_t *status; + lv_obj_t *elapsed; + lv_obj_t *arc; + stream_t streams[RAIN_MAX]; + int arc_rot; + uint32_t state_since; + uint32_t last_activity; + int power; /* 0 active, 1 ambient, 2 dormant */ + int blink_in_ms; + int blink_hold_ms; + int talk_i; + int talk_ms; + int dots_i; + int dots_ms; + int rage_ms; + int mutate; +} F; + +static uint32_t now_ms(void) { return lv_tick_get(); } +static const char *rand_glyph(void) { return GLYPHS[esp_random() % NGLYPHS]; } + +static void stream_fill(stream_t *s) +{ + char buf[16 * 4 + 16]; + int pos = 0; + for (int i = 0; i < s->len; i++) { + pos += snprintf(buf + pos, sizeof(buf) - pos, "%s%s", i ? "\n" : "", rand_glyph()); + } + lv_label_set_text(s->tail, buf); + lv_label_set_text(s->head, rand_glyph()); +} + +static void stream_spawn(stream_t *s, int speed) +{ + s->x = (esp_random() % RAIN_COLS) * RAIN_CELL; + s->len = 6 + esp_random() % 9; + s->speed = speed + esp_random() % 4; + s->y = -(s->len + 1) * 26; + if (s->tail == NULL) { + s->tail = lv_label_create(F.rain_layer); + lv_obj_set_style_text_font(s->tail, &font_rain_22, 0); + lv_obj_set_style_text_color(s->tail, lv_color_hex(0x00A050), 0); + lv_obj_set_style_text_opa(s->tail, 170, 0); + s->head = lv_label_create(F.rain_layer); + lv_obj_set_style_text_font(s->head, &font_rain_22, 0); + lv_obj_set_style_text_color(s->head, lv_color_hex(0xC3FFD7), 0); + } + lv_obj_clear_flag(s->tail, LV_OBJ_FLAG_HIDDEN); + lv_obj_clear_flag(s->head, LV_OBJ_FLAG_HIDDEN); + stream_fill(s); + s->alive = true; +} + +static void stream_hide(stream_t *s) +{ + s->alive = false; + if (s->tail != NULL) { + lv_obj_add_flag(s->tail, LV_OBJ_FLAG_HIDDEN); + lv_obj_add_flag(s->head, LV_OBJ_FLAG_HIDDEN); + } +} + +static void rain_tick(void) +{ + const face_def_t *d = &DEFS[F.state]; + int target = (F.power == 2) ? 0 : d->rain_streams; + int alive = 0; + for (int i = 0; i < RAIN_MAX; i++) { + stream_t *s = &F.streams[i]; + if (!s->alive) { + continue; + } + alive++; + s->y += s->speed; + lv_obj_set_pos(s->tail, s->x, s->y); + lv_obj_set_pos(s->head, s->x, s->y + s->len * 26); + if (F.mutate == 0 && (esp_random() % 3) == 0) { + lv_label_set_text(s->head, rand_glyph()); + } + if (s->y > SCREEN + 26) { + if (alive > target) { + stream_hide(s); + alive--; + } else { + stream_spawn(s, d->rain_speed); + } + } + } + for (int i = 0; i < RAIN_MAX && alive < target; i++) { + if (!F.streams[i].alive) { + stream_spawn(&F.streams[i], d->rain_speed); + alive++; + } + } + F.mutate = (F.mutate + 1) % 4; +} + +static void apply_power(int level) +{ + if (level == F.power) { + return; + } + F.power = level; + bsp_display_brightness_set(level == 0 ? 100 : level == 1 ? 35 : 5); + if (level == 2) { + for (int i = 0; i < RAIN_MAX; i++) { + stream_hide(&F.streams[i]); + } + } +} + +static void power_tick(void) +{ + /* conversation states hold the ladder at active */ + if (F.state != FACE_IDLE && F.state != FACE_ERROR) { + F.last_activity = now_ms(); + } + uint32_t idle_ms = now_ms() - F.last_activity; + apply_power(idle_ms > DORMANT_AFTER_MS ? 2 : idle_ms > AMBIENT_AFTER_MS ? 1 : 0); +} + +static void set_eyes_mouth(void) +{ + const face_def_t *d = &DEFS[F.state]; + if (F.state == FACE_RAGE) { + lv_obj_set_style_text_font(F.eyes, &font_rage_64, 0); + lv_label_set_text(F.eyes, RAGE_FRAMES[0].text); + lv_obj_add_flag(F.mouth, LV_OBJ_FLAG_HIDDEN); + return; + } + lv_obj_set_style_text_font(F.eyes, &font_face_140, 0); + lv_label_set_text(F.eyes, d->eyes); + lv_label_set_text(F.mouth, d->mouth); + lv_obj_clear_flag(F.mouth, LV_OBJ_FLAG_HIDDEN); +} + +static void blink_tick(void) +{ + const face_def_t *d = &DEFS[F.state]; + if (!d->blink || F.power == 2) { + return; + } + if (F.blink_hold_ms > 0) { + F.blink_hold_ms -= TICK_MS; + if (F.blink_hold_ms <= 0) { + lv_label_set_text(F.eyes, d->eyes); + } + return; + } + F.blink_in_ms -= TICK_MS; + if (F.blink_in_ms <= 0) { + char blinked[24]; + int j = 0; + for (const char *p = d->eyes; *p && j < 23; p++) { + blinked[j++] = (*p == ' ') ? ' ' : '_'; + } + blinked[j] = '\0'; + lv_label_set_text(F.eyes, blinked); + F.blink_hold_ms = 130; + F.blink_in_ms = 2600 + esp_random() % 3600; + } +} + +static void rage_tick(void) +{ + if (F.state != FACE_RAGE) { + return; + } + F.rage_ms += TICK_MS; + if (F.rage_ms >= RAGE_AUTO_EXIT_LOOPS * RAGE_LOOP_MS) { + F.state = FACE_IDLE; /* auto-compose: put the table back, return to idle */ + set_eyes_mouth(); + lv_obj_add_flag(F.arc, LV_OBJ_FLAG_HIDDEN); + lv_obj_add_flag(F.elapsed, LV_OBJ_FLAG_HIDDEN); + return; + } + int t = F.rage_ms % RAGE_LOOP_MS; + int idx = t < 900 ? 0 : t < 2200 ? 1 : 2; + lv_label_set_text(F.eyes, RAGE_FRAMES[idx].text); +} + +static void tick_cb(lv_timer_t *timer) +{ + (void)timer; + rain_tick(); + blink_tick(); + rage_tick(); + power_tick(); + + if (F.state == FACE_EFFORT) { + F.arc_rot = (F.arc_rot + 9) % 360; + lv_arc_set_rotation(F.arc, F.arc_rot); + char buf[20]; + snprintf(buf, sizeof(buf), "[ %lus ]", (unsigned long)((now_ms() - F.state_since) / 1000)); + lv_label_set_text(F.elapsed, buf); + } + + const face_def_t *d = &DEFS[F.state]; + if (d->talk) { + F.talk_ms += TICK_MS; + if (F.talk_ms >= 150) { + F.talk_ms = 0; + lv_label_set_text(F.mouth, TALK[F.talk_i++ % 6]); + } + } + if (d->thought) { + F.dots_ms += TICK_MS; + if (F.dots_ms >= 480) { + F.dots_ms = 0; + static const char *DOTS[] = { ".", "..", "..." }; + lv_label_set_text(F.thought, DOTS[F.dots_i++ % 3]); + } + } else { + lv_label_set_text(F.thought, ""); + } +} + +static void clock_cb(lv_timer_t *timer) +{ + (void)timer; + if (F.state != FACE_IDLE) { + lv_obj_add_flag(F.clock_lbl, LV_OBJ_FLAG_HIDDEN); + return; + } + time_t t = time(NULL); + struct tm tm; + localtime_r(&t, &tm); + if (tm.tm_year > 100) { + char buf[8]; + snprintf(buf, sizeof(buf), "%02d:%02d", tm.tm_hour, tm.tm_min); + lv_label_set_text(F.clock_lbl, buf); + lv_obj_clear_flag(F.clock_lbl, LV_OBJ_FLAG_HIDDEN); + } +} + +static void touch_cb(lv_event_t *e) +{ + (void)e; + app_on_touch(); +} + +void face_init(void) +{ + bsp_display_lock(UINT32_MAX); + + lv_obj_t *scr = lv_screen_active(); + lv_obj_set_style_bg_color(scr, lv_color_black(), 0); + + F.rain_layer = lv_obj_create(scr); + lv_obj_remove_style_all(F.rain_layer); + lv_obj_set_size(F.rain_layer, SCREEN, SCREEN); + + /* radial-ish shade so rain doesn't run through the face */ + F.shade = lv_obj_create(scr); + lv_obj_remove_style_all(F.shade); + lv_obj_set_size(F.shade, 520, 520); + lv_obj_center(F.shade); + lv_obj_set_style_radius(F.shade, LV_RADIUS_CIRCLE, 0); + lv_obj_set_style_bg_color(F.shade, lv_color_black(), 0); + lv_obj_set_style_bg_opa(F.shade, 215, 0); + + F.eyes = lv_label_create(scr); + lv_obj_set_style_text_font(F.eyes, &font_face_140, 0); + lv_obj_set_style_text_color(F.eyes, lv_color_hex(0xADFFC8), 0); + lv_obj_align(F.eyes, LV_ALIGN_CENTER, 0, -90); + + F.mouth = lv_label_create(scr); + lv_obj_set_style_text_font(F.mouth, &font_face_140, 0); + lv_obj_set_style_text_color(F.mouth, lv_color_hex(0xADFFC8), 0); + lv_obj_align(F.mouth, LV_ALIGN_CENTER, 0, 70); + + F.thought = lv_label_create(scr); + lv_obj_set_style_text_font(F.thought, &font_face_140, 0); + lv_obj_set_style_text_color(F.thought, lv_color_hex(0x63CF8B), 0); + lv_obj_align(F.thought, LV_ALIGN_CENTER, 170, -170); + + F.clock_lbl = lv_label_create(scr); + lv_obj_set_style_text_font(F.clock_lbl, &lv_font_montserrat_48, 0); + lv_obj_set_style_text_color(F.clock_lbl, lv_color_hex(0x2F7A4B), 0); + lv_obj_align(F.clock_lbl, LV_ALIGN_CENTER, 0, 200); + lv_obj_add_flag(F.clock_lbl, LV_OBJ_FLAG_HIDDEN); + + F.status = lv_label_create(scr); + lv_obj_set_style_text_font(F.status, &lv_font_montserrat_28, 0); + lv_obj_set_style_text_color(F.status, lv_color_hex(0x2F7A4B), 0); + lv_label_set_text(F.status, "CONNECTING"); + lv_obj_align(F.status, LV_ALIGN_CENTER, 0, 270); + + F.elapsed = lv_label_create(scr); + lv_obj_set_style_text_font(F.elapsed, &lv_font_montserrat_28, 0); + lv_obj_set_style_text_color(F.elapsed, lv_color_hex(0x2F7A4B), 0); + lv_obj_set_style_bg_color(F.elapsed, lv_color_black(), 0); + lv_obj_set_style_bg_opa(F.elapsed, 205, 0); + lv_obj_set_style_pad_all(F.elapsed, 8, 0); + lv_obj_align(F.elapsed, LV_ALIGN_CENTER, 0, 300); + lv_obj_add_flag(F.elapsed, LV_OBJ_FLAG_HIDDEN); + + F.arc = lv_arc_create(scr); + lv_obj_set_size(F.arc, 780, 780); + lv_obj_center(F.arc); + lv_arc_set_bg_angles(F.arc, 0, 40); + lv_arc_set_value(F.arc, 100); + lv_obj_remove_style(F.arc, NULL, LV_PART_KNOB); + lv_obj_clear_flag(F.arc, LV_OBJ_FLAG_CLICKABLE); + lv_obj_set_style_arc_width(F.arc, 6, LV_PART_MAIN); + lv_obj_set_style_arc_color(F.arc, lv_color_hex(0x37FF8B), LV_PART_MAIN); + lv_obj_set_style_arc_opa(F.arc, LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_arc_opa(F.arc, LV_OPA_TRANSP, LV_PART_INDICATOR); + lv_obj_add_flag(F.arc, LV_OBJ_FLAG_HIDDEN); + + /* full-screen touch catcher, topmost */ + lv_obj_t *touch = lv_obj_create(scr); + lv_obj_remove_style_all(touch); + lv_obj_set_size(touch, SCREEN, SCREEN); + lv_obj_add_flag(touch, LV_OBJ_FLAG_CLICKABLE); + lv_obj_add_event_cb(touch, touch_cb, LV_EVENT_CLICKED, NULL); + + F.state = FACE_BOOT; + F.last_activity = now_ms(); + F.state_since = now_ms(); + F.blink_in_ms = 3000; + set_eyes_mouth(); + + lv_timer_create(tick_cb, TICK_MS, NULL); + lv_timer_create(clock_cb, 1000, NULL); + + bsp_display_unlock(); +} + +void face_set(face_state_t state) +{ + bsp_display_lock(UINT32_MAX); + if (state != F.state) { + F.state = state; + F.state_since = now_ms(); + F.rage_ms = 0; + set_eyes_mouth(); + + bool effort = (state == FACE_EFFORT); + lv_obj_set_style_opa(F.eyes, state == FACE_ERROR ? 115 : 255, 0); + lv_obj_set_style_opa(F.mouth, state == FACE_ERROR ? 115 : 255, 0); + if (effort) { + lv_obj_clear_flag(F.arc, LV_OBJ_FLAG_HIDDEN); + lv_obj_clear_flag(F.elapsed, LV_OBJ_FLAG_HIDDEN); + } else { + lv_obj_add_flag(F.arc, LV_OBJ_FLAG_HIDDEN); + lv_obj_add_flag(F.elapsed, LV_OBJ_FLAG_HIDDEN); + } + if (state != FACE_BOOT) { + lv_obj_add_flag(F.status, LV_OBJ_FLAG_HIDDEN); + } else { + lv_obj_clear_flag(F.status, LV_OBJ_FLAG_HIDDEN); + } + } + bsp_display_unlock(); +} + +face_state_t face_get(void) +{ + return F.state; +} + +void face_activity(void) +{ + F.last_activity = now_ms(); + if (F.power != 0) { + bsp_display_lock(UINT32_MAX); + apply_power(0); + bsp_display_unlock(); + } +} diff --git a/firmware/main/fonts/font_face_140.c b/firmware/main/fonts/font_face_140.c new file mode 100644 index 0000000..4b7e1bc --- /dev/null +++ b/firmware/main/fonts/font_face_140.c @@ -0,0 +1,1062 @@ +/******************************************************************************* + * Size: 140 px + * Bpp: 4 + * Opts: --font /usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf -r 0x20,0x2D,0x2E,0x2F,0x3C,0x3D,0x3E,0x4F,0x5C,0x5E,0x5F,0x6F,0x78,0x7E,0xB7 --size 140 --bpp 4 --format lvgl --lv-font-name font_face_140 -o font_face_140.c + ******************************************************************************/ + +#ifdef LV_LVGL_H_INCLUDE_SIMPLE +#include "lvgl.h" +#else +#include "lvgl/lvgl.h" +#endif + +#ifndef FONT_FACE_140 +#define FONT_FACE_140 1 +#endif + +#if FONT_FACE_140 + +/*----------------- + * BITMAPS + *----------------*/ + +/*Store the image of the glyphs*/ +static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { + /* U+0020 " " */ + + /* U+002D "-" */ + 0x34, 0x4f, 0xfe, 0xbc, 0xdd, 0xff, 0xf5, 0xc0, + 0x3f, 0xff, 0xe0, 0x1f, 0xff, 0xf0, 0xf, 0xff, + 0xf8, 0x7, 0xff, 0xfc, 0x3, 0xff, 0xe0, + + /* U+002E "." */ + 0x9f, 0xff, 0xfe, 0x25, 0x0, 0x7f, 0xff, 0xc0, + 0x3f, 0xff, 0xe0, 0x1f, 0xff, 0xf0, 0xf, 0xff, + 0xf8, 0x7, 0xff, 0xc0, + + /* U+002F "/" */ + 0x0, 0xff, 0xf5, 0x3f, 0xff, 0xff, 0x2, 0x0, + 0x3f, 0xfd, 0x52, 0x1, 0xff, 0xc0, 0x90, 0xf, + 0xff, 0x4b, 0x8, 0x7, 0xfc, 0xc2, 0x1, 0xff, + 0xe9, 0xb0, 0xf, 0xfe, 0x5, 0x80, 0x7f, 0xfa, + 0x54, 0x80, 0x3f, 0xe5, 0x20, 0xf, 0xff, 0x4c, + 0x80, 0x7f, 0xf0, 0x24, 0x3, 0xff, 0xd2, 0x86, + 0x1, 0xff, 0x19, 0x80, 0x3f, 0xfd, 0x3e, 0x1, + 0xff, 0xc0, 0x80, 0xf, 0xff, 0x49, 0x20, 0x7, + 0xfc, 0x48, 0x1, 0xff, 0xe9, 0x80, 0xf, 0xfe, + 0x4, 0x0, 0x7f, 0xfa, 0x45, 0x40, 0x3f, 0xe1, + 0x50, 0xf, 0xff, 0x4c, 0x0, 0x7f, 0xf0, 0x20, + 0x3, 0xff, 0xd2, 0x2c, 0x1, 0xff, 0xb, 0x0, + 0x7f, 0xfa, 0x58, 0x3, 0xff, 0x80, 0xc0, 0x1f, + 0xfe, 0xa9, 0x0, 0xff, 0xe0, 0x48, 0x7, 0xff, + 0xa5, 0x84, 0x3, 0xfe, 0x61, 0x0, 0xff, 0xf4, + 0xd8, 0x7, 0xff, 0x2, 0xc0, 0x3f, 0xfd, 0x2a, + 0x40, 0x1f, 0xf2, 0x90, 0x7, 0xff, 0xa6, 0x0, + 0x3f, 0xf8, 0x12, 0x1, 0xff, 0xe9, 0x42, 0x0, + 0xff, 0x90, 0xc0, 0x3f, 0xfd, 0x3e, 0x1, 0xff, + 0xc0, 0xf0, 0xf, 0xff, 0x49, 0xa0, 0x7, 0xfc, + 0x68, 0x1, 0xff, 0xe9, 0x90, 0xf, 0xfe, 0x4, + 0x80, 0x7f, 0xfa, 0x49, 0x40, 0x3f, 0xe2, 0x50, + 0xf, 0xff, 0x4d, 0x80, 0x7f, 0xf0, 0x2c, 0x3, + 0xff, 0xd2, 0x2c, 0x1, 0xff, 0xb, 0x0, 0x7f, + 0xfa, 0x64, 0x3, 0xff, 0x81, 0x20, 0x1f, 0xfe, + 0xa6, 0x0, 0xff, 0xe0, 0x30, 0x7, 0xff, 0xa5, + 0xc4, 0x3, 0xfe, 0x71, 0x0, 0xff, 0xf4, 0xc8, + 0x7, 0xff, 0x2, 0x40, 0x3f, 0xfd, 0x2c, 0x20, + 0x1f, 0xf2, 0x88, 0x7, 0xff, 0xa6, 0xc0, 0x3f, + 0xf8, 0x10, 0x1, 0xff, 0xe9, 0x42, 0x0, 0xff, + 0x90, 0x80, 0x3f, 0xfd, 0x30, 0x1, 0xff, 0xc0, + 0x80, 0xf, 0xff, 0x49, 0x98, 0x3, 0xfe, 0x33, + 0x0, 0x7f, 0xfa, 0x60, 0x3, 0xff, 0x81, 0x20, + 0x1f, 0xfe, 0x92, 0x40, 0xf, 0xf8, 0x94, 0x3, + 0xff, 0xd3, 0x0, 0x1f, 0xfc, 0xb, 0x0, 0xff, + 0xf4, 0x8a, 0x80, 0x7f, 0xc2, 0xc0, 0x1f, 0xfe, + 0x99, 0x0, 0xff, 0xe0, 0x48, 0x7, 0xff, 0xa4, + 0x5c, 0x3, 0xff, 0x80, 0xe0, 0x1f, 0xfe, 0x96, + 0x0, 0xff, 0xe0, 0x38, 0x7, 0xff, 0xaa, 0x40, + 0x3f, 0xf8, 0x12, 0x1, 0xff, 0xe9, 0x61, 0x0, + 0xff, 0x98, 0x40, 0x3f, 0xfd, 0x36, 0x1, 0xff, + 0xc0, 0xb0, 0xf, 0xff, 0x4a, 0x90, 0x7, 0xfc, + 0x84, 0x1, 0xff, 0xe9, 0x90, 0xf, 0xfe, 0x4, + 0x0, 0x7f, 0xfa, 0x50, 0xc0, 0x3f, 0xe3, 0x30, + 0x7, 0xff, 0xa7, 0xc0, 0x3f, 0xf8, 0x10, 0x1, + 0xff, 0xe9, 0x34, 0x0, 0xff, 0x89, 0x0, 0x3f, + 0xfd, 0x32, 0x1, 0xff, 0xc0, 0x80, 0xf, 0xff, + 0x49, 0x28, 0x7, 0xfc, 0x2a, 0x1, 0xff, 0xe9, + 0xb0, 0xf, 0xfe, 0x4, 0x80, 0x7f, 0xfa, 0x45, + 0x80, 0x3f, 0xe1, 0x70, 0xf, 0xff, 0x4c, 0x80, + 0x7f, 0xf0, 0x18, 0x3, 0xff, 0xd4, 0xc0, 0x1f, + 0xfc, 0x9, 0x0, 0xff, 0xf4, 0xb8, 0x80, 0x7f, + 0xcc, 0x20, 0x1f, 0xfe, 0x99, 0x0, 0xff, 0xe0, + 0x58, 0x7, 0xff, 0xa5, 0x44, 0x3, 0xfe, 0x52, + 0x0, 0xff, 0xf4, 0xc0, 0x7, 0xff, 0x2, 0x40, + 0x3f, 0xfd, 0x28, 0x40, 0x1f, 0xf2, 0x18, 0x7, + 0xff, 0xa6, 0x0, 0x3f, 0xf8, 0x1e, 0x1, 0xff, + 0xe9, 0x33, 0x0, 0x7f, 0xc6, 0x80, 0x1f, 0xfe, + 0x99, 0x0, 0xff, 0xe0, 0x48, 0x7, 0xff, 0xa4, + 0x94, 0x3, 0xfe, 0x25, 0x0, 0xff, 0xf4, 0xd8, + 0x7, 0xff, 0x2, 0xc0, 0x3f, 0xfd, 0x22, 0xc0, + 0x1f, 0xf0, 0xb0, 0x7, 0xff, 0xa6, 0x40, 0x3f, + 0xf8, 0x12, 0x1, 0xff, 0xea, 0x70, 0xf, 0xfe, + 0x3, 0x0, 0x7f, 0xfa, 0x5c, 0x3, 0xff, 0x80, + 0xc2, 0x1, 0xff, 0xe9, 0x90, 0xf, 0xfe, 0x4, + 0x0, 0x7f, 0xfa, 0x58, 0x40, 0x3f, 0xe5, 0x10, + 0xf, 0xff, 0x4d, 0x80, 0x7f, 0xf0, 0x20, 0x3, + 0xff, 0xd2, 0xa4, 0x1, 0xff, 0x21, 0x0, 0x7f, + 0xfa, 0x64, 0x3, 0xff, 0x81, 0xe0, 0x1f, 0xfe, + 0x94, 0x30, 0xf, 0xf8, 0xd0, 0x3, 0xff, 0xd3, + 0xe0, 0x1f, 0xfc, 0x9, 0x0, 0xff, 0xf4, 0x92, + 0x0, 0x7f, 0xc4, 0xa0, 0x1f, 0xfe, 0x98, 0x0, + 0xff, 0xe0, 0x58, 0x7, 0xff, 0xa4, 0x54, 0x3, + 0xfe, 0x16, 0x0, 0xff, 0xf4, 0xc0, 0x7, 0xff, + 0x2, 0x40, 0x3f, 0xfd, 0x22, 0xc0, 0x1f, 0xfc, + 0x6, 0x0, 0xff, 0xf4, 0xb0, 0x7, 0xff, 0x1, + 0xc4, 0x3, 0xff, 0xd3, 0x20, 0x1f, 0xfc, 0x9, + 0x0, 0xff, 0xf4, 0xb0, 0x80, 0x7f, 0xcc, 0x20, + 0x1f, 0xfe, 0x9b, 0x0, 0xff, 0xe0, 0x58, 0x7, + 0xff, 0xa5, 0x48, 0x3, 0xfe, 0x42, 0x0, 0xff, + 0xf4, 0xc0, 0x7, 0xff, 0x2, 0x0, 0x3f, 0xfd, + 0x28, 0x40, 0x1f, 0xf1, 0x98, 0x3, 0xff, 0xd3, + 0xe0, 0x1f, 0xfc, 0x8, 0x0, 0xff, 0xf4, 0x9a, + 0x0, 0x7f, 0xc4, 0x80, 0x1f, 0xfe, 0x99, 0x0, + 0xff, 0xe0, 0x58, 0x7, 0xff, 0xa4, 0x94, 0x3, + 0xfe, 0x16, 0x0, 0xff, 0xf4, 0xd8, 0x7, 0xff, + 0x2, 0x40, 0x3f, 0xfd, 0x22, 0xc0, 0x1f, 0xf0, + 0xb8, 0x7, 0xff, 0xa6, 0x40, 0x3f, 0xf8, 0xc, + 0x1, 0xff, 0xea, 0x60, 0xf, 0xfe, 0x4, 0x80, + 0x7f, 0xfa, 0x5c, 0x40, 0x3f, 0xe6, 0x10, 0xf, + 0xff, 0x4c, 0x80, 0x7f, 0xf0, 0x2c, 0x3, 0xff, + 0xd2, 0xc2, 0x1, 0xff, 0x29, 0x0, 0x7f, 0xfa, + 0x6c, 0x3, 0xff, 0x81, 0x20, 0x1f, 0xfe, 0x94, + 0x20, 0xf, 0xf9, 0xc, 0x3, 0xff, 0xd3, 0x0, + 0x1f, 0xfc, 0xf, 0x0, 0xff, 0xf4, 0x99, 0x80, + 0x3f, 0xe2, 0x40, 0xf, 0xff, 0x4c, 0x0, 0x7f, + 0xf0, 0x20, 0x3, 0xff, 0xd2, 0x48, 0x1, 0xff, + 0xa, 0x80, 0x7f, 0xfa, 0x60, 0x3, 0xff, 0x81, + 0x0, 0x1f, 0xfe, 0x91, 0x50, 0xf, 0xf8, 0x58, + 0x3, 0xff, 0xd3, 0x20, 0x1f, 0xfc, 0x6, 0x0, + 0xff, 0xf4, 0x8b, 0x80, 0x7f, 0xf0, 0x24, 0x3, + 0xff, 0xd2, 0xc0, 0x1f, 0xfc, 0x6, 0x10, 0xf, + 0xff, 0x4c, 0x80, 0x7f, 0xf0, 0x2c, 0x3, 0xff, + 0xd2, 0xc2, 0x1, 0xff, 0x29, 0x0, 0x7f, 0xfa, + 0x6c, 0x3, 0xff, 0x81, 0x20, 0x1f, 0xfe, 0x95, + 0x20, 0xf, 0xf9, 0xc, 0x3, 0xff, 0xd3, 0x20, + 0x1f, 0xfc, 0xf, 0x0, 0xff, 0xf4, 0x80, + + /* U+003C "<" */ + 0x0, 0xff, 0xfd, 0xb1, 0x0, 0x7f, 0xfe, 0xe, + 0x7e, 0x58, 0x3, 0xff, 0xea, 0x2d, 0xb8, 0xc0, + 0x1f, 0xff, 0x63, 0xae, 0x92, 0x0, 0xff, 0xfa, + 0x8b, 0x6e, 0x28, 0x7, 0xff, 0xd8, 0xeb, 0xa4, + 0x80, 0x3f, 0xfe, 0xa2, 0xfb, 0x8a, 0x1, 0xff, + 0xf6, 0x3a, 0xe8, 0x20, 0xf, 0xff, 0xa8, 0xbe, + 0xe2, 0x80, 0x7f, 0xfd, 0x92, 0xba, 0x8, 0x3, + 0xff, 0xea, 0x2f, 0xb6, 0xa0, 0x1f, 0xff, 0x64, + 0xae, 0x82, 0x0, 0xff, 0xfa, 0x8b, 0xed, 0xa8, + 0x7, 0xff, 0x3d, 0xc0, 0x3f, 0xfb, 0x49, 0x5d, + 0x4, 0x1, 0xff, 0xce, 0x28, 0xe3, 0x0, 0xff, + 0xeb, 0x8b, 0xed, 0xa8, 0x7, 0xff, 0x3d, 0xb3, + 0x5c, 0x40, 0x3f, 0xfa, 0xc9, 0x5d, 0x4, 0x1, + 0xff, 0xce, 0x39, 0xf9, 0x30, 0xf, 0xfe, 0xb0, + 0xbe, 0xda, 0x80, 0x7f, 0xf3, 0x85, 0xf7, 0x18, + 0x3, 0xff, 0xae, 0x95, 0xd0, 0x40, 0x1f, 0xfc, + 0xe5, 0xbe, 0x82, 0x0, 0xff, 0xeb, 0xb, 0xf5, + 0xa8, 0x7, 0xff, 0x38, 0xe7, 0xa9, 0x0, 0x3f, + 0xfa, 0xe9, 0x7d, 0x2, 0x1, 0xff, 0xcd, 0x17, + 0xdc, 0x61, 0x0, 0xff, 0xeb, 0xb, 0xf5, 0xa0, + 0x7, 0xff, 0x39, 0x2f, 0xa0, 0x80, 0x3f, 0xfa, + 0xe9, 0x7d, 0x2, 0x1, 0xff, 0xcd, 0x28, 0xeb, + 0x40, 0xf, 0xfe, 0xb8, 0xc7, 0x5a, 0x0, 0x7f, + 0xf3, 0x45, 0xb3, 0x5c, 0x40, 0x3f, 0xfa, 0xe9, + 0x7c, 0xe2, 0x1, 0xff, 0xcd, 0x4a, 0xe9, 0x30, + 0xf, 0xfe, 0xb8, 0xc7, 0x5a, 0x0, 0x7f, 0xf3, + 0x4a, 0x3a, 0xd4, 0x3, 0xff, 0xb0, 0xb7, 0xce, + 0x20, 0x1f, 0xfc, 0xd6, 0xcd, 0x71, 0x0, 0xff, + 0xeb, 0x94, 0x75, 0x20, 0x7, 0xff, 0x34, 0xe7, + 0xe4, 0xc0, 0x3f, 0xfb, 0xb, 0x7a, 0xe2, 0x1, + 0xff, 0xcc, 0x17, 0xdc, 0x60, 0xf, 0xfe, 0xc1, + 0x47, 0x52, 0x0, 0x7f, 0xf3, 0x56, 0xfa, 0x8, + 0x3, 0xff, 0xb5, 0xae, 0x20, 0x1f, 0xfc, 0xc3, + 0x9e, 0xa4, 0x0, 0xff, 0xfa, 0x8b, 0xee, 0x30, + 0x80, 0x7f, 0xfd, 0x52, 0xfa, 0x8, 0x3, 0xff, + 0xea, 0x51, 0xd6, 0x80, 0x1f, 0xff, 0x51, 0x6c, + 0xd7, 0x10, 0xf, 0xff, 0xa9, 0xd7, 0x49, 0x80, + 0x7f, 0xfe, 0xf, 0xd0, 0x3, 0xff, 0xf6, 0xb7, + 0xd0, 0x40, 0x1f, 0xff, 0xa1, 0x7d, 0xc6, 0x0, + 0xff, 0xfd, 0x9c, 0xfd, 0x20, 0x7, 0xff, 0xed, + 0x6f, 0xa0, 0x80, 0x3f, 0xfc, 0x2a, 0x1, 0xff, + 0xcc, 0x17, 0xdc, 0x60, 0xf, 0xfe, 0xfd, 0x74, + 0x8, 0x7, 0xff, 0x30, 0xe7, 0xe9, 0x0, 0x3f, + 0xfb, 0xa2, 0xfd, 0x68, 0x1, 0xff, 0xcd, 0x5b, + 0xe8, 0x20, 0xf, 0xfe, 0xea, 0x5f, 0x41, 0x0, + 0x7f, 0xf3, 0x5, 0xf7, 0x18, 0x3, 0xff, 0xba, + 0x2f, 0xb6, 0xa0, 0x1f, 0xfc, 0xd3, 0x9f, 0xa4, + 0x0, 0xff, 0xee, 0xa5, 0x74, 0x10, 0x7, 0xff, + 0x35, 0x6f, 0x60, 0x80, 0x3f, 0xfb, 0x82, 0xfb, + 0x6a, 0x1, 0xff, 0xcd, 0x27, 0xdc, 0x60, 0xf, + 0xfe, 0xea, 0x57, 0x41, 0x0, 0x7f, 0xf3, 0x4e, + 0x7e, 0x4c, 0x3, 0xff, 0xb8, 0x2f, 0xb6, 0xa0, + 0x1f, 0xfc, 0xe6, 0xcd, 0x71, 0x0, 0xff, 0xee, + 0x25, 0x74, 0x10, 0x7, 0xff, 0x34, 0xa3, 0xad, + 0x40, 0x3f, 0xfb, 0x82, 0xfb, 0x6a, 0x1, 0xff, + 0xce, 0x4a, 0xf9, 0x30, 0xf, 0xfe, 0xe2, 0x57, + 0x41, 0x0, 0x7f, 0xf3, 0x9b, 0x35, 0xc4, 0x3, + 0xff, 0xb6, 0x2f, 0xb8, 0xa0, 0x1f, 0xfc, 0xe2, + 0x8e, 0xb5, 0x0, 0xff, 0xee, 0x1d, 0x74, 0x10, + 0x7, 0xff, 0x39, 0x2b, 0xe4, 0xc0, 0x3f, 0xfb, + 0x62, 0xfb, 0x8a, 0x1, 0xff, 0xcf, 0x6c, 0xd7, + 0x10, 0xf, 0xfe, 0xd9, 0xd7, 0x49, 0x0, 0x7f, + 0xf3, 0x8a, 0x3a, 0xd4, 0x3, 0xff, 0xb6, 0x2d, + 0xb8, 0xa0, 0x1f, 0xfc, 0xf4, 0xaf, 0x91, 0x0, + 0xff, 0xed, 0x9d, 0x74, 0x90, 0x7, 0xff, 0x3d, + 0x94, 0x3, 0xff, 0xba, 0x2d, 0xb8, 0xc0, 0x1f, + 0xff, 0xb3, 0x9f, 0x92, 0x0, 0xff, 0xfd, 0xb6, + 0xe3, 0x0, 0x7f, 0xfe, 0xce, 0x7e, 0x4c, 0x3, + 0xff, 0xf6, 0xd9, 0x86, 0x0, 0xff, 0xfd, 0x9c, + 0xfc, 0x98, 0x7, 0xff, 0xed, 0xb3, 0xc, 0x1, + 0xff, 0xfb, 0x39, 0xf9, 0x30, 0xf, 0xff, 0xdb, + 0x66, 0x18, 0x3, 0xff, 0xf6, 0x73, 0xf2, 0x60, + 0x1f, 0xff, 0xb6, 0xcd, 0x60, 0xf, 0xff, 0xd9, + 0x4f, 0xa0, + + /* U+003D "=" */ + 0xbb, 0xff, 0xfe, 0x1a, 0x27, 0xff, 0xf1, 0xc0, + 0x3f, 0xff, 0xe0, 0x1f, 0xff, 0xf0, 0xf, 0xff, + 0xf8, 0x7, 0xff, 0xfc, 0x3, 0xff, 0xfe, 0x1, + 0xff, 0xff, 0x0, 0xff, 0xff, 0x80, 0x7f, 0xff, + 0xc0, 0x3f, 0xff, 0xe0, 0x1f, 0xfe, 0xbf, 0xff, + 0xff, 0xe2, 0x0, 0x7f, 0xff, 0xc0, 0x3f, 0xff, + 0xe0, 0x1f, 0xff, 0xf0, 0xf, 0xff, 0xf8, 0x7, + 0xff, 0xfc, 0x3, 0xff, 0xfe, 0x1, 0xff, 0xff, + 0x0, 0xff, 0xff, 0x80, 0x7f, 0xff, 0xc0, 0x3f, + 0xff, 0xe0, 0x1f, 0xff, 0xf0, 0xf, 0xff, 0xf8, + 0x7, 0xff, 0xfc, 0x3, 0xff, 0xfe, 0x1, 0xff, + 0xe1, 0xdd, 0xff, 0xfe, 0x19, 0x17, 0xff, 0xf1, + 0xc0, 0x3f, 0xff, 0xe0, 0x1f, 0xff, 0xf0, 0xf, + 0xff, 0xf8, 0x7, 0xff, 0xfc, 0x3, 0xff, 0xfe, + 0x1, 0xff, 0xff, 0x0, 0xff, 0xff, 0x80, 0x7f, + 0xff, 0xc0, 0x3f, 0xff, 0xe0, 0x1f, 0xfe, 0xb0, + + /* U+003E ">" */ + 0x82, 0x0, 0xff, 0xfd, 0xbe, 0xda, 0x80, 0x7f, + 0xfe, 0xd2, 0xba, 0x8, 0x3, 0xff, 0xf4, 0x2f, + 0xb6, 0xa0, 0x1f, 0xff, 0xb4, 0xae, 0x82, 0x0, + 0xff, 0xfd, 0xb, 0xed, 0xa8, 0x7, 0xff, 0xed, + 0x2b, 0xa0, 0x80, 0x3f, 0xff, 0x42, 0xfb, 0x8a, + 0x1, 0xff, 0xfb, 0x3a, 0xe8, 0x20, 0xf, 0xff, + 0xd0, 0xbe, 0xe2, 0x80, 0x7f, 0xfe, 0xce, 0xba, + 0x48, 0x3, 0xff, 0xf4, 0x2d, 0xb8, 0xa0, 0x1f, + 0xff, 0xb3, 0xae, 0x92, 0x0, 0xff, 0xee, 0xfc, + 0x98, 0x7, 0xff, 0x38, 0x5b, 0x71, 0x80, 0x3f, + 0xfb, 0x8d, 0x9a, 0xe2, 0x1, 0xff, 0xce, 0x39, + 0xf9, 0x20, 0xf, 0xfe, 0xd9, 0x47, 0x5a, 0x80, + 0x7f, 0xf3, 0xdb, 0x71, 0x80, 0x3f, 0xfb, 0x89, + 0x5d, 0x26, 0x1, 0xff, 0xce, 0x39, 0xf9, 0x30, + 0xf, 0xfe, 0xd8, 0xb6, 0x6b, 0x88, 0x7, 0xff, + 0x39, 0xb3, 0xc, 0x1, 0xff, 0xdc, 0x28, 0xeb, + 0x50, 0xf, 0xfe, 0x71, 0xcf, 0xc9, 0x80, 0x7f, + 0xf7, 0x12, 0xba, 0x8, 0x3, 0xff, 0x9c, 0xd9, + 0x86, 0x0, 0xff, 0xee, 0xb, 0xee, 0x30, 0x80, + 0x7f, 0xf3, 0x4e, 0x7e, 0x4c, 0x3, 0xff, 0xb8, + 0x73, 0xd4, 0x80, 0x1f, 0xfc, 0xe6, 0xcc, 0x30, + 0x7, 0xff, 0x75, 0x6f, 0xa0, 0x80, 0x3f, 0xf9, + 0xa7, 0x3f, 0x26, 0x1, 0xff, 0xdc, 0x17, 0xdc, + 0x60, 0xf, 0xfe, 0x73, 0x66, 0xb0, 0x7, 0xff, + 0x74, 0xe7, 0xe8, 0xc0, 0x3f, 0xf9, 0xa5, 0x3f, + 0x26, 0x1, 0xff, 0xdd, 0x5c, 0xd7, 0x10, 0xf, + 0xfe, 0x6b, 0x66, 0xb0, 0x80, 0x7f, 0xf7, 0xa, + 0x3a, 0xd4, 0x3, 0xff, 0x9a, 0x53, 0xd4, 0x60, + 0x1f, 0xfd, 0xd4, 0xaf, 0x93, 0x0, 0xff, 0xe6, + 0xae, 0x6b, 0x88, 0x7, 0xff, 0x75, 0xb3, 0x5c, + 0x40, 0x3f, 0xf9, 0x85, 0x1d, 0x46, 0x1, 0xff, + 0xdd, 0x28, 0xeb, 0x50, 0xf, 0xfe, 0x6a, 0xe2, + 0x0, 0x7f, 0xf7, 0xd2, 0xba, 0x8, 0x3, 0xff, + 0xf4, 0x2f, 0xb8, 0xc2, 0x1, 0xff, 0xfa, 0x39, + 0xea, 0x40, 0xf, 0xff, 0xda, 0xdf, 0x41, 0x0, + 0x7f, 0xfe, 0x85, 0xf7, 0x18, 0x3, 0xff, 0xf4, + 0x56, 0xe0, 0x1f, 0xff, 0x71, 0x6c, 0xd7, 0x10, + 0xf, 0xff, 0xaa, 0x57, 0x49, 0x80, 0x7f, 0xfd, + 0x4a, 0x3a, 0xd4, 0x3, 0xff, 0xea, 0x2d, 0x9a, + 0xe2, 0x1, 0xff, 0xf5, 0x4a, 0xe9, 0x30, 0xf, + 0xfe, 0x61, 0xb0, 0x7, 0xff, 0x6c, 0xa3, 0xad, + 0x40, 0x3f, 0xf9, 0xad, 0x98, 0x20, 0xf, 0xfe, + 0xcb, 0x66, 0xb8, 0x80, 0x7f, 0xf3, 0xe, 0x7e, + 0x4c, 0x3, 0xff, 0xb0, 0x95, 0xf2, 0x60, 0x1f, + 0xfc, 0xd6, 0xcc, 0x30, 0x7, 0xff, 0x60, 0xa3, + 0xad, 0x40, 0x3f, 0xf9, 0xa7, 0x3f, 0x26, 0x1, + 0xff, 0xd8, 0x6c, 0xd7, 0x10, 0xf, 0xfe, 0x6b, + 0x6e, 0x30, 0x7, 0xff, 0x61, 0x2b, 0xe4, 0xc0, + 0x3f, 0xf9, 0xa7, 0x3f, 0x24, 0x1, 0xff, 0xd7, + 0x28, 0xeb, 0x50, 0xf, 0xfe, 0x68, 0xb6, 0xe3, + 0x0, 0x7f, 0xf6, 0x1b, 0x35, 0xc4, 0x3, 0xff, + 0x9a, 0x73, 0xd2, 0x40, 0x1f, 0xfd, 0x74, 0xaf, + 0x93, 0x0, 0xff, 0xe6, 0x8b, 0x6e, 0x30, 0x7, + 0xff, 0x5c, 0xa3, 0xad, 0x40, 0x3f, 0xf9, 0xc7, + 0x5d, 0x24, 0x1, 0xff, 0xd7, 0x6c, 0xd7, 0x10, + 0xf, 0xfe, 0x68, 0xb6, 0xe2, 0x80, 0x7f, 0xf5, + 0xd2, 0xbe, 0x4c, 0x3, 0xff, 0x9c, 0x75, 0xd2, + 0x40, 0x1f, 0xfd, 0x62, 0x8d, 0xb5, 0x0, 0xff, + 0xe7, 0xb, 0xee, 0x28, 0x7, 0xff, 0x5d, 0x6f, + 0x5c, 0x80, 0x3f, 0xf9, 0xc7, 0x5d, 0x4, 0x1, + 0xff, 0xd6, 0x39, 0xfa, 0x40, 0xf, 0xfe, 0x70, + 0xbe, 0xe2, 0x80, 0x7f, 0xf5, 0xdf, 0x71, 0x80, + 0x3f, 0xf9, 0xe9, 0x5d, 0x4, 0x1, 0xff, 0xd9, + 0x82, 0x0, 0xff, 0xe7, 0xb, 0xed, 0xa8, 0x7, + 0xff, 0xd9, 0x2b, 0xa0, 0x80, 0x3f, 0xfe, 0xa2, + 0xfb, 0x6a, 0x1, 0xff, 0xf6, 0x4a, 0xe8, 0x20, + 0xf, 0xff, 0xa8, 0xbe, 0xda, 0x80, 0x7f, 0xfd, + 0x92, 0xba, 0x8, 0x3, 0xff, 0xea, 0x2f, 0xd6, + 0xa0, 0x1f, 0xff, 0x64, 0xbe, 0x81, 0x0, 0xff, + 0xfa, 0x8b, 0xf5, 0xa0, 0x7, 0xff, 0xd9, 0x2f, + 0xa0, 0x40, 0x3f, 0xfe, 0xa3, 0x1d, 0x68, 0x1, + 0xff, 0xf6, 0x4b, 0xe7, 0x10, 0xf, 0xff, 0xbf, + 0x5a, 0x0, 0x7f, 0xfe, 0x80, + + /* U+004F "O" */ + 0x0, 0xff, 0xe7, 0x1b, 0x45, 0xee, 0xbb, 0xfd, + 0xdc, 0xdc, 0x96, 0x41, 0x0, 0xff, 0xf2, 0x13, + 0xdf, 0xe4, 0xba, 0x11, 0x4, 0x0, 0x22, 0x23, + 0x69, 0xbe, 0xc8, 0x30, 0xf, 0xfe, 0xfa, 0x5e, + 0xc2, 0x0, 0x7f, 0xf1, 0x8d, 0xf3, 0x58, 0x3, + 0xff, 0xb6, 0xbb, 0x68, 0x1, 0xff, 0xcc, 0x29, + 0xe7, 0x0, 0xff, 0xeb, 0x95, 0xd1, 0x0, 0x7f, + 0xf4, 0x6, 0x35, 0x0, 0x3f, 0xfa, 0x8d, 0xa8, + 0x1, 0xff, 0xd4, 0x2b, 0x90, 0xf, 0xfe, 0x94, + 0xc8, 0x3, 0xff, 0xb0, 0xd8, 0x20, 0x1f, 0xfc, + 0xfb, 0x60, 0xf, 0xfe, 0xd1, 0xf9, 0x0, 0x7f, + 0xf3, 0x6d, 0x0, 0x3f, 0xfb, 0x83, 0x84, 0x1, + 0xff, 0xcb, 0xa4, 0x0, 0xff, 0xef, 0xf, 0x88, + 0x7, 0xff, 0x26, 0x14, 0x3, 0xff, 0xc0, 0x5a, + 0x1, 0xff, 0xc8, 0x47, 0x0, 0xff, 0xe3, 0x12, + 0xc4, 0xd5, 0x26, 0x18, 0xc0, 0x3f, 0xf8, 0xc7, + 0x20, 0x1f, 0xfc, 0x61, 0xa0, 0xf, 0xfe, 0x20, + 0xbe, 0xea, 0x9d, 0x95, 0x4c, 0xf3, 0x9d, 0x24, + 0x1, 0xff, 0xc4, 0x64, 0x0, 0xff, 0xe2, 0xd0, + 0x80, 0x7f, 0xf0, 0xdf, 0xa0, 0x80, 0x3f, 0xc2, + 0xdb, 0x22, 0x1, 0xff, 0xc3, 0xa0, 0xf, 0xfe, + 0x22, 0x20, 0x3, 0xff, 0x84, 0x39, 0x0, 0x1f, + 0xfc, 0x46, 0xf4, 0x0, 0xff, 0xe1, 0xc, 0x0, + 0x7f, 0xf0, 0xe0, 0x3, 0xff, 0x84, 0x5e, 0x60, + 0x1f, 0xfc, 0x61, 0xb5, 0x0, 0xff, 0xe1, 0x39, + 0x0, 0x7f, 0xf0, 0x54, 0xc0, 0x3f, 0xf8, 0x25, + 0x82, 0x1, 0xff, 0xc9, 0xa5, 0x0, 0xff, 0xe1, + 0x40, 0x7, 0xff, 0x6, 0x0, 0x3f, 0xf8, 0x5c, + 0x20, 0x1f, 0xfc, 0xba, 0x20, 0xf, 0xfe, 0xa, + 0x90, 0x7, 0xfc, 0x84, 0x1, 0xff, 0xc1, 0x83, + 0x0, 0xff, 0xe6, 0xf0, 0x7, 0xff, 0xa, 0x80, + 0x3f, 0xef, 0x0, 0xff, 0xe0, 0x93, 0x80, 0x7f, + 0xf3, 0x8d, 0x80, 0x3f, 0xf8, 0x2e, 0x1, 0xfe, + 0x24, 0x0, 0xff, 0xe0, 0xc0, 0x7, 0xff, 0x42, + 0x0, 0x3f, 0xf8, 0x4c, 0x1, 0xfd, 0x40, 0x1f, + 0xfc, 0x12, 0x50, 0xf, 0xfe, 0x80, 0xb0, 0x7, + 0xff, 0x6, 0x80, 0x3f, 0x94, 0x3, 0xff, 0x83, + 0x60, 0x1f, 0xfd, 0x2b, 0x0, 0xff, 0xe0, 0x98, + 0x80, 0x7c, 0x44, 0x0, 0xff, 0xe0, 0xb8, 0x7, + 0xff, 0x48, 0x8c, 0x3, 0xff, 0x82, 0xc0, 0x1f, + 0x28, 0x7, 0xff, 0x5, 0x4, 0x3, 0xff, 0xa7, + 0x40, 0x1f, 0xfc, 0x1b, 0x0, 0xfa, 0xc0, 0x3f, + 0xf8, 0x3a, 0x1, 0xff, 0xd4, 0x70, 0xf, 0xfe, + 0x9, 0x88, 0x7, 0x8c, 0x3, 0xff, 0x82, 0xe0, + 0x1f, 0xfd, 0x41, 0x30, 0xf, 0xfe, 0xa, 0x0, + 0x72, 0x0, 0x7f, 0xf0, 0x48, 0x40, 0x3f, 0xfa, + 0xa8, 0x1, 0xff, 0xc1, 0xc0, 0xe, 0xc0, 0xf, + 0xfe, 0xa, 0x0, 0x7f, 0xf5, 0xb4, 0x3, 0xff, + 0x82, 0x80, 0x1c, 0x80, 0x1f, 0xfc, 0x1f, 0x0, + 0xff, 0xeb, 0x20, 0x7, 0xff, 0x4, 0x84, 0x3, + 0x18, 0x7, 0xff, 0x5, 0x0, 0x3f, 0xfa, 0xc2, + 0x20, 0xf, 0xfe, 0xa, 0x80, 0x44, 0x1, 0xff, + 0xc2, 0x20, 0xf, 0xfe, 0xba, 0x80, 0x7f, 0xf0, + 0x4c, 0x2, 0x70, 0xf, 0xfe, 0x9, 0x0, 0x7f, + 0xf6, 0xc, 0x3, 0xff, 0x83, 0xa0, 0x16, 0x80, + 0x7f, 0xf0, 0x5c, 0x3, 0xff, 0xb1, 0xc0, 0x1f, + 0xfc, 0x16, 0x0, 0x8c, 0x3, 0xff, 0x82, 0x40, + 0x1f, 0xfd, 0x85, 0x0, 0xff, 0xe0, 0x98, 0x4, + 0xc0, 0x1f, 0xfc, 0x1e, 0x0, 0xff, 0xec, 0x8, + 0x7, 0xff, 0x8, 0x80, 0x4, 0x1, 0xff, 0xc1, + 0x20, 0xf, 0xfe, 0xc1, 0x0, 0x7f, 0xf0, 0x98, + 0x4, 0x3, 0xff, 0x84, 0xc0, 0x1f, 0xfd, 0x91, + 0x0, 0xff, 0xe0, 0x88, 0x10, 0x7, 0xff, 0x8, + 0x80, 0x3f, 0xfb, 0x24, 0x1, 0xff, 0xc1, 0x20, + 0x60, 0xf, 0xff, 0x43, 0x80, 0x7f, 0xf0, 0x78, + 0xc, 0x3, 0xff, 0x82, 0x20, 0x1f, 0xfd, 0xa1, + 0x0, 0xff, 0xe0, 0x90, 0x70, 0x7, 0xff, 0x4, + 0xc0, 0x3f, 0xfb, 0x44, 0x1, 0xff, 0xc1, 0x70, + 0x10, 0xf, 0xfe, 0xb, 0x0, 0x7f, 0xf6, 0xbc, + 0x3, 0xff, 0x82, 0x20, 0x60, 0x1f, 0xfc, 0x11, + 0x0, 0xff, 0xed, 0x8, 0x7, 0xff, 0x4, 0xc0, + 0x40, 0x3f, 0xfd, 0x6, 0x1, 0xff, 0xc1, 0x10, + 0x70, 0xf, 0xfe, 0x9, 0x80, 0x7f, 0xfa, 0x44, + 0x40, 0x1f, 0xfc, 0x11, 0x0, 0xff, 0xed, 0x8, + 0x7, 0xff, 0x8, 0xcc, 0x1, 0xff, 0xe8, 0x70, + 0xf, 0xfe, 0x8f, 0x80, 0x7f, 0xfa, 0x44, 0x3, + 0xff, 0xf2, 0x20, 0x1f, 0xfe, 0x81, 0x0, 0xff, + 0xff, 0x80, 0x7e, 0x70, 0xf, 0xfe, 0x10, 0x80, + 0x7f, 0xff, 0xc0, 0x3f, 0xff, 0xe0, 0x1f, 0xfe, + 0xc1, 0x0, 0xff, 0xff, 0x80, 0x7f, 0xf8, 0xdc, + 0x40, 0x3f, 0xfd, 0x2, 0x1, 0xff, 0xff, 0x0, + 0xff, 0xe5, 0xf8, 0x7, 0xff, 0xa4, 0x4c, 0x3, + 0xff, 0xd0, 0xe0, 0x1f, 0xfc, 0x31, 0x0, 0xff, + 0xe0, 0x88, 0x7, 0xff, 0x68, 0x40, 0x3f, 0xf8, + 0x46, 0xe0, 0x1f, 0xfc, 0x13, 0x0, 0xff, 0xf4, + 0x88, 0x80, 0x3f, 0xfd, 0x6, 0x1, 0xff, 0xc1, + 0x10, 0x30, 0xf, 0xfe, 0x8, 0x80, 0x7f, 0xf6, + 0x84, 0x3, 0xff, 0x82, 0x60, 0x20, 0x1f, 0xfc, + 0x16, 0x0, 0xff, 0xed, 0x78, 0x7, 0xff, 0x4, + 0x43, 0xc0, 0x3f, 0xf8, 0x26, 0x1, 0xff, 0xda, + 0x10, 0xf, 0xfe, 0xb, 0x81, 0x0, 0x7f, 0xf0, + 0x44, 0x3, 0xff, 0xb4, 0x40, 0x1f, 0xfc, 0x12, + 0x6, 0x0, 0xff, 0xf4, 0x38, 0x7, 0xff, 0x7, + 0x80, 0x80, 0x3f, 0xf8, 0x44, 0x1, 0xff, 0xd9, + 0x20, 0xf, 0xfe, 0x9, 0x0, 0x80, 0x7f, 0xf0, + 0x98, 0x3, 0xff, 0xb2, 0x20, 0x1f, 0xfc, 0x11, + 0x0, 0x10, 0x7, 0xff, 0x4, 0x80, 0x3f, 0xfb, + 0x2, 0x1, 0xff, 0xc2, 0x60, 0x3, 0x0, 0x7f, + 0xf0, 0x78, 0x3, 0xff, 0xb0, 0x40, 0x1f, 0xfc, + 0x22, 0x0, 0x18, 0x7, 0xff, 0x4, 0x80, 0x3f, + 0xfb, 0xa, 0x1, 0xff, 0xc1, 0x30, 0xb, 0x40, + 0x3f, 0xf8, 0x2e, 0x1, 0xff, 0xd8, 0xe0, 0xf, + 0xfe, 0xb, 0x0, 0x4c, 0x1, 0xff, 0xc1, 0x20, + 0xf, 0xfe, 0xc1, 0x80, 0x7f, 0xf0, 0x74, 0x2, + 0x30, 0xf, 0xfe, 0x11, 0x0, 0x7f, 0xf5, 0xd4, + 0x3, 0xff, 0x82, 0x60, 0x18, 0xc0, 0x3f, 0xf8, + 0x2e, 0x1, 0xff, 0xd6, 0x11, 0x0, 0x7f, 0xf0, + 0x54, 0x3, 0x28, 0x7, 0xff, 0x7, 0x0, 0x3f, + 0xfa, 0xc8, 0x1, 0xff, 0xc1, 0x21, 0x0, 0xd8, + 0x1, 0xff, 0xc1, 0x40, 0xf, 0xfe, 0xb6, 0x80, + 0x7f, 0xf0, 0x50, 0x3, 0x90, 0x3, 0xff, 0x82, + 0x42, 0x1, 0xff, 0xd5, 0x40, 0xf, 0xfe, 0xe, + 0x0, 0x70, 0x90, 0x7, 0xff, 0x5, 0xc0, 0x3f, + 0xfa, 0x82, 0x60, 0x1f, 0xfc, 0x14, 0x0, 0xf2, + 0x80, 0x7f, 0xf0, 0x74, 0x3, 0xff, 0xa8, 0xe0, + 0x1f, 0xfc, 0x13, 0x10, 0xf, 0x58, 0x7, 0xff, + 0x5, 0x4, 0x3, 0xff, 0xa7, 0xa0, 0x1f, 0xfc, + 0x1b, 0x0, 0xf8, 0xc4, 0x3, 0xff, 0x82, 0xe0, + 0x1f, 0xfd, 0x22, 0x40, 0xf, 0xfe, 0xb, 0x0, + 0x7e, 0x60, 0xf, 0xfe, 0xd, 0x80, 0x7f, 0xf4, + 0xa8, 0x3, 0xff, 0x82, 0x62, 0x1, 0xfa, 0xc0, + 0x3f, 0xf8, 0x24, 0xa0, 0x1f, 0xfd, 0x1, 0x70, + 0xf, 0xfe, 0xd, 0x0, 0x7f, 0x19, 0x80, 0x3f, + 0xf8, 0x30, 0x1, 0xff, 0xd0, 0x80, 0xf, 0xfe, + 0x13, 0x0, 0x7f, 0xa4, 0x3, 0xff, 0x82, 0x4e, + 0x1, 0xff, 0xce, 0x36, 0x0, 0xff, 0xe0, 0xb8, + 0x7, 0xfc, 0xa2, 0x1, 0xff, 0xc1, 0x83, 0x0, + 0xff, 0xe6, 0xf0, 0x7, 0xff, 0xa, 0x80, 0x3f, + 0xf8, 0x12, 0x1, 0xff, 0xc2, 0xe1, 0x0, 0xff, + 0xe5, 0xd1, 0x0, 0x7f, 0xf0, 0x54, 0x80, 0x3f, + 0xf8, 0xe, 0x40, 0x1f, 0xfc, 0x12, 0xc1, 0x0, + 0xff, 0xe4, 0xd2, 0x80, 0x7f, 0xf0, 0xa0, 0x3, + 0xff, 0x85, 0x0, 0x1f, 0xfc, 0x22, 0xf3, 0x0, + 0xff, 0xe3, 0xd, 0xa8, 0x7, 0xff, 0x9, 0xc8, + 0x3, 0xff, 0x84, 0xa6, 0x1, 0xff, 0xc2, 0x1c, + 0x80, 0xf, 0xfe, 0x22, 0xfa, 0x0, 0x7f, 0xf0, + 0x86, 0x0, 0x3f, 0xf8, 0x9c, 0x1, 0xff, 0xc4, + 0x7e, 0x82, 0x0, 0xff, 0xb, 0x6d, 0x8, 0x7, + 0xff, 0xe, 0x80, 0x3f, 0xf8, 0xa5, 0x20, 0x1f, + 0xfc, 0x41, 0x7d, 0xd5, 0x3b, 0x2a, 0x99, 0xe7, + 0x3a, 0x48, 0x3, 0xff, 0x88, 0xc8, 0x1, 0xff, + 0xc6, 0x65, 0x0, 0xff, 0xe3, 0x12, 0xc4, 0xd5, + 0x26, 0x18, 0xc0, 0x3f, 0xf8, 0xc7, 0x20, 0x1f, + 0xfc, 0x8a, 0x30, 0xf, 0xff, 0x1, 0x68, 0x7, + 0xff, 0x2b, 0xc, 0x3, 0xff, 0xbc, 0x3e, 0x20, + 0x1f, 0xfc, 0xbd, 0x30, 0xf, 0xfe, 0xe0, 0xe1, + 0x0, 0x7f, 0xf3, 0x7, 0x14, 0x3, 0xff, 0xb4, + 0x7e, 0x40, 0x1f, 0xfc, 0xfa, 0x80, 0xf, 0xfe, + 0xc3, 0x60, 0x80, 0x7f, 0xf4, 0x5f, 0xc, 0x3, + 0xff, 0xa8, 0x57, 0x20, 0x1f, 0xfd, 0x43, 0xc9, + 0x10, 0xf, 0xfe, 0x80, 0xc6, 0xa0, 0x7, 0xff, + 0x5d, 0xba, 0x8c, 0x3, 0xff, 0x98, 0x53, 0xce, + 0x1, 0xff, 0xdb, 0x5c, 0xd8, 0x30, 0xf, 0xfe, + 0x31, 0xbe, 0x6b, 0x0, 0x7f, 0xf7, 0xc9, 0xf3, + 0xee, 0x59, 0x8, 0x44, 0x0, 0x11, 0x11, 0xb4, + 0x5f, 0x64, 0x18, 0x7, 0xff, 0x2c, + + /* U+005C "\\" */ + 0xc, 0xff, 0xff, 0xe0, 0x20, 0x7, 0xff, 0xaa, + 0x40, 0x3f, 0xf8, 0x1e, 0x1, 0xff, 0xea, 0x52, + 0x0, 0xff, 0x90, 0xc0, 0x3f, 0xfd, 0x56, 0x1, + 0xff, 0xc0, 0x90, 0xf, 0xff, 0x53, 0x8, 0x7, + 0xfc, 0xa4, 0x1, 0xff, 0xea, 0x90, 0xf, 0xfe, + 0x5, 0x80, 0x7f, 0xfa, 0x98, 0x3, 0xff, 0x80, + 0xc2, 0x1, 0xff, 0xe9, 0x17, 0x0, 0xff, 0xe0, + 0x48, 0x7, 0xff, 0xaa, 0x40, 0x3f, 0xf8, 0xc, + 0x1, 0xff, 0xea, 0x15, 0x0, 0xff, 0x85, 0x80, + 0x3f, 0xfd, 0x50, 0x1, 0xff, 0xc0, 0x80, 0xf, + 0xff, 0x51, 0x20, 0x7, 0xfc, 0x2a, 0x1, 0xff, + 0xea, 0x80, 0xf, 0xfe, 0x4, 0x0, 0x7f, 0xfa, + 0x8c, 0xc0, 0x1f, 0xf1, 0x20, 0x7, 0xff, 0xaa, + 0x0, 0x3f, 0xf8, 0x1e, 0x1, 0xff, 0xea, 0x42, + 0x0, 0xff, 0x90, 0xc0, 0x3f, 0xfd, 0x56, 0x1, + 0xff, 0xc0, 0x90, 0xf, 0xff, 0x53, 0x8, 0x7, + 0xfc, 0xa4, 0x1, 0xff, 0xea, 0x90, 0xf, 0xfe, + 0x5, 0x80, 0x7f, 0xfa, 0x9c, 0x40, 0x3f, 0xe6, + 0x10, 0xf, 0xff, 0x53, 0x0, 0x7f, 0xf0, 0x24, + 0x3, 0xff, 0xd5, 0x20, 0x1f, 0xfc, 0x6, 0x0, + 0xff, 0xf5, 0xb, 0x0, 0x7f, 0xc2, 0xe0, 0x1f, + 0xfe, 0xab, 0x0, 0xff, 0xe0, 0x48, 0x7, 0xff, + 0xa8, 0x94, 0x3, 0xfe, 0x16, 0x0, 0xff, 0xf5, + 0x48, 0x7, 0xff, 0x2, 0xc0, 0x3f, 0xfd, 0x46, + 0x80, 0x1f, 0xf1, 0x20, 0x7, 0xff, 0xab, 0xc0, + 0x3f, 0xf8, 0x10, 0x1, 0xff, 0xea, 0x42, 0x0, + 0xff, 0x8c, 0xc0, 0x1f, 0xfe, 0xa8, 0x0, 0xff, + 0xe0, 0x40, 0x7, 0xff, 0xa9, 0x48, 0x3, 0xfe, + 0x42, 0x0, 0xff, 0xf5, 0x58, 0x7, 0xff, 0x2, + 0xc0, 0x3f, 0xfd, 0x4c, 0x20, 0x1f, 0xf3, 0x8, + 0x7, 0xff, 0xaa, 0x40, 0x3f, 0xf8, 0x12, 0x1, + 0xff, 0xea, 0x60, 0xf, 0xfe, 0x3, 0x88, 0x7, + 0xff, 0xa4, 0x58, 0x3, 0xff, 0x80, 0xc0, 0x1f, + 0xfe, 0xa8, 0x0, 0xff, 0xe0, 0x48, 0x7, 0xff, + 0xa8, 0x54, 0x3, 0xfe, 0x16, 0x0, 0xff, 0xf5, + 0x40, 0x7, 0xff, 0x2, 0xc0, 0x3f, 0xfd, 0x44, + 0x80, 0x1f, 0xf1, 0x28, 0x7, 0xff, 0xab, 0xc0, + 0x3f, 0xf8, 0x12, 0x1, 0xff, 0xea, 0x43, 0x0, + 0xff, 0x8d, 0x0, 0x3f, 0xfd, 0x52, 0x1, 0xff, + 0xc0, 0xf0, 0xf, 0xff, 0x52, 0x90, 0x7, 0xfc, + 0x84, 0x1, 0xff, 0xea, 0xb0, 0xf, 0xfe, 0x4, + 0x0, 0x7f, 0xfa, 0x98, 0x40, 0x3f, 0xe5, 0x10, + 0xf, 0xff, 0x54, 0x80, 0x7f, 0xf0, 0x20, 0x3, + 0xff, 0xd4, 0xe0, 0x1f, 0xfc, 0x6, 0x10, 0xf, + 0xff, 0x53, 0x80, 0x7f, 0xf0, 0x18, 0x3, 0xff, + 0xd5, 0x20, 0x1f, 0xfc, 0x9, 0x0, 0xff, 0xf5, + 0xb, 0x0, 0x7f, 0xc2, 0xc0, 0x1f, 0xfe, 0xab, + 0x0, 0xff, 0xe0, 0x58, 0x7, 0xff, 0xa8, 0x94, + 0x3, 0xfe, 0x25, 0x0, 0xff, 0xf5, 0x48, 0x7, + 0xff, 0x2, 0x40, 0x3f, 0xfd, 0x46, 0x60, 0xf, + 0xf8, 0xd0, 0x3, 0xff, 0xd5, 0x0, 0x1f, 0xfc, + 0xf, 0x0, 0xff, 0xf5, 0x21, 0x0, 0x7f, 0xc8, + 0x60, 0x1f, 0xfe, 0xa8, 0x0, 0xff, 0xe0, 0x48, + 0x7, 0xff, 0xa9, 0x44, 0x3, 0xfe, 0x52, 0x0, + 0xff, 0xf5, 0x48, 0x7, 0xff, 0x2, 0xc0, 0x3f, + 0xfd, 0x4e, 0x20, 0x1f, 0xf3, 0x8, 0x7, 0xff, + 0xa9, 0x80, 0x3f, 0xf8, 0x12, 0x1, 0xff, 0xea, + 0x90, 0xf, 0xfe, 0x3, 0x0, 0x7f, 0xfa, 0x85, + 0x80, 0x3f, 0xe1, 0x70, 0xf, 0xff, 0x55, 0x80, + 0x7f, 0xf0, 0x24, 0x3, 0xff, 0xd4, 0x4a, 0x1, + 0xff, 0xa, 0x80, 0x7f, 0xfa, 0xa4, 0x3, 0xff, + 0x81, 0x0, 0x1f, 0xfe, 0xa3, 0x40, 0xf, 0xf8, + 0x90, 0x3, 0xff, 0xd5, 0xe0, 0x1f, 0xfc, 0x8, + 0x0, 0xff, 0xf5, 0x21, 0x80, 0x7f, 0xc6, 0x60, + 0xf, 0xff, 0x54, 0x80, 0x7f, 0xf0, 0x20, 0x3, + 0xff, 0xd4, 0xa4, 0x1, 0xff, 0x21, 0x0, 0x7f, + 0xfa, 0xac, 0x3, 0xff, 0x81, 0x60, 0x1f, 0xfe, + 0xa6, 0x10, 0xf, 0xf9, 0x84, 0x3, 0xff, 0xd5, + 0x20, 0x1f, 0xfc, 0x9, 0x0, 0xff, 0xf5, 0x30, + 0x7, 0xff, 0x1, 0xc0, 0x3f, 0xfd, 0x42, 0xe0, + 0x1f, 0xfc, 0x7, 0x0, 0xff, 0xf5, 0x48, 0x7, + 0xff, 0x2, 0x40, 0x3f, 0xfd, 0x42, 0xa0, 0x1f, + 0xf0, 0xb0, 0x7, 0xff, 0xaa, 0x0, 0x3f, 0xf8, + 0x16, 0x1, 0xff, 0xea, 0x24, 0x0, 0xff, 0x89, + 0x40, 0x3f, 0xfd, 0x50, 0x1, 0xff, 0xc0, 0x90, + 0xf, 0xff, 0x51, 0x98, 0x3, 0xfe, 0x33, 0x0, + 0x7f, 0xfa, 0xa0, 0x3, 0xff, 0x81, 0x0, 0x1f, + 0xfe, 0xa4, 0x20, 0xf, 0xf9, 0x8, 0x3, 0xff, + 0xd5, 0x60, 0x1f, 0xfc, 0x8, 0x0, 0xff, 0xf5, + 0x30, 0x80, 0x7f, 0xca, 0x20, 0x1f, 0xfe, 0xa9, + 0x0, 0xff, 0xe0, 0x48, 0x7, 0xff, 0xa9, 0xc4, + 0x3, 0xfe, 0x71, 0x0, 0xff, 0xf5, 0x30, 0x7, + 0xff, 0x1, 0x80, 0x3f, 0xfd, 0x52, 0x1, 0xff, + 0xc0, 0x90, 0xf, 0xff, 0x50, 0xb0, 0x7, 0xfc, + 0x2c, 0x1, 0xff, 0xea, 0xb0, 0xf, 0xfe, 0x5, + 0x80, 0x7f, 0xfa, 0x89, 0x40, 0x3f, 0xe2, 0x50, + 0xf, 0xff, 0x54, 0x80, 0x7f, 0xf0, 0x24, 0x3, + 0xff, 0xd4, 0x68, 0x1, 0xff, 0x1a, 0x0, 0x7f, + 0xfa, 0xbc, 0x3, 0xff, 0x81, 0xe0, 0x1f, 0xfe, + 0xa4, 0x20, 0xf, 0xf9, 0xc, 0x3, 0xff, 0xd5, + 0x0, 0x1f, 0xfc, 0x9, 0x0, 0xff, 0xf5, 0x29, + 0x0, 0x7f, 0xca, 0x40, 0x1f, 0xfe, 0xab, 0x0, + 0xff, 0xe0, 0x58, 0x7, 0xff, 0xa9, 0x84, 0x3, + 0xfe, 0x61, 0x0, 0xff, 0xf5, 0x48, 0x7, 0xff, + 0x2, 0x40, 0x3f, 0xfd, 0x4c, 0x1, 0xff, 0xc0, + 0x60, 0xf, 0xff, 0x50, 0xb0, 0x7, 0xfc, 0x2c, + 0x1, 0xff, 0xea, 0x80, 0xf, 0xfe, 0x4, 0x0, + 0x7f, 0xfa, 0x85, 0x40, 0x3f, 0xe1, 0x50, 0xf, + 0xff, 0x54, 0x0, 0x7f, 0xf0, 0x20, 0x3, 0xff, + 0xd4, 0x48, 0x1, 0xff, 0x12, 0x0, 0x7f, 0xfa, + 0xbc, 0x3, 0xff, 0x81, 0x0, 0x1f, 0xfe, 0xa4, + 0x30, 0xf, 0xf8, 0xcc, 0x1, 0xff, 0xea, 0x90, + 0xf, 0xfe, 0x4, 0x80, 0x7f, 0xfa, 0x94, 0x80, + 0x3f, 0xe5, 0x20, 0xf, 0xff, 0x55, 0x80, 0x7f, + 0xf0, 0x2c, 0x3, 0xff, 0xd4, 0xc2, 0x1, 0xff, + 0x30, 0x80, 0x7f, 0xfa, 0xa4, 0x3, 0xff, 0x81, + 0x20, + + /* U+005E "^" */ + 0x0, 0xff, 0xea, 0x3c, 0x47, 0xfc, 0x60, 0x1f, + 0xff, 0x2b, 0x87, 0x7f, 0xfb, 0x44, 0x3, 0xff, + 0xe1, 0x8, 0x1, 0xff, 0xc0, 0x1d, 0x0, 0xff, + 0xf7, 0xab, 0x80, 0x7f, 0xf0, 0x8e, 0x40, 0x3f, + 0xfd, 0xa5, 0x40, 0x1f, 0xfc, 0x46, 0x60, 0x7, + 0xff, 0xac, 0x7c, 0x3, 0xff, 0x8d, 0x28, 0x1, + 0xff, 0xea, 0xa2, 0x0, 0xff, 0xe3, 0xd0, 0x80, + 0x7f, 0xfa, 0x25, 0x0, 0x3f, 0xf9, 0x3, 0x80, + 0x1f, 0xfe, 0x76, 0x60, 0x7, 0xff, 0x28, 0xa8, + 0x3, 0xff, 0xca, 0x72, 0x1, 0xff, 0xcc, 0x57, + 0x0, 0xff, 0xf1, 0x8e, 0x80, 0x7f, 0xf3, 0xa1, + 0x0, 0x3f, 0xfc, 0x5a, 0x20, 0x1f, 0xfc, 0x11, + 0x0, 0xff, 0xe0, 0xd9, 0x0, 0x7f, 0xf8, 0x24, + 0xc0, 0x3f, 0xf8, 0x33, 0xa0, 0x1f, 0xfc, 0x2f, + 0x0, 0xff, 0xef, 0xb3, 0x0, 0x3f, 0xf8, 0x30, + 0xc7, 0x60, 0x1f, 0xfc, 0x12, 0xb0, 0xf, 0xfe, + 0xea, 0x48, 0x7, 0xff, 0x5, 0xdc, 0x0, 0x4a, + 0x0, 0xff, 0xe0, 0xa4, 0x0, 0x7f, 0xf6, 0xca, + 0x80, 0x3f, 0xf8, 0x2d, 0x0, 0x19, 0x64, 0x3, + 0xff, 0x82, 0xea, 0x1, 0xff, 0xda, 0xf1, 0x0, + 0xff, 0xe0, 0x24, 0x80, 0x79, 0xa0, 0x3, 0xff, + 0x83, 0x44, 0x1, 0xff, 0xd8, 0xa2, 0x0, 0xff, + 0xe0, 0x1d, 0x80, 0x7e, 0x76, 0x0, 0xff, 0xe0, + 0xf8, 0x80, 0x7f, 0xf5, 0x9d, 0x40, 0x3f, 0xf8, + 0x5, 0x80, 0x1f, 0xe9, 0x50, 0xf, 0xfe, 0x1, + 0x50, 0x7, 0xff, 0x55, 0x20, 0x3, 0xff, 0x80, + 0x58, 0x1, 0xff, 0xc0, 0xa4, 0x0, 0xff, 0xe0, + 0x24, 0x80, 0x7f, 0xf4, 0xca, 0xc0, 0x3f, 0xf8, + 0x3, 0xe2, 0x1, 0xff, 0xc1, 0xb3, 0x0, 0xff, + 0xe0, 0x33, 0x0, 0x3f, 0xfa, 0x5e, 0x1, 0xff, + 0xc1, 0xd2, 0x0, 0xff, 0xe1, 0xe9, 0x0, 0x7f, + 0xf0, 0x24, 0xc0, 0x3f, 0xfa, 0x16, 0x40, 0x1f, + 0xfc, 0xc, 0x30, 0xf, 0xfe, 0x20, 0xe1, 0x0, + 0x7f, 0xf0, 0x34, 0x40, 0x3f, 0xf9, 0xd0, 0x80, + 0x1f, 0xfc, 0xb, 0x30, 0xf, 0xfe, 0x30, 0xf8, + 0x80, 0x7f, 0xc3, 0xa0, 0x1f, 0xfc, 0xd5, 0x70, + 0xf, 0xfe, 0x4, 0xa0, 0x7, 0xff, 0x20, 0xb4, + 0x3, 0xff, 0x80, 0x72, 0x1, 0xff, 0xcb, 0x3a, + 0x0, 0xff, 0xe0, 0x43, 0x0, 0x7f, 0xf2, 0x8f, + 0x0, 0x3f, 0xf8, 0xc, 0xc0, 0xf, 0xfe, 0x48, + 0xe8, 0x7, 0xff, 0x1, 0xdc, 0x1, 0xff, 0xcc, + 0x3b, 0x0, 0xff, 0xe0, 0x4a, 0x0, 0x7f, 0xf2, + 0x28, 0x40, 0x3f, 0xe5, 0x80, 0xf, 0xfe, 0x72, + 0x48, 0x7, 0xff, 0x2, 0x88, 0x3, 0xff, 0x8d, + 0x28, 0x1, 0xff, 0x25, 0x0, 0x7f, 0xf4, 0x1a, + 0x0, 0x3f, 0xe1, 0xf0, 0xf, 0xfe, 0x2b, 0x30, + 0x3, 0xfe, 0x3b, 0x0, 0xff, 0xe9, 0x3b, 0x80, + 0x3f, 0xe2, 0xa0, 0xf, 0xfe, 0x19, 0xc8, 0x7, + 0xfc, 0x5a, 0x1, 0xff, 0xd4, 0x86, 0x0, 0xff, + 0x95, 0xc0, 0x3f, 0xf8, 0x23, 0xa0, 0x1f, 0xf1, + 0x60, 0x80, 0x7f, 0xf5, 0x65, 0x40, 0x3f, 0xe8, + 0x40, 0xf, 0xfe, 0x6, 0x88, 0x7, 0xf8, 0x7c, + 0x40, 0x3f, 0xfa, 0xf4, 0x80, 0x1f, 0xf5, 0x90, + 0x7, 0xfa, 0x4c, 0x3, 0xfe, 0xd2, 0x0, 0xff, + 0xec, 0xd9, 0x80, 0x7f, 0xde, 0x1, 0xfc, 0xcc, + 0x0, 0xff, 0xb0, 0xc0, 0x3f, 0xfb, 0x7a, 0x40, + 0x1f, 0xe2, 0xb0, 0xf, 0x92, 0x40, 0x3f, 0xea, + 0x30, 0xf, 0xfe, 0xe0, 0xe0, 0x80, 0x7f, 0x92, + 0x0, 0x38, 0xa8, 0x3, 0xfe, 0x95, 0x0, 0xff, + 0xef, 0xe, 0x8, 0x7, 0xf9, 0xd4, 0x3, 0x78, + 0x80, 0x7f, 0xa1, 0x80, 0x3f, 0xfc, 0x5, 0xa0, + 0x1f, 0xf5, 0x10, 0x2, 0x88, 0x3, 0xfc, 0xee, + 0x0, 0xff, 0xf1, 0x1d, 0x80, 0x7f, 0xde, 0x20, + + /* U+005F "_" */ + 0x88, 0xff, 0xff, 0xc4, 0x7f, 0x13, 0xbf, 0xff, + 0xfd, 0xdf, 0xf9, 0x80, 0x3f, 0xff, 0xe0, 0x1f, + 0xff, 0xf0, 0xf, 0xff, 0xf8, 0x7, 0xff, 0xfc, + 0x3, 0xff, 0xb8, + + /* U+006F "o" */ + 0x0, 0xff, 0xe6, 0xa, 0x3c, 0xde, 0xf7, 0x3f, + 0xee, 0xdc, 0xa7, 0x52, 0x0, 0xff, 0xf0, 0xa4, + 0xef, 0x5c, 0x32, 0x10, 0x88, 0x2, 0x12, 0x35, + 0x8a, 0xde, 0xa5, 0x0, 0xff, 0xed, 0x94, 0x75, + 0xb1, 0x0, 0x7f, 0xf1, 0x85, 0x6b, 0xe8, 0xc0, + 0x3f, 0xfa, 0xc5, 0x3a, 0xe2, 0x1, 0xff, 0xcd, + 0x5c, 0xb3, 0x0, 0xff, 0xe9, 0xc6, 0xb0, 0x7, + 0xff, 0x49, 0x32, 0x84, 0x3, 0xff, 0x9e, 0x7a, + 0xe0, 0x1f, 0xfd, 0x65, 0xf5, 0x0, 0xff, 0xe6, + 0xae, 0x10, 0x7, 0xff, 0x60, 0x6a, 0x0, 0x3f, + 0xf9, 0x6f, 0x40, 0x1f, 0xfd, 0xc7, 0xa0, 0xf, + 0xfe, 0x4b, 0xc0, 0x7, 0xff, 0x79, 0x6c, 0x3, + 0xff, 0x8e, 0xd0, 0x1, 0xff, 0xe0, 0x4a, 0x0, + 0xff, 0xe2, 0xa4, 0x80, 0x7f, 0xf2, 0x4, 0x8c, + 0xc4, 0x20, 0x1f, 0xfc, 0x85, 0x80, 0xf, 0xfe, + 0x18, 0xd0, 0x7, 0xff, 0x14, 0x9e, 0xfb, 0x9b, + 0x98, 0xde, 0xfc, 0x83, 0x0, 0xff, 0xe2, 0xba, + 0x0, 0x7f, 0xf0, 0xa8, 0x40, 0x3f, 0xf8, 0x67, + 0x7b, 0x8, 0x20, 0x1f, 0x1b, 0xe6, 0xb0, 0x7, + 0xff, 0x12, 0x84, 0x3, 0xff, 0x80, 0xc8, 0x1, + 0xff, 0xc2, 0x1a, 0xc4, 0x0, 0xff, 0xe1, 0x14, + 0xe1, 0x80, 0x7f, 0xf0, 0x86, 0xc0, 0x3f, 0xf8, + 0x10, 0x1, 0xff, 0xc2, 0x2c, 0x50, 0xf, 0xfe, + 0x31, 0xe2, 0x80, 0x7f, 0xf0, 0x94, 0xc0, 0x3f, + 0xd0, 0x20, 0x1f, 0xfc, 0x12, 0xc2, 0x0, 0xff, + 0xe4, 0xd3, 0x0, 0x7f, 0xf0, 0xbc, 0x3, 0xf8, + 0x5c, 0x3, 0xff, 0x82, 0x58, 0x20, 0x1f, 0xfc, + 0xb9, 0x50, 0xf, 0xfe, 0x9, 0xa0, 0x7, 0xe6, + 0x0, 0xff, 0xe1, 0x70, 0x80, 0x7f, 0xf3, 0x68, + 0x80, 0x3f, 0xf8, 0x3e, 0x1, 0xfa, 0x40, 0x3f, + 0xf8, 0x30, 0x60, 0x1f, 0xfc, 0xfe, 0x0, 0xff, + 0xe0, 0xa1, 0x0, 0x79, 0x44, 0x3, 0xff, 0x80, + 0x4e, 0x1, 0xff, 0xd0, 0x36, 0x0, 0xff, 0xe0, + 0xd8, 0x7, 0xbc, 0x3, 0xff, 0x83, 0x0, 0x1f, + 0xfd, 0x28, 0x0, 0xff, 0xe0, 0xb8, 0x7, 0x94, + 0x3, 0xff, 0x80, 0x2a, 0x1, 0xff, 0xd2, 0x16, + 0x0, 0xff, 0xe0, 0xa, 0x0, 0x65, 0x0, 0xff, + 0xe0, 0xc8, 0x7, 0xff, 0x52, 0xc0, 0x3f, 0xf8, + 0x3a, 0x1, 0xbc, 0x3, 0xff, 0x82, 0xc0, 0x1f, + 0xfd, 0x42, 0x20, 0x7, 0xff, 0x1, 0xc0, 0x33, + 0x80, 0x7f, 0xf0, 0xc, 0x40, 0x3f, 0xfa, 0xb4, + 0x1, 0xff, 0xc0, 0x12, 0x0, 0x9, 0x0, 0x7f, + 0xf0, 0x2c, 0x3, 0xff, 0xac, 0xa0, 0x1f, 0xfc, + 0x17, 0x0, 0x20, 0x7, 0xff, 0x5, 0x0, 0x3f, + 0xfa, 0xc4, 0x20, 0x1f, 0xfc, 0xc, 0x0, 0x68, + 0x7, 0xff, 0x4, 0xc0, 0x3f, 0xfa, 0xe8, 0x1, + 0xff, 0xc0, 0x50, 0x1, 0x80, 0x7f, 0xf0, 0xc, + 0x3, 0xff, 0xb1, 0xa0, 0x1f, 0xfc, 0x3, 0x0, + 0x30, 0x7, 0xff, 0x1, 0x40, 0x3f, 0xfb, 0x6, + 0x1, 0xff, 0xc1, 0x10, 0x20, 0xf, 0xfe, 0x7, + 0x80, 0x7f, 0xf6, 0x14, 0x3, 0xff, 0x82, 0xa4, + 0x1, 0xff, 0xc1, 0x20, 0xf, 0xfe, 0xc0, 0x80, + 0x7f, 0xf0, 0x48, 0x40, 0x3f, 0xf8, 0x2c, 0x1, + 0xff, 0xd9, 0x20, 0xf, 0xfe, 0x7, 0x30, 0x7, + 0xff, 0x4, 0x80, 0x3f, 0xfb, 0x2c, 0x1, 0xff, + 0xc0, 0x13, 0x0, 0xff, 0xf3, 0x88, 0x7, 0xff, + 0x0, 0xc4, 0x3, 0xff, 0x80, 0x20, 0x1f, 0xfd, + 0xa3, 0x0, 0xff, 0xe0, 0x37, 0x80, 0x7f, 0xf0, + 0x8, 0x3, 0xff, 0xb4, 0x20, 0x1f, 0xff, 0x5f, + 0x0, 0xff, 0xe0, 0x8, 0x80, 0x3f, 0xf8, 0xe, + 0x1, 0xff, 0xff, 0x0, 0xff, 0xe8, 0x88, 0x7, + 0xff, 0x0, 0xcc, 0x1, 0xff, 0xf5, 0x30, 0xf, + 0xff, 0xf8, 0x7, 0xff, 0x78, 0x40, 0x3f, 0xf8, + 0x6, 0x20, 0x1f, 0xfc, 0x7, 0x0, 0xff, 0xff, + 0x80, 0x7f, 0xf4, 0x7c, 0x3, 0xff, 0x80, 0x3e, + 0x1, 0xff, 0xc0, 0x20, 0xf, 0xfe, 0xd0, 0x80, + 0x7f, 0xf0, 0x44, 0x3, 0xff, 0x80, 0x20, 0x1f, + 0xfd, 0xa3, 0x0, 0xff, 0xe0, 0x31, 0x80, 0x7f, + 0xf9, 0xc4, 0x3, 0xff, 0x80, 0x6c, 0x1, 0xff, + 0xc1, 0x20, 0xf, 0xfe, 0xcb, 0x0, 0x7f, 0xf0, + 0x4, 0x40, 0x1f, 0xfc, 0x16, 0x0, 0xff, 0xec, + 0x90, 0x7, 0xff, 0x3, 0x88, 0x3, 0xff, 0x82, + 0x40, 0x1f, 0xfd, 0x81, 0x0, 0xff, 0xe0, 0x90, + 0x10, 0x7, 0xff, 0x3, 0xc0, 0x3f, 0xfb, 0xa, + 0x1, 0xff, 0xc1, 0x60, 0x60, 0xf, 0xfe, 0x2, + 0x80, 0x7f, 0xf6, 0xc, 0x3, 0xff, 0x82, 0x40, + 0x60, 0x1f, 0xfc, 0x3, 0x0, 0xff, 0xec, 0x68, + 0x7, 0xff, 0x0, 0x80, 0x1a, 0x1, 0xff, 0xc1, + 0x30, 0xf, 0xfe, 0xba, 0x0, 0x7f, 0xf0, 0x10, + 0x0, 0x80, 0x1f, 0xfc, 0x14, 0x0, 0xff, 0xeb, + 0x18, 0x80, 0x7f, 0xf0, 0x3c, 0x0, 0x22, 0x0, + 0xff, 0xe0, 0x58, 0x7, 0xff, 0x59, 0x0, 0x3f, + 0xf8, 0x28, 0x1, 0x20, 0x7, 0xff, 0x0, 0xc4, + 0x3, 0xff, 0xab, 0x40, 0x1f, 0xfc, 0x1, 0x20, + 0xb, 0xc0, 0x3f, 0xf8, 0x2c, 0x1, 0xff, 0xd4, + 0x32, 0x0, 0xff, 0xe0, 0x20, 0x6, 0x50, 0xf, + 0xfe, 0xc, 0x80, 0x7f, 0xf5, 0x24, 0x3, 0xff, + 0x83, 0xc0, 0x1c, 0x80, 0x1f, 0xfc, 0x1, 0x50, + 0xf, 0xfe, 0x90, 0xa8, 0x7, 0xff, 0x5, 0x0, + 0x3b, 0x80, 0x3f, 0xf8, 0x36, 0x1, 0xff, 0xd2, + 0xb0, 0xf, 0xfe, 0xa, 0x80, 0x79, 0x44, 0x3, + 0xff, 0x80, 0x30, 0x1, 0xff, 0xd0, 0x35, 0x0, + 0xff, 0xe0, 0xc8, 0x7, 0xcc, 0x1, 0xff, 0xc1, + 0x73, 0x0, 0xff, 0xe7, 0xf0, 0x7, 0xff, 0x4, + 0xcc, 0x1, 0xf4, 0x80, 0x7f, 0xf0, 0xb8, 0x40, + 0x3f, 0xf9, 0xb4, 0x40, 0x1f, 0xfc, 0x19, 0x0, + 0xfc, 0x2e, 0x1, 0xff, 0xc1, 0x2c, 0x10, 0xf, + 0xfe, 0x5c, 0xa8, 0x7, 0xff, 0x4, 0x94, 0x3, + 0xfa, 0x44, 0x3, 0xff, 0x82, 0x58, 0x40, 0x1f, + 0xfc, 0x9a, 0x60, 0xf, 0xfe, 0x14, 0x80, 0x7f, + 0x86, 0x0, 0x3f, 0xf8, 0x45, 0x8a, 0x1, 0xff, + 0xc6, 0x3d, 0x50, 0xf, 0xfe, 0x12, 0x20, 0x3, + 0xfe, 0x63, 0x0, 0xff, 0xe1, 0xd, 0x62, 0x0, + 0x7f, 0xf0, 0x8a, 0x70, 0x80, 0x3f, 0xf8, 0x43, + 0x40, 0x1f, 0xfc, 0x1d, 0x10, 0xf, 0xfe, 0x19, + 0xde, 0xc2, 0x8, 0x7, 0xc6, 0xf9, 0xac, 0x1, + 0xff, 0xc4, 0xb1, 0x0, 0xff, 0xe0, 0x8d, 0x80, + 0x7f, 0xf1, 0x49, 0xef, 0xb9, 0xb9, 0x8d, 0xef, + 0xc8, 0x30, 0xf, 0xfe, 0x2b, 0x28, 0x7, 0xff, + 0xd, 0x60, 0x3, 0xff, 0x90, 0x24, 0x66, 0x21, + 0x0, 0xff, 0xe4, 0x24, 0x80, 0x7f, 0xf1, 0x5d, + 0xc0, 0x1f, 0xfe, 0x3, 0xb0, 0xf, 0xfe, 0x3c, + 0x38, 0x7, 0xff, 0x79, 0x30, 0x3, 0xff, 0x93, + 0x14, 0x1, 0xff, 0xdc, 0x6b, 0x0, 0xff, 0xe5, + 0xae, 0x10, 0x7, 0xff, 0x66, 0x64, 0x1, 0xff, + 0xcd, 0x3d, 0x70, 0xf, 0xfe, 0xb2, 0x73, 0x0, + 0x7f, 0xf4, 0x23, 0x54, 0x3, 0xff, 0xa4, 0x77, + 0x61, 0x0, 0xff, 0xe9, 0x15, 0x6b, 0x8, 0x7, + 0xff, 0x35, 0x6f, 0x10, 0x3, 0xff, 0xac, 0x53, + 0xd6, 0xc4, 0x1, 0xff, 0xc6, 0x15, 0x9f, 0xa4, + 0x0, 0xff, 0xed, 0xa4, 0xef, 0x54, 0x32, 0x10, + 0x88, 0x2, 0x12, 0x35, 0x7a, 0xde, 0xa6, 0x0, + 0xff, 0xe4, 0x80, + + /* U+0078 "x" */ + 0x0, 0x88, 0xbf, 0xf8, 0x22, 0x1, 0xff, 0xdc, + 0x12, 0x2f, 0xfe, 0x8, 0x7, 0xd1, 0xbb, 0xff, + 0xc0, 0xe4, 0x0, 0xff, 0xed, 0x1f, 0x6e, 0xff, + 0xf0, 0x30, 0x40, 0x3d, 0x44, 0x1, 0xff, 0xc0, + 0xa1, 0x0, 0xff, 0xec, 0xf0, 0x7, 0xff, 0x7, + 0x44, 0x3, 0xee, 0x0, 0xff, 0xe0, 0xd, 0x0, + 0x7f, 0xf6, 0x28, 0x80, 0x3f, 0xf8, 0x10, 0x60, + 0x1f, 0x8e, 0x0, 0x3f, 0xf8, 0x8, 0xe0, 0x1f, + 0xfd, 0x65, 0x50, 0x7, 0xff, 0x1, 0x1c, 0x3, + 0xfc, 0xe8, 0x1, 0xff, 0xc0, 0x83, 0x0, 0xff, + 0xea, 0x15, 0x0, 0x7f, 0xf0, 0x6, 0x80, 0x3f, + 0xf8, 0x14, 0x20, 0x1f, 0xfc, 0xe, 0x0, 0xff, + 0xea, 0x70, 0x7, 0xff, 0x7, 0x44, 0x3, 0xff, + 0x80, 0x3a, 0x1, 0xff, 0xc0, 0x2a, 0x0, 0xff, + 0xe9, 0x41, 0x80, 0x7f, 0xf0, 0x20, 0xc0, 0x3f, + 0xf8, 0x47, 0x0, 0x1f, 0xfc, 0x5, 0x50, 0x7, + 0xff, 0x41, 0x1c, 0x3, 0xff, 0x80, 0x8e, 0x1, + 0xff, 0xc4, 0x74, 0x0, 0xff, 0xe0, 0x51, 0x0, + 0x7f, 0xf3, 0x86, 0x80, 0x3f, 0xf8, 0x3, 0x40, + 0x1f, 0xfc, 0x6a, 0x10, 0xf, 0xfe, 0x7, 0x0, + 0x7f, 0xf3, 0xa8, 0x40, 0x3f, 0xf8, 0x14, 0x20, + 0x1f, 0xfc, 0x61, 0xd0, 0xf, 0xfe, 0x1, 0xc0, + 0x7, 0xff, 0x31, 0x90, 0x3, 0xff, 0x80, 0xe8, + 0x1, 0xff, 0xc8, 0x38, 0x0, 0xff, 0xe0, 0x3a, + 0x0, 0x7f, 0xf2, 0x8a, 0x40, 0x3f, 0xf8, 0x7, + 0x0, 0x1f, 0xfc, 0xa7, 0x40, 0xf, 0xfe, 0x5, + 0x8, 0x7, 0xff, 0x27, 0xc0, 0x3f, 0xf8, 0x3, + 0xa0, 0x1f, 0xfc, 0xca, 0x10, 0xf, 0xf8, 0x68, + 0x3, 0xff, 0x91, 0x24, 0x1, 0xff, 0xc0, 0xa1, + 0x0, 0xff, 0xe6, 0xd, 0x0, 0x7f, 0xf0, 0x11, + 0xc0, 0x3f, 0xf8, 0xc8, 0xc0, 0x1f, 0xfc, 0x7, + 0x40, 0xf, 0xfe, 0x72, 0x38, 0x7, 0xff, 0x2, + 0xc, 0x3, 0xff, 0x88, 0x34, 0x1, 0xff, 0xc0, + 0x38, 0x0, 0xff, 0xe8, 0x41, 0x80, 0x7f, 0xf0, + 0x38, 0x3, 0xff, 0x89, 0x42, 0x1, 0xff, 0xc0, + 0xe0, 0xf, 0xfe, 0x96, 0x88, 0x7, 0xfc, 0x54, + 0x1, 0xff, 0xc2, 0x74, 0x0, 0xff, 0xe0, 0x51, + 0x0, 0x7f, 0xf4, 0x86, 0x80, 0x3f, 0xf8, 0xa, + 0xc0, 0x1f, 0xfc, 0x3, 0x80, 0xf, 0xfe, 0x3, + 0x28, 0x7, 0xff, 0x51, 0x1c, 0x3, 0xff, 0x81, + 0x24, 0x1, 0xff, 0x70, 0x7, 0xff, 0x0, 0xe4, + 0x3, 0xff, 0xad, 0x6, 0x1, 0xff, 0xc0, 0xe0, + 0xf, 0xf5, 0x10, 0x7, 0xff, 0x3, 0x80, 0x3f, + 0xfb, 0x1c, 0x1, 0xff, 0xc0, 0x38, 0x0, 0xfc, + 0xaa, 0x0, 0xff, 0xe0, 0x51, 0x0, 0x7f, 0xf6, + 0xa, 0x80, 0x3f, 0xf8, 0xe, 0x80, 0x1e, 0x2a, + 0x0, 0xff, 0xe0, 0x32, 0x80, 0x7f, 0xf6, 0x95, + 0x80, 0x3f, 0xf8, 0x14, 0x20, 0x1d, 0xc0, 0x1f, + 0xfc, 0x2, 0x90, 0xf, 0xfe, 0xe4, 0x98, 0x7, + 0xfc, 0x34, 0x1, 0xa0, 0xc0, 0x3f, 0xf8, 0x1e, + 0x1, 0xff, 0xde, 0xe0, 0xf, 0xfe, 0x2, 0x38, + 0x1, 0x1c, 0x3, 0xff, 0x81, 0x24, 0x1, 0xff, + 0xde, 0x2a, 0x0, 0xff, 0xe0, 0x41, 0x8d, 0x0, + 0x7f, 0xf0, 0x15, 0x80, 0x3f, 0xfc, 0xa, 0xc0, + 0x1f, 0xfc, 0xe, 0xa1, 0x0, 0xff, 0x8a, 0x80, + 0x3f, 0xfc, 0x52, 0x40, 0x1f, 0xf1, 0x20, 0x7, + 0xff, 0x3, 0x80, 0x3f, 0xfc, 0x9e, 0x1, 0xff, + 0xcc, 0x93, 0x0, 0xff, 0xf2, 0x14, 0x80, 0x7f, + 0xf2, 0x95, 0x80, 0x3f, 0xfc, 0xcc, 0xa0, 0x1f, + 0xfc, 0x82, 0xb0, 0xf, 0xff, 0x45, 0x10, 0x7, + 0xff, 0x1f, 0x84, 0x3, 0xff, 0xd3, 0xe0, 0x1f, + 0xfc, 0x68, 0x30, 0xf, 0xff, 0x51, 0x48, 0x7, + 0xff, 0x11, 0x1c, 0x3, 0xff, 0xd8, 0xca, 0x1, + 0xff, 0xc2, 0x1a, 0x0, 0xff, 0xf7, 0x50, 0x80, + 0x7f, 0xf0, 0x68, 0x40, 0x3f, 0xfd, 0xc8, 0x20, + 0x1f, 0xfc, 0x1c, 0x0, 0xff, 0xf7, 0xd, 0x0, + 0x7f, 0xf0, 0x9d, 0x0, 0x3f, 0xfd, 0xb4, 0x20, + 0x1f, 0xfc, 0x3a, 0x10, 0xf, 0xff, 0x5c, 0x20, + 0x7, 0xff, 0x10, 0x74, 0x3, 0xff, 0xd4, 0x8e, + 0x1, 0xff, 0xc6, 0x38, 0x0, 0xff, 0xf4, 0xd, + 0x0, 0x7f, 0xf2, 0x1d, 0x0, 0x3f, 0xfc, 0xf4, + 0x20, 0x1f, 0xfc, 0x9a, 0x10, 0xf, 0xff, 0x2b, + 0xa0, 0x7, 0xff, 0x28, 0x74, 0x3, 0xff, 0xc8, + 0x90, 0x1, 0xff, 0xcc, 0x38, 0x0, 0xff, 0xf1, + 0xd, 0x0, 0x7f, 0xf0, 0xd, 0x80, 0x3f, 0xf8, + 0xe, 0x80, 0x1f, 0xfe, 0x1a, 0x10, 0xf, 0xfe, + 0x7, 0x49, 0x0, 0x7f, 0xf0, 0x28, 0x40, 0x3f, + 0xfb, 0xee, 0x80, 0x1f, 0xfc, 0xa, 0x20, 0xf0, + 0xf, 0xfe, 0x0, 0xe8, 0x7, 0xff, 0x78, 0xe0, + 0x3, 0xff, 0x80, 0xaa, 0x0, 0x14, 0x80, 0x7f, + 0xf0, 0xe, 0x0, 0x3f, 0xfb, 0x83, 0xa0, 0x1f, + 0xfc, 0x2, 0xa0, 0xc, 0xca, 0x1, 0xff, 0xc0, + 0x74, 0x0, 0xff, 0xed, 0xd0, 0x80, 0x7f, 0xf0, + 0x38, 0x3, 0xd6, 0x20, 0x1f, 0xfc, 0xa, 0x10, + 0xf, 0xfe, 0xcb, 0xa0, 0x7, 0xff, 0x2, 0xc, + 0x3, 0xc3, 0xa0, 0x1f, 0xfc, 0x1, 0xd0, 0xf, + 0xfe, 0xc1, 0xc0, 0x7, 0xff, 0x1, 0x1c, 0x3, + 0xf1, 0xb8, 0x7, 0xff, 0x0, 0xe0, 0x3, 0xff, + 0xac, 0x3a, 0x1, 0xff, 0xc0, 0x1a, 0x0, 0xff, + 0x41, 0x80, 0x7f, 0xf0, 0x1d, 0x0, 0x3f, 0xfa, + 0xb4, 0x20, 0x1f, 0xfc, 0xa, 0x10, 0xf, 0xfb, + 0x44, 0x3, 0xff, 0x81, 0x42, 0x1, 0xff, 0xd3, + 0x74, 0x0, 0xff, 0xe0, 0x32, 0x0, 0x7f, 0xf0, + 0x6, 0xc0, 0x3f, 0xf8, 0x3, 0x40, 0x1f, 0xfd, + 0x23, 0x80, 0xf, 0xfe, 0x1, 0x48, 0x7, 0xff, + 0x9, 0x58, 0x3, 0xff, 0x80, 0x90, 0x1, 0xff, + 0xd0, 0x1d, 0x0, 0xff, 0xe0, 0xf8, 0x7, 0xff, + 0x12, 0x48, 0x3, 0xff, 0x80, 0xe8, 0x1, 0xff, + 0xcf, 0xa1, 0x0, 0xff, 0xe0, 0x49, 0x0, 0x7f, + 0xf1, 0x78, 0x3, 0xff, 0x83, 0x42, 0x1, 0xff, + 0xcd, 0x74, 0x0, 0xff, 0xe0, 0x2b, 0x0, 0x7f, + 0xf1, 0x8e, 0x40, 0x3f, 0xf8, 0x3, 0x40, 0x1f, + 0xfc, 0xc3, 0x80, 0xf, 0xfe, 0x0, 0xd8, 0x7, + 0xff, 0x21, 0x90, 0x3, 0xff, 0x80, 0x90, 0x1, + 0xff, 0xca, 0x1d, 0x0, 0xff, 0xe0, 0xe8, 0x80, + 0x7f, 0xf2, 0x68, 0x40, 0x3f, 0xf8, 0xe, 0x80, + 0x1f, 0xfc, 0x9a, 0x10, 0xf, 0xfe, 0x3, 0x98, + 0x7, 0xff, 0x28, 0x68, 0x3, 0xff, 0x83, 0x42, + 0x1, 0xff, 0xc7, 0x74, 0x0, 0xff, 0xe0, 0x1c, + 0x0, 0x7f, 0xf3, 0x11, 0xc0, 0x3f, 0xf8, 0x3, + 0x40, 0x1f, 0xfc, 0x63, 0x80, 0xf, 0xfe, 0xf, + 0x0, 0x7f, 0xf3, 0xa0, 0xc0, 0x3f, 0xf8, 0x8, + 0xe0, 0x1f, 0xfc, 0x41, 0xd0, 0xf, 0xfe, 0xd, + 0x10, 0x7, 0xff, 0x3f, 0x80, 0x3f, 0xf8, 0x30, + 0x80, 0x1f, 0xfc, 0x3a, 0x10, 0xf, 0xfe, 0x3, + 0x28, 0x7, 0xff, 0x40, 0xa8, 0x3, 0xff, 0x83, + 0x42, 0x1, 0xff, 0xc1, 0x74, 0x0, 0xff, 0xe0, + 0x14, 0x80, 0x7f, 0xf4, 0x95, 0x40, 0x1f, 0xfc, + 0x1, 0xa0, 0xf, 0xfe, 0x1, 0xc0, 0x7, 0xff, + 0x7, 0x80, 0x3f, 0xfa, 0x94, 0x40, 0x1f, 0xfc, + 0x4, 0x70, 0xf, 0xf0, 0xf0, 0x7, 0xff, 0x6, + 0xc, 0x3, 0xff, 0xab, 0xc0, 0x1f, 0xfc, 0x18, + 0x30, 0xf, 0xeb, 0x20, 0xf, 0xfe, 0x2, 0x38, + 0x7, 0xff, 0x58, 0xe0, 0x3, 0xff, 0x83, 0xa2, + 0x1, 0xf3, 0x28, 0x7, 0xff, 0x0, 0x68, 0x3, + 0xff, 0xb0, 0xe8, 0x1, 0xff, 0xc0, 0x1a, 0x0, + 0xf1, 0xc8, 0x7, 0xff, 0x6, 0x84, 0x3, 0xff, + 0xb3, 0x42, 0x1, 0xff, 0xc0, 0x47, 0x0, 0xee, + 0x0, 0xff, 0xe0, 0xba, 0x0, 0x7f, 0xf6, 0x86, + 0x80, 0x3f, 0xf8, 0x30, 0x60, 0x15, 0x10, 0x7, + 0xff, 0x0, 0xe0, 0x3, 0xff, 0xb8, 0x8e, 0x1, + 0xff, 0xc1, 0xd1, 0x6, 0x50, 0xf, 0xfe, 0xf, + 0x0, 0x7f, 0xf7, 0xa0, 0xc0, 0x3f, 0xf8, 0x3, + 0x40, + + /* U+007E "~" */ + 0x0, 0xff, 0xe0, 0x8a, 0x45, 0x67, 0x73, 0xfd, + 0xdb, 0x94, 0xe8, 0x20, 0x1f, 0xfd, 0xe6, 0x30, + 0xf, 0xf1, 0x3e, 0x75, 0xba, 0x98, 0x88, 0x0, + 0x24, 0x6b, 0x17, 0xdb, 0x6, 0x1, 0xff, 0xda, + 0x89, 0x70, 0xf, 0xc9, 0x7b, 0x6, 0x1, 0xff, + 0xc4, 0x27, 0xcd, 0x71, 0x0, 0xff, 0xea, 0x8e, + 0x38, 0x7, 0xe4, 0xdb, 0x40, 0xf, 0xfe, 0x51, + 0x47, 0x5a, 0x0, 0x7f, 0xf4, 0x97, 0xcc, 0x3, + 0xe2, 0xbb, 0x10, 0x7, 0xff, 0x3d, 0x2f, 0x54, + 0x3, 0xff, 0x9c, 0x37, 0x42, 0x1, 0xf3, 0xea, + 0x0, 0x7f, 0xf4, 0xca, 0xb9, 0xc4, 0x3, 0xff, + 0x95, 0x1c, 0x80, 0x1f, 0x16, 0x40, 0x7, 0xff, + 0x5c, 0x63, 0xa5, 0x0, 0x3f, 0xf8, 0xa2, 0xfc, + 0xe0, 0x1f, 0x97, 0x4c, 0x3, 0xff, 0xb6, 0xd7, + 0xd2, 0x82, 0x1, 0xfe, 0x15, 0xbe, 0x81, 0x0, + 0xfe, 0xa0, 0xf, 0xfe, 0xf8, 0xb5, 0xf6, 0xd4, + 0x3b, 0x31, 0xe2, 0xb7, 0xa9, 0x0, 0x3f, 0xfe, + 0x4, 0xaf, 0x13, 0x28, 0x75, 0x20, 0xf, 0xff, + 0xf8, 0x7, 0xff, 0x40, 0x91, 0xdd, 0x10, 0x76, + 0x53, 0x0, 0xff, 0xf7, 0x93, 0xdf, 0xed, 0xc4, + 0x1d, 0xd1, 0x35, 0x9f, 0xb2, 0xa0, 0x1f, 0xfd, + 0xe6, 0x40, 0xf, 0xe5, 0xcd, 0x84, 0x0, 0xff, + 0xe0, 0x13, 0x57, 0xda, 0x80, 0x7f, 0xf6, 0xaa, + 0x40, 0x3f, 0x2e, 0xd1, 0x80, 0x7f, 0xf1, 0xd2, + 0xba, 0x8, 0x3, 0xff, 0xaa, 0x9c, 0xa0, 0x1f, + 0x16, 0x51, 0x0, 0x7f, 0xf2, 0xc5, 0xf6, 0xd0, + 0x3, 0xff, 0xa2, 0x33, 0x62, 0x1, 0xf4, 0x69, + 0x80, 0x7f, 0xf4, 0x12, 0xf5, 0x80, 0x3f, 0xf9, + 0xcf, 0xcc, 0x1, 0xf1, 0x63, 0x80, 0x7f, 0xf5, + 0xa, 0x7e, 0x48, 0x3, 0xff, 0x90, 0x2f, 0xd0, + 0x1, 0xf9, 0x30, 0xc0, 0x3f, 0xfb, 0xd, 0xba, + 0x72, 0x0, 0xff, 0xe1, 0xad, 0x74, 0x8, 0x7, + 0xe6, 0xb1, 0x0, 0xff, 0xed, 0x94, 0x6f, 0x53, + 0xa1, 0x8, 0x0, 0x44, 0x6b, 0x19, 0xf4, 0xa0, + 0x1f, 0xf0, + + /* U+00B7 "·" */ + 0x0, 0xff, 0xe3, 0x4f, 0xff, 0xff, 0x12, 0x80, + 0x3f, 0xff, 0xe0, 0x1f, 0xff, 0xf0, 0xf, 0xff, + 0xf8, 0x7, 0xff, 0xfc, 0x3, 0xff, 0xe0 +}; + + +/*--------------------- + * 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 = 1349, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 0, .adv_w = 1349, .box_w = 36, .box_h = 12, .ofs_x = 24, .ofs_y = 33}, + {.bitmap_index = 23, .adv_w = 1349, .box_w = 18, .box_h = 21, .ofs_x = 33, .ofs_y = 0}, + {.bitmap_index = 43, .adv_w = 1349, .box_w = 68, .box_h = 116, .ofs_x = 6, .ofs_y = -13}, + {.bitmap_index = 898, .adv_w = 1349, .box_w = 73, .box_h = 70, .ofs_x = 6, .ofs_y = 9}, + {.bitmap_index = 1484, .adv_w = 1349, .box_w = 73, .box_h = 40, .ofs_x = 6, .ofs_y = 24}, + {.bitmap_index = 1612, .adv_w = 1349, .box_w = 73, .box_h = 70, .ofs_x = 6, .ofs_y = 9}, + {.bitmap_index = 2193, .adv_w = 1349, .box_w = 69, .box_h = 107, .ofs_x = 8, .ofs_y = -2}, + {.bitmap_index = 3439, .adv_w = 1349, .box_w = 68, .box_h = 116, .ofs_x = 6, .ofs_y = -13}, + {.bitmap_index = 4288, .adv_w = 1349, .box_w = 76, .box_h = 39, .ofs_x = 4, .ofs_y = 64}, + {.bitmap_index = 4792, .adv_w = 1349, .box_w = 85, .box_h = 6, .ofs_x = 0, .ofs_y = -33}, + {.bitmap_index = 4819, .adv_w = 1349, .box_w = 66, .box_h = 81, .ofs_x = 9, .ofs_y = -2}, + {.bitmap_index = 5798, .adv_w = 1349, .box_w = 75, .box_h = 78, .ofs_x = 5, .ofs_y = 0}, + {.bitmap_index = 6863, .adv_w = 1349, .box_w = 73, .box_h = 20, .ofs_x = 6, .ofs_y = 34}, + {.bitmap_index = 7137, .adv_w = 1349, .box_w = 18, .box_h = 22, .ofs_x = 33, .ofs_y = 39} +}; + +/*--------------------- + * CHARACTER MAPPING + *--------------------*/ + +static const uint16_t unicode_list_0[] = { + 0x0, 0xd, 0xe, 0xf, 0x1c, 0x1d, 0x1e, 0x2f, + 0x3c, 0x3e, 0x3f, 0x4f, 0x58, 0x5e, 0x97 +}; + +/*Collect the unicode lists and glyph_id offsets*/ +static const lv_font_fmt_txt_cmap_t cmaps[] = +{ + { + .range_start = 32, .range_length = 152, .glyph_id_start = 1, + .unicode_list = unicode_list_0, .glyph_id_ofs_list = NULL, .list_length = 15, .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 = 1, +#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 font_face_140 = { +#else +lv_font_t font_face_140 = { +#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 = 138, /*The maximum line height required by the font*/ + .base_line = 33, /*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 = -9, + .underline_thickness = 6, +#endif + .dsc = &font_dsc, /*The custom font data. Will be accessed by `get_glyph_bitmap/dsc` */ +#if LV_VERSION_CHECK(8, 2, 0) || LVGL_VERSION_MAJOR >= 9 + .fallback = NULL, +#endif + .user_data = NULL, +}; + + + +#endif /*#if FONT_FACE_140*/ + diff --git a/firmware/main/fonts/font_rage_64.c b/firmware/main/fonts/font_rage_64.c new file mode 100644 index 0000000..b6471a0 --- /dev/null +++ b/firmware/main/fonts/font_rage_64.c @@ -0,0 +1,425 @@ +/******************************************************************************* + * Size: 64 px + * Bpp: 4 + * Opts: --font /usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf -r 0x20,0x28,0x29,0x5F,0xB0,0xBA --font /tmp/claude-1000/-mnt-media-Projects-desklock/a3bb8d9c-268f-465a-b40b-889c5b60f451/scratchpad/NotoMonoCJKJP.ttf -r 0x25A1,0x2500,0x2501,0x252C,0x253B,0x256F,0x30CE,0xFE35 --size 64 --bpp 4 --format lvgl --lv-font-name font_rage_64 -o font_rage_64.c + ******************************************************************************/ + +#ifdef LV_LVGL_H_INCLUDE_SIMPLE +#include "lvgl.h" +#else +#include "lvgl/lvgl.h" +#endif + +#ifndef FONT_RAGE_64 +#define FONT_RAGE_64 1 +#endif + +#if FONT_RAGE_64 + +/*----------------- + * BITMAPS + *----------------*/ + +/*Store the image of the glyphs*/ +static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { + /* U+0020 " " */ + + /* U+0028 "(" */ + 0x0, 0xfe, 0xaf, 0xfc, 0xc0, 0x1f, 0x8d, 0x40, + 0x22, 0x60, 0xf, 0xdc, 0x1, 0xa4, 0x3, 0xf3, + 0x90, 0x4, 0x88, 0x0, 0xfd, 0x20, 0x1b, 0xc0, + 0x3f, 0x40, 0x80, 0x46, 0x80, 0x1f, 0xb, 0x80, + 0x69, 0x0, 0xfd, 0x20, 0x18, 0x94, 0x3, 0xf3, + 0x80, 0x6a, 0x0, 0xfc, 0xe0, 0x1c, 0xc0, 0x1f, + 0xa4, 0x3, 0x28, 0x80, 0x7c, 0x82, 0x1, 0xbc, + 0x3, 0xf7, 0x0, 0x72, 0x80, 0x7e, 0x50, 0xc, + 0xa0, 0x1f, 0x98, 0x3, 0xb0, 0x3, 0xf6, 0x0, + 0x73, 0x80, 0x7e, 0x50, 0xc, 0x42, 0x1, 0xf2, + 0x0, 0x72, 0x0, 0x7e, 0x30, 0xe, 0xf0, 0xf, + 0xd8, 0x1, 0xca, 0x1, 0xf9, 0x40, 0x38, 0x80, + 0x3e, 0x11, 0x0, 0x61, 0x10, 0x7, 0xc4, 0x1, + 0xc4, 0x1, 0xf9, 0x80, 0x39, 0x80, 0x3f, 0x10, + 0x7, 0x18, 0x7, 0xee, 0x0, 0xe1, 0x0, 0xff, + 0xe1, 0x78, 0x7, 0xe3, 0x0, 0xff, 0xe4, 0x8, + 0x7, 0xff, 0x8, 0x40, 0x3f, 0x18, 0x7, 0xff, + 0x23, 0xc0, 0x3f, 0x70, 0x7, 0x8, 0x7, 0xe2, + 0x0, 0xe2, 0x0, 0xfc, 0xc0, 0x1c, 0xe0, 0x1f, + 0x88, 0x3, 0x88, 0x3, 0xf0, 0x88, 0x3, 0x8, + 0x80, 0x3f, 0x28, 0x7, 0x28, 0x7, 0xec, 0x0, + 0xe2, 0x0, 0xfc, 0x80, 0x1d, 0x80, 0x1f, 0x8c, + 0x3, 0x90, 0x3, 0xf9, 0x40, 0x30, 0x90, 0x7, + 0xef, 0x0, 0xe4, 0x0, 0xfc, 0xa0, 0x1d, 0xa0, + 0x1f, 0xca, 0x1, 0x90, 0x3, 0xfb, 0x80, 0x39, + 0x40, 0x3f, 0x21, 0x0, 0x6e, 0x0, 0xfe, 0xb0, + 0xc, 0x82, 0x1, 0xf9, 0x84, 0x3, 0x30, 0x7, + 0xf3, 0x0, 0x69, 0x0, 0xfe, 0x90, 0xc, 0x2a, + 0x1, 0xf8, 0x5c, 0x3, 0x48, 0x7, 0xf4, 0x8, + 0x4, 0x68, 0x1, 0xfd, 0x0, 0x1a, 0x0, 0x3f, + 0x98, 0x80, 0x23, 0x40, 0xf, 0xee, 0x0, 0xd2, + 0x1, 0xfc, 0x6a, 0x1, 0x13, 0x0, + + /* U+0029 ")" */ + 0xd, 0xff, 0xc4, 0x1, 0xfe, 0x90, 0xd, 0xc0, + 0x1f, 0xe4, 0x30, 0x8, 0xd8, 0x3, 0xfd, 0xe0, + 0x1a, 0x0, 0x3f, 0xc6, 0x80, 0x10, 0xc0, 0x7, + 0xfb, 0xc0, 0x33, 0x88, 0x7, 0xf2, 0x18, 0x6, + 0x80, 0xf, 0xf4, 0x80, 0x66, 0x10, 0xf, 0xe5, + 0x10, 0xd, 0x20, 0x1f, 0xe6, 0x0, 0xcc, 0x1, + 0xfe, 0xa0, 0xc, 0x2c, 0x1, 0xfc, 0x44, 0x0, + 0xd6, 0x1, 0xfe, 0xa0, 0xc, 0x44, 0x0, 0xfe, + 0x50, 0xe, 0xa0, 0xf, 0xe2, 0x20, 0x6, 0x60, + 0xf, 0xf2, 0x0, 0x61, 0x30, 0xf, 0xec, 0x0, + 0xe4, 0x0, 0xfe, 0x40, 0xe, 0xb0, 0xf, 0xe1, + 0x10, 0x6, 0x30, 0xf, 0xf2, 0x80, 0x71, 0x80, + 0x7f, 0x18, 0x7, 0x28, 0x7, 0xf7, 0x0, 0x76, + 0x0, 0x7f, 0x10, 0x7, 0x30, 0x7, 0xf3, 0x0, + 0x71, 0x0, 0x7f, 0x10, 0x7, 0x8, 0x7, 0xff, + 0x10, 0x40, 0x3f, 0xf8, 0x66, 0x1, 0xfc, 0x20, + 0x1f, 0xfc, 0x91, 0x0, 0xff, 0xe1, 0x88, 0x7, + 0xf0, 0x80, 0x7f, 0xf2, 0x4c, 0x3, 0xff, 0x86, + 0x20, 0x1f, 0x88, 0x3, 0x84, 0x3, 0xf9, 0x80, + 0x38, 0x80, 0x3f, 0x88, 0x3, 0x98, 0x3, 0xfb, + 0x80, 0x3b, 0x0, 0x3f, 0x8c, 0x3, 0x94, 0x3, + 0xf9, 0x40, 0x38, 0xc0, 0x3f, 0x10, 0x80, 0x63, + 0x0, 0xfe, 0x40, 0xe, 0xb0, 0xf, 0xec, 0x0, + 0xe4, 0x0, 0xfe, 0x40, 0xc, 0x26, 0x1, 0xf8, + 0xc4, 0x3, 0x30, 0x7, 0xf5, 0x80, 0x75, 0x80, + 0x7f, 0x28, 0x6, 0x23, 0x0, 0xfc, 0x64, 0x1, + 0xac, 0x3, 0xfa, 0x80, 0x30, 0xb0, 0x7, 0xf3, + 0x0, 0x66, 0x0, 0xfe, 0x60, 0xe, 0x90, 0xf, + 0xeb, 0x0, 0xcc, 0x20, 0x1f, 0x90, 0x80, 0x34, + 0x0, 0x7f, 0x40, 0x6, 0x71, 0x0, 0xfc, 0x66, + 0x0, 0x86, 0x0, 0x3f, 0xbc, 0x3, 0x40, 0x7, + 0xf2, 0x98, 0x4, 0x6c, 0x1, 0xfd, 0x0, 0x1b, + 0xc0, 0x3f, 0x80, + + /* U+005F "_" */ + 0x88, 0xff, 0xed, 0x23, 0xbf, 0xff, 0x6b, 0x0, + 0x3f, 0xfb, 0x60, + + /* U+00B0 "°" */ + 0x0, 0xf2, 0x4e, 0xf7, 0xf5, 0xb0, 0x80, 0x7f, + 0x8f, 0x2d, 0x88, 0x40, 0x52, 0x79, 0xc0, 0x3f, + 0x2e, 0x18, 0x7, 0xf4, 0x58, 0x7, 0x92, 0x80, + 0x3f, 0xf8, 0x9, 0x60, 0x18, 0x68, 0x3, 0x25, + 0x77, 0x31, 0xc0, 0x32, 0x40, 0x5, 0x2, 0x1, + 0x4d, 0xa8, 0x88, 0xe3, 0x8c, 0x2, 0x71, 0x0, + 0x30, 0x5, 0xc, 0x1, 0xe1, 0xd1, 0x0, 0xa4, + 0x14, 0x2, 0x27, 0x0, 0xfc, 0x36, 0x1, 0x28, + 0x68, 0x4, 0xa0, 0x1f, 0xe5, 0x0, 0x88, 0x4, + 0x2, 0xd0, 0xf, 0xf8, 0x80, 0x22, 0x0, 0xff, + 0xe4, 0x88, 0x4, 0x40, 0x1f, 0xf1, 0x0, 0x45, + 0xa0, 0x15, 0x80, 0x7f, 0x94, 0x2, 0x10, 0x40, + 0x8, 0xd4, 0x3, 0xfa, 0x0, 0x27, 0x1, 0x40, + 0xa, 0x90, 0x3, 0xc3, 0x84, 0x1, 0x58, 0x2, + 0x40, 0x35, 0xd1, 0x80, 0x9, 0xfc, 0xc0, 0x26, + 0x20, 0x1, 0x48, 0x6, 0x5c, 0xff, 0x6c, 0x8, + 0x4, 0x72, 0x1, 0x9a, 0x0, 0x3f, 0xf8, 0x9, + 0xa0, 0x1e, 0x7b, 0x20, 0xf, 0xe7, 0xb1, 0x0, + 0xf9, 0x36, 0x94, 0x80, 0x2, 0x91, 0xd0, 0x1, + 0xc0, + + /* U+00BA "º" */ + 0x0, 0xfe, 0x35, 0x67, 0x64, 0x10, 0xf, 0xfe, + 0x10, 0xcf, 0x65, 0x4c, 0x4d, 0xf6, 0x28, 0x7, + 0xfc, 0xfc, 0xc2, 0x1, 0xf1, 0xd6, 0x10, 0x7, + 0xea, 0x80, 0xf, 0xfe, 0x1, 0xe1, 0x80, 0x7a, + 0x54, 0x3, 0x1c, 0xde, 0x5b, 0x8, 0x4, 0x38, + 0x40, 0x19, 0x58, 0x3, 0x4e, 0x32, 0x1a, 0x4f, + 0xa0, 0x6, 0xf0, 0xd, 0x0, 0x1a, 0x98, 0x3, + 0xc3, 0x66, 0x1, 0x13, 0x0, 0x14, 0x80, 0x24, + 0x50, 0xf, 0xef, 0x0, 0xd6, 0x0, 0xe0, 0xd, + 0xe0, 0x1f, 0xe3, 0x40, 0x8, 0x8c, 0x14, 0x2, + 0x14, 0x0, 0xff, 0xb4, 0x3, 0x21, 0x8, 0x4, + 0xa0, 0x1f, 0xfc, 0x5, 0x0, 0xda, 0xc0, 0x18, + 0x80, 0x3f, 0xf8, 0x6, 0x1, 0x98, 0x40, 0x30, + 0x80, 0x7f, 0xf1, 0x44, 0x3, 0xbc, 0x3, 0xff, + 0x8a, 0x62, 0x1, 0xbc, 0x3, 0xff, 0x8a, 0x6e, + 0x1, 0x84, 0x3, 0xff, 0x80, 0x20, 0x19, 0x88, + 0x3, 0x28, 0x7, 0xff, 0x1, 0x40, 0x31, 0x9, + 0x0, 0x46, 0x20, 0x1f, 0xf6, 0x80, 0x6c, 0x5, + 0x0, 0xce, 0x1, 0xff, 0x38, 0x6, 0x40, 0xa0, + 0xd, 0x2, 0x1, 0xfd, 0x2, 0x1, 0x28, 0x81, + 0x28, 0x4, 0x34, 0x1, 0xf9, 0x5c, 0x3, 0x48, + 0x5, 0x62, 0x1, 0x26, 0x98, 0x6, 0x18, 0xa0, + 0xc, 0xe6, 0x1, 0xd, 0x0, 0x62, 0xce, 0xba, + 0xce, 0x70, 0xc, 0x90, 0x1, 0xc9, 0x82, 0x1, + 0x85, 0x14, 0xc0, 0x39, 0x6c, 0x3, 0xe3, 0xf6, + 0x0, 0xff, 0x15, 0x50, 0x3, 0xf8, 0x67, 0x65, + 0x8, 0x0, 0x26, 0xd7, 0xaa, 0x1, 0xff, 0xc0, + 0x26, 0xbd, 0xff, 0x76, 0x4a, 0x0, 0x7f, 0xfb, + 0x17, 0x77, 0xff, 0x91, 0x40, 0x3, 0x22, 0xff, + 0xe4, 0x30, 0x7, 0xff, 0x94, + + /* U+2500 "─" */ + 0x99, 0xff, 0xfa, 0x33, 0x7f, 0xfd, 0x0, 0x3f, + 0xfe, 0x80, + + /* U+2501 "━" */ + 0x0, 0xff, 0xfa, 0x7f, 0xff, 0xfd, 0x0, 0x3f, + 0xff, 0xe0, 0x1f, 0xff, 0xf0, 0xf, 0xff, 0xf8, + 0x7, 0xff, 0xfc, 0x3, 0xff, 0xfe, 0x1, 0xfc, + 0xcd, 0xff, 0xf4, + + /* U+252C "┬" */ + 0x99, 0xff, 0xfa, 0x33, 0x7f, 0xfd, 0x0, 0x3f, + 0xfe, 0x9f, 0xff, 0xfd, 0x2b, 0x0, 0x5f, 0xff, + 0xff, 0x48, 0x3, 0xff, 0xfe, 0x1, 0xff, 0xff, + 0x0, 0xff, 0xff, 0x80, 0x7f, 0xff, 0xc0, 0x3f, + 0xff, 0xe0, 0x1f, 0xff, 0xf0, 0xf, 0xff, 0xf8, + 0x7, 0xff, 0xfc, 0x3, 0xff, 0xfe, 0x1, 0xff, + 0xff, 0x0, 0xff, 0xff, 0x80, 0x7f, 0xff, 0xc0, + 0x3f, 0xff, 0xe0, 0x1f, 0xff, 0xf0, 0xf, 0xff, + 0xf8, 0x7, 0xff, 0xfc, 0x3, 0xff, 0xfe, 0x1, + 0xff, 0xff, 0x0, 0xff, 0xff, 0x80, 0x7f, 0xff, + 0xc0, 0x3f, 0xff, 0xe0, 0x1f, 0xff, 0xf0, 0xf, + 0xff, 0xf8, 0x7, 0xff, 0xfc, 0x3, 0xff, 0xfe, + 0x1, 0xff, 0x3a, 0xa9, 0xc0, 0x3f, 0xfa, 0x40, + + /* U+253B "┻" */ + 0x0, 0xff, 0xe8, 0x11, 0x9f, 0x88, 0x3, 0xff, + 0xd9, 0xf9, 0x9e, 0xf0, 0xf, 0xff, 0xf8, 0x7, + 0xff, 0xfc, 0x3, 0xff, 0xfe, 0x1, 0xff, 0xff, + 0x0, 0xff, 0xff, 0x80, 0x7f, 0xff, 0xc0, 0x3f, + 0xff, 0xe0, 0x1f, 0xff, 0xf0, 0xf, 0xff, 0xf8, + 0x7, 0xff, 0xfc, 0x3, 0xff, 0xfe, 0x1, 0xff, + 0xff, 0x0, 0xff, 0xff, 0x80, 0x7f, 0xff, 0xc0, + 0x3f, 0xff, 0xe0, 0x1f, 0xff, 0xf0, 0xf, 0xff, + 0xf8, 0x7, 0xff, 0xfc, 0x3, 0xff, 0xfe, 0x1, + 0xff, 0xff, 0x0, 0xff, 0xff, 0x80, 0x7f, 0xff, + 0xc0, 0x3f, 0xff, 0xe0, 0x1f, 0xfd, 0x3f, 0xff, + 0xfe, 0x81, 0x0, 0x78, 0xbf, 0xff, 0xfa, 0x0, + 0x1f, 0xff, 0xf0, 0xf, 0xff, 0xf8, 0x7, 0xff, + 0xfc, 0x3, 0xff, 0xfe, 0x1, 0xff, 0xff, 0x0, + 0xfe, 0x66, 0xff, 0xfa, 0x0, + + /* U+256F "╯" */ + 0x0, 0xff, 0xe9, 0xa, 0x20, 0x40, 0x3f, 0xfa, + 0x4b, 0x76, 0x50, 0xf, 0xfe, 0x90, 0x80, 0x1c, + 0x3, 0xff, 0xa4, 0x60, 0x1, 0x0, 0xff, 0xe9, + 0x70, 0x0, 0xc0, 0x3f, 0xfa, 0x44, 0x2, 0x20, + 0xf, 0xfe, 0x93, 0x1, 0x0, 0x7f, 0xf4, 0xcc, + 0x14, 0x3, 0xff, 0xa4, 0x80, 0xc, 0x0, 0xff, + 0xe9, 0x60, 0x1, 0x0, 0x3f, 0xfa, 0x4a, 0x4, + 0x20, 0x1f, 0xfd, 0x13, 0x20, 0xa0, 0xf, 0xfe, + 0x95, 0x0, 0x14, 0x3, 0xff, 0xa2, 0x2c, 0x6, + 0x40, 0x1f, 0xfd, 0x19, 0x0, 0x40, 0x7, 0xff, + 0x44, 0x5c, 0xd, 0x0, 0x3f, 0xfa, 0x36, 0x0, + 0x80, 0xf, 0xfe, 0x8a, 0x28, 0x22, 0x0, 0x3f, + 0xfa, 0x3, 0x40, 0x9, 0x0, 0xff, 0xe8, 0xe8, + 0x84, 0x10, 0x7, 0xff, 0x42, 0x8c, 0x15, 0xc0, + 0x3f, 0xfa, 0xe, 0xa0, 0x74, 0x1, 0xff, 0xd0, + 0x68, 0x1, 0xd0, 0xf, 0xfe, 0x84, 0x48, 0x3, + 0x44, 0x3, 0xff, 0x9f, 0x6e, 0x0, 0xb3, 0x0, + 0xff, 0xe7, 0x16, 0xa0, 0x16, 0xa0, 0x7, 0xff, + 0x39, 0xf4, 0x81, 0x30, 0x80, 0x3f, 0xf9, 0xab, + 0xd0, 0x0, 0x6b, 0x10, 0xf, 0xfe, 0x62, 0x6d, + 0x8, 0xd, 0x48, 0x7, 0xff, 0x2c, 0x5f, 0x6c, + 0x80, 0xd, 0xca, 0x1, 0xff, 0xc8, 0x14, 0x8c, + 0xe8, 0x20, 0x3, 0x6c, 0x80, 0x7f, 0xf1, 0x66, + 0xaf, 0x3f, 0xad, 0xcc, 0x0, 0x2f, 0xd2, 0x40, + 0x1f, 0xfc, 0x66, 0x54, 0x30, 0xc, 0x4d, 0x7d, + 0x2, 0x1, 0xff, 0xc8, 0x11, 0x11, 0xac, 0x57, + 0x6c, 0xa0, 0x7, 0xff, 0x2c, + + /* U+25A1 "□" */ + 0x6f, 0xff, 0xff, 0x37, 0x0, 0x7f, 0xfa, 0xe6, + 0x7f, 0xfc, 0x4a, 0x1, 0x85, 0x9b, 0xff, 0xc5, + 0x80, 0x1f, 0xff, 0xf0, 0xf, 0xff, 0xf8, 0x7, + 0xff, 0xfc, 0x3, 0xff, 0xfe, 0x1, 0xff, 0xff, + 0x0, 0xff, 0xff, 0x80, 0x7f, 0xff, 0xc0, 0x3f, + 0xff, 0xe0, 0x1f, 0xff, 0xf0, 0xf, 0xff, 0xf8, + 0x7, 0xff, 0xfc, 0x3, 0xff, 0xfe, 0x1, 0xff, + 0xff, 0x0, 0xff, 0xff, 0x80, 0x7f, 0xff, 0xc0, + 0x3f, 0xff, 0xe0, 0x1f, 0xff, 0xf0, 0xf, 0xff, + 0xf8, 0x7, 0xff, 0xfc, 0x3, 0xff, 0xfe, 0x1, + 0xff, 0xff, 0x0, 0xff, 0xff, 0x80, 0x7f, 0xff, + 0xc0, 0x3f, 0xff, 0xe0, 0x1f, 0xff, 0xf0, 0xf, + 0xff, 0xf8, 0x7, 0xff, 0xfc, 0x3, 0xff, 0xfe, + 0x1, 0xff, 0xff, 0x0, 0xff, 0xff, 0x80, 0x7f, + 0xf7, 0xc4, 0x7f, 0xfc, 0x60, 0x18, 0x7b, 0xbf, + 0xfc, 0x50, 0x1, 0xff, 0xea, 0x7b, 0xbf, 0xff, + 0x35, 0x0, + + /* U+30CE "ノ" */ + 0x0, 0xff, 0xec, 0xba, 0x88, 0x7, 0xff, 0x70, + 0x62, 0xbb, 0x20, 0xc0, 0x3f, 0xfb, 0x28, 0x1, + 0x1b, 0xe1, 0x0, 0x7f, 0xf6, 0x30, 0x3, 0x90, + 0x80, 0x3f, 0xfb, 0x8, 0x1, 0xdc, 0x1, 0xff, + 0xd8, 0x12, 0x0, 0xe5, 0x0, 0xff, 0xec, 0x20, + 0x7, 0x28, 0x7, 0xff, 0x67, 0xc0, 0x3b, 0x80, + 0x3f, 0xfb, 0x2a, 0x1, 0x85, 0x0, 0x3f, 0xfb, + 0xa, 0x1, 0xcc, 0x1, 0xff, 0xd9, 0xe0, 0xe, + 0xa0, 0xf, 0xfe, 0xc1, 0x20, 0x6, 0x32, 0x0, + 0xff, 0xec, 0x28, 0x7, 0x50, 0x7, 0xff, 0x66, + 0x80, 0x39, 0x80, 0x3f, 0xfb, 0x8, 0x40, 0x19, + 0xc0, 0x3f, 0xfb, 0x3e, 0x1, 0xd4, 0x1, 0xff, + 0xd8, 0x34, 0x0, 0xc8, 0x40, 0x1f, 0xfd, 0x88, + 0x0, 0xef, 0x0, 0xff, 0xec, 0x22, 0x0, 0x31, + 0x20, 0x7, 0xff, 0x62, 0x0, 0x3a, 0x0, 0x3f, + 0xfb, 0x8, 0x60, 0x18, 0x94, 0x3, 0xff, 0xb1, + 0x0, 0x1d, 0x20, 0x1f, 0xfd, 0x86, 0x30, 0xc, + 0x68, 0x1, 0xff, 0xd7, 0x19, 0x0, 0xef, 0x0, + 0xff, 0xec, 0x58, 0x7, 0x21, 0x80, 0x7f, 0xf5, + 0xd9, 0x40, 0x3a, 0x40, 0x3f, 0xfa, 0xe5, 0x20, + 0x1d, 0x4, 0x1, 0xff, 0xd7, 0xf0, 0xe, 0x37, + 0x0, 0xff, 0xeb, 0xd9, 0x0, 0x77, 0x0, 0x7f, + 0xf5, 0xe5, 0x0, 0x3a, 0x8, 0x3, 0xff, 0xad, + 0xc, 0x1, 0xc6, 0xe0, 0x1f, 0xfd, 0x68, 0x70, + 0xe, 0x1d, 0x0, 0xff, 0xeb, 0x43, 0x80, 0x7b, + 0x44, 0x3, 0xff, 0xab, 0x4e, 0x1, 0xeb, 0x30, + 0xf, 0xfe, 0xa1, 0x6a, 0x80, 0x7a, 0x90, 0x3, + 0xff, 0xa8, 0x98, 0x40, 0x1e, 0x95, 0x0, 0xff, + 0xea, 0x3d, 0x88, 0x7, 0xa9, 0x80, 0x3f, 0xfa, + 0x63, 0x50, 0x1, 0xe1, 0xb5, 0x0, 0xff, 0xe9, + 0xb7, 0xa8, 0x7, 0x8b, 0x10, 0x3, 0xff, 0xa4, + 0x79, 0x22, 0x1, 0xe3, 0xc2, 0x0, 0xff, 0xe9, + 0x4e, 0x18, 0x7, 0xcb, 0x82, 0x1, 0xff, 0xd1, + 0x6e, 0x60, 0xf, 0xd1, 0x40, 0x1f, 0xfd, 0x17, + 0xe9, 0x10, 0xf, 0x8f, 0x5c, 0x3, 0xff, 0x9e, + 0x53, 0xd0, 0x20, 0x1f, 0xa3, 0x8, 0x3, 0xff, + 0x9f, 0x5a, 0xc2, 0x1, 0xf8, 0xb1, 0xc0, 0x3f, + 0xfa, 0x30, 0x20, 0x1f, 0xcf, 0xa6, 0x1, 0xff, + 0xd2, 0x2c, 0x10, 0xf, 0x2f, 0x40, 0x7, 0xff, + 0x54, 0xb0, 0x40, 0x24, 0xca, 0x10, 0xf, 0xfe, + 0xb9, 0x68, 0xb6, 0xd9, 0x80, 0x7f, 0xf6, 0x8f, + 0xa4, 0x80, 0x3f, 0xfb, 0x0, + + /* U+FE35 "︵" */ + 0x0, 0xff, 0xe5, 0x92, 0xbc, 0xd5, 0xe6, 0xeb, + 0x2e, 0xa5, 0xd4, 0x80, 0x3f, 0xfb, 0xc9, 0x19, + 0xfb, 0x50, 0xca, 0x86, 0x44, 0x34, 0x56, 0x8a, + 0xdf, 0xc8, 0x40, 0xf, 0xfe, 0xba, 0x57, 0xdb, + 0x98, 0x7, 0xff, 0x18, 0xde, 0xfe, 0x90, 0x3, + 0xff, 0xa2, 0x51, 0xd6, 0xa0, 0x1f, 0xfc, 0xe5, + 0xbe, 0x82, 0x0, 0xff, 0xe6, 0x14, 0xeb, 0x88, + 0x7, 0xff, 0x4, 0x48, 0x82, 0x1, 0xff, 0xc1, + 0x17, 0xd9, 0x20, 0xf, 0xfe, 0x40, 0xce, 0xb0, + 0x7, 0xf2, 0x3c, 0xe7, 0x7f, 0xbb, 0x75, 0xdf, + 0xee, 0xc9, 0x74, 0x0, 0xfe, 0x6d, 0x91, 0x0, + 0xff, 0xe2, 0xb7, 0xb0, 0x7, 0xc4, 0xf9, 0xf7, + 0xc, 0x62, 0x1, 0xf8, 0x4d, 0xa2, 0xfe, 0xdc, + 0x80, 0x3e, 0x6f, 0x60, 0xf, 0xfe, 0x11, 0x64, + 0x88, 0x7, 0xb, 0x66, 0xc1, 0x80, 0x7f, 0xf2, + 0x12, 0x37, 0x18, 0x40, 0x38, 0x67, 0x8, 0x3, + 0xfe, 0x5d, 0x30, 0xe, 0x19, 0xe9, 0x30, 0xf, + 0xfe, 0x71, 0xcf, 0x48, 0x80, 0x71, 0xea, 0x80, + 0x7f, 0x4d, 0x0, 0x70, 0xcf, 0x30, 0x7, 0xff, + 0x51, 0xba, 0x44, 0x3, 0xaa, 0x40, 0x3c, 0x38, + 0xc0, 0x1c, 0xdc, 0xc0, 0x1f, 0xfd, 0x86, 0xe6, + 0x0, 0xe6, 0xc1, 0x0, 0x87, 0xc, 0x3, 0x1e, + 0x48, 0x7, 0xff, 0x72, 0x70, 0xc0, 0x31, 0xe0, + 0x81, 0x79, 0x0, 0x66, 0xc3, 0x0, 0xff, 0xef, + 0x1e, 0x30, 0x6, 0x2f, 0x20, 0x10, 0x8, 0x6a, + 0x40, 0x3f, 0xfc, 0x53, 0x40, 0x18, 0x40, 0x94, + 0x0, 0x58, 0xa0, 0x1f, 0xfe, 0x45, 0xd2, 0x0, + 0x29, 0x4, 0x1, 0xe1, 0x0, 0x7f, 0xf9, 0x8b, + 0xc, 0x20, 0x0, 0x53, 0x82, 0x1, 0xff, 0xe8, + 0x1c, 0x92, 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 = 617, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 0, .adv_w = 617, .box_w = 15, .box_h = 57, .ofs_x = 13, .ofs_y = -8}, + {.bitmap_index = 254, .adv_w = 617, .box_w = 16, .box_h = 57, .ofs_x = 10, .ofs_y = -8}, + {.bitmap_index = 513, .adv_w = 617, .box_w = 39, .box_h = 3, .ofs_x = 0, .ofs_y = -15}, + {.bitmap_index = 524, .adv_w = 617, .box_w = 21, .box_h = 20, .ofs_x = 9, .ofs_y = 28}, + {.bitmap_index = 677, .adv_w = 617, .box_w = 24, .box_h = 33, .ofs_x = 7, .ofs_y = 15}, + {.bitmap_index = 914, .adv_w = 1024, .box_w = 64, .box_h = 3, .ofs_x = 0, .ofs_y = 23}, + {.bitmap_index = 924, .adv_w = 1024, .box_w = 64, .box_h = 9, .ofs_x = 0, .ofs_y = 20}, + {.bitmap_index = 951, .adv_w = 1024, .box_w = 64, .box_h = 34, .ofs_x = 0, .ofs_y = -8}, + {.bitmap_index = 1055, .adv_w = 1024, .box_w = 64, .box_h = 37, .ofs_x = 0, .ofs_y = 20}, + {.bitmap_index = 1172, .adv_w = 1024, .box_w = 34, .box_h = 34, .ofs_x = 0, .ofs_y = 23}, + {.bitmap_index = 1385, .adv_w = 1024, .box_w = 52, .box_h = 52, .ofs_x = 6, .ofs_y = -2}, + {.bitmap_index = 1515, .adv_w = 1024, .box_w = 44, .box_h = 50, .ofs_x = 8, .ofs_y = -2}, + {.bitmap_index = 1848, .adv_w = 1024, .box_w = 62, .box_h = 17, .ofs_x = 1, .ofs_y = -5} +}; + +/*--------------------- + * CHARACTER MAPPING + *--------------------*/ + +static const uint16_t unicode_list_0[] = { + 0x0, 0x8, 0x9, 0x3f, 0x90, 0x9a, 0x24e0, 0x24e1, + 0x250c, 0x251b, 0x254f, 0x2581, 0x30ae, 0xfe15 +}; + +/*Collect the unicode lists and glyph_id offsets*/ +static const lv_font_fmt_txt_cmap_t cmaps[] = +{ + { + .range_start = 32, .range_length = 65046, .glyph_id_start = 1, + .unicode_list = unicode_list_0, .glyph_id_ofs_list = NULL, .list_length = 14, .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 = 1, +#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 font_rage_64 = { +#else +lv_font_t font_rage_64 = { +#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 = 72, /*The maximum line height required by the font*/ + .base_line = 15, /*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 = 3, +#endif + .dsc = &font_dsc, /*The custom font data. Will be accessed by `get_glyph_bitmap/dsc` */ +#if LV_VERSION_CHECK(8, 2, 0) || LVGL_VERSION_MAJOR >= 9 + .fallback = NULL, +#endif + .user_data = NULL, +}; + + + +#endif /*#if FONT_RAGE_64*/ + diff --git a/firmware/main/fonts/font_rain_22.c b/firmware/main/fonts/font_rain_22.c new file mode 100644 index 0000000..0843f64 --- /dev/null +++ b/firmware/main/fonts/font_rain_22.c @@ -0,0 +1,578 @@ +/******************************************************************************* + * Size: 22 px + * Bpp: 2 + * Opts: --font /usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf -r 0x20,0x23-0x25,0x2A,0x2B,0x30-0x39,0x3C-0x3E,0x41,0x43,0x45,0x46,0x48,0x4B,0x5A --font /tmp/claude-1000/-mnt-media-Projects-desklock/a3bb8d9c-268f-465a-b40b-889c5b60f451/scratchpad/NotoMonoCJKJP.ttf -r 0x30A2,0x30A4,0x30A6,0x30A8,0x30AA,0x30AB,0x30AD,0x30AF,0x30B1,0x30B3,0x30B5,0x30B7,0x30B9,0x30BB,0x30BD,0x30BF,0x30C1,0x30C4,0x30C6,0x30C8,0x30CA,0x30CB,0x30CC,0x30CD,0x30CE --size 22 --bpp 2 --format lvgl --lv-font-name font_rain_22 -o font_rain_22.c + ******************************************************************************/ + +#ifdef LV_LVGL_H_INCLUDE_SIMPLE +#include "lvgl.h" +#else +#include "lvgl/lvgl.h" +#endif + +#ifndef FONT_RAIN_22 +#define FONT_RAIN_22 1 +#endif + +#if FONT_RAIN_22 + +/*----------------- + * BITMAPS + *----------------*/ + +/*Store the image of the glyphs*/ +static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { + /* U+0020 " " */ + + /* U+0023 "#" */ + 0xe, 0x70, 0xb8, 0x3e, 0xc2, 0x4c, 0x3e, 0x42, + 0xc4, 0x3f, 0x20, 0x43, 0xf2, 0x61, 0x21, 0xbe, + 0x8b, 0xc3, 0xe0, 0x4a, 0x2, 0x80, 0xb0, 0x1a, + 0xd, 0x1, 0x50, 0x64, 0xc2, 0x43, 0xec, 0x44, + 0xc3, 0x7c, 0x9e, 0x8b, 0xc0, 0x58, 0xa, 0x2, + 0xc0, 0xa6, 0x54, 0x35, 0x6, 0xc4, 0x4c, 0x3e, + 0x42, 0xc4, 0x3f, 0x20, 0x43, 0xe0, + + /* U+0024 "$" */ + 0xd, 0x21, 0xff, 0xc4, 0xb6, 0xf4, 0x3b, 0xc, + 0xa2, 0x25, 0x6d, 0x84, 0x87, 0xff, 0x16, 0x34, + 0x3c, 0xa2, 0x6d, 0xa, 0xe0, 0xac, 0x32, 0xac, + 0x10, 0x7d, 0x88, 0x7f, 0xa0, 0xf2, 0x2b, 0xd3, + 0x51, 0x68, 0x81, 0x58, 0x2f, 0x37, 0x7, 0xff, + 0x28, + + /* U+0025 "%" */ + 0xf, 0xfe, 0x13, 0xf4, 0x1f, 0xa2, 0x8c, 0x1e, + 0x8d, 0x52, 0x1f, 0xfc, 0x7c, 0x86, 0xe, 0x46, + 0x78, 0xc1, 0x70, 0x1f, 0xcf, 0x8f, 0x6, 0x6f, + 0x5c, 0x1a, 0xef, 0x47, 0xc8, 0x3e, 0x46, 0x66, + 0x2, 0x1a, 0x66, 0x20, 0xff, 0x94, 0x1f, 0x21, + 0x28, 0x3d, 0x13, 0x90, 0x79, 0x98, 0x80, + + /* U+002A "*" */ + 0xe, 0xc3, 0xff, 0x8b, 0xc1, 0xce, 0xd, 0xd1, + 0xe8, 0x17, 0x42, 0x9a, 0x1b, 0xb, 0xc, 0xe6, + 0x47, 0x3, 0xa0, 0x1b, 0xa, 0x43, 0xd0, 0x7f, + 0xf0, 0x0, + + /* U+002B "+" */ + 0xf, 0xfe, 0x33, 0xc1, 0xff, 0xe1, 0xfd, 0xf, + 0xe0, 0xff, 0xe0, 0xa7, 0xe8, 0x7f, 0x21, 0xff, + 0xe8, + + /* U+0030 "0" */ + 0xa, 0xfa, 0xe, 0xd1, 0x1c, 0x28, 0x1d, 0xa4, + 0x4, 0x82, 0x84, 0x32, 0x19, 0x14, 0x1f, 0xde, + 0x11, 0xd3, 0xf, 0x44, 0x12, 0x1a, 0x10, 0xfc, + 0xf0, 0x4e, 0x21, 0xd8, 0x10, 0xfe, 0xc2, 0x43, + 0x22, 0x24, 0x14, 0x20, 0x81, 0xda, 0x41, 0x68, + 0x8e, 0x0, + + /* U+0031 "1" */ + 0x1b, 0xe4, 0x26, 0x43, 0xf3, 0x68, 0x73, 0x21, + 0xff, 0xff, 0xf, 0xfe, 0xaf, 0xc9, 0x7a, 0xf, + 0xe4, + + /* U+0032 "2" */ + 0x1b, 0xf4, 0x1a, 0x43, 0x38, 0x6b, 0xf0, 0x30, + 0x68, 0x6c, 0x3f, 0xfa, 0x90, 0x87, 0xe4, 0x83, + 0xec, 0x83, 0xec, 0x50, 0x7b, 0x18, 0x3d, 0xc, + 0x1e, 0x95, 0x7, 0xa5, 0x41, 0xe5, 0xf, 0xf9, + 0xf, 0xf8, + + /* U+0033 "3" */ + 0x1b, 0xf4, 0x1a, 0x43, 0x38, 0x57, 0xf2, 0x60, + 0x43, 0xa0, 0xff, 0xe4, 0xc1, 0xeb, 0xe4, 0xc3, + 0x21, 0xb0, 0xef, 0xa3, 0x43, 0xe7, 0x20, 0xfe, + 0x44, 0x3f, 0xd8, 0x7e, 0x4d, 0x41, 0xd0, 0x1e, + 0xfe, 0x48, 0x94, 0x19, 0xd0, + + /* U+0034 "4" */ + 0xf, 0x7c, 0x1f, 0x90, 0xff, 0xa4, 0x3f, 0xa2, + 0xf, 0xca, 0x83, 0xfa, 0x50, 0x7e, 0x88, 0x3f, + 0x2c, 0x1f, 0xd1, 0x7, 0xe8, 0x83, 0xf9, 0x3a, + 0xc0, 0xa0, 0x4b, 0xc0, 0x51, 0xff, 0x3, 0xc1, + 0xff, 0xd9, + + /* U+0035 "5" */ + 0x3f, 0xf2, 0x1f, 0xfc, 0x3f, 0xf2, 0x1f, 0xfc, + 0xea, 0xc8, 0x79, 0x75, 0x2, 0x6f, 0xa1, 0x81, + 0x21, 0x30, 0x87, 0xe4, 0x8, 0x7e, 0x43, 0xfc, + 0x87, 0xff, 0x1, 0x60, 0xec, 0x35, 0xfc, 0xc, + 0x50, 0x75, 0x80, + + /* U+0036 "6" */ + 0xd, 0x7d, 0x21, 0x3a, 0x13, 0x81, 0x8b, 0xf8, + 0x11, 0x21, 0x90, 0xc8, 0x7c, 0x88, 0xd1, 0xf, + 0x72, 0xad, 0x31, 0x2f, 0x24, 0x1a, 0x41, 0x1, + 0x9, 0xd, 0x1e, 0xf, 0xe4, 0x3f, 0xe4, 0x3e, + 0xc4, 0x48, 0x25, 0x11, 0xf, 0x70, 0x85, 0xa2, + 0xa, 0x0, + + /* U+0037 "7" */ + 0xbf, 0xfa, 0xc3, 0xfb, 0x7f, 0xe0, 0x21, 0xf4, + 0x21, 0xf9, 0x20, 0xf9, 0xf, 0xf6, 0x41, 0xf9, + 0x10, 0xf9, 0x10, 0xfd, 0x18, 0x7c, 0x81, 0xf, + 0xb1, 0xf, 0xc9, 0x7, 0xc8, 0x7f, 0xa2, 0xf, + 0xf2, 0x1c, + + /* U+0038 "8" */ + 0xa, 0xfc, 0x84, 0xe8, 0x82, 0x80, 0x8b, 0xb8, + 0x43, 0x21, 0x20, 0x43, 0xff, 0x84, 0x84, 0x81, + 0x32, 0xee, 0x70, 0xb0, 0x21, 0xe7, 0x3e, 0x56, + 0x8, 0xc2, 0x91, 0x42, 0x1d, 0x9e, 0xf, 0xe7, + 0x10, 0xec, 0x50, 0x10, 0x94, 0x62, 0x5d, 0xc2, + 0x8a, 0x22, 0xa, 0x0, + + /* U+0039 "9" */ + 0x3, 0x7d, 0x6, 0x64, 0x47, 0xa, 0x2e, 0xd2, + 0x10, 0x21, 0x42, 0x62, 0x1c, 0x88, 0x7f, 0xb0, + 0xfc, 0x83, 0x10, 0xfc, 0x82, 0x3, 0x86, 0xc7, + 0xd1, 0x6, 0xe5, 0x58, 0x79, 0xa2, 0x66, 0x1f, + 0x91, 0xf, 0xb2, 0x3, 0xfc, 0x28, 0xa, 0x9, + 0xa0, 0x0, + + /* U+003C "<" */ + 0xf, 0xf3, 0x21, 0xf9, 0xe4, 0x3c, 0xdc, 0x3a, + 0x15, 0xca, 0xb8, 0x2f, 0x25, 0xc8, 0x7c, 0xe8, + 0x7e, 0x87, 0xc8, 0x7c, 0xf9, 0x2f, 0x21, 0xf5, + 0xc9, 0x70, 0x7c, 0xdc, 0x28, 0x3f, 0x9f, 0x20, + + /* U+003D "=" */ + 0x3f, 0xfe, 0x43, 0xff, 0x80, 0x9f, 0xff, 0x7, + 0xff, 0xf, 0xff, 0xe0, 0xff, 0xe0, 0xa0, + + /* U+003E ">" */ + 0x24, 0x3f, 0xe6, 0xe0, 0xfe, 0xd1, 0xf2, 0x1f, + 0x5c, 0x97, 0x21, 0xe6, 0xe5, 0x58, 0x7e, 0x64, + 0x8, 0x79, 0xf2, 0x48, 0x4d, 0xc3, 0xe4, 0x17, + 0x25, 0xc1, 0xc8, 0xf9, 0xf, 0xae, 0xf, 0xe0, + + /* U+0041 "A" */ + 0xe, 0xf8, 0x3f, 0xf8, 0x28, 0x7e, 0x42, 0xc3, + 0xf4, 0x42, 0x1f, 0xe4, 0x8, 0x79, 0x12, 0x30, + 0xf6, 0x62, 0x21, 0xe4, 0x43, 0xf9, 0xe, 0x48, + 0x36, 0x21, 0x62, 0x19, 0x1a, 0xb0, 0xfe, 0x5c, + 0x4, 0x10, 0xff, 0x44, 0x4, 0xc3, 0x90, 0xf2, + 0x1f, 0x94, 0x1f, 0xc9, 0x80, + + /* U+0043 "C" */ + 0xd, 0x7e, 0x83, 0x68, 0x66, 0x6, 0x3f, 0xac, + 0x86, 0xc, 0xa1, 0x30, 0xf9, 0x2, 0x1f, 0xff, + 0x24, 0x3f, 0xe4, 0x83, 0xf4, 0x30, 0x65, 0x3, + 0x1e, 0x9d, 0x85, 0xa2, 0x86, + + /* U+0045 "E" */ + 0xff, 0xe8, 0x3f, 0xf8, 0x17, 0xfa, 0xf, 0xfe, + 0xf5, 0xfe, 0x43, 0xf9, 0x5, 0xfe, 0xf, 0xfe, + 0xfd, 0xfe, 0x83, 0xf9, + + /* U+0046 "F" */ + 0xbf, 0xf8, 0x3f, 0x90, 0x3f, 0xe8, 0x3f, 0xfb, + 0xcf, 0xf9, 0xf, 0xe4, 0xf, 0xf8, 0x3f, 0xfe, + 0x20, + + /* U+0048 "H" */ + 0xb8, 0x39, 0xf0, 0x7f, 0xfe, 0x1f, 0xe8, 0x3f, + 0xf8, 0x6f, 0xf4, 0x1f, 0xff, 0x80, + + /* U+004B "K" */ + 0xb8, 0x3d, 0xe8, 0x3f, 0xb1, 0x83, 0xf6, 0x30, + 0x7e, 0xc6, 0xf, 0xd8, 0xc1, 0xfb, 0x18, 0x3f, + 0x40, 0x83, 0xf2, 0x80, 0x87, 0xfa, 0x20, 0xfe, + 0xd4, 0x41, 0xf2, 0x8, 0x50, 0x7f, 0xa2, 0xf, + 0xf2, 0x8c, 0x3f, 0xd0, 0x10, 0xff, 0x44, 0x1f, + 0xe4, 0x18, + + /* U+005A "Z" */ + 0x3f, 0xfc, 0x87, 0xff, 0x7, 0xfe, 0x45, 0x7, + 0xca, 0x20, 0xfd, 0x10, 0x7e, 0x85, 0x7, 0xe4, + 0x83, 0xf6, 0x41, 0xfa, 0x14, 0x1f, 0x92, 0xf, + 0xd9, 0x7, 0xe4, 0x50, 0x7e, 0x88, 0x3f, 0x44, + 0x1f, 0x94, 0x5f, 0xf2, 0x1f, 0xf6, + + /* U+30A2 "ア" */ + 0x3e, 0xaf, 0xfb, 0xd0, 0x84, 0xbf, 0xf0, 0x11, + 0xff, 0xfe, 0x12, 0x21, 0xff, 0xc3, 0x51, 0x7, + 0xf7, 0x6, 0x8c, 0x3f, 0xf8, 0x4e, 0x61, 0xff, + 0xc2, 0xa1, 0x7, 0xfc, 0x85, 0x9a, 0x1f, 0xfc, + 0x1c, 0x70, 0xff, 0xe0, 0xe2, 0x1f, 0xfc, 0x44, + 0x3f, 0xf8, 0xa8, 0x7f, 0xf1, 0xa2, 0xf, 0xfe, + 0x1c, 0x28, 0x3f, 0xf8, 0x2e, 0x90, 0x7f, 0xf0, + 0x68, 0x38, 0x7f, 0xf0, 0xa6, 0x81, 0xff, 0xc1, + + /* U+30A4 "イ" */ + 0xf, 0xfe, 0xb6, 0x87, 0xff, 0xf, 0x30, 0xff, + 0xe0, 0xb8, 0xc1, 0xff, 0xc0, 0xa1, 0x40, 0xff, + 0xe0, 0x69, 0xa1, 0xff, 0x38, 0xe1, 0xff, 0x3c, + 0x8, 0x3f, 0xd7, 0x8, 0x7f, 0x9f, 0x23, 0xc1, + 0xfd, 0xc0, 0xb8, 0x3f, 0xe9, 0xf2, 0x1f, 0xfc, + 0x16, 0xf, 0xff, 0xf8, 0x7f, 0xf7, 0x14, 0x1e, + + /* U+30A6 "ウ" */ + 0xf, 0xd4, 0xf, 0xfe, 0x22, 0x83, 0xff, 0xc3, + 0xff, 0x3, 0xfe, 0xc, 0xbf, 0xfc, 0x0, 0xf5, + 0x7f, 0xf0, 0x3, 0xff, 0xae, 0x88, 0x7f, 0xf0, + 0xe2, 0xf, 0xfe, 0x47, 0x83, 0xfd, 0x10, 0x7f, + 0xf0, 0x94, 0x21, 0xff, 0xc2, 0x88, 0x3f, 0xf8, + 0x2e, 0x28, 0x3f, 0xf8, 0x14, 0x28, 0x1f, 0xe6, + 0xd2, 0x43, 0xfd, 0xc8, 0xe8, 0x7f, 0xdb, 0x70, + 0x7e, + + /* U+30A8 "エ" */ + 0x5, 0x7f, 0xf0, 0xf0, 0xcb, 0xff, 0xc3, 0xe, + 0xff, 0x81, 0xff, 0x7, 0xff, 0xfc, 0x3f, 0xff, + 0xe1, 0xff, 0xd5, 0xf5, 0x76, 0xa, 0xf7, 0x83, + 0x2f, 0x4, 0xbe, 0xd, 0xff, 0xfc, 0x60, + + /* U+30AA "オ" */ + 0xf, 0xfe, 0x8f, 0x7, 0xff, 0xc3, 0xff, 0xc3, + 0xfc, 0x2f, 0xf0, 0x4b, 0xc5, 0x7e, 0xc0, 0xd7, + 0x7, 0xe6, 0xf, 0xfe, 0x1b, 0x18, 0x7f, 0xf0, + 0x58, 0xc3, 0xff, 0x83, 0x43, 0x9, 0xf, 0xed, + 0x30, 0xff, 0xe0, 0x38, 0xe1, 0xff, 0x3c, 0x50, + 0x3f, 0xf8, 0x4e, 0x87, 0xff, 0x5, 0xe0, 0xff, + 0xe5, 0x7e, 0x10, 0xff, 0xe0, 0x4b, 0x50, 0x38, + + /* U+30AB "カ" */ + 0xf, 0xfe, 0x67, 0x83, 0xff, 0xe1, 0xfe, 0x7, + 0xfd, 0xb, 0xe0, 0x2f, 0x82, 0xaf, 0xd, 0x78, + 0x3f, 0x26, 0x1f, 0xfc, 0x2c, 0x43, 0xff, 0x84, + 0x87, 0xc9, 0x87, 0x22, 0x1f, 0xfc, 0x28, 0x83, + 0xff, 0x83, 0x8, 0x7d, 0x88, 0x4a, 0x20, 0xf9, + 0xc, 0xc6, 0x1f, 0xfc, 0xa, 0x10, 0x6a, 0xd9, + 0x1, 0x34, 0x39, 0x61, 0x40, 0xf0, 0x7a, 0xfd, + 0x0, + + /* U+30AD "キ" */ + 0xf, 0x90, 0xff, 0xe2, 0x51, 0xf, 0xfe, 0x1e, + 0x1f, 0xfc, 0x54, 0xc3, 0x2c, 0x1f, 0xe6, 0xfa, + 0x98, 0x4d, 0x3e, 0x2, 0x6, 0xa0, 0x32, 0x85, + 0x8b, 0xd2, 0x82, 0x6f, 0xa9, 0x87, 0xfc, 0x87, + 0x26, 0x1f, 0xfc, 0x54, 0x39, 0x90, 0xff, 0x53, + 0xe9, 0xc2, 0x69, 0xe0, 0x28, 0x55, 0xd3, 0xd2, + 0x85, 0xf, 0xa8, 0x83, 0x55, 0xf5, 0x3, 0xf9, + 0xa2, 0x1e, 0x43, 0xff, 0xac, 0x87, 0xff, 0x17, + 0x10, 0xff, 0xe6, 0x0, + + /* U+30AF "ク" */ + 0xf, 0x99, 0xf, 0xfe, 0x1e, 0x87, 0xff, 0xd, + 0x42, 0x1f, 0xfc, 0x28, 0x6b, 0xe4, 0x3d, 0x1, + 0x7f, 0x41, 0xca, 0x3f, 0xe8, 0x43, 0x31, 0x87, + 0xd9, 0x84, 0xc6, 0x1f, 0x91, 0x5, 0xc, 0x3f, + 0x44, 0x5, 0x18, 0x7f, 0x22, 0x7, 0xc1, 0xfd, + 0x90, 0x7f, 0xf0, 0xa1, 0x41, 0xff, 0xc1, 0x51, + 0x7, 0xff, 0x5, 0x8c, 0x3f, 0xf8, 0x34, 0x20, + 0xff, 0xe0, 0x3a, 0x68, 0x7f, 0x9e, 0x1c, 0x3f, + 0xee, 0x7, 0x7, 0xff, 0x2, 0x7c, 0x1f, 0xf0, + + /* U+30B1 "ケ" */ + 0xf, 0xfe, 0x77, 0x83, 0xff, 0x8a, 0x88, 0x7f, + 0xf1, 0x72, 0xf, 0xfe, 0x2a, 0x1f, 0xfc, 0x68, + 0x1f, 0xff, 0xc0, 0xe, 0x45, 0xe0, 0x97, 0x83, + 0x65, 0x79, 0x3a, 0xe0, 0xa1, 0x41, 0xc8, 0x7f, + 0x49, 0x7, 0xff, 0x11, 0x30, 0xff, 0xe2, 0xf8, + 0x3e, 0x88, 0x3f, 0xf8, 0xa8, 0x87, 0xff, 0x11, + 0x10, 0xff, 0xe2, 0xc4, 0x1f, 0xfc, 0x4c, 0x83, + 0xff, 0x89, 0x8a, 0xf, 0xfe, 0x15, 0x8c, 0x1f, + 0xfc, 0x38, 0xa0, 0x7f, 0xf1, 0x74, 0x3f, 0xf8, + 0x0, + + /* U+30B3 "コ" */ + 0xf, 0xfe, 0x2f, 0xff, 0xf0, 0xc3, 0xff, 0x8b, + 0xff, 0xfc, 0x10, 0xff, 0xff, 0x87, 0xff, 0xed, + 0xff, 0xfe, 0x8, 0x7f, 0xf1, 0x9f, 0xff, 0xe0, + 0x87, 0xff, 0x13, 0xc0, + + /* U+30B5 "サ" */ + 0xf, 0xfe, 0x6f, 0x83, 0xde, 0xf, 0xff, 0xab, + 0x58, 0x15, 0xe0, 0x56, 0x35, 0xc0, 0x5f, 0x1, + 0x7a, 0xfc, 0xf, 0xf0, 0x3f, 0x21, 0xff, 0xd6, + 0x43, 0xff, 0xcc, 0xa0, 0xe8, 0xc3, 0xfd, 0x40, + 0xe4, 0x43, 0xff, 0x88, 0x88, 0x7f, 0xf1, 0x18, + 0x83, 0xff, 0x87, 0x42, 0xf, 0xfe, 0x15, 0xa6, + 0x87, 0xff, 0xa, 0x6c, 0x3f, 0x80, + + /* U+30B7 "シ" */ + 0xd, 0x21, 0xff, 0xc5, 0x68, 0x1f, 0xfc, 0x4c, + 0x74, 0x3f, 0xf8, 0x7c, 0x41, 0xff, 0xc4, 0x78, + 0x3f, 0xe9, 0xe, 0x43, 0xfc, 0xaa, 0x7, 0xff, + 0x3, 0xc3, 0x8e, 0x87, 0xf4, 0x21, 0x71, 0x7, + 0xe5, 0x10, 0x67, 0xc1, 0xf3, 0x18, 0x7f, 0xf0, + 0x98, 0x83, 0xff, 0x85, 0x42, 0x43, 0xff, 0x80, + 0xe9, 0xa1, 0xff, 0xc0, 0xa0, 0xe1, 0xff, 0x3e, + 0x4a, 0x7, 0xf3, 0x70, 0x2d, 0xf, 0xe6, 0x46, + 0xd0, 0xff, 0x9a, 0x72, 0x1f, 0xfc, 0x0, + + /* U+30B9 "ス" */ + 0x5, 0x7f, 0xf0, 0x43, 0x97, 0xff, 0x84, 0x1b, + 0xff, 0xd0, 0x10, 0xff, 0xe1, 0x64, 0x1f, 0xfc, + 0x34, 0x43, 0xff, 0x85, 0x10, 0x7f, 0xf0, 0x97, + 0x7, 0xff, 0xa, 0x20, 0xff, 0xe1, 0x62, 0x1f, + 0xfc, 0x2c, 0xa, 0xf, 0xfe, 0x6, 0x59, 0x21, + 0xfc, 0xe4, 0x99, 0x40, 0xfa, 0x84, 0x85, 0x8a, + 0xc, 0xe9, 0xa1, 0xd9, 0x23, 0xc3, 0x87, 0xe8, + 0x94, 0xa, 0x7, 0xf3, 0x5, 0xe4, 0x3f, 0xe7, + 0x40, + + /* U+30BB "セ" */ + 0xf, 0x70, 0x7f, 0xf1, 0x90, 0xff, 0xe3, 0x21, + 0xff, 0xd0, 0x43, 0xff, 0x82, 0xd3, 0xd2, 0x1f, + 0x34, 0xf4, 0xa0, 0x91, 0x57, 0x80, 0xba, 0xf4, + 0x43, 0x44, 0x37, 0xa8, 0x82, 0x11, 0x57, 0xc2, + 0x1e, 0xcc, 0x29, 0xf, 0xf4, 0x41, 0xff, 0xc3, + 0x96, 0xf, 0xfe, 0x1c, 0xc1, 0xff, 0xc5, 0x83, + 0xff, 0xa6, 0x87, 0xff, 0x1e, 0xc, 0xb5, 0x3, + 0xe8, 0x7f, 0x54, 0x87, 0xe7, 0xa2, 0xab, 0x70, + + /* U+30BD "ソ" */ + 0xf, 0xfe, 0x33, 0x7, 0xfd, 0x69, 0x28, 0x3f, + 0xf8, 0x51, 0x7, 0xf9, 0x11, 0x42, 0x1f, 0xfc, + 0x28, 0x83, 0xf2, 0x21, 0x92, 0xf, 0xb3, 0xd, + 0x8, 0x7c, 0x88, 0x77, 0x83, 0xd1, 0x7, 0xff, + 0x9, 0x10, 0xff, 0xe0, 0xe4, 0x1f, 0xfc, 0x18, + 0x50, 0x7f, 0xf0, 0x24, 0x83, 0xff, 0x81, 0x26, + 0x1f, 0xfc, 0xd, 0x30, 0xff, 0xac, 0x18, 0x7f, + 0xd2, 0x58, 0x7f, 0xf0, 0x29, 0xa1, 0xfc, + + /* U+30BF "タ" */ + 0xf, 0xd0, 0x7f, 0xf1, 0x25, 0x7, 0xff, 0xd, + 0x10, 0xff, 0xe1, 0x60, 0xaf, 0x68, 0x7a, 0x9, + 0x7c, 0x41, 0xca, 0x3f, 0xe8, 0x43, 0x31, 0x87, + 0xd1, 0x4, 0xc6, 0x1f, 0xfc, 0x16, 0x21, 0x83, + 0xa2, 0x5, 0xd, 0x37, 0x40, 0xa1, 0x4, 0xe1, + 0x50, 0xb2, 0x30, 0xd0, 0x73, 0xa6, 0x21, 0xff, + 0xc1, 0x90, 0xff, 0xe2, 0x28, 0xe, 0x1f, 0xf5, + 0xf, 0x22, 0x1f, 0xda, 0x60, 0xa2, 0x1f, 0x58, + 0xe1, 0x90, 0xe7, 0xc9, 0xc1, 0xff, 0x20, 0xb0, + 0xff, 0xe1, 0x79, 0xf, 0xfe, 0x0, + + /* U+30C1 "チ" */ + 0xf, 0xfe, 0x13, 0x7, 0xfc, 0xb5, 0xf4, 0xc1, + 0xef, 0xd5, 0x22, 0xae, 0xf, 0x57, 0x69, 0x52, + 0x1f, 0x97, 0x8c, 0x3f, 0xfc, 0xff, 0xfa, 0x2f, + 0xf8, 0xb, 0xf8, 0x25, 0xf8, 0x15, 0xf9, 0x3a, + 0xf8, 0x3f, 0xc8, 0x7f, 0xf6, 0xa2, 0xf, 0xfe, + 0x2a, 0x21, 0xff, 0xc4, 0xc8, 0x3f, 0xf8, 0x6e, + 0x28, 0x3f, 0xf8, 0x54, 0x18, 0x3f, 0xf8, 0x73, + 0x40, 0xff, 0xe0, 0x0, + + /* U+30C4 "ツ" */ + 0xf, 0x90, 0xff, 0xe2, 0x32, 0x1f, 0x25, 0x86, + 0x48, 0x3c, 0xd3, 0x20, 0xc8, 0x7d, 0x9a, 0x21, + 0xb2, 0xe, 0x44, 0x84, 0x24, 0x43, 0x22, 0x4, + 0x83, 0x50, 0x36, 0x61, 0x21, 0xca, 0xc, 0x88, + 0x56, 0x1f, 0xd1, 0x7, 0xff, 0xd, 0x10, 0xff, + 0xe1, 0x66, 0x1f, 0xfc, 0x2c, 0x43, 0xff, 0x85, + 0x8c, 0x1f, 0xfc, 0x1c, 0x10, 0x7f, 0xf0, 0x2c, + 0x70, 0xff, 0xad, 0x28, 0x1f, 0xf6, 0x8e, 0x87, + 0xff, 0x3, 0x78, 0x3f, 0xc0, + + /* U+30C6 "テ" */ + 0xf, 0xfe, 0x4b, 0xff, 0xfc, 0x8, 0x39, 0x7f, + 0xf8, 0x38, 0x7a, 0xbf, 0xf8, 0x8, 0x7f, 0xf7, + 0x6b, 0xff, 0x8c, 0x2f, 0xff, 0x18, 0xff, 0xd1, + 0x7f, 0xc1, 0xfd, 0x87, 0xff, 0x21, 0xf, 0xfe, + 0x22, 0x1f, 0xfc, 0x54, 0x43, 0xff, 0x89, 0x98, + 0x7f, 0xf0, 0xe4, 0x43, 0xff, 0x85, 0x26, 0x1f, + 0xfc, 0x17, 0x4c, 0x3f, 0xf8, 0x48, 0xe1, 0xff, + 0xc4, 0xe0, 0xff, 0xe0, 0x80, + + /* U+30C8 "ト" */ + 0xf, 0xfe, 0x7, 0x83, 0xff, 0xf9, 0xc8, 0x7f, + 0x9b, 0x83, 0xee, 0x47, 0xc8, 0x73, 0x70, 0x2c, + 0x3e, 0x78, 0x3f, 0xe7, 0xc1, 0xff, 0xf1, 0x50, + 0x7f, 0x80, + + /* U+30CA "ナ" */ + 0xf, 0xfe, 0x7b, 0xc1, 0xff, 0xd7, 0x43, 0xff, + 0xc9, 0xff, 0xc3, 0xff, 0x28, 0x3f, 0xf8, 0xd7, + 0xfd, 0xf, 0xfc, 0x87, 0xfb, 0xf, 0xfe, 0x26, + 0x1f, 0xfc, 0x64, 0x43, 0xff, 0xad, 0x10, 0x7f, + 0xf0, 0xd4, 0x21, 0xff, 0xc2, 0x63, 0xf, 0xfe, + 0x15, 0x8, 0x3f, 0xf8, 0x5a, 0x48, 0x7f, 0xf0, + 0xb7, 0x43, 0xff, 0x80, + + /* U+30CB "ニ" */ + 0xf, 0xfe, 0x47, 0xff, 0xf0, 0x60, 0xff, 0xe5, + 0x7f, 0xff, 0x6, 0xf, 0xff, 0xf8, 0x7f, 0xfe, + 0xff, 0xff, 0x8b, 0x7, 0xff, 0x17, + + /* U+30CC "ヌ" */ + 0xf, 0xfe, 0x12, 0x1b, 0xff, 0xf8, 0x14, 0x9, + 0x7f, 0xe0, 0xf5, 0x7f, 0xc0, 0x83, 0xff, 0x94, + 0x87, 0xd1, 0x7, 0x36, 0x1e, 0x44, 0x39, 0x47, + 0x5, 0x10, 0x7d, 0x63, 0xa2, 0x21, 0xfd, 0xa5, + 0x90, 0x7f, 0xd6, 0x12, 0x1f, 0xfc, 0xc, 0x2d, + 0xf, 0xf6, 0xe, 0x28, 0x1f, 0x38, 0xe3, 0x8c, + 0x19, 0xe2, 0x81, 0xb0, 0xd7, 0x3, 0x43, 0xdc, + 0xc, 0x16, 0x1f, 0xfc, 0x7, 0xc8, 0x7f, 0xf0, + 0x0, + + /* U+30CD "ネ" */ + 0xf, 0xe5, 0x7, 0xff, 0x1a, 0x81, 0xff, 0xe7, + 0xbf, 0xc0, 0xfe, 0x83, 0xb5, 0xff, 0x83, 0xf3, + 0x5f, 0xe0, 0x30, 0x7f, 0xf0, 0xe5, 0x41, 0xff, + 0xc3, 0xd5, 0x7, 0xff, 0x9, 0xc6, 0xf, 0xfe, + 0x15, 0xa, 0x7, 0xff, 0x6, 0xd0, 0x25, 0xc1, + 0xf3, 0xe4, 0x83, 0x43, 0xa1, 0x7a, 0x1f, 0x21, + 0xdc, 0x58, 0x15, 0x70, 0x7f, 0x3a, 0x15, 0x10, + 0xff, 0xe0, 0xd8, 0x7f, 0xfe, 0xbc, 0x1f, 0xc0, + + /* U+30CE "ノ" */ + 0xf, 0xfe, 0x7d, 0xa1, 0xff, 0xc0, 0x44, 0x3f, + 0xe4, 0x3f, 0xf8, 0x59, 0x7, 0xff, 0x1, 0x10, + 0xff, 0xa1, 0xf, 0xfe, 0x2, 0x41, 0xff, 0x44, + 0x1f, 0xf2, 0x84, 0x3f, 0xe8, 0x83, 0xfe, 0xc5, + 0x7, 0xf3, 0x8c, 0x1f, 0xd4, 0x18, 0x3f, 0x3a, + 0x50, 0x3e, 0x78, 0x1a, 0x1f, 0xf5, 0x87, 0xf9, + 0xf2, 0x1f, 0xf0 +}; + + +/*--------------------- + * 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 = 212, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 0, .adv_w = 212, .box_w = 14, .box_h = 16, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 54, .adv_w = 212, .box_w = 10, .box_h = 19, .ofs_x = 2, .ofs_y = -3}, + {.bitmap_index = 95, .adv_w = 212, .box_w = 13, .box_h = 16, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 142, .adv_w = 212, .box_w = 11, .box_h = 10, .ofs_x = 1, .ofs_y = 6}, + {.bitmap_index = 168, .adv_w = 212, .box_w = 13, .box_h = 12, .ofs_x = 0, .ofs_y = 1}, + {.bitmap_index = 185, .adv_w = 212, .box_w = 11, .box_h = 16, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 227, .adv_w = 212, .box_w = 10, .box_h = 16, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 244, .adv_w = 212, .box_w = 11, .box_h = 16, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 278, .adv_w = 212, .box_w = 11, .box_h = 16, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 315, .adv_w = 212, .box_w = 12, .box_h = 16, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 349, .adv_w = 212, .box_w = 11, .box_h = 16, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 384, .adv_w = 212, .box_w = 11, .box_h = 16, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 426, .adv_w = 212, .box_w = 11, .box_h = 16, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 460, .adv_w = 212, .box_w = 11, .box_h = 16, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 504, .adv_w = 212, .box_w = 11, .box_h = 16, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 546, .adv_w = 212, .box_w = 13, .box_h = 11, .ofs_x = 0, .ofs_y = 1}, + {.bitmap_index = 578, .adv_w = 212, .box_w = 13, .box_h = 6, .ofs_x = 0, .ofs_y = 4}, + {.bitmap_index = 593, .adv_w = 212, .box_w = 13, .box_h = 11, .ofs_x = 0, .ofs_y = 1}, + {.bitmap_index = 625, .adv_w = 212, .box_w = 13, .box_h = 16, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 670, .adv_w = 212, .box_w = 11, .box_h = 16, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 699, .adv_w = 212, .box_w = 10, .box_h = 16, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 719, .adv_w = 212, .box_w = 10, .box_h = 16, .ofs_x = 2, .ofs_y = 0}, + {.bitmap_index = 736, .adv_w = 212, .box_w = 11, .box_h = 16, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 750, .adv_w = 212, .box_w = 13, .box_h = 16, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 792, .adv_w = 212, .box_w = 12, .box_h = 16, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 830, .adv_w = 352, .box_w = 19, .box_h = 17, .ofs_x = 2, .ofs_y = -1}, + {.bitmap_index = 894, .adv_w = 352, .box_w = 18, .box_h = 19, .ofs_x = 1, .ofs_y = -1}, + {.bitmap_index = 942, .adv_w = 352, .box_w = 18, .box_h = 19, .ofs_x = 2, .ofs_y = -1}, + {.bitmap_index = 999, .adv_w = 352, .box_w = 20, .box_h = 15, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1030, .adv_w = 352, .box_w = 18, .box_h = 19, .ofs_x = 2, .ofs_y = -1}, + {.bitmap_index = 1086, .adv_w = 352, .box_w = 17, .box_h = 19, .ofs_x = 2, .ofs_y = -1}, + {.bitmap_index = 1143, .adv_w = 352, .box_w = 18, .box_h = 19, .ofs_x = 2, .ofs_y = -1}, + {.bitmap_index = 1211, .adv_w = 352, .box_w = 18, .box_h = 19, .ofs_x = 2, .ofs_y = -1}, + {.bitmap_index = 1283, .adv_w = 352, .box_w = 20, .box_h = 20, .ofs_x = 1, .ofs_y = -2}, + {.bitmap_index = 1356, .adv_w = 352, .box_w = 16, .box_h = 17, .ofs_x = 3, .ofs_y = -1}, + {.bitmap_index = 1384, .adv_w = 352, .box_w = 20, .box_h = 19, .ofs_x = 1, .ofs_y = -1}, + {.bitmap_index = 1438, .adv_w = 352, .box_w = 19, .box_h = 18, .ofs_x = 2, .ofs_y = -1}, + {.bitmap_index = 1509, .adv_w = 352, .box_w = 18, .box_h = 17, .ofs_x = 2, .ofs_y = -1}, + {.bitmap_index = 1574, .adv_w = 352, .box_w = 19, .box_h = 18, .ofs_x = 1, .ofs_y = -1}, + {.bitmap_index = 1638, .adv_w = 352, .box_w = 17, .box_h = 18, .ofs_x = 2, .ofs_y = -1}, + {.bitmap_index = 1701, .adv_w = 352, .box_w = 18, .box_h = 20, .ofs_x = 2, .ofs_y = -2}, + {.bitmap_index = 1779, .adv_w = 352, .box_w = 20, .box_h = 18, .ofs_x = 1, .ofs_y = -1}, + {.bitmap_index = 1839, .adv_w = 352, .box_w = 18, .box_h = 18, .ofs_x = 2, .ofs_y = -1}, + {.bitmap_index = 1908, .adv_w = 352, .box_w = 19, .box_h = 19, .ofs_x = 2, .ofs_y = -2}, + {.bitmap_index = 1969, .adv_w = 352, .box_w = 12, .box_h = 19, .ofs_x = 7, .ofs_y = -1}, + {.bitmap_index = 1995, .adv_w = 352, .box_w = 19, .box_h = 19, .ofs_x = 2, .ofs_y = -1}, + {.bitmap_index = 2047, .adv_w = 352, .box_w = 18, .box_h = 14, .ofs_x = 2, .ofs_y = 1}, + {.bitmap_index = 2069, .adv_w = 352, .box_w = 17, .box_h = 18, .ofs_x = 2, .ofs_y = -2}, + {.bitmap_index = 2134, .adv_w = 352, .box_w = 20, .box_h = 20, .ofs_x = 1, .ofs_y = -2}, + {.bitmap_index = 2198, .adv_w = 352, .box_w = 15, .box_h = 18, .ofs_x = 3, .ofs_y = -1} +}; + +/*--------------------- + * CHARACTER MAPPING + *--------------------*/ + +static const uint16_t unicode_list_0[] = { + 0x0, 0x3, 0x4, 0x5, 0xa, 0xb, 0x10, 0x11, + 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, + 0x1c, 0x1d, 0x1e, 0x21, 0x23, 0x25, 0x26, 0x28, + 0x2b, 0x3a, 0x3082, 0x3084, 0x3086, 0x3088, 0x308a, 0x308b, + 0x308d, 0x308f, 0x3091, 0x3093, 0x3095, 0x3097, 0x3099, 0x309b, + 0x309d, 0x309f, 0x30a1, 0x30a4, 0x30a6, 0x30a8, 0x30aa, 0x30ab, + 0x30ac, 0x30ad, 0x30ae +}; + +/*Collect the unicode lists and glyph_id offsets*/ +static const lv_font_fmt_txt_cmap_t cmaps[] = +{ + { + .range_start = 32, .range_length = 12463, .glyph_id_start = 1, + .unicode_list = unicode_list_0, .glyph_id_ofs_list = NULL, .list_length = 51, .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 = 2, + .kern_classes = 0, + .bitmap_format = 1, +#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 font_rain_22 = { +#else +lv_font_t font_rain_22 = { +#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 = 21, /*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 = -1, + .underline_thickness = 1, +#endif + .dsc = &font_dsc, /*The custom font data. Will be accessed by `get_glyph_bitmap/dsc` */ +#if LV_VERSION_CHECK(8, 2, 0) || LVGL_VERSION_MAJOR >= 9 + .fallback = NULL, +#endif + .user_data = NULL, +}; + + + +#endif /*#if FONT_RAIN_22*/ + diff --git a/firmware/main/gw_client.c b/firmware/main/gw_client.c new file mode 100644 index 0000000..5fdc82a --- /dev/null +++ b/firmware/main/gw_client.c @@ -0,0 +1,124 @@ +/* WebSocket link to the DeskLock gateway. + * Protocol: docs/architecture.md "WebSocket protocol" — keep in sync. + */ + +#include + +#include "cJSON.h" +#include "esp_log.h" +#include "esp_websocket_client.h" + +#include "desklock.h" +#include "secrets.h" + +static const char *TAG = "gw"; + +static esp_websocket_client_handle_t s_ws; +static volatile bool s_connected; + +static void handle_text(const char *data, int len) +{ + cJSON *root = cJSON_ParseWithLength(data, len); + if (root == NULL) { + return; + } + const cJSON *type = cJSON_GetObjectItem(root, "type"); + if (!cJSON_IsString(type)) { + cJSON_Delete(root); + return; + } + face_activity(); + + if (strcmp(type->valuestring, "state") == 0) { + const cJSON *value = cJSON_GetObjectItem(root, "value"); + if (cJSON_IsString(value)) { + if (strcmp(value->valuestring, "thinking") == 0) { + face_set(FACE_EFFORT); + } else if (strcmp(value->valuestring, "idle") == 0 && !audio_is_playing()) { + face_set(FACE_IDLE); + } + } + } else if (strcmp(type->valuestring, "transcript") == 0) { + const cJSON *text = cJSON_GetObjectItem(root, "text"); + ESP_LOGI(TAG, "transcript: %s", cJSON_IsString(text) ? text->valuestring : "?"); + } else if (strcmp(type->valuestring, "reply_text") == 0) { + const cJSON *text = cJSON_GetObjectItem(root, "text"); + ESP_LOGI(TAG, "tatlock: %s", cJSON_IsString(text) ? text->valuestring : "?"); + } else if (strcmp(type->valuestring, "audio_start") == 0) { + audio_playback_begin(); + face_set(FACE_SPEAKING); + } else if (strcmp(type->valuestring, "audio_end") == 0) { + audio_playback_end(); + } else if (strcmp(type->valuestring, "error") == 0) { + face_set(FACE_RAGE); + } + cJSON_Delete(root); +} + +static void ws_event(void *arg, esp_event_base_t base, int32_t id, void *data) +{ + (void)arg; + (void)base; + esp_websocket_event_data_t *ev = (esp_websocket_event_data_t *)data; + switch (id) { + case WEBSOCKET_EVENT_CONNECTED: + ESP_LOGI(TAG, "gateway connected"); + s_connected = true; + face_set(FACE_IDLE); + break; + case WEBSOCKET_EVENT_DISCONNECTED: + case WEBSOCKET_EVENT_ERROR: + if (s_connected) { + ESP_LOGW(TAG, "gateway lost"); + } + s_connected = false; + audio_capture_stop(); + face_set(FACE_ERROR); + break; + case WEBSOCKET_EVENT_DATA: + if (ev->op_code == 0x01) { /* text */ + handle_text(ev->data_ptr, ev->data_len); + } else if (ev->op_code == 0x02 && ev->data_len > 0) { /* binary PCM */ + audio_playback_feed((const uint8_t *)ev->data_ptr, ev->data_len); + } + break; + default: + break; + } +} + +void gw_start(void) +{ + if (s_ws != NULL) { + return; + } + esp_websocket_client_config_t cfg = { + .uri = GATEWAY_WS_URI, + .buffer_size = 8192, + .reconnect_timeout_ms = 5000, + .network_timeout_ms = 10000, + }; + s_ws = esp_websocket_client_init(&cfg); + esp_websocket_register_events(s_ws, WEBSOCKET_EVENT_ANY, ws_event, NULL); + esp_websocket_client_start(s_ws); + ESP_LOGI(TAG, "connecting to %s", GATEWAY_WS_URI); +} + +bool gw_connected(void) +{ + return s_connected; +} + +void gw_send_text(const char *json) +{ + if (s_connected) { + esp_websocket_client_send_text(s_ws, json, strlen(json), pdMS_TO_TICKS(5000)); + } +} + +void gw_send_bin(const uint8_t *data, size_t len) +{ + if (s_connected) { + esp_websocket_client_send_bin(s_ws, (const char *)data, len, pdMS_TO_TICKS(5000)); + } +} diff --git a/firmware/main/idf_component.yml b/firmware/main/idf_component.yml index bc788cf..b74b53c 100644 --- a/firmware/main/idf_component.yml +++ b/firmware/main/idf_component.yml @@ -1,3 +1,6 @@ dependencies: idf: ">=5.4" waveshare/esp32_p4_wifi6_touch_lcd_xc: "^3.0.1" + espressif/esp_wifi_remote: "0.14.*" + espressif/esp_hosted: "1.4.*" + espressif/esp_websocket_client: "~1.3.0" diff --git a/firmware/main/net.c b/firmware/main/net.c new file mode 100644 index 0000000..78d24a4 --- /dev/null +++ b/firmware/main/net.c @@ -0,0 +1,83 @@ +/* Wi-Fi STA via ESP-Hosted (C6 radio) + SNTP, then start the gateway link. */ + +#include + +#include "esp_event.h" +#include "esp_log.h" +#include "esp_netif.h" +#include "esp_netif_sntp.h" +#include "esp_wifi.h" +#include "nvs_flash.h" + +#include "desklock.h" +#include "secrets.h" + +static const char *TAG = "net"; + +static void scan_then_connect(void *arg) +{ + (void)arg; + ESP_LOGI(TAG, "scanning for APs…"); + if (esp_wifi_scan_start(NULL, true) == ESP_OK) { + uint16_t n = 12; + wifi_ap_record_t recs[12]; + if (esp_wifi_scan_get_ap_records(&n, recs) == ESP_OK) { + for (int i = 0; i < n; i++) { + ESP_LOGI(TAG, " ap: '%s' rssi=%d ch=%d auth=%d", + (const char *)recs[i].ssid, recs[i].rssi, + recs[i].primary, recs[i].authmode); + } + } + } + esp_wifi_connect(); + vTaskDelete(NULL); +} + +static void wifi_event(void *arg, esp_event_base_t base, int32_t id, void *data) +{ + (void)arg; + (void)data; + if (base == WIFI_EVENT && id == WIFI_EVENT_STA_START) { + xTaskCreate(scan_then_connect, "scan", 4096, NULL, 4, NULL); + } else if (base == WIFI_EVENT && id == WIFI_EVENT_STA_DISCONNECTED) { + wifi_event_sta_disconnected_t *dc = (wifi_event_sta_disconnected_t *)data; + ESP_LOGW(TAG, "wifi disconnected (reason %d), retrying", dc ? dc->reason : -1); + face_set(FACE_ERROR); + vTaskDelay(pdMS_TO_TICKS(3000)); + esp_wifi_connect(); + } else if (base == IP_EVENT && id == IP_EVENT_STA_GOT_IP) { + ip_event_got_ip_t *ev = (ip_event_got_ip_t *)data; + ESP_LOGI(TAG, "got ip " IPSTR, IP2STR(&ev->ip_info.ip)); + setenv("TZ", "CET-1CEST,M3.5.0,M10.5.0/3", 1); + tzset(); + esp_sntp_config_t sntp = ESP_NETIF_SNTP_DEFAULT_CONFIG("pool.ntp.org"); + esp_netif_sntp_init(&sntp); + gw_start(); + } +} + +void net_start(void) +{ + esp_err_t err = nvs_flash_init(); + if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) { + ESP_ERROR_CHECK(nvs_flash_erase()); + ESP_ERROR_CHECK(nvs_flash_init()); + } + ESP_ERROR_CHECK(esp_netif_init()); + ESP_ERROR_CHECK(esp_event_loop_create_default()); + esp_netif_create_default_wifi_sta(); + + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + ESP_ERROR_CHECK(esp_wifi_init(&cfg)); + ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, wifi_event, NULL)); + ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, wifi_event, NULL)); + + wifi_config_t wc = { 0 }; + wc.sta.scan_method = WIFI_ALL_CHANNEL_SCAN; + strlcpy((char *)wc.sta.ssid, WIFI_SSID, sizeof(wc.sta.ssid)); + strlcpy((char *)wc.sta.password, WIFI_PASS, sizeof(wc.sta.password)); + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); + ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wc)); + ESP_ERROR_CHECK(esp_wifi_start()); + ESP_LOGI(TAG, "wifi starting, ssid=%s", WIFI_SSID); +} diff --git a/firmware/main/secrets.h.example b/firmware/main/secrets.h.example new file mode 100644 index 0000000..7d352aa --- /dev/null +++ b/firmware/main/secrets.h.example @@ -0,0 +1,5 @@ +#pragma once + +#define WIFI_SSID "your-ssid" +#define WIFI_PASS "your-password" +#define GATEWAY_WS_URI "ws://192.168.86.149:8600/ws/voice" diff --git a/firmware/partitions.csv b/firmware/partitions.csv new file mode 100644 index 0000000..79d7a73 --- /dev/null +++ b/firmware/partitions.csv @@ -0,0 +1,4 @@ +# Name, Type, SubType, Offset, Size +nvs, data, nvs, 0x9000, 0x6000 +phy_init, data, phy, 0xf000, 0x1000 +factory, app, factory, 0x10000, 8M diff --git a/firmware/sdkconfig.defaults b/firmware/sdkconfig.defaults index 67a23b8..a88f50a 100644 --- a/firmware/sdkconfig.defaults +++ b/firmware/sdkconfig.defaults @@ -3,7 +3,8 @@ CONFIG_IDF_TARGET="esp32p4" # 32 MB NOR flash CONFIG_ESPTOOLPY_FLASHSIZE_32MB=y -CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" # PSRAM at 200 MHz — REQUIRED for the 800x800 MIPI-DSI framebuffer. # 200 MHz is gated behind IDF_EXPERIMENTAL_FEATURES; without it the build @@ -21,3 +22,9 @@ CONFIG_FREERTOS_HZ=1000 # LVGL font for the bring-up placeholder face CONFIG_LV_FONT_MONTSERRAT_48=y + +# LVGL font for status/elapsed/clock chrome +CONFIG_LV_FONT_MONTSERRAT_28=y + +# ESP-Hosted C6 radio +CONFIG_ESP_WIFI_SOFTAP_SUPPORT=n