MeowOS for HiBy R3 Pro II — 公共发布版本(历史已重置)
• 全新单提交:清除含敏感信息的旧历史(sudo 口令、内网 IP、SSH 密钥路径、热点 SSID、设备 MAC) • 本地开发文档/测试记录/构建脚本全部移入 gitignored 的 devdocs/ 与 scripts/build/(不入库) • 保留:MeowOS 源码(launcher/watchdog/bootmenu/meow_svcd/SDK)、项目规范文档、mips-repo 增补组件:SDK 统一日志+通知 API、meow_svcd 服务管理器、mips-repo 软件仓库
This commit is contained in:
commit
245bee2946
136 files changed
+32730
No files matched your search
Executable
+49
@@ -0,0 +1,49 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# S90meow_launcherd - R3 Pro II Plan B app-launcher daemon (zero patch)
|
||||
#
|
||||
# Design (ANALYSIS.md §18):
|
||||
# * PASSIVE daemon: never EVIOCGRABs, never injects events. Reads keys via
|
||||
# EVIOCGKEY state polling (immune to any grab the player holds), touch via
|
||||
# normal event reads on event1 (not grabbed). Zero interference with the
|
||||
# player's own key handling.
|
||||
# * Hotkey: hold PREVIOUS + VOL_UP together >=300ms -> app menu
|
||||
# (cross-device: PREVIOUS is a GPIO key on event0, VOL_UP is an ADC key
|
||||
# on event2. A two-key chord on event2 alone is impossible — its four
|
||||
# keys share ONE ADC channel, so the old dual-volume hotkey can never
|
||||
# register physically; see ANALYSIS.md §18.8).
|
||||
# * Starts BEFORE S92_03_start_music_player (S90 < S92) so it is up early;
|
||||
# the input devices are created by S11module_driver_default.
|
||||
# * Stop sends SIGTERM; the daemon SIGCONTs a frozen player before exiting.
|
||||
#
|
||||
case "$1" in
|
||||
start)
|
||||
echo -n "Starting meow_launcherd: "
|
||||
if [ -x /usr/bin/meow_launcherd ]; then
|
||||
/usr/bin/meow_launcherd >/dev/null 2>&1 &
|
||||
echo "OK"
|
||||
else
|
||||
echo "MISSING /usr/bin/meow_launcherd"
|
||||
fi
|
||||
;;
|
||||
stop)
|
||||
echo -n "Stopping meow_launcherd: "
|
||||
if [ -f /usr/data/meow_launcherd.pid ]; then
|
||||
kill "$(cat /usr/data/meow_launcherd.pid)" 2>/dev/null
|
||||
fi
|
||||
killall meow_launcherd 2>/dev/null
|
||||
sleep 1
|
||||
echo "OK"
|
||||
;;
|
||||
restart|reload)
|
||||
"$0" stop
|
||||
sleep 1
|
||||
"$0" start
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 {start|stop|restart}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
Executable
+26
@@ -0,0 +1,26 @@
|
||||
#!/bin/bash
|
||||
# build_launcher.sh — MeowOS launcher (A-1/A-2: launcher 用 SDK 渲染栈).
|
||||
#
|
||||
# 变更点(相对 M2.27 / A-0):
|
||||
# - launcher 不再自建 back_buf/meow_present/refresh_governor —— 改用 SDK 渲染栈:
|
||||
# fb 指向 SDK 的 back_buf(meow_ui_back_buf),呈现统一 meow_ui_flush()(SDK present,
|
||||
# 内含 vsync + 帧率门控 + 原子 blit 脏区);刷新率档位经 meow_ui_set_refresh_rate()/
|
||||
# set_refresh_always_max() 交给 SDK(归口 PERF_SCHEDULER 显示子域)。
|
||||
# - 播放器 fb 双缓冲交互(fb_backup_player/fb_norm_buf0/fb_restore_player/FBIOPAN/yoffset)
|
||||
# 保留不动(与 present 上屏不同层)。
|
||||
# - launcher 与 SDK 共用同一 meow_font.o(已打进 meow_ui.a)——不再单独链 meow_font.a。
|
||||
# - MEOWOS_VERSION 0.7.21 → 0.7.23(M2.28)。
|
||||
#
|
||||
# Build(在 patch_v2/meow_launcherd 下):
|
||||
# zig-mipsel-cc -I../sdk -Os -static meow_launcherd.c meow_touch.c meow_settings.c meow_notif.c ../sdk/meow_ui.a <sysroot>/lib/libz.a -lpthread -o meow_launcherd
|
||||
set -e
|
||||
cd "$(dirname "$0")"
|
||||
ROOT="$HOME/Project/R3ProII"
|
||||
CC="$ROOT/.tools/zig-mipsel-cc"
|
||||
SYSROOT="$ROOT/.tools/mipsel-linux-muslsf-cross/mipsel-linux-muslsf"
|
||||
[ -f "../sdk/meow_ui.a" ] || { echo "!! 缺 ../sdk/meow_ui.a,先跑 sdk/build_sdk.sh"; exit 1; }
|
||||
"$CC" -I"../sdk" -Os -static meow_launcherd.c meow_touch.c meow_settings.c meow_notif.c "../sdk/meow_ui.a" "$SYSROOT/lib/libz.a" -lpthread -o meow_launcherd
|
||||
echo "== meow_launcherd =="
|
||||
ls -la meow_launcherd
|
||||
md5sum meow_launcherd
|
||||
file meow_launcherd
|
||||
Executable
BIN
Binary file not shown.
@@ -0,0 +1,268 @@
|
||||
/* evtool.c — tiny evdev probe tool for R3 Pro II (static MIPS32r2 musl).
|
||||
*
|
||||
* Subcommands:
|
||||
* evtool codes <dev> dump EV bits (types + key codes)
|
||||
* evtool dump <dev> [dev...] read + print events (no grab)
|
||||
* evtool send <dev> <type> <code> <value> inject one event via write()
|
||||
* evtool grab <dev> [dev...] EVIOCGRAB, then read + print
|
||||
* evtool fwd <dev> EVIOCGRAB, read, write back every event
|
||||
* (forward experiment) + print
|
||||
* evtool keys <dev> EVIOCGKEY poll loop; print state changes
|
||||
* evtool grabchk <dev> EVIOCGRAB result only (0 / errno)
|
||||
*
|
||||
* Event struct is fixed 16 bytes on MIPS32: timeval(8) + type(2) + code(2) + value(4).
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/poll.h>
|
||||
#include <linux/input.h>
|
||||
|
||||
#ifndef EVIOCGRAB
|
||||
#define EVIOCGRAB _IOW('E', 0x90, int)
|
||||
#endif
|
||||
#ifndef EVIOCGKEY
|
||||
#define EVIOCGKEY(len) _IOC(_IOC_READ, 'E', 0x18, len)
|
||||
#endif
|
||||
|
||||
#define EV_MAXC 0x1f
|
||||
#define KEY_MAXC 0x2ff
|
||||
#define KEY_WORDS ((KEY_MAXC + 1 + 31) / 32)
|
||||
|
||||
static unsigned long long now_ms(void)
|
||||
{
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
return (unsigned long long)ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
|
||||
}
|
||||
|
||||
static int open_dev(const char *dev, int wr)
|
||||
{
|
||||
int fd = open(dev, wr ? O_RDWR : O_RDONLY);
|
||||
if (fd < 0) { fprintf(stderr, "open %s: %s\n", dev, strerror(errno)); return -1; }
|
||||
return fd;
|
||||
}
|
||||
|
||||
static void print_ev(const char *tag, const unsigned char *ev)
|
||||
{
|
||||
uint16_t type = *(uint16_t *)(ev + 8);
|
||||
uint16_t code = *(uint16_t *)(ev + 10);
|
||||
int32_t val = *(int32_t *)(ev + 12);
|
||||
fprintf(stderr, "%s t=%llu type=%d code=%d val=%d\n",
|
||||
tag, now_ms(), type, code, val);
|
||||
}
|
||||
|
||||
/* ---------- codes ---------- */
|
||||
static void cmd_codes(const char *dev)
|
||||
{
|
||||
int fd = open_dev(dev, 0);
|
||||
if (fd < 0) return;
|
||||
unsigned long evbits[EV_MAXC / 32 + 1];
|
||||
memset(evbits, 0, sizeof evbits);
|
||||
if (ioctl(fd, EVIOCGBIT(0, sizeof evbits), evbits) < 0) {
|
||||
perror("EVIOCGBIT(0)"); return;
|
||||
}
|
||||
printf("EV bits:");
|
||||
for (int i = 0; i <= EV_MAXC; i++)
|
||||
if (evbits[i / 32] & (1UL << (i % 32))) printf(" %d", i);
|
||||
printf("\n");
|
||||
|
||||
unsigned long kb[KEY_WORDS];
|
||||
memset(kb, 0, sizeof kb);
|
||||
if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof kb), kb) >= 0) {
|
||||
printf("KEY codes:");
|
||||
for (int i = 0; i <= KEY_MAXC; i++)
|
||||
if (kb[i / 32] & (1UL << (i % 32))) printf(" %d", i);
|
||||
printf("\n");
|
||||
} else {
|
||||
perror("EVIOCGBIT(EV_KEY)");
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
/* ---------- dump ---------- */
|
||||
static void dump_dev(const char *dev, const char *tag)
|
||||
{
|
||||
int fd = open_dev(dev, 0);
|
||||
if (fd < 0) return;
|
||||
printf("opened %s as %s\n", dev, tag);
|
||||
fflush(stdout);
|
||||
struct pollfd pfd = { fd, POLLIN, 0 };
|
||||
unsigned char ev[16];
|
||||
for (;;) {
|
||||
int r = poll(&pfd, 1, -1);
|
||||
if (r < 0) { perror("poll"); break; }
|
||||
if (pfd.revents & POLLIN) {
|
||||
ssize_t n = read(fd, ev, sizeof ev);
|
||||
if (n == 16) print_ev(tag, ev);
|
||||
else if (n < 0) { perror("read"); break; }
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static void cmd_dump(int argc, char **argv)
|
||||
{
|
||||
for (int i = 0; i < argc; i++) {
|
||||
pid_t p = fork();
|
||||
if (p == 0) { dump_dev(argv[i], argv[i]); _exit(0); }
|
||||
}
|
||||
for (;;) pause();
|
||||
}
|
||||
|
||||
/* ---------- send ---------- */
|
||||
static void cmd_send(const char *dev, int type, int code, int value)
|
||||
{
|
||||
int fd = open_dev(dev, 1);
|
||||
if (fd < 0) return;
|
||||
struct input_event ev;
|
||||
memset(&ev, 0, sizeof ev);
|
||||
ev.type = type; ev.code = code; ev.value = value;
|
||||
ssize_t n = write(fd, &ev, sizeof ev);
|
||||
printf("write(%s) -> %zd errno=%d (%s)\n", dev, n, errno, strerror(errno));
|
||||
close(fd);
|
||||
}
|
||||
|
||||
/* ---------- grab / fwd ---------- */
|
||||
static int do_grab(int fd, int on)
|
||||
{
|
||||
int v = on ? 1 : 0;
|
||||
int r = ioctl(fd, EVIOCGRAB, v);
|
||||
printf("EVIOCGRAB(%d) -> %d errno=%d (%s)\n", on, r, errno, strerror(errno));
|
||||
return r;
|
||||
}
|
||||
|
||||
static void loop_forward(const char *dev, int fwd)
|
||||
{
|
||||
int fd = open_dev(dev, 1);
|
||||
if (fd < 0) return;
|
||||
if (do_grab(fd, 1) < 0) return;
|
||||
printf("GRABBED %s (fwd=%d), reading...\n", dev, fwd);
|
||||
fflush(stdout);
|
||||
struct pollfd pfd = { fd, POLLIN, 0 };
|
||||
unsigned char ev[16];
|
||||
unsigned long long nread = 0, nwritten = 0;
|
||||
for (;;) {
|
||||
int r = poll(&pfd, 1, -1);
|
||||
if (r < 0) { perror("poll"); break; }
|
||||
if (pfd.revents & POLLIN) {
|
||||
ssize_t n = read(fd, ev, sizeof ev);
|
||||
if (n != 16) { if (n < 0) perror("read"); continue; }
|
||||
nread++;
|
||||
print_ev("G", ev);
|
||||
if (fwd) {
|
||||
ssize_t w = write(fd, ev, sizeof ev);
|
||||
nwritten++;
|
||||
if (w != 16) fprintf(stderr, " write-back failed: %s\n", strerror(errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
/* ---------- fwdt: grab + self-inject + forward ---------- */
|
||||
/* Sequence: grab <dev>; after wait_ms inject press(code); after +300ms inject
|
||||
* release(code); meanwhile forward every read event back to <dev>.
|
||||
* Optional 5th arg: total duration ms (0 = run forever).
|
||||
* A second reader on <dev> tells us whether write-back reaches non-grabbers. */
|
||||
static void loop_fwdt(const char *dev, int code, int wait_ms, int dur_ms)
|
||||
{
|
||||
int fd = open_dev(dev, 1);
|
||||
if (fd < 0) return;
|
||||
if (do_grab(fd, 1) < 0) return;
|
||||
printf("FWDT grabbed %s code=%d wait=%d dur=%d\n", dev, code, wait_ms, dur_ms);
|
||||
fflush(stdout);
|
||||
struct pollfd pfd = { fd, POLLIN, 0 };
|
||||
unsigned char ev[16];
|
||||
unsigned long long t0 = now_ms(), inject_done = 0;
|
||||
int phase = 0; /* 0=idle, 1=pressed, 2=released */
|
||||
for (;;) {
|
||||
unsigned long long t = now_ms();
|
||||
if (dur_ms > 0 && t - t0 >= (unsigned long long)dur_ms) break;
|
||||
if (!inject_done && t - t0 >= (unsigned long long)wait_ms) {
|
||||
struct input_event e; memset(&e, 0, sizeof e);
|
||||
e.type = EV_KEY; e.code = code; e.value = 1;
|
||||
if (write(fd, &e, sizeof e) != sizeof e) fprintf(stderr, "inject press fail\n");
|
||||
printf("== injected PRESS %d\n", code);
|
||||
phase = 1; inject_done = 1;
|
||||
} else if (phase == 1 && t - t0 >= (unsigned long long)wait_ms + 300) {
|
||||
struct input_event e; memset(&e, 0, sizeof e);
|
||||
e.type = EV_KEY; e.code = code; e.value = 0;
|
||||
if (write(fd, &e, sizeof e) != sizeof e) fprintf(stderr, "inject release fail\n");
|
||||
printf("== injected RELEASE %d\n", code);
|
||||
phase = 2;
|
||||
}
|
||||
int r = poll(&pfd, 1, 100);
|
||||
if (r < 0) { perror("poll"); break; }
|
||||
if (pfd.revents & POLLIN) {
|
||||
ssize_t n = read(fd, ev, sizeof ev);
|
||||
if (n == 16) {
|
||||
print_ev("RD", ev);
|
||||
ssize_t w = write(fd, ev, sizeof ev);
|
||||
if (w != 16) fprintf(stderr, " WB fail: %s\n", strerror(errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
/* ---------- keys (EVIOCGKEY poll) ---------- */
|
||||
static void cmd_keys(const char *dev, int dur_ms)
|
||||
{
|
||||
int fd = open_dev(dev, 0);
|
||||
if (fd < 0) return;
|
||||
unsigned long prev[KEY_WORDS], cur[KEY_WORDS];
|
||||
memset(prev, 0, sizeof prev);
|
||||
printf("EVIOCGKEY poll on %s (dur=%dms)\n", dev, dur_ms);
|
||||
fflush(stdout);
|
||||
unsigned long long t0 = now_ms();
|
||||
for (;;) {
|
||||
if (dur_ms > 0 && now_ms() - t0 >= (unsigned long long)dur_ms) break;
|
||||
memset(cur, 0, sizeof cur);
|
||||
if (ioctl(fd, EVIOCGKEY(sizeof cur), cur) < 0) { perror("EVIOCGKEY"); break; }
|
||||
for (int w = 0; w < KEY_WORDS; w++) {
|
||||
if (cur[w] != prev[w]) {
|
||||
for (int b = 0; b < 32; b++) {
|
||||
int cb = (cur[w] >> b) & 1;
|
||||
int pb = (prev[w] >> b) & 1;
|
||||
if (cb != pb)
|
||||
printf("key %d %s\n", w * 32 + b, cb ? "DOWN" : "UP");
|
||||
}
|
||||
prev[w] = cur[w];
|
||||
}
|
||||
}
|
||||
fflush(stdout);
|
||||
usleep(10000); /* 10 ms */
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
setvbuf(stderr, NULL, _IONBF, 0);
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "usage: evtool codes|dump|send|grab|fwd|keys|grabchk <args>\n");
|
||||
return 1;
|
||||
}
|
||||
const char *cmd = argv[1];
|
||||
if (!strcmp(cmd, "codes") && argc >= 3) { cmd_codes(argv[2]); return 0; }
|
||||
if (!strcmp(cmd, "dump") && argc >= 3) { cmd_dump(argc - 2, argv + 2); return 0; }
|
||||
if (!strcmp(cmd, "send") && argc >= 6) { cmd_send(argv[2], atoi(argv[3]), atoi(argv[4]), atoi(argv[5])); return 0; }
|
||||
if (!strcmp(cmd, "grab") && argc >= 3) { loop_forward(argv[2], 0); return 0; }
|
||||
if (!strcmp(cmd, "fwd") && argc >= 3) { loop_forward(argv[2], 1); return 0; }
|
||||
if (!strcmp(cmd, "keys") && argc >= 3) { cmd_keys(argv[2], argc >= 4 ? atoi(argv[3]) : 0); return 0; }
|
||||
if (!strcmp(cmd, "fwdt") && argc >= 4) { loop_fwdt(argv[2], atoi(argv[3]), argc >= 5 ? atoi(argv[4]) : 1000, argc >= 6 ? atoi(argv[5]) : 0); return 0; }
|
||||
if (!strcmp(cmd, "grabchk") && argc >= 3) {
|
||||
int fd = open_dev(argv[2], 1);
|
||||
if (fd >= 0) { do_grab(fd, 1); do_grab(fd, 0); close(fd); }
|
||||
return 0;
|
||||
}
|
||||
fprintf(stderr, "bad args\n");
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/* fbcopy — copy buffer0 -> buffer1 within /dev/fb0 (mmap both, memcpy).
|
||||
* Reproduces the player's "screen-off frame lives in buffer1" state so the
|
||||
* launcher's bug condition (yoffset=1 at menu open) can be tested without
|
||||
* pressing power (which would also pause the player). */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define GETV 0x4600
|
||||
|
||||
int main(void) {
|
||||
int fd = open("/dev/fb0", O_RDWR);
|
||||
if (fd < 0) { perror("open"); return 1; }
|
||||
unsigned char v[160]; memset(v,0,sizeof v);
|
||||
if (ioctl(fd, GETV, v) < 0) { perror("getvar"); return 1; }
|
||||
uint32_t yres = *(uint32_t*)(v+4);
|
||||
uint32_t yv = *(uint32_t*)(v+12);
|
||||
uint32_t bpp = *(uint32_t*)(v+24);
|
||||
if (yv <= yres) { printf("not double-buffered (yv=%u yres=%u)\n", yv, yres); return 2; }
|
||||
/* line_length via fix info */
|
||||
unsigned char f[68]; memset(f,0,sizeof f);
|
||||
if (ioctl(fd, 0x4602, f) < 0) { perror("getfix"); return 1; }
|
||||
uint32_t line = *(uint32_t*)(f+44);
|
||||
if (!line) line = yres * (bpp/8);
|
||||
size_t frame = (size_t)line * yres;
|
||||
unsigned char *p = mmap(NULL, frame*2, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
if (p == MAP_FAILED) { perror("mmap"); return 1; }
|
||||
memcpy(p + frame, p, frame); /* buffer1 <- buffer0 */
|
||||
printf("copied %zu bytes buffer0 -> buffer1 (line=%u yres=%u frame=%zu)\n", frame, line, yres, frame);
|
||||
munmap(p, frame*2);
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/* fbpan — set /dev/fb0 yoffset (pan) to argv[1] and print the result. */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define GETV 0x4600
|
||||
#define PAN 0x4606
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int fd = open("/dev/fb0", O_RDWR);
|
||||
if (fd < 0) { perror("open"); return 1; }
|
||||
unsigned char v[160]; memset(v,0,sizeof v);
|
||||
if (ioctl(fd, GETV, v) < 0) { perror("getvar"); return 1; }
|
||||
uint32_t orig = *(uint32_t*)(v+20);
|
||||
uint32_t yres = *(uint32_t*)(v+4);
|
||||
uint32_t target = argc > 1 ? (uint32_t)atoi(argv[1]) : 0;
|
||||
if (yres) target = (target / yres) * yres; /* snap to whole-screen offset */
|
||||
*(uint32_t*)(v+16) = 0;
|
||||
*(uint32_t*)(v+20) = target;
|
||||
errno = 0;
|
||||
int r = ioctl(fd, PAN, v);
|
||||
int e = errno;
|
||||
unsigned char w[160]; memset(w,0,sizeof w);
|
||||
ioctl(fd, GETV, w);
|
||||
printf("pan(%u): r=%d errno=%d(%s) yoffset %u -> %u (yres=%u)\n",
|
||||
target, r, e, strerror(e), orig, *(uint32_t*)(w+20), yres);
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/* fbpantest.c — empirically find the ioctl that pans /dev/fb0 by yoffset.
|
||||
* Confirmed already: fb0 is 480x720 RGB565, yres_virtual=1440 (double),
|
||||
* yoffset selects the displayed buffer, ypanstep=1. We try candidate ioctls
|
||||
* that set yoffset to the OTHER buffer and read yoffset back; whichever
|
||||
* changes it is the pan mechanism. We restore yoffset immediately.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define GETV 0x4600
|
||||
|
||||
static int get_info(int fd, uint32_t *yoff, uint32_t *yres) {
|
||||
unsigned char v[160];
|
||||
memset(v, 0, sizeof v);
|
||||
if (ioctl(fd, GETV, v) < 0) return -1;
|
||||
*yres = *(uint32_t*)(v + 4);
|
||||
*yoff = *(uint32_t*)(v + 20);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void write_yoffset_to(int fd, uint32_t cmd, uint32_t yoffset) {
|
||||
unsigned char v[160];
|
||||
memset(v, 0, sizeof v);
|
||||
if (ioctl(fd, GETV, v) < 0) return;
|
||||
/* modify only the offset fields, keep everything else */
|
||||
*(uint32_t*)(v + 16) = 0;
|
||||
*(uint32_t*)(v + 20) = yoffset;
|
||||
ioctl(fd, cmd, v);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
int fd = open("/dev/fb0", O_RDWR);
|
||||
if (fd < 0) { perror("open /dev/fb0"); return 1; }
|
||||
uint32_t orig = 0, yres = 0;
|
||||
if (get_info(fd, &orig, &yres) < 0) { perror("getvar"); return 1; }
|
||||
uint32_t target = (orig < yres) ? yres : 0;
|
||||
printf("orig yoffset=%u yres=%u target(other buf)=%u\n", orig, yres, target);
|
||||
|
||||
unsigned tests[] = { 0x4601, 0x4606 }; /* PUT_VSCREENINFO, PAN_DISPLAY(nr 0x06) */
|
||||
for (unsigned i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) {
|
||||
uint32_t cmd = tests[i];
|
||||
write_yoffset_to(fd, cmd, target);
|
||||
uint32_t now = 0, tmp = 0;
|
||||
int ok = get_info(fd, &now, &tmp);
|
||||
printf(" cmd=0x%04X -> yoffset=%u (target %u) %s\n",
|
||||
cmd, now, target, (ok==0 && now==target) ? "*** PAN WORKS ***" : "");
|
||||
/* restore */
|
||||
if (ok == 0 && now == target) {
|
||||
write_yoffset_to(fd, cmd, orig);
|
||||
uint32_t back = 0;
|
||||
get_info(fd, &back, &tmp);
|
||||
printf(" restored to yoffset=%u\n", back);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* also probe FBIOBLANK candidate 0x4611 and 0x4603 just to report which blanks */
|
||||
errno = 0;
|
||||
int b1 = ioctl(fd, 0x4603, 5);
|
||||
int e1 = errno; errno = 0;
|
||||
int b2 = ioctl(fd, 0x4611, 5);
|
||||
int e2 = errno;
|
||||
printf(" blank 0x4603(5) r=%d errno=%d ; 0x4611(5) r=%d errno=%d\n", b1, e1, b2, e2);
|
||||
/* ensure unblanked back to 0 regardless */
|
||||
ioctl(fd, 0x4611, 0); /* unblank (works per launcher) */
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/* fbpantest2.c — does fb0 actually PAN? Print ioctl return + errno.
|
||||
* Key question: is the display pannable via FBIOPAN_DISPLAY/FBIOPUT_VSCREENINFO,
|
||||
* or is the double buffer flipped by direct LCDC register writes (desar) that
|
||||
* the fb var yoffset never reflects?
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define GETV 0x4600
|
||||
|
||||
static int get_info(int fd, uint32_t *yoff, uint32_t *yres) {
|
||||
unsigned char v[160]; memset(v,0,sizeof v);
|
||||
if (ioctl(fd, GETV, v) < 0) return -1;
|
||||
*yres = *(uint32_t*)(v + 4);
|
||||
*yoff = *(uint32_t*)(v + 20);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
int fd = open("/dev/fb0", O_RDWR);
|
||||
if (fd < 0) { perror("open"); return 1; }
|
||||
uint32_t orig=0,yres=0; get_info(fd,&orig,&yres);
|
||||
uint32_t target=(orig<yres)?yres:0;
|
||||
printf("orig yoffset=%u yres=%u target=%u\n", orig,yres,target);
|
||||
|
||||
unsigned char v[160];
|
||||
memset(v,0,sizeof v);
|
||||
ioctl(fd, GETV, v);
|
||||
*(uint32_t*)(v+16)=0; *(uint32_t*)(v+20)=target;
|
||||
v[84]=0; /* activate = 0 (implies activate-on-next?) */
|
||||
|
||||
errno=0;
|
||||
int r6=ioctl(fd, 0x4606, v);
|
||||
int e6=errno; errno=0;
|
||||
uint32_t now=0; get_info(fd,&now,&yres);
|
||||
printf("PAN_DISPLAY(0x4606) r=%d errno=%d(%s) -> yoffset now %u\n", r6,e6,strerror(e6),now);
|
||||
if (now==target) { errno=0; ioctl(fd,0x4606,v); /* restore */ }
|
||||
|
||||
/* now try PUT_VSCREENINFO with activate=FB_ACTIVATE_NOW */
|
||||
memset(v,0,sizeof v); ioctl(fd, GETV, v);
|
||||
*(uint32_t*)(v+16)=0; *(uint32_t*)(v+20)=target;
|
||||
errno=0;
|
||||
int r1=ioctl(fd, 0x4601, v);
|
||||
int e1=errno; errno=0;
|
||||
get_info(fd,&now,&yres);
|
||||
printf("PUT_VSCREENINFO(0x4601) r=%d errno=%d(%s) -> yoffset now %u\n", r1,e1,strerror(e1),now);
|
||||
if (now==target) { memset(v,0,sizeof v); ioctl(fd,GETV,v); *(uint32_t*)(v+16)=0; *(uint32_t*)(v+20)=orig; ioctl(fd,0x4601,v); }
|
||||
|
||||
/* getid; also read FBIOGET_DISPINFO(0x4618) */
|
||||
unsigned char d[256]; memset(d,0,sizeof d);
|
||||
errno=0;
|
||||
int rd=ioctl(fd, 0x4618, d);
|
||||
int ed=errno;
|
||||
printf("GET_DISPINFO(0x4618) r=%d errno=%d(%s)\n", rd, ed, strerror(ed));
|
||||
for (unsigned i=0;i<64;i+=4){ if (*(uint32_t*)(d+i)) printf(" d[%u]=%08x\n", i, *(uint32_t*)(d+i)); }
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/* fbprobe.c — inspect /dev/fb0 geometry & current pan position.
|
||||
* Device-verified ioctl numbers (do NOT swap): FBIOGET_VSCREENINFO=0x4600,
|
||||
* FBIOGET_FSCREENINFO=0x4602, FBIOBLANK=0x4611.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define FBIOGET_VSCREENINFO 0x4600
|
||||
#define FBIOGET_FSCREENINFO 0x4602
|
||||
#define FBIOBLANK 0x4611
|
||||
#define FBIO_PAN_DISPLAY 0x4606
|
||||
#define FBIO_WAITFORVSYNC 0x4620
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int fd = open("/dev/fb0", O_RDWR);
|
||||
if (fd < 0) { perror("open /dev/fb0"); return 1; }
|
||||
|
||||
unsigned char v[160], f[68];
|
||||
memset(v, 0, sizeof v); memset(f, 0, sizeof f);
|
||||
if (ioctl(fd, 0x4600, v) < 0) { perror("vscreeninfo(0x4600)"); return 1; }
|
||||
if (ioctl(fd, 0x4602, f) < 0) { perror("fscreeninfo(0x4602)"); return 1; }
|
||||
|
||||
uint32_t xres = *(uint32_t*)(v + 0);
|
||||
uint32_t yres = *(uint32_t*)(v + 4);
|
||||
uint32_t xv = *(uint32_t*)(v + 8);
|
||||
uint32_t yv = *(uint32_t*)(v + 12);
|
||||
uint32_t xoff = *(uint32_t*)(v + 16);
|
||||
uint32_t yoff = *(uint32_t*)(v + 20);
|
||||
uint32_t bpp = *(uint32_t*)(v + 24);
|
||||
uint32_t vmode = *(uint32_t*)(v + 80);
|
||||
|
||||
uint32_t smem_len = *(uint32_t*)(f + 20);
|
||||
uint32_t visual = *(uint32_t*)(f + 32);
|
||||
uint16_t xs = *(uint16_t*)(f + 36);
|
||||
uint16_t ys = *(uint16_t*)(f + 38);
|
||||
uint32_t line_len = *(uint32_t*)(f + 44);
|
||||
uint32_t type = *(uint32_t*)(f + 24);
|
||||
|
||||
printf("V: xres=%u yres=%u xres_v=%u yres_v=%u xoffset=%u yoffset=%u bpp=%u vmode=%u\n",
|
||||
xres, yres, xv, yv, xoff, yoff, bpp, vmode);
|
||||
printf("V: red(offset%u,len%u) green(off%u,len%u) blue(off%u,len%u) transp(off%u,len%u)\n",
|
||||
*(uint32_t*)(v+28)&0xFF, *(uint32_t*)(v+28)>>8,
|
||||
*(uint32_t*)(v+32)&0xFF, *(uint32_t*)(v+32)>>8,
|
||||
*(uint32_t*)(v+36)&0xFF, *(uint32_t*)(v+36)>>8,
|
||||
*(uint32_t*)(v+40)&0xFF, *(uint32_t*)(v+40)>>8);
|
||||
printf("F: id='%.16s' smem_len=%u type=%u visual=%u xpanstep=%u ypanstep=%u line_length=%u\n",
|
||||
(char*)f, smem_len, type, visual, xs, ys, line_len);
|
||||
|
||||
unsigned long one = (unsigned long)line_len * yres;
|
||||
printf("frame size (line*yres) = %lu ; 2*frame = %lu ; smem_len = %u\n",
|
||||
one, one * 2, smem_len);
|
||||
printf("DOUBLE-BUFFER? %s\n",
|
||||
(smem_len >= one * 2) ? "YES (>= 2 frames in smem)" : "single (1 frame)");
|
||||
printf("YRES_VIRTUAL = %u ; yoffset = %u ; displayed buffer index = %u\n",
|
||||
yv, yoff, yv > 0 ? (yoff / (yres ? yres : 1)) : 0);
|
||||
printf("display starts at byte %u (=%u*line_len)\n", yoff * line_len, yoff);
|
||||
printf("=> visible window x=%u..%u y=%u..%u (of %ux%u virtual)\n",
|
||||
xoff, xoff + xres, yoff, yoff + yres, xv, yv);
|
||||
|
||||
/* try FBIOPAN_DISPLAY to read back set-able + WAITFORVSYNC presence */
|
||||
unsigned char pan[160];
|
||||
memcpy(pan, v, sizeof pan);
|
||||
pan[20] = 0; pan[16] = 0; /* yoffset=0 xoffset=0, only to test */
|
||||
errno = 0;
|
||||
/* don't actually pan (avoid disturbing the player); just report errno of a
|
||||
* no-op probe would need a real pan. Instead check WAITFORVSYNC support. */
|
||||
uint32_t zero = 0;
|
||||
errno = 0;
|
||||
int wfs = ioctl(fd, 0x4620, &zero);
|
||||
printf("FBIO_WAITFORVSYNC(0x4620) = %d (errno=%d %s)\n", wfs, errno, strerror(errno));
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/* fbtool — fb0 helper: pan <yoffs> | blank <0|4> | copy | status.
|
||||
* Used to seed the double-buffer bug condition and clean up /dev/fb0.
|
||||
* ioctls: GETV 0x4600, GETFIX 0x4602, PAN 0x4606, BLANK 0x4611.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define GETV 0x4600
|
||||
#define GETFIX 0x4602
|
||||
#define PAN 0x4606
|
||||
#define BLANK 0x4611
|
||||
|
||||
static int set_blank(int fd, int bl) {
|
||||
errno = 0;
|
||||
int r = ioctl(fd, BLANK, bl);
|
||||
printf("blank(%d) r=%d errno=%d\n", bl, r, errno);
|
||||
return r;
|
||||
}
|
||||
static int set_pan(int fd, int yoff) {
|
||||
unsigned char v[160]; memset(v,0,sizeof v);
|
||||
if (ioctl(fd, GETV, v) < 0) { perror("getvar"); return -1; }
|
||||
*(uint32_t*)(v+16)=0; *(uint32_t*)(v+20)=(uint32_t)yoff;
|
||||
errno = 0;
|
||||
int r = ioctl(fd, PAN, v);
|
||||
unsigned char w[160]; memset(w,0,sizeof w);
|
||||
ioctl(fd, GETV, w);
|
||||
printf("pan(%u) r=%d errno=%d yoffset now=%u\n", yoff, r, errno, *(uint32_t*)(w+20));
|
||||
return r;
|
||||
}
|
||||
static int do_copy(int fd) {
|
||||
unsigned char v[160]; memset(v,0,sizeof v);
|
||||
if (ioctl(fd, GETV, v) < 0) { perror("getvar"); return -1; }
|
||||
uint32_t yres=*(uint32_t*)(v+4), yv=*(uint32_t*)(v+12), bpp=*(uint32_t*)(v+24);
|
||||
unsigned char f[68]; memset(f,0,sizeof f);
|
||||
if (ioctl(fd, GETFIX, f) < 0) { perror("getfix"); return -1; }
|
||||
uint32_t line = *(uint32_t*)(f+44); if (!line) line = yres*(bpp/8);
|
||||
if (yv < yres) { printf("not double-buffered\n"); return -1; }
|
||||
size_t frame = (size_t)line * yres;
|
||||
unsigned char *p = mmap(NULL, frame*2, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
if (p == MAP_FAILED) { perror("mmap"); return -1; }
|
||||
memcpy(p+frame, p, frame);
|
||||
munmap(p, frame*2);
|
||||
printf("copy buffer0 -> buffer1 (%zu bytes)\n", frame);
|
||||
return 0;
|
||||
}
|
||||
int main(int argc, char **argv) {
|
||||
if (argc < 2) { fprintf(stderr,"usage: fbtool {blank 0|4} | {pan N} | {copy}\n"); return 2; }
|
||||
int fd = open("/dev/fb0", O_RDWR);
|
||||
if (fd < 0) { perror("open"); return 1; }
|
||||
int r = 0;
|
||||
if (!strcmp(argv[1],"blank") && argc>2) r = set_blank(fd, atoi(argv[2]));
|
||||
else if (!strcmp(argv[1],"pan") && argc>2) r = set_pan(fd, atoi(argv[2]));
|
||||
else if (!strcmp(argv[1],"copy")) r = do_copy(fd);
|
||||
else fprintf(stderr,"unknown cmd\n"), r=2;
|
||||
close(fd);
|
||||
return r<0?1:0;
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
#!/usr/bin/env python3
|
||||
# gen_ui_font.py — 预渲染 MeowOS UI 位图字库(替代 freetype,零依赖)
|
||||
#
|
||||
# 输入默认字体(本脚本用设备自带 default.otf,因为 ~/Fonts 属主为 10195 不可读;
|
||||
# 如需切换思源黑体/MiSans,改 SRC 路径并把字体拷到可读处,或经 meow.conf font_file= 指定)。
|
||||
# 输出 ui_font.dat:自定义二进制位图字库(8-bit alpha 灰度,白字用 alpha,blit 时着色)。
|
||||
# 布局(小端):
|
||||
# +0 uint32 magic "UIF1"
|
||||
# +4 uint16 px (设计字号,用于行距/参考)
|
||||
# +6 uint16 flags (0 = 8-bit alpha 灰度)
|
||||
# +8 uint32 n (glyph 数)
|
||||
# +12 uint16 atlas_w (位图集宽)
|
||||
# +14 uint16 atlas_h
|
||||
# +16 16*n entry: uint32 cp; uint16 x,y,w,h,adv
|
||||
# +16+16*n bitmap: atlas_w*atlas_h 字节(8-bit alpha)
|
||||
#
|
||||
# 字符集:ASCII 0x20-0x7E + GB2312 一级汉字(0xB0-0xD7) + 常用 CJK 标点 + UI 显式字符串。
|
||||
import struct, sys
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
|
||||
SRC = "fw_ssh/squashfs-root/usr/resource/fonts/default.otf"
|
||||
PX = 24 # 设计像素高(大字,配合 40px 状态栏)
|
||||
OUT = sys.argv[1] if len(sys.argv) > 1 else "/tmp/ftg/ui_font.dat"
|
||||
|
||||
# ---- 字符集 ----
|
||||
chars = set()
|
||||
for c in range(0x20, 0x7F):
|
||||
chars.add(chr(c)) # ASCII 可打印
|
||||
# GB2312 一级汉字: 0xB0A1(176,161) .. 0xD7F9(215,249),每行 94
|
||||
for row in range(0xB0, 0xD8):
|
||||
for col in range(0xA1, 0xFF):
|
||||
b = bytes([row, col])
|
||||
try:
|
||||
ch = b.decode('gb2312')
|
||||
except Exception:
|
||||
continue
|
||||
if ch and not ch.startswith(' '):
|
||||
# 去掉 PUA/未定义区
|
||||
if ord(ch[0]) >= 0x4E00 or (0xFF00 <= ord(ch[0]) <= 0xFFEF):
|
||||
chars.add(ch[0])
|
||||
# 常用 CJK 标点 / 全角
|
||||
for ch in ",。、!?:;()《》【】「」『』—…¥%·×÷=+-· 〇":
|
||||
chars.add(ch)
|
||||
# UI 显式中文(电源菜单/状态栏/提示),确保必有
|
||||
for ch in "关机重启回到取消电源菜单音量蓝牙电量充电返回播放器需网络设置我你的好中英文数分秒年月日应用没有存储卡请插入后开吃到找到放缺失导航打触摸选择无法启动以确认上下":
|
||||
chars.add(ch)
|
||||
chars = sorted(chars)
|
||||
|
||||
# 宽字符(CJK)用 PX 高,ASCII 用较小一点以保持基线一致;Pillow 自带 advance
|
||||
font = ImageFont.truetype(SRC, PX)
|
||||
|
||||
# ---- 栅格化并打包进 atlas(行优先)----
|
||||
# 先用足够大的空白画布测量每个字符 bitmap,再打包
|
||||
tmp_img_cache = {}
|
||||
maxw = PX * 2
|
||||
packed = [] # (char, bbox_img, w, h, adv)
|
||||
scale = 1
|
||||
# 计算每个字符的 bitmap(grayscale alpha)
|
||||
metas = []
|
||||
for ch in chars:
|
||||
if ch == ' ':
|
||||
# 空格无 bitmap,只记 advance
|
||||
adv = font.getlength(' ')
|
||||
metas.append((ch, None, 0, 0, int(adv)))
|
||||
continue
|
||||
try:
|
||||
bbox = font.getbbox(ch)
|
||||
except Exception:
|
||||
bbox = None
|
||||
if not bbox:
|
||||
adv = int(font.getlength(ch))
|
||||
metas.append((ch, None, 0, 0, adv))
|
||||
continue
|
||||
x0, y0, x1, y1 = bbox
|
||||
w = max(1, x1 - x0); h = max(1, y1 - y0)
|
||||
# 渲染到 grayscale (alpha=灰度)
|
||||
im = Image.new('L', (w, h), 0)
|
||||
# 用 getmask 更精确;这里直接画到临时图再裁
|
||||
mask = font.getmask(ch, mode='L')
|
||||
im = Image.frombytes('L', mask.size, bytes(mask))
|
||||
# 裁到 bbox 对应的部分
|
||||
if 0 <= y0 < im.height and 0 <= x0 < im.width:
|
||||
im = im.crop((max(0, x0), max(0, y0), min(im.width, x1), min(im.height, y1)))
|
||||
adv = int(font.getlength(ch))
|
||||
metas.append((ch, im, im.width, im.height, adv))
|
||||
|
||||
# 打包:放入 atlas(简单行打包,一行放满再换行)
|
||||
atlas_w = 512
|
||||
atlas_rows = []
|
||||
x = 0; y = 0; maxY = 0
|
||||
entry_pos = {} # char -> (x,y,w,h,adv)
|
||||
# 先按宽高打包
|
||||
pos_list = []
|
||||
curx = 0; cury = 0; rowh = 0
|
||||
entries = []
|
||||
for ch, im, w, h, adv in metas:
|
||||
if im is None:
|
||||
entries.append((ch, 0, 0, 0, 0, adv)); continue
|
||||
if curx + w > atlas_w:
|
||||
curx = 0; cury += rowh; rowh = 0
|
||||
entry_pos[ch] = (curx, cury, w, h)
|
||||
entries.append((ch, curx, cury, w, h, adv))
|
||||
curx += w + 1
|
||||
rowh = max(rowh, h)
|
||||
if cury + rowh > 4096:
|
||||
raise RuntimeError("atlas too tall")
|
||||
atlas_h = cury + rowh
|
||||
|
||||
atlas = bytearray(atlas_w * atlas_h)
|
||||
for ch, im, w, h, adv in metas:
|
||||
if im is None: continue
|
||||
x, y, w, h = entry_pos[ch][0], entry_pos[ch][1], entry_pos[ch][2], entry_pos[ch][3]
|
||||
for yy in range(h):
|
||||
for xx in range(w):
|
||||
v = im.getpixel((xx, yy))
|
||||
atlas[(y + yy) * atlas_w + (x + xx)] = v
|
||||
|
||||
# ---- 写文件 ----
|
||||
with open(OUT, 'wb') as f:
|
||||
f.write(struct.pack('<I', 0x55494631)) # magic "UIF1"
|
||||
f.write(struct.pack('<H', PX)) # px
|
||||
f.write(struct.pack('<H', 0)) # flags 8-bit alpha
|
||||
f.write(struct.pack('<I', len(entries))) # n
|
||||
f.write(struct.pack('<H', atlas_w)) # atlas_w
|
||||
f.write(struct.pack('<H', atlas_h)) # atlas_h
|
||||
for ch, x, y, w, h, adv in entries:
|
||||
f.write(struct.pack('<IHHHHH', ord(ch), x, y, w, h, adv))
|
||||
f.write(bytes(atlas))
|
||||
|
||||
print(f"chars={len(chars)} entries={len(entries)} atlas={atlas_w}x{atlas_h} out={OUT}")
|
||||
import os
|
||||
print(f"size={os.path.getsize(OUT)} bytes")
|
||||
|
||||
# 自检:渲染取样图(含中文 + 英文)
|
||||
img = Image.new('RGB', (480, 40), (0,0,0))
|
||||
d = ImageDraw.Draw(img)
|
||||
f = ImageFont.truetype(SRC, PX)
|
||||
d.text((4, 4), "关机重启 回到HibyOS 取消 音量蓝牙 12:30:45 100%", font=f, fill=(255,255,255))
|
||||
img.save('/tmp/ftg/ui_font_sample.png')
|
||||
print("sample saved /tmp/ftg/ui_font_sample.png")
|
||||
@@ -0,0 +1,8 @@
|
||||
#!/bin/sh
|
||||
# meow_card_path.sh - TF 卡 MeowOS/opt/bin(外围 CLI 迁卡后)在卡在时前插 PATH;无卡跳过不崩。
|
||||
# 安装到 rootfs /etc/profile.d/(由 /etc/profile 对登录 shell source)。
|
||||
# 使 SSH 登录会话可直接用卡上工具(curl/socat/tmux/jq/rsync/nano/htop/ncdu/file/xxd)。
|
||||
# MeowOS 启动器把该目录前插进自启子进程的 PATH(见 meow_launcherd.c);本文件覆盖 SSH 会话。
|
||||
if [ -d /usr/data/mnt/sd_0/MeowOS/opt/bin ]; then
|
||||
export PATH="/usr/data/mnt/sd_0/MeowOS/opt/bin:$PATH"
|
||||
fi
|
||||
@@ -0,0 +1,57 @@
|
||||
#ifndef MEOW_FONT_H
|
||||
#define MEOW_FONT_H
|
||||
/*
|
||||
* meow_font.h — MeowOS 预渲染位图字体运行时(独立、可复用,不绑定启动器)。
|
||||
*
|
||||
* 数据来源:由 gen/gen_font.py 生成的 font.png(灰度 PNG,bit depth 4|8,含各字号面)
|
||||
* + font.idx(索引:头部 + 每面元数据 + 每字符 16B 记录)。
|
||||
*
|
||||
* 设备端加载:模块内建最小 PNG 解码(仅支持灰度非隔行)经 zlib inflate + 反滤波还原像素,
|
||||
* 无需 libpng;交叉链接 musl 静态 libz.a。像素面按 depth=4|8 打包存储,取像素时按 nibble 解包。
|
||||
*
|
||||
* 绘制模型:drawtext(fb, x, y, utf8, color, size);(x,y)=行首「升线(top)」锚点;
|
||||
* baseline = y + ascent;每字形 blit 于 (x + pen + dx, y + dy);pen 累加 advance。
|
||||
* color 为 565 位 RGB(R 在 bit15..11,G bit10..5,B bit4..0),与 launcher 一致。
|
||||
* 无字回退:缺码位画空心方块(tofu)并前进空格宽度。
|
||||
*
|
||||
* 字号:字库含若干原生面(如 28、20)。drawtext 请求 size 时先找精确匹配面;
|
||||
* 若无则就近取一面做最近邻缩放(最优仍用原生字号)。
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* 设置 framebuffer 几何:宽/高(像素)与每行字节数(如 480*2)。绘制前调用一次。 */
|
||||
void meow_font_set_fb(unsigned fb_w, unsigned fb_h, unsigned pitch_bytes);
|
||||
|
||||
/* 加载字库(全部字号)。成功返回 0,失败返回负值。可重复调用(先卸载旧的)。 */
|
||||
int meow_font_load(const char *png_path, const char *idx_path);
|
||||
|
||||
/* 释放字库。 */
|
||||
void meow_font_unload(void);
|
||||
|
||||
/* 某字号是否存在(命中原生面返回 1)。 */
|
||||
int meow_font_has_size(int size);
|
||||
|
||||
/* UTF-8 字符串渲染宽度(px)。字面不存在返回 0。 */
|
||||
int meow_font_width_text(const char *utf8, int size);
|
||||
|
||||
/* 行高(px = ascent + descent)。 */
|
||||
int meow_font_line_height(int size);
|
||||
int meow_font_ascent(int size);
|
||||
|
||||
/* 绘制文本:(x,y)=行首升线顶部;color=RGB565。已按 fb_w/fb_h 裁剪。 */
|
||||
void meow_font_drawtext(uint16_t *fb, int x, int y, const char *utf8,
|
||||
uint16_t color, int size);
|
||||
|
||||
/* 描边绘制:先以 outline_color 将每字形向 4/8 邻域平移 ol 绘制一圈,再以 color 填充。 */
|
||||
void meow_font_drawtext_outline(uint16_t *fb, int x, int y, const char *utf8,
|
||||
uint16_t color, uint16_t outline_color, int ol, int size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* MEOW_FONT_H */
|
||||
Executable
BIN
Binary file not shown.
@@ -0,0 +1,334 @@
|
||||
/* meow_ipc.c — MeowOS IPC 测试钩子(阶段 D · M0+M1;与 evtool 同定位)。
|
||||
*
|
||||
* 向 meow_launcherd 的 AF_UNIX IPC(FRAMEWORK_DESIGN §1)发帧、收应答并打印。
|
||||
* 静态 MIPS32r2 musl(用 zig-mipsel-cc 编译),qemu-mipsel 亦可用。
|
||||
*
|
||||
* 子命令:
|
||||
* meow_ipc hello <app_id> [version] [flags] → MSG_HELLO,期望 MSG_ACK
|
||||
* meow_ipc ping [app_id] → hello 别名(默认 meow_ipc)
|
||||
* meow_ipc query <app_id> <activity> → MSG_ACT_QUERY,期望 MSG_ACT_RESULT
|
||||
* meow_ipc declare <app_id> <route_id=chain> [...] → MSG_ACT_DECLARE,期望 MSG_ACK
|
||||
* 全局:
|
||||
* --sock <path> 覆盖 socket 路径(默认可被 MEOW_IPC_SOCK 覆盖,再回退 /usr/data/meow_ipc.sock)
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/stat.h>
|
||||
#include "meow_ipc.h"
|
||||
|
||||
static const char *g_sock = NULL;
|
||||
|
||||
static void print_err(const m_err_t *e)
|
||||
{
|
||||
fprintf(stderr, "ERR 0x%x: %.*s\n", e->code, e->msg_len < 64 ? e->msg_len : 64, e->msg);
|
||||
}
|
||||
|
||||
static int connect_path(const char *path)
|
||||
{
|
||||
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (fd < 0) { perror("socket"); return -1; }
|
||||
struct sockaddr_un a;
|
||||
memset(&a, 0, sizeof a);
|
||||
a.sun_family = AF_UNIX;
|
||||
strncpy(a.sun_path, path, sizeof a.sun_path - 1);
|
||||
if (connect(fd, (struct sockaddr *)&a, sizeof a) < 0) {
|
||||
fprintf(stderr, "connect %s: %s\n", path, strerror(errno));
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
/* 发一帧(头+负载),读回一帧(头+负载)。返回应答类型;-1=失败。 */
|
||||
static int xchg(int fd, uint16_t type, uint32_t req_id, const void *payload, uint32_t len,
|
||||
uint8_t *rbuf, uint32_t rcap)
|
||||
{
|
||||
uint8_t hdr[MEOW_IPC_HDR_LEN];
|
||||
uint32_t magic = MEOW_IPC_MAGIC;
|
||||
uint16_t ver = MEOW_IPC_VERSION;
|
||||
memcpy(hdr + 0, &magic, 4);
|
||||
memcpy(hdr + 4, &ver, 2);
|
||||
memcpy(hdr + 6, &type, 2);
|
||||
memcpy(hdr + 8, &req_id, 4);
|
||||
memcpy(hdr + 12, &len, 4);
|
||||
size_t off = 0;
|
||||
while (off < sizeof hdr) {
|
||||
ssize_t w = write(fd, hdr + off, sizeof hdr - off);
|
||||
if (w <= 0) { perror("write hdr"); return -1; }
|
||||
off += (size_t)w;
|
||||
}
|
||||
if (len && payload) {
|
||||
size_t p = 0;
|
||||
while (p < len) {
|
||||
ssize_t w = write(fd, (const uint8_t *)payload + p, len - p);
|
||||
if (w <= 0) { perror("write payload"); return -1; }
|
||||
p += (size_t)w;
|
||||
}
|
||||
}
|
||||
/* read response header */
|
||||
uint8_t rhdr[MEOW_IPC_HDR_LEN];
|
||||
off = 0;
|
||||
while (off < sizeof rhdr) {
|
||||
ssize_t r = read(fd, rhdr + off, sizeof rhdr - off);
|
||||
if (r <= 0) { perror("read hdr"); return -1; }
|
||||
off += (size_t)r;
|
||||
}
|
||||
uint32_t rmagic, rlen;
|
||||
uint16_t rver, rtype;
|
||||
memcpy(&rmagic, rhdr, 4);
|
||||
memcpy(&rver, rhdr + 4, 2);
|
||||
memcpy(&rtype, rhdr + 6, 2);
|
||||
memcpy(&rlen, rhdr + 12, 4);
|
||||
if (rmagic != MEOW_IPC_MAGIC) { fprintf(stderr, "bad resp magic %08x\n", rmagic); return -1; }
|
||||
if (rver != MEOW_IPC_VERSION) { fprintf(stderr, "bad resp version %u\n", rver); return -1; }
|
||||
if (rlen > rcap) rlen = rcap;
|
||||
off = 0;
|
||||
while (off < rlen) {
|
||||
ssize_t r = read(fd, rbuf + off, rlen - off);
|
||||
if (r <= 0) { perror("read payload"); return -1; }
|
||||
off += (size_t)r;
|
||||
}
|
||||
return (int)rtype;
|
||||
}
|
||||
|
||||
static int cmd_hello(const char *app_id, uint32_t version, uint32_t flags)
|
||||
{
|
||||
const char *sock = g_sock;
|
||||
int fd = connect_path(sock);
|
||||
if (fd < 0) return 1;
|
||||
m_hello_t h;
|
||||
memset(&h, 0, sizeof h);
|
||||
strncpy(h.app_id, app_id, MEOW_APP_ID_MAX - 1);
|
||||
h.version = version;
|
||||
h.flags = flags;
|
||||
uint8_t rbuf[256];
|
||||
int rt = xchg(fd, MSG_HELLO, 1, &h, sizeof h, rbuf, sizeof rbuf);
|
||||
close(fd);
|
||||
if (rt == MSG_ACK) {
|
||||
m_ack_t a;
|
||||
memcpy(&a, rbuf, sizeof a);
|
||||
printf("HELLO ok: code=%d status=%u (apps registered)\n", a.code, a.status);
|
||||
return a.code == MEOW_OK ? 0 : 1;
|
||||
}
|
||||
if (rt == MSG_ERR) { print_err((const m_err_t *)rbuf); return 1; }
|
||||
fprintf(stderr, "HELLO: unexpected resp type 0x%04x\n", rt);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int cmd_query(const char *app_id, const char *activity)
|
||||
{
|
||||
int fd = connect_path(g_sock);
|
||||
if (fd < 0) return 1;
|
||||
m_act_query_t q;
|
||||
memset(&q, 0, sizeof q);
|
||||
strncpy(q.app_id, app_id, MEOW_APP_ID_MAX - 1);
|
||||
strncpy(q.activity, activity, MEOW_ACT_MAX - 1);
|
||||
uint8_t rbuf[256];
|
||||
int rt = xchg(fd, MSG_ACT_QUERY, 2, &q, sizeof q, rbuf, sizeof rbuf);
|
||||
close(fd);
|
||||
if (rt == MSG_ACT_RESULT) {
|
||||
m_act_result_t r;
|
||||
memcpy(&r, rbuf, sizeof r);
|
||||
size_t cl = r.chain_len < MEOW_CHAIN_MAX ? r.chain_len : MEOW_CHAIN_MAX - 1;
|
||||
char chain[MEOW_CHAIN_MAX];
|
||||
memcpy(chain, r.chain, cl);
|
||||
chain[cl] = 0;
|
||||
printf("QUERY ok: app=%s act=%s depth=%u chain=%s\n", app_id, activity,
|
||||
r.depth, cl ? chain : "(empty)");
|
||||
return r.code == MEOW_OK ? 0 : 1;
|
||||
}
|
||||
if (rt == MSG_ERR) { print_err((const m_err_t *)rbuf); return 1; }
|
||||
fprintf(stderr, "QUERY: unexpected resp type 0x%04x\n", rt);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int cmd_declare(const char *app_id, int nent, char **ents)
|
||||
{
|
||||
int fd = connect_path(g_sock);
|
||||
if (fd < 0) return 1;
|
||||
m_act_declare_t d;
|
||||
memset(&d, 0, sizeof d);
|
||||
strncpy(d.app_id, app_id, MEOW_APP_ID_MAX - 1);
|
||||
int n = 0;
|
||||
char *p = d.entries;
|
||||
int cap = (int)sizeof(d.entries);
|
||||
for (int i = 0; i < nent && n < 8; i++) {
|
||||
size_t l = strlen(ents[i]);
|
||||
if (l + 1 > (size_t)(d.entries + sizeof d.entries - p)) break;
|
||||
memcpy(p, ents[i], l + 1);
|
||||
p += l + 1;
|
||||
n++;
|
||||
}
|
||||
d.count = (uint16_t)n;
|
||||
uint32_t len = (uint32_t)(sizeof d.app_id + 2 + 2 + (p - d.entries));
|
||||
uint8_t rbuf[256];
|
||||
int rt = xchg(fd, MSG_ACT_DECLARE, 3, &d, len, rbuf, sizeof rbuf);
|
||||
close(fd);
|
||||
if (rt == MSG_ACK) {
|
||||
m_ack_t a;
|
||||
memcpy(&a, rbuf, sizeof a);
|
||||
printf("DECLARE ok: app=%s n=%d code=%d\n", app_id, n, a.code);
|
||||
return a.code == MEOW_OK ? 0 : 1;
|
||||
}
|
||||
if (rt == MSG_ERR) { print_err((const m_err_t *)rbuf); return 1; }
|
||||
fprintf(stderr, "DECLARE: unexpected resp type 0x%04x\n", rt);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int cmd_focus(const char *app_id, const char *activity)
|
||||
{
|
||||
int fd = connect_path(g_sock);
|
||||
if (fd < 0) return 1;
|
||||
m_act_focus_t f;
|
||||
memset(&f, 0, sizeof f);
|
||||
strncpy(f.app_id, app_id, MEOW_APP_ID_MAX - 1);
|
||||
strncpy(f.activity, activity, MEOW_ACT_MAX - 1);
|
||||
uint8_t rbuf[256];
|
||||
int rt = xchg(fd, MSG_ACT_FOCUS, 4, &f, sizeof f, rbuf, sizeof rbuf);
|
||||
close(fd);
|
||||
if (rt == MSG_ACK) {
|
||||
m_ack_t a;
|
||||
memcpy(&a, rbuf, sizeof a);
|
||||
printf("FOCUS ok: app=%s act=%s code=%d\n", app_id, activity, a.code);
|
||||
return a.code == MEOW_OK ? 0 : 1;
|
||||
}
|
||||
if (rt == MSG_ERR) { print_err((const m_err_t *)rbuf); return 1; }
|
||||
fprintf(stderr, "FOCUS: unexpected resp type 0x%04x\n", rt);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int cmd_back(void)
|
||||
{
|
||||
int fd = connect_path(g_sock);
|
||||
if (fd < 0) return 1;
|
||||
uint8_t rbuf[256];
|
||||
int rt = xchg(fd, MSG_ACT_BACK, 5, NULL, 0, rbuf, sizeof rbuf);
|
||||
close(fd);
|
||||
if (rt == MSG_ACK) {
|
||||
m_ack_t a;
|
||||
memcpy(&a, rbuf, sizeof a);
|
||||
printf("BACK ok: code=%d\n", a.code);
|
||||
return a.code == MEOW_OK ? 0 : 1;
|
||||
}
|
||||
if (rt == MSG_ERR) { print_err((const m_err_t *)rbuf); return 1; }
|
||||
fprintf(stderr, "BACK: unexpected resp type 0x%04x\n", rt);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* M2a:推送通知 → MSG_NOTIFY,期望 MSG_NOTIFY_ACK。 */
|
||||
static int cmd_notify(const char *app_id, const char *category, const char *summary,
|
||||
const char *body, uint32_t replaces_id, int ongoing, int media, int progress)
|
||||
{
|
||||
int fd = connect_path(g_sock);
|
||||
if (fd < 0) return 1;
|
||||
m_notify_t n;
|
||||
memset(&n, 0, sizeof n);
|
||||
strncpy(n.app_id, app_id, MEOW_APP_ID_MAX - 1);
|
||||
strncpy(n.category, category, sizeof n.category - 1);
|
||||
strncpy(n.summary, summary, sizeof n.summary - 1);
|
||||
if (body) strncpy(n.body, body, sizeof n.body - 1);
|
||||
n.replaces_id = replaces_id;
|
||||
n.ongoing = ongoing ? 1 : 0;
|
||||
n.media = media ? 1 : 0;
|
||||
n.progress = progress;
|
||||
n.expire_timeout = ongoing ? 0xFFFFFFFFu : 0; /* ONGOING 常驻 */
|
||||
uint8_t rbuf[256];
|
||||
int rt = xchg(fd, MSG_NOTIFY, 6, &n, sizeof n, rbuf, sizeof rbuf);
|
||||
close(fd);
|
||||
if (rt == MSG_NOTIFY_ACK) {
|
||||
m_ack_t a;
|
||||
memcpy(&a, rbuf, sizeof a);
|
||||
printf("NOTIFY ok: id=%u code=%d\n", a.status, a.code);
|
||||
return a.code == MEOW_OK ? 0 : 1;
|
||||
}
|
||||
if (rt == MSG_ERR) { print_err((const m_err_t *)rbuf); return 1; }
|
||||
fprintf(stderr, "NOTIFY: unexpected resp type 0x%04x\n", rt);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* M2a:撤下通知 → MSG_NOTIFY_DISMISS,期望 MSG_ACK。 */
|
||||
static int cmd_dismiss(uint32_t id)
|
||||
{
|
||||
int fd = connect_path(g_sock);
|
||||
if (fd < 0) return 1;
|
||||
uint8_t rbuf[256];
|
||||
int rt = xchg(fd, MSG_NOTIFY_DISMISS, 7, &id, sizeof id, rbuf, sizeof rbuf);
|
||||
close(fd);
|
||||
if (rt == MSG_ACK) {
|
||||
m_ack_t a;
|
||||
memcpy(&a, rbuf, sizeof a);
|
||||
printf("DISMISS ok: id=%u code=%d\n", id, a.code);
|
||||
return a.code == MEOW_OK ? 0 : 1;
|
||||
}
|
||||
if (rt == MSG_ERR) { print_err((const m_err_t *)rbuf); return 1; }
|
||||
fprintf(stderr, "DISMISS: unexpected resp type 0x%04x\n", rt);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *env = getenv("MEOW_IPC_SOCK");
|
||||
g_sock = (env && env[0]) ? env : MEOW_IPC_PATH;
|
||||
|
||||
/* parse leading global options */
|
||||
int i = 1;
|
||||
for (; i < argc; i++) {
|
||||
if (!strcmp(argv[i], "--sock") && i + 1 < argc) { g_sock = argv[++i]; }
|
||||
else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
|
||||
fprintf(stderr, "usage: meow_ipc [--sock <path>] hello|ping|query|declare ...\n");
|
||||
return 0;
|
||||
}
|
||||
else break;
|
||||
}
|
||||
if (i >= argc) { fprintf(stderr, "bad args; try --help\n"); return 1; }
|
||||
|
||||
const char *cmd = argv[i];
|
||||
if (!strcmp(cmd, "hello")) {
|
||||
if (i + 1 >= argc) { fprintf(stderr, "hello needs <app_id>\n"); return 1; }
|
||||
uint32_t ver = (i + 2 < argc) ? (uint32_t)strtoul(argv[i + 2], NULL, 0) : 1;
|
||||
uint32_t flg = (i + 3 < argc) ? (uint32_t)strtoul(argv[i + 3], NULL, 0) : 0;
|
||||
return cmd_hello(argv[i + 1], ver, flg);
|
||||
}
|
||||
if (!strcmp(cmd, "ping")) {
|
||||
const char *app = (i + 1 < argc) ? argv[i + 1] : "meow_ipc";
|
||||
return cmd_hello(app, 1, 0);
|
||||
}
|
||||
if (!strcmp(cmd, "query")) {
|
||||
if (i + 2 >= argc) { fprintf(stderr, "query needs <app_id> <activity>\n"); return 1; }
|
||||
return cmd_query(argv[i + 1], argv[i + 2]);
|
||||
}
|
||||
if (!strcmp(cmd, "declare")) {
|
||||
if (i + 2 >= argc) { fprintf(stderr, "declare needs <app_id> <route_id=chain> [...]\n"); return 1; }
|
||||
return cmd_declare(argv[i + 1], argc - i - 2, argv + i + 2);
|
||||
}
|
||||
if (!strcmp(cmd, "focus")) {
|
||||
if (i + 2 >= argc) { fprintf(stderr, "focus needs <app_id> <activity>\n"); return 1; }
|
||||
return cmd_focus(argv[i + 1], argv[i + 2]);
|
||||
}
|
||||
if (!strcmp(cmd, "back")) {
|
||||
return cmd_back();
|
||||
}
|
||||
if (!strcmp(cmd, "notify")) {
|
||||
/* notify <app_id> <category> <summary> [body] [replaces_id] [ongoing] [media] [progress] */
|
||||
if (i + 2 >= argc) { fprintf(stderr, "notify needs <app_id> <category> <summary>\n"); return 1; }
|
||||
const char *body = (i + 4 < argc) ? argv[i + 4] : "";
|
||||
uint32_t rid = (i + 5 < argc) ? (uint32_t)strtoul(argv[i + 5], NULL, 0) : 0;
|
||||
int ongoing = (i + 6 < argc) ? atoi(argv[i + 6]) : 0;
|
||||
int media = (i + 7 < argc) ? atoi(argv[i + 7]) : 0;
|
||||
int progress = (i + 8 < argc) ? atoi(argv[i + 8]) : -1;
|
||||
return cmd_notify(argv[i + 1], argv[i + 2], argv[i + 3], body, rid, ongoing, media, progress);
|
||||
}
|
||||
if (!strcmp(cmd, "dismiss")) {
|
||||
if (i + 1 >= argc) { fprintf(stderr, "dismiss needs <id>\n"); return 1; }
|
||||
return cmd_dismiss((uint32_t)strtoul(argv[i + 1], NULL, 0));
|
||||
}
|
||||
fprintf(stderr, "unknown cmd %s; try --help\n", cmd);
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
/* meow_ipc.h — MeowOS IPC 协议定义(FRAMEWORK_DESIGN §1 / MEOWOS_API.md §1)。
|
||||
*
|
||||
* 客户端(meow_ipc 测试钩子)与守护进程(meow_launcherd)共用一份,杜绝两端漂移。
|
||||
* 传输:AF_UNIX SOCK_STREAM,路径默认 /usr/data/meow_ipc.sock(可被 --ipc-sock /
|
||||
* MEOW_IPC_SOCK 覆盖,供 qemu sim)。
|
||||
* 帧格式:定长头(16B) + 变长负载,**全部小端 LE**(mipsel 原生)。
|
||||
*
|
||||
* struct ipc_hdr { LE 字节序
|
||||
* uint32_t magic; = 0x4D4F5701 == 'MEOW'|1
|
||||
* uint16_t version; = 1
|
||||
* uint16_t type; = msg_type
|
||||
* uint32_t req_id; = 请求id,响应回显
|
||||
* uint32_t len; = payload 字节数
|
||||
* };
|
||||
*
|
||||
* 本阶段(D · M0+M1)通讯子集:MSG_HELLO/ACK/ERR + MSG_ACT_DECLARE/QUERY/RESULT。
|
||||
*/
|
||||
#ifndef MEOW_IPC_H
|
||||
#define MEOW_IPC_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#define MEOW_IPC_MAGIC 0x4D4F5701u
|
||||
#define MEOW_IPC_VERSION 1u
|
||||
#define MEOW_IPC_PATH "/usr/data/meow_ipc.sock"
|
||||
#define MEOW_IPC_SOCK_LEN 108 /* sockaddr_un.sun_path */
|
||||
#define MEOW_IPC_MAX 4096u /* 单帧负载上限 */
|
||||
#define MEOW_IPC_HDR_LEN 16u
|
||||
|
||||
/* 列表编码上限(count 个 NUL 字符串时,distinct 工作缓冲上限) */
|
||||
#define MEOW_IPC_CARGO 1024u /* 守护进程入队拷贝上限(可小于 MEOW_IPC_MAX) */
|
||||
|
||||
/* ---- 消息类型(FRAMEWORK_DESIGN §1 表)---- */
|
||||
enum {
|
||||
MSG_NONE = 0x0000,
|
||||
MSG_HELLO = 0x0001, /* ↑ 声明 app_id/版本/能力 */
|
||||
MSG_ACK = 0x0002, /* ↓ 握手/应答 */
|
||||
MSG_ERR = 0x0003, /* ↓ 错误码 */
|
||||
MSG_REGISTER = 0x0010, /* ↑ 注册后台服务(保持连接) */
|
||||
MSG_SERVICE_OK = 0x0011, /* ↓ 服务登记成功 */
|
||||
MSG_SERVICE_STOP = 0x0012, /* ↑ 请求停止服务 */
|
||||
MSG_NOTIFY = 0x0020, /* ↑ 推送/更新通知 */
|
||||
MSG_NOTIFY_ACK = 0x0021, /* ↓ 落库结果 */
|
||||
MSG_NOTIFY_DISMISS = 0x0022, /* ↑ 撤下通知 */
|
||||
MSG_NOTIFY_LIST = 0x0023, /* ↓ 下发通知清单(重同步) */
|
||||
MSG_ACT_DECLARE = 0x0030, /* ↑ (重)声明路由表 */
|
||||
MSG_ACT_QUERY = 0x0031, /* ↑ 解析 activity 链路 */
|
||||
MSG_ACT_RESULT = 0x0032, /* ↓ 返回链路 */
|
||||
MSG_ACT_FOCUS = 0x0033, /* ↑ 上报当前顶层 activity(keep_awake 判定,M2.17) */
|
||||
MSG_ACT_BACK = 0x0034, /* ↑ 上报回到根/无 activity(清 keep_awake,M2.17) */
|
||||
MSG_NAV = 0x0040, /* ↑ 上报导航/请求退出 */
|
||||
MSG_SHOW_ACTIVITY= 0x0041, /* ↓ 令前端应用显示某屏 */
|
||||
MSG_SYS = 0x00F0 /* ↓ 系统事件(守护关闭/服务死亡/播放器状态) */
|
||||
};
|
||||
|
||||
/* ---- 返回码(MEOWOS_API.md §1,与 HTTP 层一致)---- */
|
||||
enum {
|
||||
MEOW_OK = 0,
|
||||
MEOW_ERR_INVAL = -1,
|
||||
MEOW_ERR_NOENT = -2,
|
||||
MEOW_ERR_EXISTS = -3,
|
||||
MEOW_ERR_PERM = -4,
|
||||
MEOW_ERR_IO = -5,
|
||||
MEOW_ERR_NOMEM = -6,
|
||||
MEOW_ERR_NOTINIT = -7,
|
||||
MEOW_ERR_BUSY = -8,
|
||||
MEOW_ERR_TIMEOUT = -9,
|
||||
MEOW_ERR_NODEV = -10,
|
||||
MEOW_ERR_INTERNAL = -255
|
||||
};
|
||||
|
||||
/* ---- HELLO flags(附录 A 声明式权限)---- */
|
||||
#define MF_BACKGROUND 0x00000001u /* 可后台常驻 */
|
||||
#define MF_PLAYBACK 0x00000002u /* 后台音频/播放 */
|
||||
|
||||
/* ---- 标识/长度 ---- */
|
||||
#define MEOW_APP_ID_MAX 32
|
||||
#define MEOW_ACT_MAX 64
|
||||
#define MEOW_CHAIN_MAX 160
|
||||
|
||||
/* ---- 负载结构(全部 LE;mipsel 原生对齐,字段 4 字节对齐)---- */
|
||||
|
||||
/* MSG_HELLO ↑:应用声明 */
|
||||
typedef struct m_hello {
|
||||
char app_id[MEOW_APP_ID_MAX];
|
||||
uint32_t version;
|
||||
uint32_t flags;
|
||||
uint32_t caps; /* 预留能力位 */
|
||||
} m_hello_t; /* 44 B */
|
||||
|
||||
/* MSG_ACK ↓:握手/应答 */
|
||||
typedef struct m_ack {
|
||||
uint32_t code; /* 0=MEOW_OK */
|
||||
uint32_t status; /* 附加(如已注册 app 数) */
|
||||
} m_ack_t; /* 8 B */
|
||||
|
||||
/* MSG_ERR ↓:错误码 + 短消息 */
|
||||
typedef struct m_err {
|
||||
uint32_t code;
|
||||
uint16_t msg_len;
|
||||
char msg[64];
|
||||
} m_err_t;
|
||||
|
||||
/* MSG_ACT_QUERY ↑:解析某 app 的 activity 链路 */
|
||||
typedef struct m_act_query {
|
||||
char app_id[MEOW_APP_ID_MAX];
|
||||
char activity[MEOW_ACT_MAX];
|
||||
} m_act_query_t; /* 96 B */
|
||||
|
||||
/* MSG_ACT_FOCUS ↑:上报当前顶层 activity(keep_awake 判定,M2.17) */
|
||||
typedef struct m_act_focus {
|
||||
char app_id[MEOW_APP_ID_MAX];
|
||||
char activity[MEOW_ACT_MAX];
|
||||
} m_act_focus_t; /* 96 B */
|
||||
|
||||
/* MSG_ACT_RESULT ↓:返回链路(root..target),depth=链路逻辑深度 */
|
||||
typedef struct m_act_result {
|
||||
uint32_t depth;
|
||||
uint32_t code; /* MEOW_OK / MEOW_ERR_NOENT(act 未注册) */
|
||||
uint16_t chain_len; /* chain 有效字节 */
|
||||
uint16_t pad;
|
||||
char chain[MEOW_CHAIN_MAX];
|
||||
} m_act_result_t; /* 172 B */
|
||||
|
||||
/* MSG_ACT_DECLARE ↑:运行时声明路由表。app_id + count 个 NUL 结尾字符串,
|
||||
* 每串形如 "<route_id>=<chain>"(如 "nowplaying=home;search;nowplaying")。
|
||||
* 守护进程并集覆盖静态 app.json 路由。 */
|
||||
typedef struct m_act_declare {
|
||||
char app_id[MEOW_APP_ID_MAX];
|
||||
uint16_t count;
|
||||
uint16_t pad;
|
||||
char entries[MEOW_IPC_CARGO - MEOW_APP_ID_MAX - 4];
|
||||
} m_act_declare_t;
|
||||
|
||||
/* MSG_NOTIFY ↑:推送/更新通知(freedesktop 对齐 + MeowOS 扩展;定长 LE)。
|
||||
* - summary/body/app_icon/expire_timeout 直通 freedesktop 字段;
|
||||
* - target_activity/progress 为 MeowOS 专有(存储层映射为 hints 的
|
||||
* meow.target_activity / meow.progress);
|
||||
* - actions[]/hints{} v1 走定长空串(M2b D-Bus 桥再填);media/ongoing 标记。
|
||||
* 宿主:NOTIFICATION_SYSTEM.md §2/§4 + FRAMEWORK_DESIGN §4/附C。 */
|
||||
typedef struct m_notify {
|
||||
char app_id[MEOW_APP_ID_MAX]; /* 来源应用;系统事件="system" */
|
||||
char category[24]; /* 通知类型(媒体通知="media") */
|
||||
char summary[64];
|
||||
char body[96];
|
||||
char app_icon[48];
|
||||
char target_activity[MEOW_ACT_MAX]; /* MeowOS:点击跳转目标 activity */
|
||||
uint32_t replaces_id; /* 0=新建;>0=替换已存在通知 */
|
||||
uint32_t expire_timeout; /* ms;0xFFFFFFFF=ONGOING 常驻 */
|
||||
int32_t progress; /* MeowOS:0-100;<0=无 */
|
||||
uint8_t media; /* 1=媒体通知 */
|
||||
uint8_t ongoing; /* 1=常驻通知 */
|
||||
uint16_t pad;
|
||||
} m_notify_t; /* 定长 LE */
|
||||
|
||||
#endif /* MEOW_IPC_H */
|
||||
Executable
BIN
Binary file not shown.
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,502 @@
|
||||
/* meow_notif.c — MeowOS 通知存储 + 分发(阶段 D · M2a)
|
||||
*
|
||||
* 实现与设计:NOTIFICATION_SYSTEM.md §1-§8 + FRAMEWORK_DESIGN §4/附C。
|
||||
* - 通知数据结构:对齐 freedesktop.org Desktop Notifications 字段
|
||||
* (app_name/app_icon/summary/body/actions[]/hints{}/expire_timeout)
|
||||
* + MeowOS 扩展(target_activity / progress,来自 hints)。
|
||||
* - 内存存储:固定活跃槽表(ring 语义——每 App×category 配额,满丢该类型最旧条)。
|
||||
* - 配额(§7,用户拍板):每 App ≤ notify.categories 个类型;每类型活跃
|
||||
* 通知 ≤ notify.category_quota;媒体通知每 App ≤ notify.media_quota(允许多媒体 App
|
||||
* 同时)。系统事件=App(app_id="system"),同走配额。配额只管内存活跃态。
|
||||
* - TTL(§8):通知创建 10s 后自动转储到 TF(无论是否过期/被清)——本批只做
|
||||
* dump 钩子/日志/回调(notif_dump_cb),实际 TF 落盘 M2c 后置。ONGOING 通知
|
||||
* 转储后仍保留内存(服务死随清)。
|
||||
* - 转储钩子:meow_notif_dump_now()(关机前转储所有未上卡);
|
||||
* meow_notif_before_poweroff()(dump + 清板载)。
|
||||
*
|
||||
* 空洞实现风格:本文件自包含(不依赖 meow_launcherd.c 的 logmsg/now_ms),配额经
|
||||
* meow_settings(B2a)读 notify.categories/category_quota/media_quota(键缺省用默认值),
|
||||
* 文件 I/O 失败仅打点,绝不崩。注释风格中文 +「M2.a 说明」。
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h> /* strcasecmp */
|
||||
#include <stdarg.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "meow_notif.h"
|
||||
#include "meow_settings.h" /* B2a:读 notify.* 配额(MEOW_OK/MEOW_ERR_*) */
|
||||
|
||||
/* == 应用/槽位容量(确定静态内存;配额常量由 meow_settings 或默认覆盖)== */
|
||||
#define MEOW_NOTIF_MAX_APPS 8 /* 同时跟踪的应用数(含 "system") */
|
||||
#define MEOW_NOTIF_MAX_CATS 4 /* 每 App 类型上限(notify.categories 上限) */
|
||||
#define MEOW_NOTIF_MAX_SLOTS (MEOW_NOTIF_MAX_APPS * MEOW_NOTIF_MAX_CATS * MEOW_NOTIF_CAT_QUOTA_DEF) /* 128 */
|
||||
|
||||
/* 应用条目:已声明类型集 + 活跃媒体通知计数 */
|
||||
typedef struct notif_app {
|
||||
char app_id[MEOW_NOTIF_APP_ID_MAX];
|
||||
char cats[MEOW_NOTIF_MAX_CATS][MEOW_NOTIF_CAT_MAX];
|
||||
int ncats;
|
||||
int media_count; /* 当前活跃媒体通知数 */
|
||||
} notif_app_t;
|
||||
|
||||
static notif_app_t g_apps[MEOW_NOTIF_MAX_APPS];
|
||||
static int g_napps = 0;
|
||||
static meow_notif_t g_slots[MEOW_NOTIF_MAX_SLOTS];
|
||||
static uint32_t g_next_id = 1;
|
||||
static int g_dumped_total = 0; /* 会话内累计转储计数(统计用) */
|
||||
|
||||
/* 配额(运行时从 meow_settings notify.* 读;键缺省用默认) */
|
||||
static int g_max_cats = MEOW_NOTIF_CATS_DEF;
|
||||
static int g_cat_quota = MEOW_NOTIF_CAT_QUOTA_DEF;
|
||||
static int g_media_quota = MEOW_NOTIF_MEDIA_QUOTA_DEF;
|
||||
|
||||
static meow_notif_dump_cb g_dump_cb = NULL;
|
||||
static int g_inited = 0;
|
||||
|
||||
/* ---- 日志(自包含,不依赖 launcher 的 logmsg;前缀 "notif:")---- */
|
||||
static void notif_log(const char *fmt, ...)
|
||||
{
|
||||
char msg[256];
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(msg, sizeof msg, fmt, ap);
|
||||
va_end(ap);
|
||||
fprintf(stderr, "notif: %s\n", msg);
|
||||
}
|
||||
|
||||
/* ---- 时钟:墙钟 epoch ms(created_ms,供归档/显示)+ monotonic ms(TTL 判定)---- */
|
||||
static uint64_t wall_ms(void)
|
||||
{
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_REALTIME, &ts);
|
||||
return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
|
||||
}
|
||||
static uint64_t mono_ms(void)
|
||||
{
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
|
||||
}
|
||||
|
||||
/* ---- 短串拷贝(保证 NUL 终止 + 截断到 len-1)---- */
|
||||
static void n_strncpy(char *dst, const char *src, size_t len)
|
||||
{
|
||||
if (!dst || len == 0) return;
|
||||
if (!src) { dst[0] = 0; return; }
|
||||
strncpy(dst, src, len - 1);
|
||||
dst[len - 1] = 0;
|
||||
}
|
||||
|
||||
/* ---- 配额读取(B2a;键缺省/取失败用默认值)---- */
|
||||
static void read_quota(void)
|
||||
{
|
||||
int v;
|
||||
if (meow_settings_get_int("notify.categories", &v) == MEOW_OK && v > 0)
|
||||
g_max_cats = v;
|
||||
if (meow_settings_get_int("notify.category_quota", &v) == MEOW_OK && v > 0)
|
||||
g_cat_quota = v;
|
||||
if (meow_settings_get_int("notify.media_quota", &v) == MEOW_OK && v > 0)
|
||||
g_media_quota = v;
|
||||
notif_log("quota: cats=%d cat_quota=%d media_quota=%d", g_max_cats, g_cat_quota, g_media_quota);
|
||||
}
|
||||
|
||||
/* ---- 生命周期 ---- */
|
||||
int meow_notif_init(void)
|
||||
{
|
||||
if (g_inited) return NOTIF_OK;
|
||||
memset(g_apps, 0, sizeof g_apps);
|
||||
memset(g_slots, 0, sizeof g_slots);
|
||||
g_napps = 0;
|
||||
g_next_id = 1;
|
||||
g_dumped_total = 0;
|
||||
read_quota(); /* B2a:notify.* 配额 */
|
||||
g_inited = 1;
|
||||
notif_log("init: slots=%d default dump_cb=log-only (M2c -> TF)", MEOW_NOTIF_MAX_SLOTS);
|
||||
return NOTIF_OK;
|
||||
}
|
||||
|
||||
int meow_notif_shutdown(void)
|
||||
{
|
||||
if (!g_inited) return NOTIF_OK;
|
||||
/* 退出前归档所有未转储项(不清理;before_poweroff 负责清板载) */
|
||||
meow_notif_dump_now();
|
||||
return NOTIF_OK;
|
||||
}
|
||||
|
||||
/* ---- App 表查找/创建 ---- */
|
||||
static notif_app_t *find_app(const char *app_id)
|
||||
{
|
||||
for (int i = 0; i < g_napps; i++)
|
||||
if (!strcmp(g_apps[i].app_id, app_id)) return &g_apps[i];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static notif_app_t *get_or_add_app(const char *app_id)
|
||||
{
|
||||
notif_app_t *a = find_app(app_id);
|
||||
if (a) return a;
|
||||
if (g_napps >= MEOW_NOTIF_MAX_APPS) return NULL; /* 满:丢弃(防御) */
|
||||
a = &g_apps[g_napps++];
|
||||
memset(a, 0, sizeof *a);
|
||||
n_strncpy(a->app_id, app_id, sizeof a->app_id);
|
||||
return a;
|
||||
}
|
||||
|
||||
/* 某 App 已声明的类型是否包含 cat;无=返回 -1 */
|
||||
static int app_cat_index(const notif_app_t *a, const char *cat)
|
||||
{
|
||||
for (int i = 0; i < a->ncats; i++)
|
||||
if (!strcmp(a->cats[i], cat)) return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 声明类型:已在集合→ok;否则若未超上限则加入;超上限→返回 NOTIF_ERR_QUOTA。 */
|
||||
static int declare_cat(notif_app_t *a, const char *cat)
|
||||
{
|
||||
if (app_cat_index(a, cat) >= 0) return NOTIF_OK;
|
||||
if (a->ncats >= MEOW_NOTIF_MAX_CATS || a->ncats >= g_max_cats)
|
||||
return NOTIF_ERR_QUOTA; /* App 类型数超限 */
|
||||
n_strncpy(a->cats[a->ncats++], cat, sizeof a->cats[0]);
|
||||
return NOTIF_OK;
|
||||
}
|
||||
|
||||
/* ---- 媒体通知判定:category 命中 MEOW_NOTIF_MEDIA_CAT(前缀)---- */
|
||||
static int is_media_cat(const char *cat)
|
||||
{
|
||||
return (cat && strncasecmp(cat, MEOW_NOTIF_MEDIA_CAT, strlen(MEOW_NOTIF_MEDIA_CAT)) == 0);
|
||||
}
|
||||
|
||||
/* ---- 槽位 ---- */
|
||||
static int slot_free_index(void)
|
||||
{
|
||||
for (int i = 0; i < MEOW_NOTIF_MAX_SLOTS; i++)
|
||||
if (!g_slots[i].active) return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 统计某 App × 某类型 的活跃(active 且未撤下)通知数 —— 配额「活跃(未过期)」含义:
|
||||
* 瞬时通知 10s 后已释放(不占位);ONGOING 常驻(转储后仍占位)——故只看 dismissed。 */
|
||||
static int count_active_cat(const notif_app_t *a, const char *cat)
|
||||
{
|
||||
int n = 0;
|
||||
for (int i = 0; i < MEOW_NOTIF_MAX_SLOTS; i++) {
|
||||
meow_notif_t *s = &g_slots[i];
|
||||
if (s->active && !s->dismissed &&
|
||||
!strcmp(s->app_id, a->app_id) && !strcmp(s->category, cat))
|
||||
n++;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
/* 统计某 App 的活跃媒体通知数(同样只看 dismissed;ONGOING 媒体仍占配额) */
|
||||
static int count_active_media(const notif_app_t *a)
|
||||
{
|
||||
int n = 0;
|
||||
for (int i = 0; i < MEOW_NOTIF_MAX_SLOTS; i++) {
|
||||
meow_notif_t *s = &g_slots[i];
|
||||
if (s->active && !s->dismissed && s->media &&
|
||||
!strcmp(s->app_id, a->app_id)) n++;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
/* 找某 App × 某类型 最旧(created_ms 最小)活跃通知槽;无=返回 -1 */
|
||||
static int oldest_slot_cat(const notif_app_t *a, const char *cat)
|
||||
{
|
||||
int best = -1;
|
||||
uint64_t best_ms = UINT64_MAX;
|
||||
for (int i = 0; i < MEOW_NOTIF_MAX_SLOTS; i++) {
|
||||
meow_notif_t *s = &g_slots[i];
|
||||
if (s->active && !s->dismissed &&
|
||||
!strcmp(s->app_id, a->app_id) && !strcmp(s->category, cat)) {
|
||||
if (s->created_ms < best_ms) { best_ms = s->created_ms; best = i; }
|
||||
}
|
||||
}
|
||||
return best;
|
||||
}
|
||||
|
||||
/* 找某 App 最旧媒体通知槽;无=返回 -1 */
|
||||
static int oldest_media_slot(const notif_app_t *a)
|
||||
{
|
||||
int best = -1;
|
||||
uint64_t best_ms = UINT64_MAX;
|
||||
for (int i = 0; i < MEOW_NOTIF_MAX_SLOTS; i++) {
|
||||
meow_notif_t *s = &g_slots[i];
|
||||
if (s->active && !s->dismissed && s->media &&
|
||||
!strcmp(s->app_id, a->app_id)) {
|
||||
if (s->created_ms < best_ms) { best_ms = s->created_ms; best = i; }
|
||||
}
|
||||
}
|
||||
return best;
|
||||
}
|
||||
|
||||
/* 归档(dump)单条:调 dump_cb + 标 dumped。返回是否首次转储。 */
|
||||
static int archive_one(meow_notif_t *s)
|
||||
{
|
||||
if (!s->active || s->dumped) return 0;
|
||||
if (g_dump_cb) g_dump_cb(s); /* M2c 替换为 TF 落盘;本批默认日志/空 */
|
||||
s->dumped = 1;
|
||||
g_dumped_total++;
|
||||
notif_log("dump: id=%u app=%s cat=%s ongoing=%d dumped_total=%d",
|
||||
s->id, s->app_id, s->category, s->ongoing, g_dumped_total);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* 释放槽(清 active,槽位可复用) */
|
||||
static void slot_release(int idx)
|
||||
{
|
||||
if (idx < 0 || idx >= MEOW_NOTIF_MAX_SLOTS) return;
|
||||
memset(&g_slots[idx], 0, sizeof g_slots[idx]);
|
||||
}
|
||||
|
||||
/* 按 id 找活跃槽;无=返回 -1 */
|
||||
static int slot_by_id(uint32_t id)
|
||||
{
|
||||
for (int i = 0; i < MEOW_NOTIF_MAX_SLOTS; i++)
|
||||
if (g_slots[i].active && g_slots[i].id == id) return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* ---- 核心:post ---- */
|
||||
int meow_notif_post(const meow_notif_t *n, uint32_t *out_id)
|
||||
{
|
||||
int rc = NOTIF_OK;
|
||||
if (out_id) *out_id = 0;
|
||||
if (!g_inited) return NOTIF_ERR_NOTINIT;
|
||||
if (!n || !n->app_id[0]) return NOTIF_ERR_INVAL;
|
||||
if (!n->category[0]) return NOTIF_ERR_INVAL;
|
||||
|
||||
/* 更新(replace)语义:id>0 且已存在 → 就地更新字段 */
|
||||
if (n->id != 0) {
|
||||
int idx = slot_by_id(n->id);
|
||||
if (idx >= 0) {
|
||||
meow_notif_t *s = &g_slots[idx];
|
||||
n_strncpy(s->category, n->category, sizeof s->category);
|
||||
n_strncpy(s->summary, n->summary, sizeof s->summary);
|
||||
n_strncpy(s->body, n->body, sizeof s->body);
|
||||
n_strncpy(s->app_icon, n->app_icon, sizeof s->app_icon);
|
||||
n_strncpy(s->actions, n->actions, sizeof s->actions);
|
||||
n_strncpy(s->hints, n->hints, sizeof s->hints);
|
||||
n_strncpy(s->target_activity, n->target_activity, sizeof s->target_activity);
|
||||
s->expire_timeout = n->expire_timeout;
|
||||
s->progress = n->progress;
|
||||
s->ongoing = n->ongoing;
|
||||
s->media = n->media;
|
||||
if (out_id) *out_id = s->id;
|
||||
notif_log("post: UPDATE id=%u app=%s cat=%s", s->id, s->app_id, s->category);
|
||||
return NOTIF_OK;
|
||||
}
|
||||
/* 指定 id 但不存在 → 落为新建(freedesktop 行为:replaces_id 不存在则新建) */
|
||||
}
|
||||
|
||||
notif_app_t *a = get_or_add_app(n->app_id);
|
||||
if (!a) { notif_log("post: app table full, drop app=%s", n->app_id); return NOTIF_ERR_NOMEM; }
|
||||
|
||||
rc = declare_cat(a, n->category);
|
||||
if (rc != NOTIF_OK) {
|
||||
notif_log("post: QUOTA app=%s cat=%s (cats=%d max=%d)", n->app_id, n->category,
|
||||
a->ncats, g_max_cats);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int media = (n->media != 0) || is_media_cat(n->category);
|
||||
/* 配额 + 满丢该类型最旧条 */
|
||||
if (media) {
|
||||
if (count_active_media(a) >= g_media_quota) {
|
||||
int old = oldest_media_slot(a);
|
||||
if (old >= 0) {
|
||||
notif_log("post: media quota full app=%s -> drop id=%u", n->app_id, g_slots[old].id);
|
||||
slot_release(old); /* 满丢最旧媒体通知 */
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (count_active_cat(a, n->category) >= g_cat_quota) {
|
||||
int old = oldest_slot_cat(a, n->category);
|
||||
if (old >= 0) {
|
||||
notif_log("post: cat quota full app=%s cat=%s -> drop id=%u", n->app_id,
|
||||
n->category, g_slots[old].id);
|
||||
slot_release(old); /* 满丢该类型最旧条 */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int idx = slot_free_index();
|
||||
if (idx < 0) { notif_log("post: NOMEM slots full app=%s", n->app_id); return NOTIF_ERR_NOMEM; }
|
||||
|
||||
meow_notif_t *s = &g_slots[idx];
|
||||
memset(s, 0, sizeof *s);
|
||||
s->id = g_next_id++;
|
||||
n_strncpy(s->app_id, n->app_id, sizeof s->app_id);
|
||||
n_strncpy(s->category, n->category, sizeof s->category);
|
||||
n_strncpy(s->summary, n->summary, sizeof s->summary);
|
||||
n_strncpy(s->body, n->body, sizeof s->body);
|
||||
n_strncpy(s->app_icon, n->app_icon, sizeof s->app_icon);
|
||||
n_strncpy(s->actions, n->actions, sizeof s->actions);
|
||||
n_strncpy(s->hints, n->hints, sizeof s->hints);
|
||||
n_strncpy(s->target_activity, n->target_activity, sizeof s->target_activity);
|
||||
s->expire_timeout = n->expire_timeout;
|
||||
s->progress = n->progress;
|
||||
s->ongoing = n->ongoing;
|
||||
s->media = media ? 1 : 0;
|
||||
s->created_ms = wall_ms();
|
||||
s->dump_at_ms = mono_ms() + MEOW_NOTIF_TTL_MS; /* §8:创建 10s 转储 */
|
||||
s->active = 1;
|
||||
if (out_id) *out_id = s->id;
|
||||
notif_log("post: NEW id=%u app=%s cat=%s media=%d ongoing=%d", s->id, s->app_id,
|
||||
s->category, s->media, s->ongoing);
|
||||
return NOTIF_OK;
|
||||
}
|
||||
|
||||
/* ---- dismiss:撤下 + 立即归档 + 释放槽 ---- */
|
||||
int meow_notif_dismiss(uint32_t id)
|
||||
{
|
||||
if (!g_inited) return NOTIF_ERR_NOTINIT;
|
||||
int idx = slot_by_id(id);
|
||||
if (idx < 0) return NOTIF_ERR_NOENT;
|
||||
meow_notif_t *s = &g_slots[idx];
|
||||
archive_one(s); /* 未被清/过期也已转储(§8) */
|
||||
s->dismissed = 1;
|
||||
notif_log("dismiss: id=%u app=%s", id, s->app_id);
|
||||
slot_release(idx);
|
||||
return NOTIF_OK;
|
||||
}
|
||||
|
||||
/* ---- count ---- */
|
||||
int meow_notif_count(const char *app_id)
|
||||
{
|
||||
if (!g_inited) return -NOTIF_ERR_NOTINIT;
|
||||
int n = 0;
|
||||
for (int i = 0; i < MEOW_NOTIF_MAX_SLOTS; i++) {
|
||||
meow_notif_t *s = &g_slots[i];
|
||||
if (s->active && !s->dismissed &&
|
||||
(!app_id || !app_id[0] || !strcmp(s->app_id, app_id)))
|
||||
n++;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
/* ---- list ---- */
|
||||
int meow_notif_list(const char *app_id,
|
||||
int (*cb)(const meow_notif_t *n, void *ctx), void *ctx)
|
||||
{
|
||||
if (!g_inited) return -NOTIF_ERR_NOTINIT;
|
||||
if (!cb) return -NOTIF_ERR_INVAL;
|
||||
int n = 0;
|
||||
for (int i = 0; i < MEOW_NOTIF_MAX_SLOTS; i++) {
|
||||
meow_notif_t *s = &g_slots[i];
|
||||
if (!s->active || s->dismissed) continue;
|
||||
if (app_id && app_id[0] && strcmp(s->app_id, app_id)) continue;
|
||||
n++;
|
||||
if (cb(s, ctx) != 0) break;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
/* ---- dump_now:把当前状态「排空到 TTL 归档态」——归档所有未转储;非 ONGOING 释放槽,
|
||||
* ONGOING 转储后保留(常驻)。等价「立即触发所有 slot 的 §8 转储」。停机前用。 ---- */
|
||||
int meow_notif_dump_now(void)
|
||||
{
|
||||
if (!g_inited) return -NOTIF_ERR_NOTINIT;
|
||||
int n = 0;
|
||||
for (int i = 0; i < MEOW_NOTIF_MAX_SLOTS; i++) {
|
||||
meow_notif_t *s = &g_slots[i];
|
||||
if (!s->active || s->dumped) continue;
|
||||
int was_ongoing = s->ongoing;
|
||||
n += archive_one(s);
|
||||
if (!was_ongoing) slot_release(i); /* 与 tick 一致:非 ONGOING 转储后释放槽 */
|
||||
else notif_log("dump_now: ongoing id=%u archived (kept for UI)", s->id);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
/* ---- tick:TTL 转储 + 释放非 ONGOING;ONGOING 转储后保留 ---- */
|
||||
void meow_notif_tick(void)
|
||||
{
|
||||
if (!g_inited) return;
|
||||
uint64_t now = mono_ms();
|
||||
for (int i = 0; i < MEOW_NOTIF_MAX_SLOTS; i++) {
|
||||
meow_notif_t *s = &g_slots[i];
|
||||
if (!s->active || s->dumped) continue;
|
||||
if (now >= s->dump_at_ms) { /* §8:10s 到点自动转储 */
|
||||
int was_ongoing = s->ongoing;
|
||||
archive_one(s);
|
||||
if (!was_ongoing) slot_release(i); /* 非 ONGOING:转储后释放槽 */
|
||||
else notif_log("tick: ongoing id=%u archived (kept for UI)", s->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ---- before_poweroff:转储所有未上卡 + 清板载 ---- */
|
||||
void meow_notif_before_poweroff(void)
|
||||
{
|
||||
if (!g_inited) return;
|
||||
int n = meow_notif_dump_now();
|
||||
notif_log("before_poweroff: dumped=%d, clearing board", n);
|
||||
memset(g_slots, 0, sizeof g_slots);
|
||||
memset(g_apps, 0, sizeof g_apps);
|
||||
g_napps = 0;
|
||||
g_next_id = 1;
|
||||
}
|
||||
|
||||
/* ---- 设置 dump 回调 ---- */
|
||||
void meow_notif_set_dump_cb(meow_notif_dump_cb cb)
|
||||
{
|
||||
g_dump_cb = cb; /* NULL=恢复默认(无回调,仅日志;M2c 接 TF) */
|
||||
}
|
||||
|
||||
/* ---- MSG_NOTIFY_LIST 序列化(守护→App 下发清单;M5 通知中心/重同步用)----
|
||||
* 负载: [u16 count] + count 条 定长 meow_notif 记录(records 以 app_id/category/
|
||||
* summary/body/app_icon/target_activity 为主,精简 payload,适配 MEOW_IPC_CARGO)。 */
|
||||
int meow_notif_serialize_list(const char *app_id, uint8_t *buf, int buf_len)
|
||||
{
|
||||
if (!g_inited || !buf || buf_len < (int)(2 + sizeof(uint16_t))) return -NOTIF_ERR_INVAL;
|
||||
/* 简化 v1:序列化 count(u16)+ 每条固定 128B 之摘要记录(id/category/summary/body/
|
||||
* app_icon/target_activity/ongoing/progress/media/dismissed)。M5 全套结构后调。 */
|
||||
uint16_t count = 0;
|
||||
uint8_t *p = buf + 2;
|
||||
int cap = buf_len - 2;
|
||||
const uint16_t rec = 128;
|
||||
for (int i = 0; i < MEOW_NOTIF_MAX_SLOTS; i++) {
|
||||
meow_notif_t *s = &g_slots[i];
|
||||
if (!s->active || s->dismissed) continue;
|
||||
if (app_id && app_id[0] && strcmp(s->app_id, app_id)) continue;
|
||||
if ((int)(rec) > cap) break;
|
||||
memset(p, 0, rec);
|
||||
uint32_t id = s->id;
|
||||
memcpy(p, &id, 4); /* +0 id */
|
||||
n_strncpy((char *)(p + 4), s->category, 24); /* +4 category[24] */
|
||||
n_strncpy((char *)(p + 28), s->summary, 64); /* +28 summary[64] */
|
||||
n_strncpy((char *)(p + 92), s->body, 24); /* +92 body[24](v1 截断) */
|
||||
p[116] = s->ongoing;
|
||||
p[117] = s->media;
|
||||
p[118] = s->dismissed;
|
||||
/* +119 target_activity[8] 预留;v1 截断,M5 扩充 */
|
||||
memcpy(p + 119, s->target_activity, 8);
|
||||
p += rec;
|
||||
cap -= rec;
|
||||
count++;
|
||||
}
|
||||
memcpy(buf, &count, 2);
|
||||
return 2 + (int)count * rec;
|
||||
}
|
||||
|
||||
/* ---- 调试打印 ---- */
|
||||
void meow_notif_dump(const char *log_prefix)
|
||||
{
|
||||
const char *lp = log_prefix ? log_prefix : "";
|
||||
notif_log("%sactive=%d apps=%d next_id=%u dumped_total=%d",
|
||||
lp, meow_notif_count(NULL), g_napps, g_next_id, g_dumped_total);
|
||||
for (int i = 0; i < g_napps; i++) {
|
||||
notif_log("%s app=%s cats=%d media=%d", lp, g_apps[i].app_id,
|
||||
g_apps[i].ncats, g_apps[i].media_count);
|
||||
}
|
||||
for (int i = 0; i < MEOW_NOTIF_MAX_SLOTS; i++) {
|
||||
meow_notif_t *s = &g_slots[i];
|
||||
if (!s->active) continue;
|
||||
notif_log("%s slot%02d id=%u app=%s cat=%s sum=%s ong=%d media=%d dumped=%d",
|
||||
lp, i, s->id, s->app_id, s->category, s->summary,
|
||||
s->ongoing, s->media, s->dumped);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
/* meow_notif.h — MeowOS 通知存储 + 分发(阶段 D · M2a)
|
||||
*
|
||||
* 定位:MeowOS 通知中心后端(存储 + 分发),是阶段 B 通知中心 UI(M5)+ 阶段 D
|
||||
* (M2b D-Bus 桥 / M2c 转储 TF 卡)的前提。设计规范:NOTIFICATION_SYSTEM.md §1-§8
|
||||
* + FRAMEWORK_DESIGN §4/附C(freedesktop.org Desktop Notifications)。
|
||||
*
|
||||
* 本批(M2a)只做核心存储骨架:
|
||||
* - 通知数据结构(对齐 freedesktop 字段 + MeowOS 扩展 target_activity/progress);
|
||||
* - 内存配额(每 App ≤ notify.categories 个类型;每类型活跃 ≤ notify.category_quota;
|
||||
* 媒体通知每 App ≤ notify.media_quota,允许多媒体 App 同时);
|
||||
* - TTL 10s 转储钩子(设计 §8,实际 TF 落盘 M2c 后置,本批预留 notif_dump_cb);
|
||||
* - 原生 IPC 通道接入点(MSG_NOTIFY→ACK / MSG_NOTIFY_DISMISS→ACK;MSG_NOTIFY_LIST
|
||||
* 为守护→App 下发,本批提供序列化 helper,UI(M5) 接入)。
|
||||
*
|
||||
* 空洞实现风格:本文件自包含(不依赖 meow_launcherd.c 的 logmsg/now_ms),
|
||||
* 配额从 meow_settings 读(B2a;键缺省时用本文件默认值)。注释风格中文 +「M2.a 说明」。
|
||||
*/
|
||||
#ifndef MEOW_NOTIF_H
|
||||
#define MEOW_NOTIF_H
|
||||
|
||||
#include <stdint.h> /* uint32_t/uint64_t/int32_t */
|
||||
#include <stddef.h> /* size_t */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* == 返回码(对齐 meow_ipc.h / MEOWOS_API.md §1,通知专用枚举)== */
|
||||
enum {
|
||||
NOTIF_OK = 0,
|
||||
NOTIF_ERR_INVAL = -1, /* 参数非法 */
|
||||
NOTIF_ERR_NOMEM = -6, /* 槽满/内存不足 */
|
||||
NOTIF_ERR_NOTINIT = -7, /* 未 init */
|
||||
NOTIF_ERR_QUOTA = -12, /* 配额超限(App 类型数 / 类型条数 / 媒体数) */
|
||||
NOTIF_ERR_NOENT = -2 /* 通知 id 不存在 */
|
||||
};
|
||||
|
||||
/* == 容量/长度(单设备上限;定长,控制静态内存)== */
|
||||
#define MEOW_NOTIF_APP_ID_MAX 32
|
||||
#define MEOW_NOTIF_CAT_MAX 24
|
||||
#define MEOW_NOTIF_SUMMARY_MAX 64
|
||||
#define MEOW_NOTIF_BODY_MAX 96
|
||||
#define MEOW_NOTIF_ICON_MAX 48
|
||||
#define MEOW_NOTIF_ACTIVITY_MAX 48
|
||||
#define MEOW_NOTIF_ACTIONS_MAX 96 /* NUL 分隔动作键列表 */
|
||||
#define MEOW_NOTIF_HINTS_MAX 96 /* 原始 "k=v;..." 提示串 */
|
||||
|
||||
/* == 配额默认(运行时从 meow_settings notify.* 覆盖;键缺省用此)== */
|
||||
#define MEOW_NOTIF_CATS_DEF 4 /* 每 App 最多申请的通知类型数(notify.categories) */
|
||||
#define MEOW_NOTIF_CAT_QUOTA_DEF 4 /* 每类型活跃(未过期)通知上限(notify.category_quota) */
|
||||
#define MEOW_NOTIF_MEDIA_QUOTA_DEF 1 /* 每 App 媒体通知上限(notify.media_quota) */
|
||||
#define MEOW_NOTIF_TTL_MS 10000 /* 设计 §8:通知创建 10s 后自动转储到 TF */
|
||||
|
||||
/* 媒体通知(category)约定名:命中即按 notify.media_quota 约束(单 App 1 条) */
|
||||
#define MEOW_NOTIF_MEDIA_CAT "media"
|
||||
|
||||
/* 系统事件作为 App 的 app_id(NOTIFICATION_SYSTEM.md §7:系统也抽象为 App,同样走配额) */
|
||||
#define MEOW_NOTIF_SYSTEM_APP "system"
|
||||
|
||||
/* 通知结构(对齐 freedesktop + MeowOS 扩展)。
|
||||
* fields 注释:NOTIFICATION_SYSTEM.md §4。 */
|
||||
typedef struct meow_notif {
|
||||
uint32_t id; /* 全局递增通知 id(0=无效/未分配) */
|
||||
char app_id[MEOW_NOTIF_APP_ID_MAX]; /* 来源应用;系统事件="system" */
|
||||
char category[MEOW_NOTIF_CAT_MAX]; /* 通知类型(媒体通知="media") */
|
||||
char summary[MEOW_NOTIF_SUMMARY_MAX]; /* 标题(单行) */
|
||||
char body[MEOW_NOTIF_BODY_MAX]; /* 正文(可多行) */
|
||||
char app_icon[MEOW_NOTIF_ICON_MAX]; /* 图标 icon name 或 path */
|
||||
char actions[MEOW_NOTIF_ACTIONS_MAX]; /* actions[](NUL 分隔;v1 空,M2b 填) */
|
||||
char hints[MEOW_NOTIF_HINTS_MAX]; /* hints{} 原始 "k=v;..." 串(v1 空,M2b 填) */
|
||||
uint32_t expire_timeout; /* 超时 ms;0xFFFFFFFF=ONGOING 常驻 */
|
||||
uint64_t created_ms; /* 创建时刻(墙钟 epoch ms,供归档/显示) */
|
||||
uint64_t dump_at_ms; /* 转储时刻(monotonic ms,TTL=创建+10s;ONGOING 亦到此转储) */
|
||||
int32_t progress; /* MeowOS:0-100 进度;<0=无 */
|
||||
char target_activity[MEOW_NOTIF_ACTIVITY_MAX]; /* MeowOS:点击跳转目标 activity */
|
||||
uint8_t ongoing; /* 1=常驻通知(服务死随清) */
|
||||
uint8_t media; /* 1=媒体通知(走 notify.media_quota) */
|
||||
uint8_t dismissed; /* 1=已撤下 */
|
||||
uint8_t dumped; /* 1=已转储(归档) */
|
||||
uint8_t active; /* 1=槽位占用 */
|
||||
} meow_notif_t;
|
||||
|
||||
/* 转储回调(M2c 落盘 / 本批默认仅日志):通知归档时调用。 */
|
||||
typedef void (*meow_notif_dump_cb)(const meow_notif_t *n);
|
||||
|
||||
/* == 生命周期 == */
|
||||
int meow_notif_init(void); /* 幂等;从 meow_settings 读 notify.* 配额(B2a) */
|
||||
int meow_notif_shutdown(void); /* 保存/清理(进程退出前调;本批=归档未转储项) */
|
||||
|
||||
/* == 核心 API == */
|
||||
/* 推送/更新通知。n->id 为 0(新建);若 n->id>0 或 replace 语义,
|
||||
* 按 n 中同 id 更新已存在通知(未找到则新建)。返回 NOTIF_OK/NOTIF_ERR_*;
|
||||
* *out_id 返回分配/更新的通知 id(可为 NULL)。 */
|
||||
int meow_notif_post(const meow_notif_t *n, uint32_t *out_id);
|
||||
|
||||
/* 撤下通知(dismiss)。随之为该通知归档(未转储则立即调 dump_cb + 标记),并释放槽。 */
|
||||
int meow_notif_dismiss(uint32_t id);
|
||||
|
||||
/* 活跃(未转储)通知数。app_id 为 NULL/空=全部。 */
|
||||
int meow_notif_count(const char *app_id);
|
||||
|
||||
/* 遍历(回调)当前通知。app_id 为 NULL/空=全部。返回遍历到的条数;
|
||||
* 回调返回非 0 则中止遍历。 */
|
||||
int meow_notif_list(const char *app_id,
|
||||
int (*cb)(const meow_notif_t *n, void *ctx), void *ctx);
|
||||
|
||||
/* 立即转储所有未上卡(未 dumped)通知:逐条调 dump_cb + 标 dumped(不释放;
|
||||
* 停机前转储用)。返回转储条数。 */
|
||||
int meow_notif_dump_now(void);
|
||||
|
||||
/* 主循环周期调(每 10ms 排空 TODO):TTL 到期 → 归档 + (非 ONGOING)释放槽;
|
||||
* dismissed 且未转储 → 归档 + 释放;ONGOING 转储后仍保留内存(服务死随清)。 */
|
||||
void meow_notif_tick(void);
|
||||
|
||||
/* 正常电源事件(关机/重启)前调用:先转储所有未上卡通知,再清板载。 */
|
||||
void meow_notif_before_poweroff(void);
|
||||
|
||||
/* 覆盖转储回调(NULL=恢复默认日志;M2c 接 TF 落盘)。 */
|
||||
void meow_notif_set_dump_cb(meow_notif_dump_cb cb);
|
||||
|
||||
/* 调试:打印当前 Active 表/App 表(前缀)。 */
|
||||
void meow_notif_dump(const char *log_prefix);
|
||||
|
||||
/* MSG_NOTIFY_LIST(守护→App 下发清单,M5 通知中心/重同步用):
|
||||
* 把 app_id 的当前通知序列化为 MSG_NOTIFY_LIST 负载写入 buf(≤MEOW_IPC_CARGO),
|
||||
* 返回负载字节数;<0=无(app 无通知)。 */
|
||||
int meow_notif_serialize_list(const char *app_id, uint8_t *buf, int buf_len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* MEOW_NOTIF_H */
|
||||
@@ -0,0 +1,709 @@
|
||||
/* meow_settings.c — MeowOS 系统设置后端(阶段 B2a)
|
||||
*
|
||||
* 实现与设计:SYSTEM_SETTINGS.md §1/§2/§3 + MEOWOS_API.md §2。
|
||||
* - 统一存储:板载 /usr/data/meow/settings.conf(UBIFS,KB 级小文件,扁平 key=value)。
|
||||
* 导入/导出(备份)走同一后端;默认备份路径 TF 卡 MeowOS/backups/settings/setting.bak。
|
||||
* - 单点数据源:全部设置键存于本模块内存表(名称/类型/默认/取值域/当前值),
|
||||
* 实体 UI / Web 面板 / CLI 全走 meow_settings_* API,不留旁路。
|
||||
* - clamp/校验集中 set(亮度 auto clamp >= display.brightness_min;枚举越界拒绝;
|
||||
* str 截断 MEOW_SET_MAX_LEN);set 成功后标记脏 + 向 listener 广播(key 字符串)。
|
||||
* - 落盘:meow_settings_save()(写板载 settings.conf,保留 "# meow-settings 1" 头)。
|
||||
* 为避免 UBIFS 高频写,调用方在低频点(如音量渐变结束)才落盘一次。
|
||||
*
|
||||
* 空实现风格:本文件自包含(不依赖 meow_launcherd.c 的 logmsg),文件 I/O 失败仅打点,
|
||||
* 绝不崩(内存继续用,符合 SYSTEM_SETTINGS.md §8「无卡/无板载用内存缓存」)。
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h> /* strcasecmp */
|
||||
#include <stdarg.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "meow_settings.h"
|
||||
|
||||
/* 存储路径(板载 UBIFS 小文件)/ 默认备份路径(TF 卡)。
|
||||
* 允许编译期覆盖(供宿主机单元测试指向临时文件;设备上默认不变)。 */
|
||||
#ifndef MEOW_SETTINGS_FILE
|
||||
#define MEOW_SETTINGS_FILE "/usr/data/meow/settings.conf"
|
||||
#endif
|
||||
#ifndef MEOW_SETTINGS_BAK
|
||||
#define MEOW_SETTINGS_BAK "/usr/data/mnt/sd_0/MeowOS/backups/settings/setting.bak"
|
||||
#endif
|
||||
|
||||
/* 表/监听器/临时缓冲上限 */
|
||||
#define MEOW_SET_MAX_KEYS 64
|
||||
#define MEOW_SET_MAX_LISTENERS 16
|
||||
#define MEOW_SET_NAME_LEN 48
|
||||
#define MEOW_SET_ENUM_LEN 96
|
||||
#define MEOW_SET_LABELS_LEN 160
|
||||
#define MEOW_SET_ENUM_MAX_OPT 8
|
||||
|
||||
/* 一个设置项:名称/类型/默认/当前值(统一字符串)+ clamp 域 + 枚举名/标签 */
|
||||
typedef struct meow_setting {
|
||||
char key[MEOW_SET_NAME_LEN];
|
||||
meow_set_type type;
|
||||
char def[MEOW_SET_MAX_LEN];
|
||||
char cur[MEOW_SET_MAX_LEN];
|
||||
int min, max; /* SET_INT 取值域(max<=0 表示仅保底、无上界) */
|
||||
char enum_names[MEOW_SET_ENUM_LEN];
|
||||
char enum_labels[MEOW_SET_LABELS_LEN];
|
||||
int dirty;
|
||||
} meow_setting;
|
||||
|
||||
static meow_setting g_sets[MEOW_SET_MAX_KEYS];
|
||||
static int g_nsets = 0;
|
||||
static meow_settings_listener g_listeners[MEOW_SET_MAX_LISTENERS];
|
||||
static int g_nlisteners = 0;
|
||||
static int g_inited = 0;
|
||||
static int g_broadcasting = 0; /* 防 listener 递归 set */
|
||||
|
||||
/* ---- 默认值表:与 SYSTEM_SETTINGS.md §1 逐键一致(新增设置照附录扩展)---- */
|
||||
static const meow_setting_def g_defs[] = {
|
||||
/* 显示 */
|
||||
{ "display.brightness", SET_INT, "101", 0, 255, NULL, NULL },
|
||||
{ "display.brightness_min", SET_INT, "1", 0, 255, NULL, NULL },
|
||||
{ "display.screen_off_mode", SET_ENUM, "panel",0, 0, "panel,black", "面板下电,背光全黑" },
|
||||
{ "display.screen_off_timeout", SET_INT, "30", 0, 86400, NULL, NULL },
|
||||
{ "display.refresh_rate", SET_ENUM, "60", 0, 0, "60,30,15", "60Hz,30Hz,15Hz" },
|
||||
{ "display.refresh_always_max", SET_BOOL, "0", 0, 0, NULL, NULL },
|
||||
{ "display.theme", SET_ENUM, "dark", 0, 0, "dark,light", "深色,浅色" },
|
||||
/* B2b 主题三方式:display.theme_mode 决定判定方式(manual=读 display.theme;
|
||||
* auto=按深色时段)。时段两键为分钟数 0-1439,start==end 视为未配置(回退 manual)。
|
||||
* 注释:SYSTEM_SETTINGS.md §1 同步新增三行。 */
|
||||
{ "display.theme_mode", SET_ENUM, "manual", 0, 0, "manual,auto", "手动,时段自动" },
|
||||
{ "display.theme_dark_start", SET_INT, "0", 0, 1439, NULL, NULL },
|
||||
{ "display.theme_dark_end", SET_INT, "0", 0, 1439, NULL, NULL },
|
||||
{ "display.background", SET_STR, "black",0, 0, NULL, NULL },
|
||||
/* 电源 */
|
||||
{ "power.longpress_menu_ms", SET_INT, "3000", 0, 0, NULL, NULL },
|
||||
{ "power.forceoff_ms", SET_INT, "8000", 0, 0, NULL, NULL },
|
||||
{ "power.defeat_hotkey", SET_STR, "power_voldown", 0,0, NULL, NULL },
|
||||
/* 开机 */
|
||||
{ "boot.default", SET_ENUM, "meow", 0, 0, "meow,hiby", "MeowOS,HiByOS" },
|
||||
{ "boot.menu_enabled", SET_BOOL, "1", 0, 0, NULL, NULL },
|
||||
{ "boot.timeout_ms", SET_INT, "5000", 0, 0, NULL, NULL },
|
||||
/* 输入 */
|
||||
{ "input.hotkey_seq", SET_STR, "volup,volup,volup", 0,0, NULL, NULL },
|
||||
{ "input.hotkey_window_ms", SET_INT, "2500", 0, 0, NULL, NULL },
|
||||
{ "input.touch_arm_delay_ms", SET_INT, "700", 0, 0, NULL, NULL },
|
||||
/* M2.38:设置页滑动方向切换(0=标准:手指上滑→列表往下翻;1=反向) */
|
||||
{ "input.swipe_invert", SET_BOOL, "0", 0, 0, NULL, NULL },
|
||||
/* 字体/主题 */
|
||||
{ "font.file", SET_STR, "MeowAPPs/fonts/font.png", 0,0, NULL, NULL },
|
||||
{ "font.size.title", SET_INT, "28", 0, 0, NULL, NULL },
|
||||
{ "font.size.body", SET_INT, "20", 0, 0, NULL, NULL },
|
||||
{ "ui.style", SET_ENUM, "md3", 0, 0, "md3,miui", "Material You,MIUI" },
|
||||
/* 通知 */
|
||||
{ "notify.center_enabled", SET_BOOL, "1", 0, 0, NULL, NULL },
|
||||
{ "notify.app_quota", SET_INT, "16", 0, 0, NULL, NULL },
|
||||
/* M2a:通知配额(NOTIFICATION_SYSTEM.md §7,用户拍板 2026-08-29)。
|
||||
* notify.categories = 每 App 最多申请的通知类型数(≤4)
|
||||
* notify.category_quota = 每类型活跃(未过期)通知上限(默认 4)
|
||||
* notify.media_quota = 每 App 媒体通知上限(默认 1;允许多媒体 App 同时) */
|
||||
{ "notify.categories", SET_INT, "4", 1, 4, NULL, NULL },
|
||||
{ "notify.category_quota", SET_INT, "4", 1, 16, NULL, NULL },
|
||||
{ "notify.media_quota", SET_INT, "1", 1, 1, NULL, NULL },
|
||||
/* 日志 */
|
||||
{ "log.level", SET_ENUM, "info", 0, 0, "error,warn,info,debug", "错误,警告,信息,调试" },
|
||||
{ "log.to_card", SET_BOOL, "1", 0, 0, NULL, NULL },
|
||||
/* 音频 */
|
||||
{ "audio.volume", SET_INT, "60", 0, 100, NULL, NULL },
|
||||
{ "audio.volume_max", SET_INT, "100", 0, 100, NULL, NULL },
|
||||
{ "audio.volume_step", SET_INT, "1", 1, 5, NULL, NULL },
|
||||
{ "audio.output", SET_STR, "hw:0,0", 0,0, NULL, NULL },
|
||||
/* 网络(M2.39 设置页 WiFi/蓝牙开关;wifi 默认开=允许 ensure_wifi 自动连网,
|
||||
* 用户关=0 则 ensure_wifi 不再自动拉起 / 蓝牙默认关=少耗电) */
|
||||
{ "network.wifi_enabled", SET_BOOL, "1", 0, 0, NULL, NULL },
|
||||
{ "network.bluetooth_enabled", SET_BOOL, "0", 0, 0, NULL, NULL },
|
||||
};
|
||||
|
||||
/* ---- 日志(自包含,不依赖 launcher 的 logmsg;前缀 "settings:")---- */
|
||||
static void sset_log(const char *fmt, ...)
|
||||
{
|
||||
char msg[256];
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(msg, sizeof msg, fmt, ap);
|
||||
va_end(ap);
|
||||
fprintf(stderr, "settings: %s\n", msg);
|
||||
}
|
||||
|
||||
/* ---- 内部查找 ---- */
|
||||
static meow_setting *find_set(const char *key)
|
||||
{
|
||||
if (!key) return NULL;
|
||||
for (int i = 0; i < g_nsets; i++)
|
||||
if (!strcmp(g_sets[i].key, key)) return &g_sets[i];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* ---- 枚举名/标签的逗号串切分辅助 ---- */
|
||||
static int enum_count_str(const char *names)
|
||||
{
|
||||
if (!names || !names[0]) return 0;
|
||||
int n = 1;
|
||||
for (const char *p = names; *p; p++)
|
||||
if (*p == ',') n++;
|
||||
return n;
|
||||
}
|
||||
|
||||
/* 取第 idx 个名字(返回指向 names 内部,静态覆盖;用完即弃) */
|
||||
static const char *enum_at_str(const char *names, int idx)
|
||||
{
|
||||
static char buf[MEOW_SET_ENUM_LEN * 2];
|
||||
if (!names || idx < 0) return NULL;
|
||||
strncpy(buf, names, sizeof buf - 1);
|
||||
buf[sizeof buf - 1] = 0;
|
||||
char *p = buf;
|
||||
for (int i = 0; i < idx; i++) {
|
||||
while (*p && *p != ',') p++;
|
||||
if (*p == ',') p++; else return NULL;
|
||||
}
|
||||
while (*p == ' ' || *p == '\t') p++;
|
||||
/* 截到逗号/结尾 */
|
||||
char *e = p;
|
||||
while (*e && *e != ',') e++;
|
||||
*e = 0;
|
||||
return p;
|
||||
}
|
||||
|
||||
static int enum_index_of_name_str(const char *names, const char *name)
|
||||
{
|
||||
if (!names || !name) return -1;
|
||||
int n = enum_count_str(names);
|
||||
for (int i = 0; i < n; i++) {
|
||||
const char *s = enum_at_str(names, i);
|
||||
if (s && !strcmp(s, name)) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* ---- clamp/校验集中:int 取值域(max<=0 → 仅保底)---- */
|
||||
static int clamp_int(meow_setting *s, int v)
|
||||
{
|
||||
if (s->max > 0) {
|
||||
if (v < s->min) v = s->min;
|
||||
if (v > s->max) v = s->max;
|
||||
} else {
|
||||
if (v < s->min) v = s->min;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
/* display.brightness 额外 clamp >= display.brightness_min(防黑屏,SYSTEM_SETTINGS §3)
|
||||
* 且 M2.39 上限 100(max_brightness=101,但 101 会闪屏,用户确认上限 100)。 */
|
||||
static int clamp_brightness(int v)
|
||||
{
|
||||
int mn = 1; /* def 默认(brightness_min 未 init/空时用默认 1=极暗但非全黑,屏仍可见) */
|
||||
meow_setting *bm = find_set("display.brightness_min");
|
||||
if (bm && bm->cur[0]) mn = atoi(bm->cur);
|
||||
if (v < mn) v = mn;
|
||||
if (v > 100) v = 100;
|
||||
return v;
|
||||
}
|
||||
|
||||
/* ---- 按类型把字符串值 apply 到 cur(读文件/导入时用;含 clamp/校验)---- */
|
||||
static void apply_value(meow_setting *s, const char *v)
|
||||
{
|
||||
if (!s || !v) return;
|
||||
switch (s->type) {
|
||||
case SET_INT: {
|
||||
int iv = atoi(v);
|
||||
iv = clamp_int(s, iv);
|
||||
if (!strcmp(s->key, "display.brightness")) iv = clamp_brightness(iv);
|
||||
snprintf(s->cur, sizeof s->cur, "%d", iv);
|
||||
break;
|
||||
}
|
||||
case SET_BOOL: {
|
||||
int b = 0;
|
||||
char p[16], *q = p;
|
||||
strncpy(p, v, sizeof p - 1); p[sizeof p - 1] = 0;
|
||||
while (*q == ' ' || *q == '\t') q++;
|
||||
long n = strtol(q, NULL, 10);
|
||||
if (!strcasecmp(q, "true") || !strcasecmp(q, "yes") || !strcasecmp(q, "on")) b = 1;
|
||||
else if (q[0] && n != 0) b = 1; /* 数值非 0(含旧风格 "2")视为 true;向后兼容 */
|
||||
snprintf(s->cur, sizeof s->cur, "%d", b);
|
||||
break;
|
||||
}
|
||||
case SET_ENUM: {
|
||||
int idx = enum_index_of_name_str(s->enum_names, v);
|
||||
if (idx < 0) idx = atoi(v); /* 向后兼容:数值索引 */
|
||||
if (idx >= 0 && idx < enum_count_str(s->enum_names)) {
|
||||
const char *name = enum_at_str(s->enum_names, idx);
|
||||
if (name) strncpy(s->cur, name, sizeof s->cur - 1);
|
||||
}
|
||||
/* 未知值忽略(保留默认) */
|
||||
break;
|
||||
}
|
||||
case SET_STR:
|
||||
strncpy(s->cur, v, sizeof s->cur - 1);
|
||||
s->cur[sizeof s->cur - 1] = 0;
|
||||
break;
|
||||
}
|
||||
s->dirty = 0;
|
||||
}
|
||||
|
||||
/* ---- 广播(防 listener 递归 set)---- */
|
||||
static void notify_key(const char *key)
|
||||
{
|
||||
if (g_broadcasting) return;
|
||||
g_broadcasting = 1;
|
||||
for (int i = 0; i < g_nlisteners; i++)
|
||||
if (g_listeners[i]) g_listeners[i](key);
|
||||
g_broadcasting = 0;
|
||||
}
|
||||
|
||||
/* import 内部:apply + 脏 + 广播(定义在下方 import 之前声明) */
|
||||
static void apply_value_nosave(meow_setting *s, const char *v, int *applied);
|
||||
|
||||
/* ---- 注册 ---- */
|
||||
int meow_settings_register(const meow_setting_def *def)
|
||||
{
|
||||
if (!def || !def->key) return MEOW_ERR_INVAL;
|
||||
if (g_nsets >= MEOW_SET_MAX_KEYS) return MEOW_ERR_NOMEM;
|
||||
if (find_set(def->key)) return MEOW_ERR_EXISTS;
|
||||
meow_setting *s = &g_sets[g_nsets++];
|
||||
memset(s, 0, sizeof *s);
|
||||
strncpy(s->key, def->key, sizeof s->key - 1);
|
||||
s->type = def->type;
|
||||
strncpy(s->def, def->def ? def->def : "", sizeof s->def - 1);
|
||||
strncpy(s->cur, s->def, sizeof s->cur - 1);
|
||||
s->min = def->min;
|
||||
s->max = def->max;
|
||||
if (def->enum_names) strncpy(s->enum_names, def->enum_names, sizeof s->enum_names - 1);
|
||||
if (def->enum_labels) strncpy(s->enum_labels, def->enum_labels, sizeof s->enum_labels - 1);
|
||||
s->dirty = 0;
|
||||
return MEOW_OK;
|
||||
}
|
||||
|
||||
/* ---- 初始化(幂等;重载=重置默认 + 重读 settings.conf)---- */
|
||||
int meow_settings_init(void)
|
||||
{
|
||||
if (g_nsets == 0) {
|
||||
for (unsigned i = 0; i < sizeof g_defs / sizeof g_defs[0]; i++) {
|
||||
int rc = meow_settings_register(&g_defs[i]);
|
||||
/* 表满/重复为内部异常;防御性继续(注册失败仅该键缺失) */
|
||||
(void)rc;
|
||||
}
|
||||
}
|
||||
/* 重置全部到默认,再读文件(与旧 settings_load 语义一致:默认 + 覆盖) */
|
||||
for (int i = 0; i < g_nsets; i++) {
|
||||
strncpy(g_sets[i].cur, g_sets[i].def, sizeof g_sets[i].cur - 1);
|
||||
g_sets[i].dirty = 0;
|
||||
}
|
||||
FILE *f = fopen(MEOW_SETTINGS_FILE, "r");
|
||||
if (!f) {
|
||||
sset_log("no %s, defaults active", MEOW_SETTINGS_FILE);
|
||||
g_inited = 1;
|
||||
return MEOW_OK;
|
||||
}
|
||||
char buf[768];
|
||||
while (fgets(buf, sizeof buf, f)) {
|
||||
char *eq = strchr(buf, '=');
|
||||
if (!eq) continue;
|
||||
*eq = 0;
|
||||
/* 左去空 */
|
||||
char *k = buf;
|
||||
while (*k == ' ' || *k == '\t') k++;
|
||||
int kl = (int)strlen(k);
|
||||
while (kl > 0 && (k[kl-1] == ' ' || k[kl-1] == '\t')) k[--kl] = 0;
|
||||
if (!k[0] || k[0] == '#') continue; /* 空行/注释 */
|
||||
/* 右值去空 */
|
||||
char *v = eq + 1;
|
||||
while (*v == ' ' || *v == '\t') v++;
|
||||
int vl = (int)strlen(v);
|
||||
while (vl > 0 && (v[vl-1] == '\n' || v[vl-1] == '\r')) v[--vl] = 0;
|
||||
while (vl > 0 && (v[vl-1] == ' ' || v[vl-1] == '\t')) v[--vl] = 0;
|
||||
meow_setting *s = find_set(k);
|
||||
if (s) apply_value(s, v);
|
||||
/* 未知键忽略(SYSTEM_SETTINGS §3 存储格式) */
|
||||
}
|
||||
fclose(f);
|
||||
/* 读取后统一补一次亮度下限 clamp(brightness_min 可能在 brightness 之后读入) */
|
||||
meow_setting *b = find_set("display.brightness");
|
||||
if (b) {
|
||||
int iv = atoi(b->cur);
|
||||
int cv = clamp_brightness(iv);
|
||||
snprintf(b->cur, sizeof b->cur, "%d", cv);
|
||||
}
|
||||
g_inited = 1;
|
||||
|
||||
/* M2.39:迁移旧持久亮度下限 25 → 1(SYSTEM_SETTINGS §1 下限默认已改 1,但设备
|
||||
* settings.conf 里还残留旧版写入的 display.brightness_min=25,覆盖默认表,导致亮度
|
||||
* 滑条被 clamp 在 25 调不下去;且 SMENU 设置页并不暴露 brightness_min 这一项,故 25
|
||||
* 只能是旧默认残留→强制视为待迁移,改写为 1 并落盘,让用户能调到「极暗但可见」的 1)。
|
||||
* 此处只针对恰为旧默认 25 的值;用户其它自定义值(非 25)不动。 */
|
||||
meow_setting *bmin = find_set("display.brightness_min");
|
||||
if (bmin && !strcmp(bmin->cur, "25")) {
|
||||
snprintf(bmin->cur, sizeof bmin->cur, "%d", 1);
|
||||
bmin->dirty = 1;
|
||||
sset_log("brightness_min stale default 25 -> 1 (migrated)");
|
||||
meow_settings_save();
|
||||
}
|
||||
return MEOW_OK;
|
||||
}
|
||||
|
||||
/* ---- 生命周期 ---- */
|
||||
int meow_settings_shutdown(void)
|
||||
{
|
||||
if (g_inited) meow_settings_save();
|
||||
return MEOW_OK;
|
||||
}
|
||||
|
||||
void meow_settings_dump(const char *log_prefix)
|
||||
{
|
||||
const char *lp = log_prefix ? log_prefix : "";
|
||||
for (int i = 0; i < g_nsets; i++)
|
||||
sset_log("%s%s = %s", lp, g_sets[i].key, g_sets[i].cur);
|
||||
}
|
||||
|
||||
/* ---- get ---- */
|
||||
int meow_settings_get_int(const char *key, int *out)
|
||||
{
|
||||
meow_setting *s = find_set(key);
|
||||
if (!s) return MEOW_ERR_NOENT;
|
||||
if (!g_inited) return MEOW_ERR_NOTINIT;
|
||||
if (s->type != SET_INT) return MEOW_ERR_INVAL;
|
||||
if (!out) return MEOW_ERR_INVAL;
|
||||
*out = atoi(s->cur);
|
||||
return MEOW_OK;
|
||||
}
|
||||
|
||||
int meow_settings_get_str(const char *key, char *buf, int buf_len)
|
||||
{
|
||||
meow_setting *s = find_set(key);
|
||||
if (!s) return MEOW_ERR_NOENT;
|
||||
if (!g_inited) return MEOW_ERR_NOTINIT;
|
||||
if (s->type != SET_STR) return MEOW_ERR_INVAL;
|
||||
if (!buf || buf_len <= 0) return MEOW_ERR_INVAL;
|
||||
strncpy(buf, s->cur, buf_len);
|
||||
buf[buf_len - 1] = 0;
|
||||
return MEOW_OK;
|
||||
}
|
||||
|
||||
int meow_settings_get_enum(const char *key, int *out)
|
||||
{
|
||||
meow_setting *s = find_set(key);
|
||||
if (!s) return MEOW_ERR_NOENT;
|
||||
if (!g_inited) return MEOW_ERR_NOTINIT;
|
||||
if (s->type != SET_ENUM) return MEOW_ERR_INVAL;
|
||||
if (!out) return MEOW_ERR_INVAL;
|
||||
*out = enum_index_of_name_str(s->enum_names, s->cur);
|
||||
if (*out < 0) *out = 0; /* 非法当前值兜底:首项 */
|
||||
return MEOW_OK;
|
||||
}
|
||||
|
||||
int meow_settings_get_bool(const char *key, int *out)
|
||||
{
|
||||
meow_setting *s = find_set(key);
|
||||
if (!s) return MEOW_ERR_NOENT;
|
||||
if (!g_inited) return MEOW_ERR_NOTINIT;
|
||||
if (s->type != SET_BOOL) return MEOW_ERR_INVAL;
|
||||
if (!out) return MEOW_ERR_INVAL;
|
||||
*out = (s->cur[0] == '1');
|
||||
return MEOW_OK;
|
||||
}
|
||||
|
||||
/* ---- 标注脏 + 广播的公共尾部 ---- */
|
||||
static void mark_changed(meow_setting *s, const char *newval)
|
||||
{
|
||||
if (strcmp(newval, s->cur) == 0) return; /* 未变:不广播 */
|
||||
strncpy(s->cur, newval, sizeof s->cur - 1);
|
||||
s->cur[sizeof s->cur - 1] = 0;
|
||||
s->dirty = 1;
|
||||
notify_key(s->key);
|
||||
}
|
||||
|
||||
/* ---- set ---- */
|
||||
int meow_settings_set_int(const char *key, int v)
|
||||
{
|
||||
meow_setting *s = find_set(key);
|
||||
if (!s) return MEOW_ERR_NOENT;
|
||||
if (!g_inited) return MEOW_ERR_NOTINIT;
|
||||
if (s->type != SET_INT) return MEOW_ERR_INVAL;
|
||||
v = clamp_int(s, v);
|
||||
if (!strcmp(s->key, "display.brightness")) v = clamp_brightness(v);
|
||||
char tmp[24];
|
||||
snprintf(tmp, sizeof tmp, "%d", v);
|
||||
mark_changed(s, tmp);
|
||||
return MEOW_OK;
|
||||
}
|
||||
|
||||
int meow_settings_set_str(const char *key, const char *v)
|
||||
{
|
||||
meow_setting *s = find_set(key);
|
||||
if (!s) return MEOW_ERR_NOENT;
|
||||
if (!g_inited) return MEOW_ERR_NOTINIT;
|
||||
if (s->type != SET_STR) return MEOW_ERR_INVAL;
|
||||
char tmp[MEOW_SET_MAX_LEN];
|
||||
strncpy(tmp, v ? v : "", sizeof tmp - 1);
|
||||
tmp[sizeof tmp - 1] = 0;
|
||||
mark_changed(s, tmp);
|
||||
return MEOW_OK;
|
||||
}
|
||||
|
||||
int meow_settings_set_enum(const char *key, int idx)
|
||||
{
|
||||
meow_setting *s = find_set(key);
|
||||
if (!s) return MEOW_ERR_NOENT;
|
||||
if (!g_inited) return MEOW_ERR_NOTINIT;
|
||||
if (s->type != SET_ENUM) return MEOW_ERR_INVAL;
|
||||
int n = enum_count_str(s->enum_names);
|
||||
if (idx < 0 || idx >= n) return MEOW_ERR_INVAL; /* 越界拒绝 */
|
||||
const char *name = enum_at_str(s->enum_names, idx);
|
||||
if (!name) return MEOW_ERR_INVAL;
|
||||
mark_changed(s, name);
|
||||
return MEOW_OK;
|
||||
}
|
||||
|
||||
int meow_settings_set_bool(const char *key, int v)
|
||||
{
|
||||
meow_setting *s = find_set(key);
|
||||
if (!s) return MEOW_ERR_NOENT;
|
||||
if (!g_inited) return MEOW_ERR_NOTINIT;
|
||||
if (s->type != SET_BOOL) return MEOW_ERR_INVAL;
|
||||
char tmp[8];
|
||||
snprintf(tmp, sizeof tmp, "%d", v ? 1 : 0);
|
||||
mark_changed(s, tmp);
|
||||
return MEOW_OK;
|
||||
}
|
||||
|
||||
/* ---- listener ---- */
|
||||
int meow_settings_add_listener(meow_settings_listener cb)
|
||||
{
|
||||
if (!cb) return MEOW_ERR_INVAL;
|
||||
for (int i = 0; i < g_nlisteners; i++)
|
||||
if (g_listeners[i] == cb) return MEOW_ERR_EXISTS;
|
||||
if (g_nlisteners >= MEOW_SET_MAX_LISTENERS) return MEOW_ERR_NOMEM;
|
||||
g_listeners[g_nlisteners++] = cb;
|
||||
return MEOW_OK;
|
||||
}
|
||||
|
||||
int meow_settings_remove_listener(meow_settings_listener cb)
|
||||
{
|
||||
for (int i = 0; i < g_nlisteners; i++) {
|
||||
if (g_listeners[i] == cb) {
|
||||
memmove(&g_listeners[i], &g_listeners[i+1],
|
||||
(g_nlisteners - i - 1) * sizeof *g_listeners);
|
||||
g_nlisteners--;
|
||||
return MEOW_OK;
|
||||
}
|
||||
}
|
||||
return MEOW_ERR_NOENT;
|
||||
}
|
||||
|
||||
/* ---- enum 辅助 ---- */
|
||||
int meow_settings_enum_label(const char *key, int idx, char *buf, int buf_len)
|
||||
{
|
||||
meow_setting *s = find_set(key);
|
||||
if (!s) return MEOW_ERR_NOENT;
|
||||
if (s->type != SET_ENUM) return MEOW_ERR_INVAL;
|
||||
if (!buf || buf_len <= 0) return MEOW_ERR_INVAL;
|
||||
if (idx < 0 || idx >= enum_count_str(s->enum_names)) return MEOW_ERR_INVAL;
|
||||
const char *lab = enum_at_str(s->enum_labels, idx);
|
||||
if (!lab || !lab[0]) lab = enum_at_str(s->enum_names, idx); /* 无标签回退名字 */
|
||||
if (!lab) return MEOW_ERR_INVAL;
|
||||
strncpy(buf, lab, buf_len);
|
||||
buf[buf_len - 1] = 0;
|
||||
return MEOW_OK;
|
||||
}
|
||||
|
||||
int meow_settings_enum_count(const char *key)
|
||||
{
|
||||
meow_setting *s = find_set(key);
|
||||
if (!s) return -MEOW_ERR_NOENT;
|
||||
if (s->type != SET_ENUM) return -MEOW_ERR_INVAL;
|
||||
return enum_count_str(s->enum_names);
|
||||
}
|
||||
|
||||
int meow_settings_enum_index_of_name(const char *key, const char *name)
|
||||
{
|
||||
meow_setting *s = find_set(key);
|
||||
if (!s) return MEOW_ERR_NOENT;
|
||||
if (s->type != SET_ENUM) return MEOW_ERR_INVAL;
|
||||
return enum_index_of_name_str(s->enum_names, name);
|
||||
}
|
||||
|
||||
void meow_settings_enum_names(const char *key, const char **out_names, int *n)
|
||||
{
|
||||
static char scratch[MEOW_SET_ENUM_LEN];
|
||||
static const char *ptrs[MEOW_SET_ENUM_MAX_OPT];
|
||||
if (n) *n = 0;
|
||||
meow_setting *s = find_set(key);
|
||||
if (!s || s->type != SET_ENUM || !out_names) return;
|
||||
strncpy(scratch, s->enum_names, sizeof scratch - 1);
|
||||
scratch[sizeof scratch - 1] = 0;
|
||||
char *p = scratch;
|
||||
int k = 0;
|
||||
while (*p && k < MEOW_SET_ENUM_MAX_OPT) {
|
||||
while (*p == ' ' || *p == '\t') p++;
|
||||
if (!*p) break;
|
||||
ptrs[k++] = p;
|
||||
while (*p && *p != ',') p++;
|
||||
if (*p == ',') { *p = 0; p++; }
|
||||
}
|
||||
for (int i = 0; i < k; i++) out_names[i] = ptrs[i];
|
||||
if (n) *n = k;
|
||||
}
|
||||
|
||||
/* ---- list ---- */
|
||||
int meow_settings_list(int (*cb)(const char *key, meow_set_type t, void *ctx), void *ctx)
|
||||
{
|
||||
if (!cb) return MEOW_ERR_INVAL;
|
||||
if (!g_inited) return MEOW_ERR_NOTINIT;
|
||||
for (int i = 0; i < g_nsets; i++)
|
||||
cb(g_sets[i].key, g_sets[i].type, ctx);
|
||||
return MEOW_OK;
|
||||
}
|
||||
|
||||
/* ---- 默认值 / 复位 ---- */
|
||||
int meow_settings_get_default(const char *key, char *buf, int len)
|
||||
{
|
||||
meow_setting *s = find_set(key);
|
||||
if (!s) return MEOW_ERR_NOENT;
|
||||
if (!buf || len <= 0) return MEOW_ERR_INVAL;
|
||||
strncpy(buf, s->def, len);
|
||||
buf[len - 1] = 0;
|
||||
return MEOW_OK;
|
||||
}
|
||||
|
||||
int meow_settings_reset(const char *key)
|
||||
{
|
||||
meow_setting *s = find_set(key);
|
||||
if (!s) return MEOW_ERR_NOENT;
|
||||
if (strcmp(s->cur, s->def) != 0) {
|
||||
strncpy(s->cur, s->def, sizeof s->cur - 1);
|
||||
s->cur[sizeof s->cur - 1] = 0;
|
||||
s->dirty = 1;
|
||||
notify_key(s->key);
|
||||
}
|
||||
return MEOW_OK;
|
||||
}
|
||||
|
||||
int meow_settings_reset_all(void)
|
||||
{
|
||||
for (int i = 0; i < g_nsets; i++) {
|
||||
meow_setting *s = &g_sets[i];
|
||||
if (strcmp(s->cur, s->def) != 0) {
|
||||
strncpy(s->cur, s->def, sizeof s->cur - 1);
|
||||
s->cur[sizeof s->cur - 1] = 0;
|
||||
s->dirty = 1;
|
||||
notify_key(s->key);
|
||||
}
|
||||
}
|
||||
return MEOW_OK;
|
||||
}
|
||||
|
||||
/* ---- 落盘(写板载 settings.conf;保留 "# meow-settings 1" 头)---- */
|
||||
static void write_full_conf(int fd)
|
||||
{
|
||||
char buf[576];
|
||||
int l = snprintf(buf, sizeof buf, "# meow-settings 1\n");
|
||||
if (l > 0) write(fd, buf, l);
|
||||
for (int i = 0; i < g_nsets; i++) {
|
||||
meow_setting *s = &g_sets[i];
|
||||
const char *val = s->cur;
|
||||
char num[24];
|
||||
/* 非字符串类型把 cur 规范为可读形式(enum=名字,bool/int=数字) */
|
||||
if (s->type == SET_INT) { snprintf(num, sizeof num, "%d", atoi(s->cur)); val = num; }
|
||||
else if (s->type == SET_BOOL) { snprintf(num, sizeof num, "%d", s->cur[0] == '1'); val = num; }
|
||||
else if (s->type == SET_ENUM) { val = s->cur; }
|
||||
l = snprintf(buf, sizeof buf, "%s = %s\n", s->key, val);
|
||||
if (l > 0) write(fd, buf, l);
|
||||
}
|
||||
}
|
||||
|
||||
int meow_settings_save(void)
|
||||
{
|
||||
if (!g_inited) return MEOW_ERR_NOTINIT;
|
||||
if (system("mkdir -p /usr/data/meow 2>/dev/null") != 0) {
|
||||
/* 目录已存在等返回非 0 也属正常,不视为失败 */
|
||||
}
|
||||
int fd = open(MEOW_SETTINGS_FILE, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||
if (fd < 0) {
|
||||
sset_log("save: open %s fail: %s", MEOW_SETTINGS_FILE, strerror(errno));
|
||||
return MEOW_ERR_IO;
|
||||
}
|
||||
write_full_conf(fd);
|
||||
close(fd);
|
||||
for (int i = 0; i < g_nsets; i++) g_sets[i].dirty = 0;
|
||||
return MEOW_OK;
|
||||
}
|
||||
|
||||
/* ---- export:写一份 .conf 到 path(默认 TF 卡备份)---- */
|
||||
int meow_settings_export(const char *path)
|
||||
{
|
||||
const char *p = path ? path : MEOW_SETTINGS_BAK;
|
||||
/* 自动建目录(取 p 的 dirname),失败静默(导出尽力而为) */
|
||||
{
|
||||
char dir[320];
|
||||
char cmd[344];
|
||||
snprintf(dir, sizeof dir, "%s", p);
|
||||
char *slash = strrchr(dir, '/');
|
||||
if (slash) {
|
||||
if (slash == dir) slash[1] = 0; else *slash = 0;
|
||||
snprintf(cmd, sizeof cmd, "mkdir -p '%s' 2>/dev/null", dir);
|
||||
system(cmd);
|
||||
}
|
||||
}
|
||||
int fd = open(p, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||
if (fd < 0) {
|
||||
sset_log("export: open %s fail: %s", p, strerror(errno));
|
||||
return MEOW_ERR_IO;
|
||||
}
|
||||
write_full_conf(fd);
|
||||
close(fd);
|
||||
sset_log("exported -> %s", p);
|
||||
return MEOW_OK;
|
||||
}
|
||||
|
||||
/* ---- import:从 .conf 读入覆盖;逐键校验,损坏键不中断 ---- */
|
||||
int meow_settings_import(const char *path)
|
||||
{
|
||||
if (!g_inited) return MEOW_ERR_NOTINIT;
|
||||
const char *p = path ? path : MEOW_SETTINGS_BAK;
|
||||
FILE *f = fopen(p, "r");
|
||||
if (!f) { sset_log("import: open %s fail: %s", p, strerror(errno)); return MEOW_ERR_NOENT; }
|
||||
int bad = 0, applied = 0;
|
||||
char buf[768];
|
||||
while (fgets(buf, sizeof buf, f)) {
|
||||
char *eq = strchr(buf, '=');
|
||||
if (!eq) continue;
|
||||
*eq = 0;
|
||||
char *k = buf;
|
||||
while (*k == ' ' || *k == '\t') k++;
|
||||
int kl = (int)strlen(k);
|
||||
while (kl > 0 && (k[kl-1] == ' ' || k[kl-1] == '\t')) k[--kl] = 0;
|
||||
if (!k[0] || k[0] == '#') continue;
|
||||
char *v = eq + 1;
|
||||
while (*v == ' ' || *v == '\t') v++;
|
||||
int vl = (int)strlen(v);
|
||||
while (vl > 0 && (v[vl-1] == '\n' || v[vl-1] == '\r')) v[--vl] = 0;
|
||||
while (vl > 0 && (v[vl-1] == ' ' || v[vl-1] == '\t')) v[--vl] = 0;
|
||||
meow_setting *s = find_set(k);
|
||||
if (!s) { bad++; continue; } /* 未知键:计损坏,不中断 */
|
||||
/* 逐键校验:走 set 的 clamp/校验(apply_value 已 clamp);值合法才算成功 */
|
||||
apply_value_nosave(s, v, &applied);
|
||||
}
|
||||
fclose(f);
|
||||
meow_settings_save(); /* 导入后落盘(应用覆盖) */
|
||||
sset_log("imported %s: applied=%d invalid=%d", p, applied, bad);
|
||||
return applied > 0 ? MEOW_OK : MEOW_ERR_INVAL;
|
||||
}
|
||||
|
||||
/* ---- import 内部:apply + 脏 + 广播(不重置整表)---- */
|
||||
static void apply_value_nosave(meow_setting *s, const char *v, int *applied)
|
||||
{
|
||||
if (!s || !v) return;
|
||||
char before[MEOW_SET_MAX_LEN];
|
||||
strncpy(before, s->cur, sizeof before - 1); before[sizeof before - 1] = 0;
|
||||
apply_value(s, v);
|
||||
if (strcmp(before, s->cur) != 0) {
|
||||
s->dirty = 1;
|
||||
notify_key(s->key);
|
||||
if (applied) (*applied)++;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/* meow_settings.h — MeowOS 系统设置后端(阶段 B2a)
|
||||
*
|
||||
* 统一设置子系统:全部系统设置抽象为「名称/类型/默认/取值域」的扁平表,
|
||||
* 单点存板载 /usr/data/meow/settings.conf(UBIFS,KB 级小文件,key=value)。
|
||||
* 实体 UI / Web 面板 / CLI 均走本 API,不留旁路。
|
||||
*
|
||||
* 设计规范:SYSTEM_SETTINGS.md §1/§2/§3 + MEOWOS_API.md §2。
|
||||
* 返回码:MEOWOS_API.md §1(MEOW_OK=0,负值错误码)。
|
||||
* 注释风格:与 meow_launcherd.c 一致(中文注释 + 「M2.x 说明」格式)。
|
||||
*
|
||||
* 阶段 B2a 只建后端 + 核心 API;实体设置页(B2b)/Web 面板(C)后续复用。
|
||||
*/
|
||||
#ifndef MEOW_SETTINGS_H
|
||||
#define MEOW_SETTINGS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* 统一错误码(MEOWOS_API.md §1;C 函数返回 int,0=成功,负=错误码) */
|
||||
#ifndef MEOW_OK
|
||||
#define MEOW_OK 0 /* 成功 */
|
||||
#define MEOW_ERR_INVAL -1 /* 参数/取值非法 */
|
||||
#define MEOW_ERR_NOENT -2 /* 键/资源不存在 */
|
||||
#define MEOW_ERR_EXISTS -3 /* 已存在(如重复注册) */
|
||||
#define MEOW_ERR_PERM -4 /* 无权限(本机信任模型下少用,保留) */
|
||||
#define MEOW_ERR_IO -5 /* 读写(存储/文件)失败 */
|
||||
#define MEOW_ERR_NOMEM -6 /* 内存不足 */
|
||||
#define MEOW_ERR_NOTINIT -7 /* 未初始化(如 settings 未 init) */
|
||||
#define MEOW_ERR_BUSY -8 /* 忙(如服务已运行) */
|
||||
#define MEOW_ERR_TIMEOUT -9 /* 超时 */
|
||||
#define MEOW_ERR_NODEV -10 /* 设备不存在(如无卡) */
|
||||
#define MEOW_ERR_INTERNAL -255 /* 内部错误 */
|
||||
#endif /* MEOW_OK */
|
||||
|
||||
/* 字符串类型最大长度(set_str 截断;str 存取缓冲区建议为此值) */
|
||||
#define MEOW_SET_MAX_LEN 256
|
||||
|
||||
/* 类型 schema:每个设置键注册“名称/类型/默认/取值域”,存取统一走表 */
|
||||
typedef enum { SET_INT, SET_STR, SET_ENUM, SET_BOOL } meow_set_type;
|
||||
|
||||
/* 设置项注册描述(MEOWOS_API §2.7:新增设置照此;实体 UI/web/CLI 自动生成控件) */
|
||||
typedef struct meow_setting_def {
|
||||
const char *key; /* 如 "display.brightness" */
|
||||
meow_set_type type;
|
||||
const char *def; /* 默认值字符串(int/str/enum/bool 统一字符串) */
|
||||
int min, max; /* SET_INT 取值域(max<=0 表示仅保底、无上界);其他 0 */
|
||||
const char *enum_names; /* SET_ENUM:逗号分隔选项名,如 "panel,black" */
|
||||
const char *enum_labels; /* 对应中文标签,如 "面板下电,背光全黑双击" */
|
||||
} meow_setting_def;
|
||||
|
||||
/* 变更通知回调:key 变化时调用(实体 UI 据此重绘 / web 经 MeowPanel 推送) */
|
||||
typedef void (*meow_settings_listener)(const char *key);
|
||||
|
||||
/* ---- 初始化/生命周期 ---- */
|
||||
/* 加载 storage + 注册默认;幂等,可重载(重载=重置默认再读 settings.conf)。
|
||||
* 返回 MEOW_OK / MEOW_ERR_IO(文件可读性)/ MEOW_ERR_NOMEM(表满)。 */
|
||||
int meow_settings_init(void);
|
||||
/* 保存 + 清理(进程退出前调;不自动调用) */
|
||||
int meow_settings_shutdown(void);
|
||||
/* 调试:打印当前全部键(前缀 + key = value) */
|
||||
void meow_settings_dump(const char *log_prefix);
|
||||
|
||||
/* ---- 设置项注册(启动时批量注册;重复注册返回 MEOW_ERR_EXISTS)---- */
|
||||
int meow_settings_register(const meow_setting_def *def);
|
||||
|
||||
/* ---- 类型化存取(get 返回 0=成功,负=错误码;set 含 clamp/校验 + 广播)---- */
|
||||
int meow_settings_get_int (const char *key, int *out);
|
||||
int meow_settings_get_str (const char *key, char *buf, int buf_len);
|
||||
int meow_settings_get_enum(const char *key, int *out); /* 返回索引(名字->索引) */
|
||||
int meow_settings_get_bool(const char *key, int *out); /* 0/1 */
|
||||
|
||||
int meow_settings_set_int (const char *key, int v); /* clamp 到取值域 */
|
||||
int meow_settings_set_str (const char *key, const char *v);/* 长度截断 MEOW_SET_MAX_LEN */
|
||||
int meow_settings_set_enum(const char *key, int idx); /* 校验枚举合法,越界拒绝 */
|
||||
int meow_settings_set_bool(const char *key, int v);
|
||||
|
||||
/* ---- 变更通知(set 成功后广播 key 字符串)---- */
|
||||
int meow_settings_add_listener(meow_settings_listener cb);
|
||||
int meow_settings_remove_listener(meow_settings_listener cb);
|
||||
|
||||
/* ---- 枚举辅助(供 UI/web 显示中文标签)---- */
|
||||
int meow_settings_enum_label(const char *key, int idx, char *buf, int buf_len);
|
||||
int meow_settings_enum_count(const char *key); /* 选项数;错误负值 */
|
||||
int meow_settings_enum_index_of_name(const char *key, const char *name);
|
||||
void meow_settings_enum_names(const char *key, const char **out_names, int *n);
|
||||
|
||||
/* ---- 列表:枚举当前全部键,供 web 面板 / 设置页生成控件 ---- */
|
||||
int meow_settings_list(int (*cb)(const char *key, meow_set_type t, void *ctx), void *ctx);
|
||||
|
||||
/* ---- 默认值 / 复位 ---- */
|
||||
int meow_settings_get_default(const char *key, char *buf, int len);
|
||||
int meow_settings_reset(const char *key); /* 单键复位默认 */
|
||||
int meow_settings_reset_all(void); /* 全量复位 */
|
||||
|
||||
/* ---- 落盘 / 导入导出(备份)---- */
|
||||
int meow_settings_save(void); /* 写板载 settings.conf,保留 "# meow-settings 1" 头 */
|
||||
int meow_settings_export(const char *path); /* 写一份 .conf 到 path;NULL=默认 TF 卡备份路径 */
|
||||
int meow_settings_import(const char *path); /* 从 .conf 读入覆盖;逐键校验,记录损坏键不中断 */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* MEOW_SETTINGS_H */
|
||||
@@ -0,0 +1,69 @@
|
||||
/* meow_touch.c — 实现 Launcher 统一触摸接口(见 meow_touch.h)。 */
|
||||
#include "meow_touch.h"
|
||||
|
||||
void mt_reset(meow_touch *mt)
|
||||
{
|
||||
mt->down = 0;
|
||||
mt->valid = 0;
|
||||
mt->down_x = -1;
|
||||
mt->down_y = -1;
|
||||
mt->last_x = -1;
|
||||
mt->last_y = -1;
|
||||
}
|
||||
|
||||
void mt_abs(meow_touch *mt, int x, int y)
|
||||
{
|
||||
if (x >= 0) mt->last_x = x;
|
||||
if (y >= 0) mt->last_y = y;
|
||||
/* 已按下且原点未锁,且两轴终于都有效 → 锁原点(goodix 时序免疫:只认 down 之后
|
||||
* 的首个有效坐标,绝不锁残留 -1/上一手势旧坐标)。 */
|
||||
if (mt->down && !mt->valid && mt->last_x >= 0 && mt->last_y >= 0) {
|
||||
mt->down_x = mt->last_x;
|
||||
mt->down_y = mt->last_y;
|
||||
mt->valid = 1;
|
||||
}
|
||||
}
|
||||
|
||||
int mt_down(meow_touch *mt)
|
||||
{
|
||||
mt->down = 1;
|
||||
mt->valid = 0;
|
||||
/* 本次以「无坐标」起步:BTN_TOUCH 先于 ABS(本设备实测),down 前的 last 是上一
|
||||
* 手势残留(-1/旧坐标),必须丢弃,只认 down 后到来的首个有效 ABS。 */
|
||||
mt->last_x = -1;
|
||||
mt->last_y = -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int mt_up(meow_touch *mt, int *dx, int *dy)
|
||||
{
|
||||
int tx = mt->down_x, ty = mt->down_y;
|
||||
int was_valid = mt->valid;
|
||||
int ddx = mt->last_x - tx, ddy = mt->last_y - ty;
|
||||
int adx = ddx < 0 ? -ddx : ddx, ady = ddy < 0 ? -ddy : ddy;
|
||||
if (dx) *dx = ddx;
|
||||
if (dy) *dy = ddy;
|
||||
/* 复位手势态(down/valid);保留 down_x/y 供 mt_in 判定按钮命中,调用方下一手势
|
||||
* 再由 mt_down 重置。 */
|
||||
mt->down = 0;
|
||||
mt->valid = 0;
|
||||
if (!was_valid || tx < 0 || ty < 0) return 0; /* 从未锁到有效坐标:ghost/残留,丢本次 */
|
||||
if (adx >= MEOW_TOUCH_SWIPE_THRESH || ady >= MEOW_TOUCH_SWIPE_THRESH) return 0; /* 滑动 */
|
||||
return 1; /* 有效 tap */
|
||||
}
|
||||
|
||||
int mt_in(meow_touch *mt, int x, int y, int w, int h)
|
||||
{
|
||||
return mt->down_x >= x && mt->down_x < x + w &&
|
||||
mt->down_y >= y && mt->down_y < y + h;
|
||||
}
|
||||
|
||||
/* 全局左缘返回判定(A-0):原点在左缘 + 向右位移≥MEOW_EDGE_SWIPE 且横向主导。
|
||||
* 与 SDK meow_ui_input.c 的 EDGE_W/SWIPE_THRESH 同一语义,供设置页/应用列表复用。 */
|
||||
int meow_edge_back(int down_x, int dx, int dy)
|
||||
{
|
||||
int ady = dy < 0 ? -dy : dy;
|
||||
if (down_x >= 0 && down_x < MEOW_EDGE_W && dx >= MEOW_EDGE_SWIPE && ady < dx)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/* meow_touch.h — Launcher 统一触摸接口(轻量,不依赖 SDK)。
|
||||
*
|
||||
* 背景:Launcher 的低性能 UI(应用列表 / 电源菜单 / 确认框)各自有一套独立、重复的
|
||||
* 触摸解析,除应用列表(M2.23 已修原点锁定)外其余都踩同一个 goodix 依赖 bug:
|
||||
* BTN_TOUCH=1 按下边沿到来时 ABS 坐标可能尚未更新(goodix 时序不保证 ABS 与
|
||||
* BTN_TOUCH 先后),旧代码在按下边沿用「当时 t_last_x/y」立即锁原点 → 锁到上一手势
|
||||
* 残留(-1/旧坐标)→ 抬手命中按钮失败 → 「点两下」。本接口把「坐标时序免疫」的
|
||||
* 手势解析收敛成一份,供各 UI 复用,语义与 M2.23 应用列表修法一致。
|
||||
*
|
||||
* 关键语义:
|
||||
* - mt_down() 不立即锁原点:只标「已按下」,并把 last 坐标归 -1(本次以无坐标起步),
|
||||
* 原点由 mt_abs() 在 down 之后出现的首个有效坐标锁定(BOTH >=0 才锁)。杜绝 GOODIX
|
||||
* 残留,与 M2.23 应用列表 t_down_valid 同源。
|
||||
* - mt_up() 算抬手位移:abs(dx)>=MEOW_TOUCH_SWIPE_THRESH || abs(dy)>=… → 判滑动
|
||||
* (返回 0,供将来切屏),否则有效 tap(返回 1)。抬手后复位手势态(down/valid),
|
||||
* 但保留 down_x/y 供 mt_in() 判定按钮命中 —— 调用方处理完再开下一手势。
|
||||
* - mt_reset() 彻底清空,杜绝跨手势污染。
|
||||
*
|
||||
* 与应用列表(run_menu 内联,M2.23 直接内联实现)语义一致;列表保留内联(含 cooldown
|
||||
* 丢弃/滑动日志/行带判定等额外逻辑),其余 UI 迁到本接口。
|
||||
*/
|
||||
#ifndef MEOW_TOUCH_H
|
||||
#define MEOW_TOUCH_H
|
||||
|
||||
typedef struct meow_touch {
|
||||
int down, valid; /* down=已按下;valid=原点已锁(down 后首个有效 ABS) */
|
||||
int down_x, down_y; /* 按下原点(goodix 时序免疫:等 down 后首个有效坐标才锁) */
|
||||
int last_x, last_y; /* 最新坐标(-1=本次尚未见到有效坐标) */
|
||||
} meow_touch;
|
||||
|
||||
/* 抬手位移 >= 阈值判为滑动(不命中);与 launcher MENU_SWIPE_THRESH(65) 一致。 */
|
||||
#define MEOW_TOUCH_SWIPE_THRESH 65
|
||||
|
||||
/* 全局左缘返回判定(A-0 方案,M2.39 抽出共享,供设置页/应用列表等 system 界面复用,
|
||||
* 与 SDK meow_ui_input.c 的 EDGE_W(24)/SWIPE_THRESH(65) 对齐——同一套"左缘起点+右滑≥阈值"
|
||||
* 语义,避免各界面自造重复判定。 */
|
||||
#define MEOW_EDGE_W 24 /* 左缘起点宽度(down_x < 此值才认返回手势) */
|
||||
#define MEOW_EDGE_SWIPE 65 /* 向右位移阈值(dx >= 此值且横向主导 → 左缘返回) */
|
||||
|
||||
/* 左缘返回判定:down_x=按下原点X,dx/dy=抬手位移。
|
||||
* 返回 1=命中(left-edge + 向右≥MEOW_EDGE_SWIPE 且横向主导);0=否。
|
||||
* 供设置页/应用列表等系统界面复用;SDK 手势引擎对 APP 用 on_swipe(LEFT) 同语义。 */
|
||||
int meow_edge_back(int down_x, int dx, int dy);
|
||||
|
||||
/* 手势结束彻底清空(下一手势零污染;也用于起始初始化)。 */
|
||||
void mt_reset(meow_touch *mt);
|
||||
|
||||
/* 喂 ABS_X/ABS_Y(调用方按事件逐个喂:AX 事件传 (val, mt->last_y),AY 事件传
|
||||
* (mt->last_x, val)):更新 last;若已按下且未锁原点且两轴均有效 → 锁原点。 */
|
||||
void mt_abs(meow_touch *mt, int x, int y);
|
||||
|
||||
/* BTN_TOUCH=1 按下边沿:标 down + last 归 -1(本次以无坐标起步,只认 down 后首个有效
|
||||
* ABS 作原点)。返回 1=接受此按下(是否进一步处理由调用方决定,如 cooldown/日志)。 */
|
||||
int mt_down(meow_touch *mt);
|
||||
|
||||
/* BTN_TOUCH=0 抬手边沿:计算位移写入 dx/dy 输出参数;复位 down/valid(保留 down_x/y 供 mt_in)。
|
||||
* 返回 1=有效 tap,0=滑动(位移>=阈值)或从未锁到有效坐标(ghost/残留)。 */
|
||||
int mt_up(meow_touch *mt, int *dx, int *dy);
|
||||
|
||||
/* 按下原点是否落在矩形 [x, x+w) × [y, y+h)(tap 命中;须在 mt_up() 返回 1 后调用)。 */
|
||||
int mt_in(meow_touch *mt, int x, int y, int w, int h);
|
||||
|
||||
#endif /* MEOW_TOUCH_H */
|
||||
@@ -0,0 +1,80 @@
|
||||
/* pm_icons.h — 电源菜单圆钮图标(Material Symbols Rounded, MD3),单通道 alpha 位图 56x56。
|
||||
* 生成自 material-symbols@0.47.0 rounded 字体光栅化;每像素 0..255(亮度/alpha)。
|
||||
* ★ 统一 ink 高度 36px + 几何居中:5 图标视觉大小一致、圆心对齐。
|
||||
* ★ 为日/夜间预留:位图只存亮度,绘制颜色由 pm_theme_* 提供,换主题仅改配色。 */
|
||||
#ifndef PM_ICONS_H
|
||||
#define PM_ICONS_H
|
||||
|
||||
#define PM_ICON_SIZE 56
|
||||
|
||||
typedef struct { const unsigned char *data; } pm_icon_t;
|
||||
|
||||
static const unsigned char PM_ICON_POWER[3136]={
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,74,238,238,74,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,193,255,255,193,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,201,254,254,201,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,0,0,0,0,0,0,0,0,1,0,199,255,255,199,0,1,0,0,0,0,0,0,0,0,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,1,0,200,255,255,200,0,1,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,29,0,0,0,0,0,0,0,0,1,0,200,255,255,200,0,1,0,0,0,0,0,0,0,0,29,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,1,2,8,186,247,148,1,2,0,0,0,0,0,1,0,200,255,255,200,0,1,0,0,0,0,0,2,1,148,247,186,8,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,153,255,254,255,46,0,2,0,0,0,0,1,0,200,255,255,200,0,1,0,0,0,0,2,0,46,255,254,255,153,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,71,255,249,253,238,26,1,1,0,0,0,0,1,0,200,255,255,200,0,1,0,0,0,0,1,1,26,238,253,249,255,71,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,5,213,254,250,255,89,0,3,0,0,0,0,0,1,0,200,255,255,200,0,1,0,0,0,0,0,3,0,89,255,250,254,213,5,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,87,255,248,255,176,0,3,0,0,0,0,0,0,1,0,200,255,255,200,0,1,0,0,0,0,0,0,3,0,176,255,248,255,87,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,193,254,252,249,40,1,3,0,0,0,0,0,0,1,0,200,255,255,200,0,1,0,0,0,0,0,0,3,1,40,249,252,254,193,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,250,252,255,174,0,3,0,0,0,0,0,0,0,1,0,200,255,255,200,0,1,0,0,0,0,0,0,0,3,0,174,255,252,250,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,118,255,249,255,79,1,4,0,0,0,0,0,0,0,1,0,200,255,255,200,0,1,0,0,0,0,0,0,0,4,1,79,255,249,255,118,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,180,255,254,240,19,0,1,0,0,0,0,0,0,0,1,0,200,255,255,200,0,1,0,0,0,0,0,0,0,1,0,19,240,254,255,180,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,221,255,255,201,0,1,0,0,0,0,0,0,0,0,1,0,200,255,255,200,0,1,0,0,0,0,0,0,0,0,1,0,202,255,255,221,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,243,254,255,171,0,3,0,0,0,0,0,0,0,0,1,0,199,255,255,199,0,1,0,0,0,0,0,0,0,0,3,0,171,255,254,243,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,253,251,255,155,0,4,0,0,0,0,0,0,0,0,1,0,202,252,252,202,0,1,0,0,0,0,0,0,0,0,4,0,155,255,251,253,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,253,251,255,156,0,4,0,0,0,0,0,0,0,0,3,0,183,255,255,183,0,3,0,0,0,0,0,0,0,0,4,0,156,255,251,253,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,244,254,255,171,0,3,0,0,0,0,0,0,0,0,2,1,40,181,181,40,1,2,0,0,0,0,0,0,0,0,3,0,171,255,254,244,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,222,255,255,199,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,199,255,255,222,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,183,255,255,237,16,0,1,0,0,0,0,0,0,0,0,0,2,2,2,2,0,0,0,0,0,0,0,0,0,1,0,16,237,255,255,183,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,122,255,250,255,70,1,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,1,70,255,250,255,122,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,48,251,252,255,161,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,161,255,252,251,48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,198,254,252,245,30,1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,1,30,245,252,254,198,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,92,255,248,255,165,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,165,255,248,255,92,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,217,254,250,255,84,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,84,255,250,254,217,6,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,76,255,249,253,243,50,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,50,243,253,249,255,76,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,159,255,248,255,233,51,0,4,2,0,0,0,0,0,0,0,0,0,0,0,0,2,4,0,51,233,255,248,255,159,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,10,205,255,248,255,241,86,0,0,3,3,1,0,0,0,0,0,0,1,3,3,0,0,86,241,255,248,255,205,10,3,1,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,2,0,26,217,255,248,255,255,160,36,0,0,0,1,3,4,4,3,1,0,0,0,36,160,255,255,248,255,217,26,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,27,202,255,251,251,255,244,158,72,19,0,0,0,0,0,0,19,72,158,244,255,251,251,255,202,27,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,10,156,255,255,248,255,255,255,236,199,171,155,155,171,200,236,255,255,255,248,255,255,156,10,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,79,210,255,255,253,250,255,255,255,255,255,255,255,255,250,253,255,255,210,79,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,0,6,94,193,249,255,255,255,254,251,251,254,255,255,255,249,193,94,6,0,3,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,50,120,180,220,243,253,253,243,220,180,120,50,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
};
|
||||
|
||||
static const unsigned char PM_ICON_RESTART[3136]={
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,42,209,240,129,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,38,223,255,255,255,40,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,38,227,255,251,255,255,45,4,6,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,36,225,255,252,253,253,130,0,0,0,0,0,4,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,1,35,224,255,252,255,255,251,186,176,149,104,49,1,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,189,255,250,255,255,255,255,255,255,255,255,255,208,116,18,0,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,2,225,252,253,255,255,255,255,252,248,247,248,254,255,255,226,99,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,4,4,1,3,0,116,255,250,255,255,255,254,255,255,255,255,255,249,250,255,255,169,13,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,132,255,251,254,254,249,118,89,133,190,249,255,255,252,251,255,203,22,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,2,98,100,7,0,1,3,0,134,255,251,252,255,209,0,0,0,40,144,250,255,252,250,255,207,15,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,156,255,255,171,2,2,1,4,0,135,255,251,250,255,58,4,5,0,0,52,210,255,252,250,255,180,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,87,255,248,251,245,14,0,1,1,4,0,137,255,255,217,15,1,1,2,5,0,15,190,255,252,250,255,113,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,14,229,254,250,255,188,2,2,0,0,1,2,0,77,108,26,0,1,0,0,0,4,0,11,206,255,251,253,243,27,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,115,255,250,253,245,41,0,2,0,0,0,0,1,0,0,0,1,0,0,0,0,0,3,0,35,242,253,250,255,140,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,7,217,254,250,255,128,0,4,0,0,0,0,0,0,3,4,2,0,0,0,0,0,0,0,4,0,118,255,250,254,231,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,71,255,253,255,237,18,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,13,232,255,252,255,87,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,147,255,248,255,158,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,150,255,248,254,158,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,203,255,250,255,85,1,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,1,81,255,250,255,208,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,235,255,254,254,42,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,40,253,254,255,237,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,250,255,255,242,22,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,22,242,255,255,251,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,254,255,238,18,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,18,238,255,254,254,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,248,255,255,245,25,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,26,245,255,255,248,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,231,255,253,255,49,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,49,255,253,255,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,196,255,249,255,97,1,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,1,98,255,249,255,194,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,138,255,248,255,175,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,176,255,248,255,136,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,62,254,253,254,246,32,1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,1,33,247,254,254,254,59,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,209,254,249,255,159,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,162,255,249,254,206,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100,255,251,252,255,72,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,77,255,252,251,255,96,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,216,255,251,254,236,39,0,5,0,0,0,0,0,0,0,0,0,0,0,0,5,0,44,238,254,251,255,212,6,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,63,255,251,252,255,226,47,0,2,3,1,0,0,0,0,0,0,1,4,1,0,53,230,255,252,251,255,59,0,3,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,125,255,250,252,255,241,101,0,0,0,2,0,0,0,0,2,0,0,2,107,245,255,252,250,255,120,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,4,0,154,255,251,252,255,255,197,90,17,0,1,0,0,1,0,17,93,201,255,255,252,251,255,150,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,0,146,255,255,250,252,255,255,230,82,0,3,3,0,82,230,255,255,252,251,255,255,144,0,3,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,0,103,242,255,255,250,249,255,230,9,1,1,9,231,255,249,250,255,255,241,101,0,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,36,159,245,255,255,255,230,10,0,0,9,227,255,255,255,245,159,35,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,46,142,224,241,97,0,3,3,0,92,240,224,142,46,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
};
|
||||
|
||||
static const unsigned char PM_ICON_BACK[3136]={
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,31,186,248,242,150,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,29,215,255,254,255,255,149,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,29,219,255,251,255,254,253,249,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,28,216,255,251,255,255,255,253,253,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,27,215,255,251,255,255,255,251,255,195,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,26,214,255,252,255,255,255,252,255,223,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,25,213,255,251,255,255,255,252,255,227,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,25,212,255,251,255,255,255,252,255,227,39,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,24,211,255,251,255,255,255,252,255,228,40,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,22,210,255,251,255,255,255,252,255,229,42,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,22,209,255,251,255,255,255,252,255,230,42,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,21,208,255,251,255,255,255,252,255,231,43,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,20,206,255,251,255,255,255,252,255,232,45,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,19,205,255,251,255,255,255,252,255,233,46,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,205,255,251,255,255,255,252,255,234,47,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,200,255,251,255,255,255,253,255,235,48,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,176,255,251,255,255,255,253,255,237,49,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,251,253,255,255,255,253,254,229,43,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,251,253,255,255,255,253,254,229,43,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,176,255,251,255,255,255,253,255,237,50,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,200,255,251,255,255,255,253,255,235,48,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,205,255,251,255,255,255,252,255,234,47,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,19,205,255,251,255,255,255,252,255,233,46,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,20,206,255,251,255,255,255,252,255,232,45,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,21,208,255,251,255,255,255,252,255,231,44,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,22,209,255,251,255,255,255,252,255,230,43,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,23,210,255,251,255,255,255,252,255,230,42,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,24,211,255,251,255,255,255,252,255,228,40,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,25,212,255,251,255,255,255,252,255,227,40,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,25,214,255,251,255,255,255,252,255,227,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,26,214,255,252,255,255,255,252,255,223,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,27,215,255,251,255,255,255,251,255,195,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,28,216,255,251,255,255,255,253,253,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,29,219,255,251,255,254,253,249,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,30,215,255,254,255,255,149,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,31,186,248,243,150,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
};
|
||||
|
||||
static const unsigned char PM_ICON_UPGRADE[3136]={
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,31,201,249,201,31,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,28,214,255,252,255,214,28,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,28,218,255,252,255,252,255,218,28,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,27,216,255,251,255,255,255,251,255,216,27,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,27,215,255,251,255,255,255,255,255,251,255,215,27,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,26,214,255,251,255,255,255,255,255,255,255,251,255,214,26,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,25,213,255,251,255,253,255,255,255,255,255,253,255,251,255,213,25,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,25,212,255,251,255,253,255,252,255,255,255,252,255,253,255,251,255,212,25,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,25,212,255,251,255,251,255,134,194,255,250,255,194,134,255,251,255,251,255,212,25,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,184,255,250,255,251,255,143,0,199,255,250,255,200,0,142,255,251,255,250,255,184,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,241,250,252,250,255,143,0,1,201,255,250,255,201,1,0,140,255,250,251,250,242,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,204,255,255,255,144,0,4,0,200,255,250,255,200,0,4,0,140,255,255,255,196,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42,186,213,123,0,3,2,0,200,255,250,255,200,0,2,3,0,115,201,174,35,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,200,255,250,255,200,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,0,3,0,0,1,0,200,255,250,255,200,0,1,0,0,3,1,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,200,255,250,255,200,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,200,255,250,255,200,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,200,255,250,255,200,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,200,255,250,255,200,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,200,255,250,255,200,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,200,255,250,255,200,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,200,255,250,255,200,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,200,255,250,255,200,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,199,255,250,255,199,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,203,252,247,252,203,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,137,255,255,255,137,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,7,132,188,132,7,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,4,2,4,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,115,156,156,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,156,156,115,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,175,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,175,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,250,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,250,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,224,255,254,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,254,255,224,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,220,254,254,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,254,254,220,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
};
|
||||
|
||||
static const unsigned char PM_ICON_CANCEL[3136]={
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,194,250,227,90,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,90,227,250,194,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,197,255,253,255,252,91,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,91,252,255,253,255,197,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,253,255,253,254,255,93,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,93,255,254,253,255,253,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,235,255,253,255,254,253,255,92,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,92,255,253,254,255,253,255,235,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,88,254,253,254,255,254,253,255,93,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,92,255,253,254,255,254,253,254,88,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,91,255,253,254,255,254,253,255,92,0,5,0,0,0,0,0,0,0,0,0,0,0,0,5,0,92,255,253,254,255,254,253,255,91,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,4,0,93,255,253,254,255,254,253,255,93,0,5,0,0,0,0,0,0,0,0,0,0,5,0,93,255,253,254,255,254,253,255,93,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,92,255,253,254,255,254,253,255,92,0,4,0,0,0,0,0,0,0,0,4,0,92,255,253,254,255,254,253,255,92,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,92,255,253,254,255,254,253,255,93,0,5,0,0,0,0,0,0,5,0,92,255,253,254,255,254,253,255,92,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,93,255,253,254,255,254,253,255,93,0,5,0,0,0,0,5,0,93,255,253,254,255,254,253,255,92,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,93,255,253,254,255,254,253,255,93,0,4,0,0,4,0,92,255,253,254,255,254,253,255,92,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,93,255,253,254,255,254,253,255,92,0,5,5,0,92,255,253,254,255,254,253,255,93,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,93,255,253,254,255,254,253,255,93,0,0,93,255,253,254,255,254,253,255,92,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,93,255,253,254,255,254,253,255,83,83,255,253,254,255,254,253,255,93,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,92,255,253,254,255,254,255,255,255,255,254,255,254,253,255,92,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,93,255,253,254,255,254,255,255,254,255,254,253,255,93,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,93,255,255,254,255,254,254,255,254,255,255,93,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,83,247,253,255,255,255,255,253,247,83,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,83,247,253,255,255,255,255,253,247,83,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,93,255,255,254,255,254,254,255,254,255,255,93,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,93,255,253,254,255,254,255,255,254,255,254,253,255,93,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,92,255,253,254,255,254,255,255,255,255,254,255,254,253,255,92,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,93,255,253,254,255,254,253,255,83,83,255,253,254,255,254,253,255,93,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,92,255,253,254,255,254,253,255,93,0,0,93,255,253,254,255,254,253,255,93,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,93,255,253,254,255,254,253,255,92,0,5,5,0,92,255,253,254,255,254,253,255,93,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,92,255,253,254,255,254,253,255,92,0,4,0,0,4,0,93,255,253,254,255,254,253,255,93,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,92,255,253,254,255,254,253,255,93,0,5,0,0,0,0,5,0,93,255,253,254,255,254,253,255,93,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,92,255,253,254,255,254,253,255,92,0,5,0,0,0,0,0,0,5,0,93,255,253,254,255,254,253,255,92,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,92,255,253,254,255,254,253,255,92,0,4,0,0,0,0,0,0,0,0,4,0,92,255,253,254,255,254,253,255,92,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,93,255,253,254,255,254,253,255,93,0,5,0,0,0,0,0,0,0,0,0,0,5,0,93,255,253,254,255,254,253,255,93,0,4,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,91,255,253,254,255,254,253,255,92,0,5,0,0,0,0,0,0,0,0,0,0,0,0,5,0,92,255,253,254,255,254,253,255,91,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,88,254,253,254,255,254,253,255,92,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,93,255,253,254,255,254,253,254,88,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,235,255,253,255,254,253,255,92,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,92,255,253,254,255,253,255,235,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,253,255,253,254,255,93,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,93,255,254,253,255,253,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,197,255,253,255,252,91,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,91,252,255,253,255,197,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,194,250,227,90,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,90,227,250,194,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
};
|
||||
|
||||
static const pm_icon_t pm_icons[5] = {
|
||||
{ PM_ICON_POWER },
|
||||
{ PM_ICON_RESTART },
|
||||
{ PM_ICON_BACK },
|
||||
{ PM_ICON_UPGRADE },
|
||||
{ PM_ICON_CANCEL },
|
||||
};
|
||||
|
||||
/* 图标绘制颜色(RGB565,16 位)。为日/夜间预留:选中/未选中 + 圆钮背景。
|
||||
* MD3 无边框高亮:选中=未选中底色稍亮(深灰微冷调,无描边圈);icon_sel 白 / icon_nor 浅灰蓝。
|
||||
* 换主题仅改此表,不重生成图标。 */
|
||||
typedef struct { unsigned short icon_sel, icon_nor, btn_sel_bg, btn_nor_bg; } pm_theme_t;
|
||||
static const pm_theme_t pm_theme_light = {
|
||||
0xFFFF, 0xBC63, /* icon_sel 亮白, icon_nor 浅灰蓝(#B8C0D8) */
|
||||
0x4A6B, 0x39E9 }; /* btn_sel_bg(#4A4F5A 底稍亮), btn_nor_bg(#3A3E48 底) */
|
||||
static const pm_theme_t pm_theme_dark = {
|
||||
0xFFFF, 0x9D39, /* icon_sel 亮白, icon_nor 浅灰蓝(#9AA4C8) */
|
||||
0x2967, 0x1904 }; /* btn_sel_bg(#2A2E38 底稍亮), btn_nor_bg(#1D2027 底) */
|
||||
#endif /* PM_ICONS_H */
|
||||
@@ -0,0 +1,42 @@
|
||||
#!/bin/sh
|
||||
# run_ab.sh — A/B launcher v6.5 (bug) vs v6.6 (fix) with the display panned to
|
||||
# buffer1 (yoffset=720). Reproduces the reported bug: launcher draws the menu
|
||||
# to buffer0 while the panel shows buffer1 -> menu invisible.
|
||||
HPID=976
|
||||
st(){ awk '{print $3}' "/proc/$HPID/stat" 2>/dev/null; }
|
||||
yoff(){ /data/fbprobe 2>/dev/null | grep -oE "yoffset = [0-9]+"; }
|
||||
|
||||
seed(){
|
||||
/data/fbtool blank 0 >/dev/null 2>&1 # unblank so pan is not EBUSY
|
||||
/data/fbtool pan 720 >/dev/null 2>&1 # display -> buffer1 (yoffset=720)
|
||||
echo " seeded yoffset=$(yoff)"
|
||||
}
|
||||
|
||||
run_one(){
|
||||
BIN=$1; TAG=$2
|
||||
seed
|
||||
echo "=== $TAG ($BIN) ==="
|
||||
rm -f /usr/data/meow_launcherd.pid
|
||||
"$BIN" --sim-hotkey 1200 --sim-exit 9000 >/tmp/m_$TAG.log 2>&1 &
|
||||
LPID=$!
|
||||
sleep 4
|
||||
echo " DURING t=4s: player_stat=$(st) yoffset=$(yoff)"
|
||||
dd if=/dev/fb0 of=/tmp/${TAG}_menu_b0.raw bs=960 count=720 status=none 2>/dev/null
|
||||
echo " menu_b0=$(md5sum /tmp/${TAG}_menu_b0.raw 2>/dev/null | awk '{print $1}')"
|
||||
echo " log: $(grep -E 'fb:|fb backup|fb pan|menu open' /tmp/m_$TAG.log | tr '\n' ' | ')"
|
||||
sleep 6
|
||||
echo " AFTER t=10s: player_stat=$(st) yoffset=$(yoff)"
|
||||
echo " log2: $(grep -E 'fb restore|menu close|restore:|SIGCONT' /tmp/m_$TAG.log | tr '\n' ' | ')"
|
||||
kill "$LPID" 2>/dev/null; sleep 1; killall meow_launcherd 2>/dev/null
|
||||
echo " killed; player_stat=$(st)"
|
||||
}
|
||||
|
||||
echo "player pid=$HPID"
|
||||
run_one /data/meow_launcherd.v65 OLD
|
||||
run_one /data/meow_launcherd.v66 NEW
|
||||
echo "=== cleanup: restore player's natural screen-off (brightness 0 + blank) ==="
|
||||
/data/fbtool blank 0 >/dev/null 2>&1
|
||||
/data/fbtool pan 0 >/dev/null 2>&1
|
||||
echo "brightness now: $(cat /sys/class/backlight/backlight_pwm0/brightness)"
|
||||
echo "final yoffset=$(yoff) player_stat=$(st)"
|
||||
echo DONE
|
||||
@@ -0,0 +1,48 @@
|
||||
#!/bin/sh
|
||||
# run_bugcond.sh — A/B test of launcher v6.5 (bug) vs v6.6 (fix) under the
|
||||
# bug condition: the display is on buffer1 (yoffset=720) with the player's
|
||||
# frame in buffer1 (the post-power screen-off state). Reproduces the reported
|
||||
# "menu invisible / screen frozen on last frame".
|
||||
HPID=976
|
||||
st(){ awk '{print $3}' "/proc/$HPID/stat" 2>/dev/null; }
|
||||
yoff(){ /data/fbprobe 2>/dev/null | grep -oE "yoffset = [0-9]+"; }
|
||||
|
||||
setup_bugcond(){
|
||||
# player frame into buffer1 (simulates the player's screen-off frame), then
|
||||
# put the display on buffer1 so yoffset=720 -> buffer1 displayed.
|
||||
/data/fbcopy >/dev/null 2>&1
|
||||
/data/fbpan 720 >/dev/null 2>&1
|
||||
echo " setup: buffer1<-buffer0, yoffset=$(yoff)"
|
||||
}
|
||||
|
||||
run_one(){
|
||||
BIN=$1; TAG=$2
|
||||
echo "=== $TAG ($BIN) ==="
|
||||
rm -f /usr/data/meow_launcherd.pid
|
||||
"$BIN" --sim-hotkey 1200 --sim-exit 9000 >/tmp/m_$TAG.log 2>&1 &
|
||||
LPID=$!
|
||||
sleep 4
|
||||
echo " DURING t=4s: player_stat=$(st) yoffset=$(yoff)"
|
||||
dd if=/dev/fb0 of=/tmp/${TAG}_menu_b0.raw bs=960 count=720 status=none
|
||||
dd if=/dev/fb0 of=/tmp/${TAG}_menu_b1.raw bs=960 skip=720 count=720 status=none
|
||||
echo " menu b0=$(md5sum /tmp/${TAG}_menu_b0.raw 2>/dev/null | awk '{print $1}') b1=$(md5sum /tmp/${TAG}_menu_b1.raw 2>/dev/null | awk '{print $1}')"
|
||||
echo " player_stat_after_capture=$(st)"
|
||||
sleep 6
|
||||
echo " AFTER t=10s: player_stat=$(st) yoffset=$(yoff)"
|
||||
dd if=/dev/fb0 of=/tmp/${TAG}_close_b1.raw bs=960 skip=720 count=720 status=none
|
||||
echo " close b1=$(md5sum /tmp/${TAG}_close_b1.raw 2>/dev/null | awk '{print $1}')"
|
||||
echo " log: $(grep -E 'fb:|fb backup|fb pan|fb restore|menu open|menu close' /tmp/m_$TAG.log | tr '\n' ' | ')"
|
||||
kill "$LPID" 2>/dev/null; sleep 1; killall meow_launcherd 2>/dev/null
|
||||
echo " killed; player_stat=$(st)"
|
||||
}
|
||||
|
||||
echo "launcher stopped, player pid=$HPID"
|
||||
setup_bugcond
|
||||
run_one /data/meow_launcherd.v65 OLD
|
||||
setup_bugcond # re-setup for the NEW run (player frame still in buffer1)
|
||||
run_one /data/meow_launcherd.v66 NEW
|
||||
echo "=== cleanup ==="
|
||||
/data/fbpan 720 >/dev/null 2>&1 # leave display on buffer1 (player's frame)
|
||||
echo "final yoffset=$(yoff) player_stat=$(st)"
|
||||
echo "BACKLIGHT: $(cat /sys/class/backlight/backlight_pwm0/brightness 2>/dev/null)"
|
||||
echo DONE
|
||||
@@ -0,0 +1,40 @@
|
||||
#!/bin/sh
|
||||
# run_final.sh — clean single verification of v6.6 under the bug condition,
|
||||
# waiting long enough for the menu-relative sim-exit so the menu-close restore
|
||||
# path is observed, then a device health check.
|
||||
HPID=976
|
||||
st(){ awk '{print $3}' "/proc/$HPID/stat" 2>/dev/null; }
|
||||
yoff(){ /data/fbprobe 2>/dev/null | grep -oE "yoffset = [0-9]+"; }
|
||||
|
||||
echo "=== seed bug-cond: unblank + pan to buffer1 (yoffset=720) ==="
|
||||
/data/fbtool blank 0 >/dev/null 2>&1
|
||||
/data/fbtool pan 720 >/dev/null 2>&1
|
||||
echo "seed: yoffset=$(yoff) player_stat=$(st)"
|
||||
|
||||
echo "=== run v6.6 (sim-hotkey 1200, sim-exit 9000) ==="
|
||||
rm -f /usr/data/meow_launcherd.pid
|
||||
/data/meow_launcherd.v66 --sim-hotkey 1200 --sim-exit 9000 >/tmp/m_fin.log 2>&1 &
|
||||
LPID=$!
|
||||
# menu opens ~2s after start; sim-exit fires at menu-open+9s ~= start+11s.
|
||||
sleep 4
|
||||
echo "=== DURING MENU (t=4s) ==="
|
||||
echo " player_stat=$(st) yoffset=$(yoff)"
|
||||
dd if=/dev/fb0 of=/tmp/fin_menu_b0.raw bs=960 count=720 status=none 2>/dev/null
|
||||
echo " menu_b0=$(md5sum /tmp/fin_menu_b0.raw 2>/dev/null | awk '{print $1}')"
|
||||
sleep 9 # now ~13s: sim-exit (menu-rel 9s) has fired
|
||||
echo "=== AFTER sim-exit (t=13s) ==="
|
||||
echo " player_stat=$(st) yoffset=$(yoff)"
|
||||
echo " log2: $(grep -E 'menu close|fb restore|restore:|SIGCONT|=== meow_launcherd exit' /tmp/m_fin.log | tr '\n' ' | ')"
|
||||
kill "$LPID" 2>/dev/null; sleep 1; killall meow_launcherd 2>/dev/null
|
||||
|
||||
echo "=== HEALTH CHECK ==="
|
||||
echo " launcher procs: $(pgrep -c meow_launcherd 2>/dev/null || echo 0)"
|
||||
echo " hiby procs: $(pgrep -c hiby_player 2>/dev/null || echo 0)"
|
||||
echo " player stat=$(st)"
|
||||
echo " recovery_all: $(ls /data/recovery_all 2>/dev/null || echo absent)"
|
||||
echo " brightness=$(cat /sys/class/backlight/backlight_pwm0/brightness) bl_power=$(cat /sys/class/backlight/backlight_pwm0/bl_power 2>/dev/null)"
|
||||
echo " yoffset=$(yoff)"
|
||||
echo " loadavg=$(cat /proc/loadavg)"
|
||||
echo "=== last 12 log lines ==="
|
||||
tail -12 /tmp/m_fin.log
|
||||
echo DONE
|
||||
@@ -0,0 +1,216 @@
|
||||
/* sb_icons.h — 状态栏/通知中心图标(Material Symbols Rounded, MD3),单通道 alpha 位图 32x32。
|
||||
* 生成自 material-symbols@0.47.0 rounded 字体光栅化;每像素 0..255(亮度/alpha)。
|
||||
* ★ 为日/夜间预留:位图只存亮度;绘制颜色由调用方主题表提供,换主题仅改配色。 */
|
||||
#ifndef SB_ICONS_H
|
||||
#define SB_ICONS_H
|
||||
|
||||
#define SB_ICON_SIZE 32
|
||||
|
||||
typedef struct { const unsigned char *data; } sb_icon_t;
|
||||
|
||||
static const unsigned char SB_ICON_WIFI[1024]={
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,4,3,3,2,2,3,3,4,3,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,4,1,0,0,0,0,0,0,0,0,0,0,0,0,1,4,1,0,0,0,0,0,0,0,0,0,0,0,0,1,3,0,0,0,30,77,122,154,177,187,187,177,154,122,77,30,0,0,0,3,1,0,0,0,0,0,0,0,0,0,3,0,0,25,108,191,244,255,255,255,255,255,255,255,255,255,255,244,191,108,25,0,0,3,0,0,0,0,0,0,1,1,0,27,140,235,255,255,255,249,248,251,254,255,255,254,251,248,249,255,255,255,235,140,27,0,1,1,0,0,0,2,0,0,110,235,255,255,249,251,255,255,255,255,246,240,240,246,255,255,255,255,251,249,255,255,235,110,0,0,2,0,1,0,25,181,255,255,249,253,255,255,216,151,92,53,29,18,18,29,53,92,151,217,255,255,253,249,255,255,181,25,0,1,
|
||||
1,30,220,255,250,251,255,255,180,74,6,0,0,0,0,0,0,0,0,0,0,6,75,180,255,255,251,250,255,220,30,1,0,124,255,244,252,255,207,69,0,0,0,6,7,4,0,0,0,0,4,7,6,0,0,0,69,207,255,252,244,255,123,0,0,76,255,255,255,147,8,0,3,6,0,0,0,0,7,15,15,7,0,0,0,0,6,3,0,8,147,255,255,255,76,0,1,0,93,151,80,0,0,5,1,0,2,67,140,193,221,235,235,221,192,138,64,0,0,1,5,0,0,80,151,93,0,1,0,0,0,0,0,2,2,0,0,97,207,255,255,255,255,255,255,255,255,255,255,204,93,0,0,2,2,0,0,0,0,0,0,0,3,4,3,2,0,37,191,255,255,251,248,255,255,255,255,255,254,248,251,255,255,187,35,0,2,3,4,3,0,0,0,0,0,0,1,1,7,212,255,248,251,255,255,246,213,193,193,214,247,255,255,250,248,255,211,7,1,1,0,0,0,0,0,0,0,0,1,0,10,235,255,255,255,197,98,31,3,0,0,3,33,100,200,255,255,255,234,10,0,1,0,0,0,0,
|
||||
0,0,0,0,0,2,0,85,216,206,95,0,0,0,1,6,6,1,0,0,0,99,208,215,81,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,4,3,0,0,0,0,3,3,0,0,1,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,3,0,1,0,48,119,107,25,0,1,0,3,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,2,0,95,251,255,255,230,48,0,2,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,21,241,255,249,248,255,190,1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,63,255,252,255,254,253,235,14,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,46,255,251,253,251,252,225,7,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,185,255,255,255,255,124,0,3,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,1,0,20,163,231,223,128,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
};
|
||||
|
||||
static const unsigned char SB_ICON_BT[1024]={
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,3,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,9,153,156,6,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,3,0,61,255,255,183,8,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,3,0,66,252,247,255,186,10,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,2,3,0,65,255,253,255,255,188,11,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,44,221,195,23,0,6,0,65,255,251,227,255,255,191,13,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,85,255,255,208,23,0,1,65,255,254,69,167,255,255,193,16,2,1,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,2,5,159,255,255,209,25,0,69,255,255,63,0,175,252,255,165,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,160,255,255,212,17,55,255,255,57,16,197,251,255,150,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,0,159,255,255,198,88,254,254,88,198,255,255,171,6,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,0,158,255,255,244,254,254,244,255,255,167,2,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,0,158,255,255,255,255,255,255,164,1,1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,0,153,251,253,253,251,156,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,18,235,254,254,236,19,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,21,204,254,253,253,253,204,20,0,3,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,3,0,20,204,255,255,255,255,255,255,203,19,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,21,205,255,255,214,254,254,214,255,255,203,19,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,21,206,255,255,151,60,255,255,60,151,255,255,203,21,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,22,206,255,255,167,0,63,255,255,66,0,169,253,255,170,0,3,0,0,0,0,0,0,0,0,0,0,0,0,1,1,21,203,255,255,163,1,1,67,255,255,54,25,206,251,255,148,0,3,0,0,0,0,0,0,0,0,0,0,0,0,4,0,92,255,255,162,0,4,0,65,255,253,101,211,255,255,176,6,2,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,22,169,140,0,1,5,0,65,255,252,252,255,255,178,5,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,0,65,255,253,251,255,180,5,1,2,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,1,3,3,1,0,3,0,66,252,247,255,182,6,1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,60,255,255,183,7,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,8,151,157,7,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,3,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
};
|
||||
|
||||
static const unsigned char SB_ICON_BATT[1024]={
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,16,16,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,4,75,235,237,237,235,75,4,7,4,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,124,255,255,255,255,124,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,80,123,115,184,253,251,251,253,184,116,123,98,8,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,49,255,255,255,255,255,255,255,255,255,255,255,255,107,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,68,253,249,239,236,239,238,238,239,236,236,246,252,131,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,64,255,255,77,16,19,17,17,17,16,32,235,255,125,0,4,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,3,0,65,255,255,62,0,0,0,0,0,0,13,234,255,126,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,65,255,255,66,1,4,1,1,2,1,18,234,255,126,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,65,255,255,67,2,5,2,2,3,2,19,234,255,126,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,65,255,255,56,0,0,0,0,0,0,6,233,255,126,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,65,255,254,206,190,190,190,190,190,190,194,247,255,127,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,65,255,253,255,255,255,255,255,255,255,255,252,255,128,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,65,255,253,253,252,252,252,252,252,252,252,251,255,128,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,65,255,253,255,255,255,255,255,255,255,255,251,255,128,0,4,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,3,0,65,255,253,255,255,255,255,255,255,255,255,251,255,128,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,65,255,253,255,255,255,255,255,255,255,255,251,255,128,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,65,255,253,255,255,255,255,255,255,255,255,251,255,128,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,65,255,253,255,255,255,255,255,255,255,255,251,255,128,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,65,255,253,255,255,255,255,255,255,255,255,251,255,128,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,65,255,253,255,255,255,255,255,255,255,255,251,255,128,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,65,255,253,255,255,255,255,255,255,255,255,251,255,128,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,65,255,253,255,255,255,255,255,255,255,255,251,255,128,0,4,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,3,0,64,255,253,255,255,255,255,255,255,255,255,251,255,127,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,67,253,249,251,251,251,251,251,251,251,251,247,251,131,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,51,255,255,255,255,255,255,255,255,255,255,255,255,111,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,88,128,126,128,128,128,128,128,128,127,127,110,11,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,4,4,4,4,4,4,4,4,4,4,4,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
};
|
||||
|
||||
static const unsigned char SB_ICON_VOL[1024]={
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,1,2,1,1,20,193,209,94,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,2,0,48,255,255,255,178,21,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,53,198,127,1,3,2,104,229,255,255,211,24,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,58,239,255,245,15,0,2,0,23,172,255,255,199,7,3,1,0,0,0,0,0,0,0,0,0,3,3,3,3,5,0,57,239,255,252,236,17,0,0,3,0,0,161,255,255,131,0,3,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,58,239,255,255,255,238,17,0,4,3,0,3,5,206,254,245,32,0,2,0,0,0,0,0,0,0,0,51,66,65,66,88,238,255,255,227,255,238,20,0,110,209,24,3,0,64,253,255,130,0,4,0,0,0,0,0,3,0,87,255,255,255,255,255,255,255,111,117,255,234,21,0,130,255,187,2,2,0,198,254,205,2,1,0,0,0,0,0,4,0,133,255,249,255,255,255,254,122,0,127,255,234,21,0,128,253,255,78,0,0,125,255,242,28,0,2,0,0,0,0,4,0,125,255,238,72,58,62,49,0,2,127,255,234,21,0,129,255,254,159,0,0,83,255,255,55,0,3,0,0,0,0,4,0,126,255,233,2,0,0,0,9,0,126,255,234,21,0,129,255,255,187,0,0,67,255,255,64,0,3,0,0,0,0,4,0,125,255,235,31,15,17,9,0,2,126,255,234,21,0,129,255,254,173,0,0,76,255,255,59,0,3,0,0,0,0,4,0,131,251,245,228,226,227,220,71,0,131,255,234,21,0,129,254,255,108,0,1,112,255,247,36,0,2,0,0,
|
||||
0,0,4,0,111,255,255,255,255,255,255,249,61,111,255,234,21,0,127,255,225,17,1,0,178,255,217,6,0,1,0,0,0,0,1,0,11,110,127,126,126,148,255,255,240,197,255,237,21,0,127,249,61,0,2,37,245,255,153,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,106,255,255,255,255,238,18,0,25,41,0,6,0,173,255,254,54,0,3,0,0,0,0,0,0,0,1,4,4,4,4,5,0,106,255,250,254,236,17,0,0,0,5,0,112,255,255,169,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,106,255,255,245,17,0,3,0,0,117,254,255,232,26,1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,102,243,176,3,3,0,53,184,255,255,244,60,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,26,4,1,1,38,251,255,255,224,60,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,2,0,35,238,246,153,23,0,3,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,1,0,1,0,31,39,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,3,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
};
|
||||
|
||||
static const unsigned char SB_ICON_BRIGHT[1024]={
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,14,64,64,32,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,4,4,4,6,0,36,212,255,255,240,77,0,5,4,4,4,3,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,47,226,255,255,254,255,251,91,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,67,125,126,127,131,234,255,255,118,73,248,255,253,147,126,126,126,89,2,0,1,0,0,0,0,0,0,0,0,3,0,106,255,255,255,255,255,255,255,119,0,0,71,243,255,255,255,255,255,255,162,2,2,0,0,0,0,0,0,0,1,0,7,227,254,237,226,227,225,228,111,0,8,9,0,64,218,227,226,226,232,252,255,46,0,2,0,0,0,0,0,0,1,0,17,234,255,132,12,16,13,14,0,0,0,0,0,0,9,14,15,12,74,255,254,67,0,3,0,0,0,
|
||||
0,0,0,1,0,18,234,255,124,0,1,0,0,15,77,119,124,89,31,0,0,1,0,63,255,255,66,0,3,0,0,0,0,0,0,1,1,14,233,255,126,1,7,0,98,224,255,255,255,255,240,135,5,4,1,65,255,255,61,2,3,0,0,0,0,0,0,3,0,30,241,253,130,0,0,125,255,255,252,251,251,252,255,255,177,6,1,69,254,255,85,0,5,0,0,0,0,0,2,0,21,204,253,255,116,0,78,255,251,253,255,255,255,255,254,249,255,137,0,57,255,253,234,58,0,3,0,0,0,1,0,23,206,255,255,169,10,3,203,254,252,255,255,255,255,255,255,254,252,246,29,0,118,255,255,240,59,0,2,0,0,2,5,194,255,255,173,2,0,37,251,255,254,255,255,255,255,255,255,255,252,255,92,0,0,119,255,255,238,31,1,1,3,0,57,255,253,176,0,6,1,63,255,253,255,255,255,255,255,255,255,255,251,254,124,0,9,0,120,253,255,119,0,5,2,0,45,255,253,204,28,0,1,59,255,254,255,255,255,255,255,255,255,255,251,254,120,1,5,5,162,253,255,102,0,4,
|
||||
0,2,0,151,255,255,216,27,0,27,245,254,254,255,255,255,255,255,255,255,252,255,78,0,3,171,255,255,204,13,1,1,0,1,2,1,160,255,255,213,33,0,179,255,251,255,255,255,255,255,255,253,253,231,16,10,169,255,255,206,22,0,1,0,0,0,1,2,0,158,252,255,131,0,47,246,255,251,254,255,255,254,252,251,255,96,0,67,255,252,202,21,0,2,0,0,0,0,0,2,0,12,236,253,126,0,0,76,244,255,255,253,253,255,255,255,126,0,1,66,253,255,64,0,5,0,0,0,0,0,0,1,1,18,233,255,128,4,11,0,50,175,241,255,255,248,198,81,0,9,4,68,255,255,65,1,3,0,0,0,0,0,0,1,0,18,233,255,117,0,0,0,0,0,28,59,63,37,0,0,0,0,0,51,255,254,65,0,3,0,0,0,0,0,0,1,0,15,237,252,184,116,119,117,118,24,0,0,0,0,0,107,119,118,116,152,253,255,65,0,3,0,0,0,0,0,0,0,2,2,192,255,255,255,255,255,255,208,26,0,6,3,163,255,255,255,255,255,255,241,24,0,1,0,0,0,
|
||||
0,0,0,0,2,0,34,187,234,234,234,237,255,255,212,24,0,169,255,255,243,234,234,234,209,70,0,2,0,0,0,0,0,0,0,0,0,0,0,0,16,17,18,20,159,255,255,207,175,255,255,205,35,18,17,17,1,0,1,0,0,0,0,0,0,0,0,0,0,0,2,1,0,0,0,0,0,159,255,255,255,255,206,21,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,2,2,0,151,252,255,190,22,0,3,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,45,56,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
};
|
||||
|
||||
static const unsigned char SB_ICON_WIFI_STRONG[1024]={
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,2,3,4,3,3,2,2,3,3,4,3,2,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,1,4,1,0,0,0,0,0,0,0,0,0,0,0,0,1,4,1,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,1,3,0,0,0,30,77,122,154,177,187,187,177,154,122,77,30,0,0,0,3,1,0,0,0,0,0,
|
||||
0,0,0,0,3,0,0,25,108,191,244,255,255,255,255,255,255,255,255,255,255,244,191,108,25,0,0,3,0,0,0,0,
|
||||
0,0,1,1,0,27,140,235,255,255,255,249,248,251,254,255,255,254,251,248,249,255,255,255,235,140,27,0,1,1,0,0,
|
||||
0,2,0,0,110,235,255,255,249,251,255,255,255,255,246,240,240,246,255,255,255,255,251,249,255,255,235,110,0,0,2,0,
|
||||
1,0,25,181,255,255,249,253,255,255,216,151,92,53,29,18,18,29,53,92,151,217,255,255,253,249,255,255,181,25,0,1,
|
||||
1,30,220,255,250,251,255,255,180,74,6,0,0,0,0,0,0,0,0,0,0,6,75,180,255,255,251,250,255,220,30,1,
|
||||
0,124,255,244,252,255,207,69,0,0,0,6,7,4,0,0,0,0,4,7,6,0,0,0,69,207,255,252,244,255,123,0,
|
||||
0,76,255,255,255,147,8,0,3,6,0,0,0,0,7,15,15,7,0,0,0,0,6,3,0,8,147,255,255,255,76,0,
|
||||
1,0,93,151,80,0,0,5,1,0,2,67,140,193,221,235,235,221,192,138,64,0,0,1,5,0,0,80,151,93,0,1,
|
||||
0,0,0,0,0,2,2,0,0,97,207,255,255,255,255,255,255,255,255,255,255,204,93,0,0,2,2,0,0,0,0,0,
|
||||
0,0,3,4,3,2,0,37,191,255,255,251,248,255,255,255,255,255,254,248,251,255,255,187,35,0,2,3,4,3,0,0,
|
||||
0,0,0,0,1,1,7,212,255,248,251,255,255,246,213,193,193,214,247,255,255,250,248,255,211,7,1,1,0,0,0,0,
|
||||
0,0,0,0,1,0,10,235,255,255,255,197,98,31,3,0,0,3,33,100,200,255,255,255,234,10,0,1,0,0,0,0,
|
||||
0,0,0,0,0,2,0,85,216,206,95,0,0,0,1,6,6,1,0,0,0,99,208,215,81,0,2,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,4,0,0,0,4,3,0,0,0,0,3,3,0,0,1,3,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,2,0,0,3,0,1,0,48,119,107,25,0,1,0,3,0,0,2,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,1,1,0,2,0,95,251,255,255,230,48,0,2,0,1,1,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,1,0,21,241,255,249,248,255,190,1,2,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,3,0,63,255,252,255,254,253,235,14,0,1,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,2,0,46,255,251,253,251,252,225,7,0,1,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,2,2,185,255,255,255,255,124,0,3,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,1,0,20,163,231,223,128,2,1,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
};
|
||||
|
||||
static const unsigned char SB_ICON_WIFI_MEDIUM[1024]={
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,1,3,4,2,2,2,2,2,2,4,3,1,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,2,0,0,3,68,141,187,189,189,189,189,186,139,65,1,0,1,2,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,1,0,1,99,209,255,255,255,255,255,255,255,255,255,255,205,95,0,0,1,0,0,0,0,0,0,
|
||||
0,0,0,0,0,2,0,39,194,255,255,251,248,255,255,255,255,255,254,248,251,255,255,190,37,0,2,0,0,0,0,0,
|
||||
0,0,0,0,1,1,7,215,255,248,251,255,255,246,213,193,193,213,247,255,255,251,248,255,213,7,1,1,0,0,0,0,
|
||||
0,0,0,0,1,0,10,233,255,255,255,194,96,31,3,0,0,3,32,99,197,255,255,255,232,9,0,1,0,0,0,0,
|
||||
0,0,0,0,0,2,0,80,210,199,89,0,0,0,1,6,6,1,0,0,0,93,202,209,76,0,2,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,1,3,3,0,0,0,0,4,4,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,2,0,0,3,0,1,0,25,107,119,47,0,1,0,3,0,0,2,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,1,0,0,2,0,48,230,255,255,251,94,0,2,0,0,1,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,2,1,191,255,248,249,255,241,20,0,1,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,1,0,14,236,253,254,255,252,255,63,0,3,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,1,0,7,226,252,251,253,251,255,46,0,2,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,3,0,124,255,255,255,255,184,2,2,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,1,2,128,223,231,162,19,0,1,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,13,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,3,1,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
};
|
||||
|
||||
static const unsigned char SB_ICON_WIFI_WEAK[1024]={
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,1,0,4,17,17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,2,0,52,213,237,238,184,19,1,1,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,1,1,10,219,255,255,255,255,160,0,3,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,3,0,57,255,252,254,252,252,232,11,0,1,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,3,0,57,255,252,255,253,252,232,11,0,1,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,1,1,10,219,255,251,251,255,160,0,3,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,2,0,52,215,255,255,185,20,1,1,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,1,0,9,59,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
};
|
||||
|
||||
/* 网络状态位图(M2.48):WiFi 开未连接/关闭、蓝牙 未连接/已连接/关闭/搜索中 */
|
||||
static const unsigned char SB_ICON_WIFI_NO[1024]={
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,4,3,3,2,2,3,3,4,3,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,4,1,0,0,0,0,0,0,0,0,0,0,0,0,1,4,1,0,0,0,0,0,0,0,0,0,0,0,0,1,3,0,0,0,30,77,122,154,177,187,187,177,154,122,77,30,0,0,0,3,1,0,0,0,0,0,0,0,0,0,3,0,0,25,108,191,244,255,255,255,255,255,255,255,255,255,255,244,191,108,25,0,0,3,0,0,0,0,0,0,1,1,0,27,140,235,255,255,255,249,248,251,254,255,255,254,251,248,249,255,255,255,235,140,27,0,1,1,0,0,0,2,0,0,110,235,255,255,249,251,255,255,255,255,246,240,240,246,255,255,255,255,251,249,255,255,235,110,0,0,2,0,1,0,25,181,255,255,249,253,255,255,216,151,92,53,29,18,18,29,53,92,151,217,255,255,253,249,255,255,181,25,0,1,
|
||||
1,30,220,255,250,251,255,255,180,74,6,0,0,0,0,0,0,0,0,0,0,6,75,180,255,255,251,250,255,220,30,1,0,124,255,244,252,255,207,69,0,0,0,6,7,4,0,0,0,0,4,7,6,0,0,0,69,207,255,252,244,255,123,0,0,76,255,255,255,147,8,0,3,6,0,0,0,0,7,15,15,7,0,0,0,0,6,3,0,8,147,255,255,255,76,0,1,0,93,151,80,0,0,5,1,0,2,67,140,193,221,235,235,221,192,138,64,0,0,1,5,0,0,80,151,93,0,1,0,0,0,0,0,2,2,0,0,97,207,255,255,255,255,255,255,255,255,255,255,204,93,0,0,2,2,0,0,0,0,0,0,0,3,4,3,2,0,37,191,255,255,251,248,255,255,255,255,255,254,248,251,255,255,187,35,0,2,3,4,3,0,0,0,0,0,0,1,1,7,212,255,248,251,255,255,246,213,193,193,214,247,255,255,250,248,255,211,7,1,1,0,0,0,0,0,0,0,0,1,0,10,235,255,255,255,197,98,31,3,0,0,3,33,100,200,255,255,255,234,10,0,1,0,0,0,0,
|
||||
0,0,0,0,0,2,0,85,216,206,95,0,0,0,1,6,6,1,0,0,0,99,208,215,81,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,4,3,0,0,0,0,3,3,0,0,1,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,3,0,1,0,48,119,107,25,0,1,0,3,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,2,0,95,251,255,255,230,48,0,2,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,21,241,255,249,248,255,190,1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,63,255,252,255,254,253,235,14,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,46,255,251,253,251,252,225,7,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,185,255,255,255,255,124,0,3,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,1,0,20,163,231,223,128,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
};
|
||||
|
||||
static const unsigned char SB_ICON_WIFI_OFF[1024]={
|
||||
0,0,0,1,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,1,3,3,3,3,3,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,22,55,0,1,1,0,0,0,2,0,0,0,0,0,0,0,0,1,4,3,1,0,0,0,0,0,0,0,0,1,1,6,208,255,135,0,3,1,0,1,0,14,54,65,65,64,56,39,16,0,0,0,0,3,2,0,0,0,0,0,0,1,1,6,207,255,255,137,0,4,3,1,54,225,255,255,255,255,255,251,235,201,147,77,13,0,0,3,1,0,0,0,0,0,2,0,34,212,252,255,136,0,6,0,171,255,247,249,248,248,250,253,255,255,255,255,224,135,35,0,0,3,0,0,0,0,0,5,0,56,247,251,255,135,0,1,134,255,255,255,255,255,255,255,255,255,248,250,255,255,242,141,20,0,3,0,0,0,1,0,92,226,253,253,248,255,135,0,13,139,177,147,132,129,142,170,205,245,255,255,254,248,255,255,225,84,0,0,0,
|
||||
2,5,143,255,255,253,254,255,255,255,133,0,0,0,0,0,0,0,0,0,30,91,179,252,255,253,249,255,255,140,4,2,0,98,255,249,250,255,255,175,217,255,255,132,0,7,4,4,4,4,4,3,0,0,0,48,164,255,255,250,250,255,96,0,0,109,255,255,255,225,85,0,37,228,255,255,130,0,4,1,0,0,0,0,0,7,3,0,0,70,217,255,254,255,113,0,1,14,176,234,168,26,0,6,0,34,212,252,255,128,0,4,2,0,34,53,3,0,0,5,4,0,18,160,233,185,18,1,0,0,0,15,0,0,4,0,0,21,163,254,249,255,127,0,7,0,143,255,211,127,23,0,1,3,0,0,14,0,0,0,0,1,1,0,2,2,0,6,121,239,255,254,252,247,255,126,0,4,17,190,255,255,231,104,0,1,2,2,0,1,1,0,0,0,0,1,1,2,7,181,255,255,250,254,255,255,255,255,125,0,0,12,190,255,254,255,155,3,2,0,1,0,0,0,0,0,0,0,2,0,33,255,249,251,255,255,196,131,229,255,255,123,0,2,13,193,255,254,255,32,0,2,0,0,0,0,
|
||||
0,0,0,0,1,2,5,183,255,255,191,63,0,0,48,234,255,255,122,0,1,14,183,249,173,8,2,1,0,0,0,0,0,0,0,0,0,1,0,10,89,72,0,0,1,7,0,46,232,255,255,121,0,1,0,35,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,1,0,0,6,56,221,255,255,119,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,4,3,0,1,0,19,162,234,211,177,234,255,255,118,0,6,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,184,255,255,255,255,173,228,255,255,117,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,46,255,251,253,251,255,209,57,236,255,255,116,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,63,255,252,255,254,253,241,0,54,240,255,255,115,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,20,240,255,249,248,255,188,4,0,59,240,255,255,114,0,2,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,2,0,92,250,255,255,228,46,0,6,0,61,241,255,255,109,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,47,119,107,24,0,1,0,4,0,63,242,255,255,31,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,2,0,0,0,4,0,63,224,185,13,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,4,4,1,0,0,0,0,0,2,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
};
|
||||
|
||||
static const unsigned char SB_ICON_BT_NO[1024]={
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,3,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,9,153,156,6,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,3,0,61,255,255,183,8,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,3,0,66,252,247,255,186,10,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,2,3,0,65,255,253,255,255,188,11,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,44,221,195,23,0,6,0,65,255,251,227,255,255,191,13,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,85,255,255,208,23,0,1,65,255,254,69,167,255,255,193,16,2,1,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,2,5,159,255,255,209,25,0,69,255,255,63,0,175,252,255,165,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,160,255,255,212,17,55,255,255,57,16,197,251,255,150,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,0,159,255,255,198,88,254,254,88,198,255,255,171,6,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,0,158,255,255,244,254,254,244,255,255,167,2,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,0,158,255,255,255,255,255,255,164,1,1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,0,153,251,253,253,251,156,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,18,235,254,254,236,19,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,21,204,254,253,253,253,204,20,0,3,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,3,0,20,204,255,255,255,255,255,255,203,19,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,21,205,255,255,214,254,254,214,255,255,203,19,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,21,206,255,255,151,60,255,255,60,151,255,255,203,21,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,22,206,255,255,167,0,63,255,255,66,0,169,253,255,170,0,3,0,0,0,0,0,0,0,0,0,0,0,0,1,1,21,203,255,255,163,1,1,67,255,255,54,25,206,251,255,148,0,3,0,0,0,0,0,0,0,0,0,0,0,0,4,0,92,255,255,162,0,4,0,65,255,253,101,211,255,255,176,6,2,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,22,169,140,0,1,5,0,65,255,252,252,255,255,178,5,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,0,65,255,253,251,255,180,5,1,2,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,1,3,3,1,0,3,0,66,252,247,255,182,6,1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,60,255,255,183,7,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,8,151,157,7,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,3,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
};
|
||||
|
||||
static const unsigned char SB_ICON_BT_CONN[1024]={
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,3,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,8,153,155,6,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,3,0,61,255,255,181,7,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,3,0,66,252,247,255,183,8,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,1,0,2,3,0,65,255,253,255,255,185,9,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,40,219,199,25,0,6,0,65,255,251,228,255,255,187,10,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,77,255,255,210,24,0,1,65,255,254,69,170,255,255,188,13,2,1,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,2,4,153,255,255,209,25,0,69,255,255,63,0,179,252,255,156,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,155,255,255,211,15,55,255,255,57,14,197,252,255,141,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,3,5,4,0,155,255,255,195,84,254,254,84,195,255,255,165,4,3,5,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,155,255,255,241,254,254,241,255,255,163,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,96,113,15,0,4,0,155,255,255,255,255,255,255,161,0,3,1,15,113,95,2,1,0,0,0,0,0,0,0,3,0,125,255,255,183,3,3,3,0,152,251,253,253,251,154,1,2,3,3,183,255,255,125,0,3,0,0,0,0,0,0,3,0,195,254,250,247,13,0,5,0,18,235,254,254,235,18,0,5,0,13,247,250,254,195,0,3,0,0,0,0,0,0,3,0,88,250,255,140,0,5,0,20,203,253,253,253,253,202,19,0,5,0,140,255,249,87,0,3,0,0,0,
|
||||
0,0,0,0,1,0,41,54,0,2,0,19,202,255,255,255,255,255,255,200,17,0,2,0,54,41,0,1,0,0,0,0,0,0,0,0,0,1,0,0,3,0,19,203,255,255,210,254,254,210,255,255,199,16,0,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,2,5,0,19,202,255,255,147,58,255,255,58,148,255,255,198,18,2,4,2,0,0,0,0,0,0,0,0,0,0,0,0,1,0,19,202,255,255,165,0,64,255,255,67,0,170,253,255,161,0,4,0,0,0,0,0,0,0,0,0,0,0,0,1,2,19,198,255,255,164,1,1,67,255,255,53,28,209,251,255,140,0,3,0,0,0,0,0,0,0,0,0,0,0,0,3,0,83,255,255,165,1,4,0,65,255,253,102,213,255,255,169,5,2,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,19,166,143,1,1,5,0,65,255,252,252,255,255,172,2,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,0,65,255,253,251,255,175,3,1,2,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,1,3,3,1,0,3,0,66,252,247,255,178,5,1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,60,255,255,180,6,1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,8,151,156,6,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,3,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
};
|
||||
|
||||
static const unsigned char SB_ICON_BT_DIS[1024]={
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,3,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,2,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,1,1,8,153,155,6,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,83,165,43,0,4,0,0,0,0,3,0,61,255,255,181,7,0,2,0,0,0,0,0,0,0,0,0,0,0,0,1,1,224,255,231,47,0,4,0,0,0,3,0,66,252,247,255,182,7,0,2,0,0,0,0,0,0,0,0,0,0,0,2,0,112,255,255,232,45,0,4,0,0,3,0,65,255,253,254,255,183,7,0,2,0,0,0,0,0,0,0,0,0,0,0,2,0,122,255,255,231,44,0,4,0,3,0,65,255,251,240,255,255,183,7,0,1,0,0,0,0,0,0,0,0,0,0,0,4,0,124,255,255,230,43,0,4,3,0,64,255,253,82,188,255,255,184,10,2,1,0,0,0,0,0,0,0,
|
||||
0,0,0,1,4,0,126,255,255,229,41,0,7,0,68,254,255,59,7,187,252,255,157,0,3,0,0,0,0,0,0,0,0,0,0,0,1,4,0,127,255,255,228,40,0,2,52,255,254,60,2,183,252,255,161,0,3,0,0,0,0,0,0,0,0,0,0,0,0,1,4,0,128,255,255,227,39,0,2,108,255,70,175,255,255,188,13,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,4,0,130,255,255,226,38,0,0,116,246,255,255,188,10,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,4,0,132,255,255,225,36,0,0,121,255,187,10,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,4,0,133,255,255,223,35,0,0,85,16,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,0,134,248,255,222,34,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,1,0,220,251,255,221,33,0,4,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,2,1,5,178,254,255,252,255,220,31,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,1,4,176,255,255,231,254,252,255,218,30,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,1,3,175,255,255,179,74,254,254,255,255,217,29,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,3,174,255,255,195,6,58,255,251,212,255,255,216,28,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,7,169,255,255,194,14,0,68,255,255,52,147,253,255,214,27,0,3,0,0,0,0,0,0,0,0,0,0,0,0,3,0,74,255,255,195,14,0,1,65,255,253,83,181,253,255,255,213,26,0,3,0,0,0,0,0,0,0,0,0,0,0,1,0,26,195,178,15,0,6,0,65,255,251,241,255,255,225,255,255,212,25,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,0,65,255,253,253,255,183,16,144,255,255,211,24,0,2,0,0,0,0,
|
||||
0,0,0,0,0,0,0,1,1,1,1,0,3,0,66,252,247,255,183,8,0,0,149,255,255,209,23,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,61,255,255,183,8,0,3,3,0,152,255,255,201,13,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,8,151,156,7,0,2,0,1,3,0,154,255,255,31,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,1,0,106,81,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,3,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
};
|
||||
|
||||
static const unsigned char SB_ICON_BT_SEARCH[1024]={
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,2,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,67,179,74,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,3,0,191,255,251,84,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,2,0,0,2,0,190,252,251,252,87,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,2,0,2,0,190,255,254,255,253,91,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,140,229,104,0,4,3,0,189,255,230,244,255,254,95,0,3,0,0,0,2,4,1,0,0,0,0,0,0,0,0,1,0,215,255,255,110,0,6,0,187,255,175,67,250,255,255,98,0,2,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,2,1,57,238,255,255,111,0,2,188,255,190,0,61,241,253,255,52,0,4,0,75,140,10,1,1,0,0,0,0,0,0,0,2,0,59,239,255,255,115,0,188,255,188,0,98,245,255,248,44,1,4,0,206,255,116,0,4,0,0,0,0,0,0,0,0,4,0,58,239,255,255,102,177,255,177,99,255,255,248,74,0,2,4,0,134,251,210,4,1,1,0,0,0,0,0,0,0,0,4,0,57,239,255,254,243,255,242,254,255,245,70,0,0,0,0,0,49,253,252,44,0,2,0,0,0,0,0,0,0,0,0,4,0,57,238,255,255,255,255,255,243,66,0,0,53,207,52,0,11,223,255,89,0,4,0,0,0,0,0,0,0,0,0,0,4,0,59,225,253,253,252,227,64,0,4,57,233,255,113,0,0,193,255,116,0,4,0,0,0,0,0,0,0,0,0,0,0,7,0,137,255,248,255,141,0,10,0,171,255,249,126,0,0,186,255,124,0,4,0,0,0,0,0,0,0,0,0,0,4,0,107,250,252,254,252,250,109,0,4,29,210,255,108,0,1,197,255,112,0,4,0,0,
|
||||
0,0,0,0,0,0,0,4,0,105,255,255,255,255,255,255,255,107,0,0,29,177,43,0,15,230,255,79,0,3,0,0,0,0,0,0,0,0,4,0,106,255,255,235,225,255,224,234,255,255,108,0,0,0,0,0,59,255,244,28,0,2,0,0,0,0,0,0,0,4,0,107,255,255,243,54,174,255,174,52,242,255,255,107,0,5,4,0,151,252,187,0,2,0,0,0,0,0,0,0,2,0,107,255,255,242,65,0,190,255,191,0,49,240,253,255,54,0,4,0,198,255,83,0,3,0,0,0,0,0,0,3,0,101,255,255,241,62,0,2,187,255,186,0,113,246,254,248,44,0,4,0,42,83,0,1,0,0,0,0,0,0,0,1,0,224,255,239,61,0,7,0,187,255,181,118,255,255,251,77,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,93,179,55,0,4,2,0,190,255,246,255,253,251,79,0,3,0,0,0,2,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,2,0,190,255,251,252,251,80,0,4,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,2,3,2,0,0,2,0,190,252,251,252,81,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,190,255,251,83,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,64,178,77,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
};
|
||||
|
||||
static const sb_icon_t sb_icons[] = {
|
||||
{ SB_ICON_WIFI },
|
||||
{ SB_ICON_BT },
|
||||
{ SB_ICON_BATT },
|
||||
{ SB_ICON_VOL },
|
||||
{ SB_ICON_BRIGHT },
|
||||
{ SB_ICON_WIFI_STRONG },
|
||||
{ SB_ICON_WIFI_MEDIUM },
|
||||
{ SB_ICON_WIFI_WEAK },
|
||||
{ SB_ICON_WIFI_NO },
|
||||
{ SB_ICON_WIFI_OFF },
|
||||
{ SB_ICON_BT_NO },
|
||||
{ SB_ICON_BT_CONN },
|
||||
{ SB_ICON_BT_DIS },
|
||||
{ SB_ICON_BT_SEARCH },
|
||||
};
|
||||
|
||||
/* 枚举索引(与 sb_icons[] 对应) */
|
||||
enum { SB_I_WIFI=0, SB_I_BT=1, SB_I_BATT=2, SB_I_VOL=3, SB_I_BRIGHT=4,
|
||||
SB_I_WIFI_STRONG=5, SB_I_WIFI_MEDIUM=6, SB_I_WIFI_WEAK=7,
|
||||
SB_I_WIFI_NO=8, SB_I_WIFI_OFF=9, SB_I_BT_NO=10, SB_I_BT_CONN=11,
|
||||
SB_I_BT_DIS=12, SB_I_BT_SEARCH=13 };
|
||||
#endif /* SB_ICONS_H */
|
||||
Reference in new issue
Block a user