Phase 2: full LVGL face + Wi-Fi + gateway WebSocket + touch-to-talk
Test, Build and Push / test-gateway (push) Successful in 10s
Test, Build and Push / release (push) Skipped
Test, Build and Push / build-gateway (push) Skipped

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 <noreply@anthropic.com>
This commit is contained in:
2026-07-14 21:42:51 +02:00
co-authored by Claude Fable 5
parent ae9f6e0abb
commit ed0e8221f1
17 changed files with 3073 additions and 145 deletions
+1 -1
View File
@@ -4,7 +4,7 @@ firmware/managed_components/
firmware/sdkconfig
firmware/sdkconfig.old
firmware/dependencies.lock
firmware/secrets.h
firmware/main/secrets.h
# Python
__pycache__/
+2 -2
View File
@@ -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
+19
View File
@@ -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:
+12 -1
View File
@@ -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)
+208
View File
@@ -0,0 +1,208 @@
/* Audio: gong synthesis, mic capture -> gateway, gateway PCM -> speaker. */
#include <math.h>
#include <string.h>
#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;
}
+46
View File
@@ -0,0 +1,46 @@
/* Shared app types and cross-module hooks. */
#pragma once
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
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);
+32 -140
View File
@@ -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 <math.h>
#include <stdlib.h>
#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");
}
+461
View File
@@ -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 <stdio.h>
#include <string.h>
#include <time.h>
#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();
}
}
File diff suppressed because it is too large Load Diff
+425
View File
@@ -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*/
+578
View File
@@ -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*/
+124
View File
@@ -0,0 +1,124 @@
/* WebSocket link to the DeskLock gateway.
* Protocol: docs/architecture.md "WebSocket protocol" — keep in sync.
*/
#include <string.h>
#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));
}
}
+3
View File
@@ -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"
+83
View File
@@ -0,0 +1,83 @@
/* Wi-Fi STA via ESP-Hosted (C6 radio) + SNTP, then start the gateway link. */
#include <string.h>
#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);
}
+5
View File
@@ -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"
+4
View File
@@ -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
1 # Name Type SubType Offset Size
2 nvs data nvs 0x9000 0x6000
3 phy_init data phy 0xf000 0x1000
4 factory app factory 0x10000 8M
+8 -1
View File
@@ -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