Files
MeowOS-For-R3P2/SYSTEM_SETTINGS.md
T
MeowOS 4e3f41a5a3 M2.90: MIUIx 风格包落地 + ui.style 一键切换闭环
- meow_ui_theme.c: 为 MEOW_STYLE_MIUIX 实现整套 light/dark 配色(暖基面+小米橙 primary
  0xF57200/0xFF8C4A+蓝 tertiary;圆角 20/卡片 28、间距 12、细描边 1),与 MD3 可感知差异
- display.background 随 style×mode 派生 MIUIx 色板(bg_surfaces 增 style 参;图片背景保持各 style 默认面)
- meow_settings.c g_defs: ui.style 值域 'md3,miui'→'md3,miuix'(label Material You,MIUIx);
  apply_value SET_ENUM 对存量 'miui' 兼容映射为 miuix
- settings_page s_commit: ui.style 分支 → meow_ui_set_style + paint_sb_right + meow_dirty_full 即时换肤
- font_theme s_ui_theme() 接 ui.style + MIUIx dark/light 表;main_menu 背景签名含 ui.style + 纯色底随 style 换族
- 宿主编译 -Wall -Wextra 0 warning;test_meow_ui_theme 四套 s×m 渲染全 PASS;
  test_meow_ui_widgets/test_sdk_fixes 全 PASS(MD3 行为一致)
- 产物 md5: meow_ui.a a4231296 / launcher 9f97af1b(未部署走固件)/ hello e5527578 /
  files 993e41ca / ncm 6b9eeb0f(三 App 已 .new+mv 热更到卡, 设备 md5 已核一致)
- 待后续: 状态栏图标集仍 MD3 一套(sb_icons.h 无 per-style 换集接口, MIUIx 仅换配色);
  App 进程 SDK 主题缓存 g_loaded 不随 settings 外部改写重读, 运行中 App 下次启动才换肤
2026-08-31 20:17:51 +08:00

199 lines
24 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# MeowOS 系统设置子系统设计(阶段 B2a 后端 + B2b UI)
> 状态:设计稿(2026-08-28)。**后端 B2a 前置到阶段 B 之前**(B 的通告栏快捷按钮/亮度滑条/主题开关全是设置项,必须先有统一后端,B 直接消费、零返工);B2b 实体设置页 UI 在 B 之后;阶段 C(MeowPanel)调同一后端。
> 原则:**一套设置后端,多端(实体 UI / Web 面板 / CLI)共用同一 API**,单一数据源,不留旁路。
---
## 0. 目标与一句话
把 MeowOS 全部系统设置抽象成**统一设置子系统**(结构化存储 + C API + 变更通知);阶段 **B2a** 落地这套后端(`meow_settings_*` + `settings.conf` + listener,**先于阶段 B**);阶段 **B** 的通告栏控件直接消费它;阶段 **B2b** 用同一 API 建**实体设置 UI**;阶段 C 的 MeowPanel 设置页**直接调同一后端**(HTTP 转发 C API),实体与 web 镜像、改哪边都同步。
## 1. 设置项清单(覆盖 MeowOS 全部可配置项)
| 分组 | 设置键 | 类型 | 默认 | 说明 |
|---|---|---|---|---|
| **显示** | `display.brightness` | int 0-255 | 101 | 当前亮度(clamp ≥`display.brightness_min`,防黑屏;设置页滑条 clamp 到 1-100,101 会闪屏) |
| | `display.brightness_min` | int | **1** | 亮度安全下限(用户可调;M2.39 由 25 改 1,旧持久 25 视为残留默认自动迁移到 1,使亮度滑条可调到「极暗但可见」) |
| | `display.screen_off_mode` | enum | `panel` | `panel`=面板下电+背光0+FBIOPBLANK / `black`=背光0全黑+双击亮屏 |
| | `display.screen_off_timeout` | int 秒 | 30 | 息屏时长(0=常亮) |
| | `display.refresh_rate` | enum | `60` | 刷新率上限三档 `60`/`30`/`15`(默认 60,不逼 62Hz 瓶颈) |
| | `display.refresh_always_max` | bool | false | 始终最大刷新率(=60 且不自动降档);关=允许自适应降档(60→30→15) |
| | `display.theme` | enum | `dark` | `dark`/`light`(该顶级主题 style 下的**明暗**;manual 模式下 s_ui_theme 直读它;**切明暗→同 style 浅/深背景自动切换**,见 MEOW_APP_SDK §8.1) |
| | `display.theme_mode` | enum | `manual` | 主题判定方式:`manual`(=读 `display.theme`)/`auto`(按深色时段)。**B2b 新增** |
| | `display.theme_dark_start` | int 分钟 0-1439 | `0` | 深色时段开始(如 19:00=1140);`start==end` 视为未配置 → auto 回退 manual。**B2b 新增** |
| | `display.theme_dark_end` | int 分钟 0-1439 | `0` | 深色时段结束(如 07:00=420);`start>end`=跨午夜。**B2b 新增** |
| | `display.background` | enum/图片 | `black` | **由「当前 style × 当前 mode」决定的背景底选项集**(非独立全局维度;可选集+默认随 style/mode 一起变):**MD3×dark**=黑/深蓝/墨绿(默认黑)、**MD3×light**=白/浅蓝/浅绿(默认白)、**MIUIx×dark/light**各一套(草案)。每种配色定义**深/浅两套 surface/bg**,随 `display.theme` 切换(修复"背景仅对主页生效/仅深蓝/浅色不搭")。亦可为图片路径 `MeowAPPs/backgrounds/xx.png`(**定案**:图片 **cover 居中裁剪**,深浅作用于文字/角色色、背景图不随深浅换,叠加层固定跟明暗主题)。见 MEOW_APP_SDK §8.1 |
| **电源** | `power.longpress_menu_ms` | int | 3000 | 长按电源弹电源菜单阈值 |
| | `power.forceoff_ms` | int | 8000 | 长按电源强关阈值 |
| | `power.defeat_hotkey` | string | `power_voldown` | 切系统/切 MeowOS 热键组合 |
| **开机** | `boot.default` | enum | `meow` | 开机默认进入。**权威文件 = 板载 `/data/meow_boot_default`(O_TRUNC 单值:0=MeowOS / 1=HiByOS);`boot.default` 每次保存同步写该文件**(launcher `meow_settings_save` 同步;bootmenu `set_boot_default_meow`/launcher `set_boot_default_hiby` 同文件同语义);init 读入不触发、不反向覆盖。`meow.conf` 不再承担 boot_default [源:M2.61 同步修复][源:2026-08-30] |
| | `boot.menu_enabled` | bool | true | 是否显示引导选单 |
| | `boot.timeout_ms` | int | 5000 | 选单超时(有输入暂停重计) |
| **输入** | `input.hotkey_seq` | string | `volup,volup,volup` | 应用列表热键序列 |
| | `input.hotkey_window_ms` | int | 2500 | 组合/序列窗口 |
| | `input.touch_arm_delay_ms` | int | 700 | 触摸布防延迟(防幽灵) |
| | `input.swipe_invert` | bool | false | 设置页滑动方向(0=手指上滑→往下翻;1=反向) |
| **字体/主题** | `font.file` | path | `MeowOS/fonts/default/regular/font.png` | 字体图集(M2.6 指 `<family>/<weight>/font.png`,默认 `default/regular`;设置页「字体文件」行为 family→字重两级子菜单) |
| | `display.multi_font` | int 0/1 | 0 | **多字体**:1=按字符类别逐字符路由;0=单字体(只走 `font.file`,零额外内存/性能) |
| | `font.class_cjk` | path | *(空=跟全局)* | 多字体:CJK 表意+扩展 所用字体(family 相对路径) |
| | `font.class_cjk_sym` | path | *(空=跟全局)* | 多字体:全角/中文标点 所用字体 |
| | `font.class_num` | path | *(空=跟全局)* | 多字体:0-9 所用字体 |
| | `font.class_latin` | path | *(空=跟全局)* | 多字体:A-Za-z 所用字体 |
| | `font.class_latin_sym` | path | *(空=跟全局)* | 多字体:半角标点 所用字体 |
| | `font.class_other` | path | *(空=跟全局)* | 多字体:其他字符 所用字体 |
| | `font.load_full` | int 0/1 | 0 | **加载大字库(M2.5x)**:1=**强制全系统用大字库(`gbk`≈20k 档)**,覆盖 app 未声明/覆盖默认 `font.file`;0=默认小字库(`common`≈4k),仅 app 声明 `fonts:"full"` 才大字库 [源:用户 2026-08-30] |
| | `font.size.title` / `font.size.body` | int | 28/20 | 标题/正文字号 |
| | `ui.style` | enum | `md3` | `md3`(默认,Material You)/`miuix`(MIUIx,**M2.90 已实现**:完整 light/dark 配色+控件形态参数,见 MEOW_APP_SDK §8.1.3)——**顶级主题风格族**(定义整套配色风格/控件形态/圆角/间距/描边),对应 SDK `MEOW_STYLE_MD3`/`MEOW_STYLE_MIUIX`(MEOW_APP_SDK §8.1)。`g_defs` 值域 `"md3,miuix"`(label "Material You,MIUIx");存量 `"miui"` 兼容映射为 `miuix`。**状态栏图标集仍 MD3 一套**(无 per-style 换集接口,MIUIx 仅换配色) |
| **通知** | `notify.center_enabled` | bool | true | 下拉通知中心开关 |
| | `notify.app_quota` | int | 16 | 每应用通知配额 |
| | `notify.categories` | int | 4 | 通知类型数上限(每 App,M2.53)[源:审计 2026-08-30]|
| | `notify.category_quota` | int | 4 | 每类型活动通知上限(4×4=16/App)|
| | `notify.media_quota` | int | 1 | 媒体通知单例(每 App 仅 1 条)|
| | `notify.dnd` | bool | false | 通知中心「勿扰」面板内开关(通知列表上方小 toggle;开=只显示 `urgency>=2`(HIGH/CRITICAL),关=全部;面板内读写 `meow_settings_*`,零旁路)[源:用户 2026-08-30] |
| **日志** | `log.level` | enum | `info` | `error/warn/info/debug` |
| | `log.to_card` | bool | true | 写 TF 卡(无卡回退内存环) |
| **音频** | `audio.volume` | int 0-100 | 60 | 系统音量(MeowOS 直写 CS43198 DAC;读回为追踪值) |
| | `audio.volume_max` | int 0-100 | 100 | MeowOS 内部音量上限(clamp;**不与 HibyOS user.ini 上限同步**——其带 CRC 有风险,已定案不做;用户可自设 MeowOS 上限) |
| | `audio.volume_step` | int 1-5 | **1** | 音量键跳步(默认 1%,可配 1-5,最大 5) |
| | `audio.output` | string | `hw:0,0` | MeowAPPs 音频输出设备 |
| **网络** | `network.wifi_enabled` | bool | true | WiFi 开关(写 wlan0;设置页开关经 `wifi_up.sh`/`ip link set wlan0`,`ensure_wifi()` 尊重此值——关=0 则不再自动连网) |
| | `network.bluetooth_enabled` | bool | false | 蓝牙开关(写 `hciconfig hci0 up/down`;默认关=少耗电) |
| **系统** | `system.hostname` | string | `meowos` | 主机名(RFC1035 首标签;bootmenu 的 S89meow_svcd 开机读它 `sethostname`,缺省 `meowos`;供自研 mDNS 应答器 `meow_mdns` 公布 `<host>.local`)[源:M2.54] |
> **字体尺寸标记(M2.5x,随「加载大字库」一起落地)**:字体/主题选择器**每个字体选项标注库大小标记**,如 `MiSans Regular(common≈4k)` / `gbk≈20k` / `full`,直观标注码位/体积量级,让用户知道所选字库大小(M2.6 含字重:`<name> <Weight>(<marker>)`)。对应 `MeowOS/fonts/<family>/<weight>/font.json` 的 `charset`(`common|gbk|full`)+ `glyph_count`;档位枚举 `MEOW_FONT_TIER_COMMON`(默认/≈4k)/`GBK`(大/≈20k)/`FULL`(全/可选);`gen_font.py --charset common|gbk|full [--weight <name>]` 按档生成。定案见 MEOWOS_SPEC_REF §5.2「字体档位/大字库」与 §5.7.8 [源:用户 2026-08-30]。
> 新增设置项时:在清单加一行 + 存储 schema + API 常量/枚举 + 实体 UI 控件 + web 面板控件(四端同步)。
> **主题三键语义(2026-08-30 定案,实现权威见 MEOW_APP_SDK §8.1)**:`ui.style`(MD3/MIUIx)=**顶级主题风格族**(定义整套配色/控件形态/圆角/描边);`display.theme`(dark/light)=该 style 下的**明暗**;`display.background` =**由「当前 style × 当前 mode」决定的背景底选项集**(非独立全局维度,可选集+默认随 style/mode 一起变)。三者关系:**切明暗 → 同 style 浅/深背景自动切换**(修复"浅色不搭");**切 style → 整套配色+背景换族**(修复"背景仅对主页生效/只有深色")——同时把 `display.background` 从"仅 launcher 主页/仅深色"改为"**全局背景源**"(状态栏/未声明背景 App/主页同步;App 显式声明背景则覆盖,App 声明优先)。`meow_ui_theme` 旧字段 `bg/fg/accent/dim` 保留映射到 MD3 语义色(§5.8.4)。**注**:`ui.style` 值域已由 `"md3,miui"` 对齐为 **`"md3,miuix"`**(label "Material You,MIUIx",对应 `MEOW_STYLE_MIUIX`);存量 `settings.conf`/备份里的 `"miui"` 在 `meow_settings.c apply_value`(SET_ENUM)里兼容映射为 `miuix`。**MIUIx 已实现**(M2.90):`meow_ui_theme.c` 为 `MEOW_STYLE_MIUIX` 提供整套 light/dark 配色+控件形态参数,`display.background` 按 style×mode 派生 MIUIx 色板;状态栏图标集仍为 MD3 一套(无 per-style 换集接口)。
## 2. 统一存储(单一数据源)
- **主持久化位置:板载 `/usr/data/meow/settings.conf`**(UBIFS)。settings.conf 是**小文件**(几十行、<10KB),持久在板载可跨换卡/掉卡保留配置,避免换音乐卡丢失设置。板载仅此小设置文件(日志/字库/媒体等大数据仍留 TF 卡,符合"板载不写大文件"纪律;KB 级设置除外)。
- **导入/导出(备份):**
- **导出默认路径**:TF 卡 `MeowOS/backups/settings/setting.bak`(自动建目录)。用户可在导出时改路径。
- 本地 TF 卡:导入 = 从该 .bak 文件读入覆盖(选择/确认 + 校验)。
- Web 面板(阶段 C):`GET /api/settings/export`(下载 .conf)/ `POST /api/settings/import`(上传覆盖)。
- 二者都调用同一 `meow_settings_export(path)` / `import(path)`。
- **无卡/无板载时**:内存缓存,启动加载;板载在则自动落盘。
- **格式**:`key = value` 扁平文本(收敛旧 meow.conf),支持注释 `#`。
- 处理:`settings_load()`(启动读 + 变更即 `settings_save()` 落到 /data)、`settings_save()`(有变更/定时/掉电前)。避免频繁写(UBIFS 有磨损但 KB 级低频无碍)。
- 版本:文件头 `# meow-settings 1`。
## 3. C API 契约(后端,`meow_settings.h`)
```c
/* 类型 schema:每个设置键注册“名称/类型/默认/取值域”,存取统一走表 */
typedef enum { SET_INT, SET_STR, SET_ENUM, SET_BOOL } meow_set_type;
int meow_settings_init(void); /* 加载存储,注册默认 */
int meow_settings_get_int(const char *key, int *out);
int meow_settings_get_str(const char *key, char *buf, int len);
int meow_settings_get_enum(const char *key, int *out); /* 按枚举名/索引 */
int meow_settings_get_bool(const char *key, int *out);
int meow_settings_set_int(const char *key, int v); /* clamp 到取值域 */
int meow_settings_set_str(const char *key, const char *v);
int meow_settings_set_enum(const char *key, int v);
int meow_settings_set_bool(const char *key, int v);
/* 变更通知:注册回调(实体 UI 重绘 / web 推送) */
typedef void (*meow_settings_listener)(const char *key);
int meow_settings_add_listener(meow_settings_listener cb);
int meow_settings_remove_listener(...);
/* 枚举辅助:名字<->索引,供 UI/web 显示中文标签 */
int meow_settings_enum_label(const char *key, int idx, char *buf, int len);
int meow_settings_enum_count(const char *key);
/* 列表:枚举当前全部键,供 web 面板 / 设置页生成控件 */
int meow_settings_list(int (*cb)(const char *key, meow_set_type t, void*), void *ctx);
/* 导入/导出(备份) */
int meow_settings_export(const char *path); /* 写一份 .conf 到 path */
int meow_settings_import(const char *path); /* 从 .conf 读入覆盖,校验 + 通知 */
```
- **clamp/校验集中在 set**:如 `brightness` 自动 clamp ≥ `brightness_min`(默认 1;M2.39 由 25 改 1);`screen_off_timeout >= 0`;枚举越界拒绝。
- **变更通知**在 set 成功后对注册 listener 广播(key 字符串),实体 UI 据此重绘;web 端经 MeowPanel 长连接推送。
## 4. 阶段 B2b:实体系统设置页(Launcher 内,用 B2a 已就位后端)
- 入口:应用列表加一个**系统设置**卡片/图标(或列表项),点进设置页。
- UI:列表式(与应用列表同款渲染),**分组**:显示 / 电源 / 开机 / 输入 / 字体主题 / 通知 / 日志 / 音频。每项 = 标题 + 控件:
- 开关(bool):`display.theme` 深浅、`notify.center_enabled`…
- 滑条(int):亮度(**clamp ≥25**)、音量、息屏时长时间
- 选择器(enum):息屏模式、开机默认、主题、日志级别——选择器用子菜单/对话框,选项中文标签来自 `enum_label`
- 路径(str):字体、背景——文件浏览器选择(可先用内置几个预设,自定义文件选择后期);**字体(M2.6 字重结构)用 family→字重两级子菜单**:点「字体文件」/多字体类别行 → 一级列扫描到的 family(多字体行首项「跟随全局」)→ 二级列该 family 的可用字重(regular/bold/italic…),点字重即选中(写 `font.file`/`font.class_*`= `<family>/<weight>/font.png` 卡根相对路径)
- **所有控件只调 `meow_settings_set_*` / `get_*`**,绝不直接改文件;改完 `settings_save()`,UI 按 listener 重绘。保证与 web/CLI 一致。
- 权限/安全:本机信任,设置页不做鉴权。
## 5. 阶段 C 复用(MeowPanel 设置页)
- MeowPanel 后端新增 `/api/settings`:
- `GET /api/settings` → 返回全部键值(调 `meow_settings_list` + get_*)
- `POST /api/settings` (body: key/value)→ 调 `meow_settings_set_*` + save
- `POST /api/settings/restore` → 恢复默认
- web 设置页**与实体设置页同一套 key/控件定义**(前端每 key 渲染对应控件),共用 `meow_settings` 后端。改 web → 实体立即反映(listener/轮询);改实体 → web 下拉刷新。
- 设置 API 也暴露给 **CLI/MCP**(`meowcli settings get/set`)供调试/自动化。
## 6. 与阶段 B / D 的衔接
- **阶段 B**:搭 `meow_settings` 后端 + 状态栏/通知中心期间,逐步把**现有散落的配置**(meow.conf 的 boot_default/hotkey/bg_color/字体路径)**迁移**进 `settings.conf` 卸载旧 meow.conf;状态栏/通知中心读设置(如通知中心开关、字体字号)走 API。
- **阶段 D(Activity/通知框架)**:通知配额/行为等设置进 settings;应用可通过 IPC 读改名(可选暴露只读 `meow_settings_get_*`)。
## 7. 实现里程碑
M1 存储+核心 API(get/set/save/load/listen/list/枚举)→ M2 实体设置页(分组列表+各类控件)→ M3 迁移旧 meow.conf + 状态栏/通知中心走 API → M4 web 设置页对接 → M5 加固(clamp/校验/掉电保存/测试)。
## 8. 风险/注意
- 板载存储不写:settings.conf 只落 TF 卡,未挂载用内存,挂载后落盘;掉电前 save。
- clamp 必须集中在 set(防亮度 0 / 非法枚举)。
- 迁移 meow.conf 时保持向后兼容(旧文件读入,写回新格式),避免把现有用户配置弄丢。
- 字体/背景路径若失效回退默认(不崩)。
## 附:系统状态重抓清单与策略(进 MeowOS 全量快照)
**状态项**(进 MeowOS 时全量抓,HibyOS 改过也同步):
- 电量(百分比/充电状态/电压/温度)、WiFi(开关/SSID/IP/信号/链路)、蓝牙(开关/连设备数)、音量(settings)、亮度(sysfs)、存储(/data 剩余/TF卡挂载容量)、性能(loadavg/meminfo)、温度(thermal_zone)、系统(模式/应用数/版本)、音频输出(后续)
**性能策略**:
- 进 MeowOS 一次性全量 `meow_sys_snapshot()`(阻塞可接受)。
- 主循环 10ms 热键轮询**绝不读系统状态**;单独 1s 轻刷仅时钟/电量/WiFi 信号。
- 性能/温度类用后台定时低频率(1-2s)读,仅 MeowPanel 用,别占 UI。
- 统一封装 `meow_sys_state` + `meow_sys_refresh()`,状态栏/设置/面板共用。
## 附 B:设备属性域(device attributes)——meow_sys 只读+可控子域
> 承接 §18.44 设备全属性只读枚举(任务要求「覆盖设备所有属性:4.4 平衡口插入、3.5 单端口插入、低增益/高增益输出、及所有自带属性」)。在 `meow_sys_state`(`g_sys`)上扩展 `struct meow_sys_devattr`,状态栏/MeowPanel/设置页共用,只读属性与可控(kcontrol)分开标注。**只设计接口,不改 launcher 实现**(落地留框架批次)。
**检测源(只读居多,可控项白名单):**
| 域字段 | 类型 | 读取源 | 可写 | 说明/单位 |
|---|---|---|---|---|
| `out.port` | int 0-7 | `amixer cget numid=9` | **写=切输出**(白名单1-4) | 现读=0(空闲);1=lineout/2=headset(3.5)/3=balance(4.4)/4=Type-C SPDIF;**0/5 危险勿写**。**line-out(1)=固定满幅电平,保守默认不响应音量键、不受 lock_vol 限制**(无实机接功放可测,按最保守处理,见 §附B line-out) |
| `out.headset_present` | bool | `/sys/class/switch/headset/state` | 只读 | 3.5 插入(=1) |
| `out.balance_present` | bool | `/sys/class/switch/balance/state` | 只读 | 4.4 插入(=1) |
| `out.earpods_adc_sw` | bool | `/sys/devices/platform/earpods_adc/earpods_adc/earpods_adc_sw` | 只读 | 耳塞型判定 |
| `out.balance_lineout_en` | bool | `amixer cget numid=8` | 写 | 平衡 Lineout 使能 |
| `vol.left`/`vol.right` | int 0-255 | `amixer cget numid=1/2`(读恒 0,dummy get) | **写(真写 DAC)** | meow_vol_set 已用;get 仅跟踪值 |
| `out.vol_max_headset`/`out.vol_max_balance` | int % | `config.json` volume.`lock_vol` | 只读(玩家态) | 3.5=55 / 4.4=43 ——**按输出口分级音量上限(实际「增益/响度等级」代理)** |
| `out.vol_default_headset`/`out.vol_default_balance` | int % | `volume.default_vol` | 只读 | 20 / 15 |
| `out.vol_warn_headset`/`out.vol_warn_balance` | int % | `volume.warn_vol` | 只读 | 34 / 28 |
| `codec.soft_mute`/`mute_out`/`nos_en`/`dre_en`/`dop_en` | bool | numid=5/3/6/7/10 | 写 | 软静音/硬静音/关过采样/动态范围增强/DoP 编码(numid 8/10 put=存驱动标志,get=dummy) |
| `codec.digital_filter` | int 0-4 | numid=4 | 写 | 滤波模式 |
| `dac.sample_rate` / `dac.is_dsd` | int/bool | **无任何只读路径**:`/proc/asound` 不存在、codec `reg_val/write_reg_val` **只写**(`--w-------`,回读 EACCES)、`current_samplerate` 未导出、dmesg 已滚出 | 只读 | **Unsupported**(标记 `MEOW_ERR_NOENT`);需玩家态或改驱动导出 |
| `usb_dac.mode` | bool | `/sys/class/udc/13500000.otg_new/is_a_peripheral`+`state` + `configfs usb_gadget/*/UDC` | 只读 | 当前 `is_a_peripheral=0`,state=not attached → 非 DAC 模式;=1 当 `is_a_peripheral=1`+gadget pid=0x0004 |
| `usb_dac.vid`/`pid`/`dac_pid` | int | `/usr/resource/config.json` | 只读 | 0x32BB / 0x0101 / 0x0004 |
| `bt.powered` | bool | `bluetoothctl show` `Powered`(或 `hciconfig` UP/DOWN);**勿用** `rfkill/*/soft` | 写(可控开/关) | 当前 no(rfkill soft=0/hard=0 但 HCI 未上电) |
| `bt.mac`/`bt.name`/`bt.codec` | str | `/sys/class/bluetooth/hci0/{address,name}` + 连接后 bluealsa | 只读 | codec 无连接不可读 |
| `batt.capacity`/`voltage`/`status` | int%/µV/enum | `power_supply/battery/*` | 只读 | 100% / 4342000µV / Discharging |
| `chg.online`/`current`/`temp` | bool/µA | `fusb302-typec-source/online` + `mp2731-charger/*` | 只读 | 0 / 0µA / 30.0℃(当前未充) |
| `ac.present` | bool | `power_supply/ac/present` | 只读 | 0 |
| `sys.temperature` | int | 无 thermal_zone | 只读 | **不可读**(x1600 未暴露) |
**关键结论**:① 3.5/4.4 是独立输出口,由 `Output Port Switch`(numid=9) 路由、由 `/sys/class/switch/headset|balance` 判别插入(headset 走 ADC=1 通道、balance 走 GPIO=PC24;`balancelo`/`lineout` 开关**未启用**),**有独立端口检测、无独立"平衡/单端"切换控件**;② **硬件/驱动层无高/低增益接口**——`codec_set_gain` 反汇编=**strcmp**、`codec_set_pregain/lrbalance/dsd_compensate`=**`jr ra` 空操作**、无 gain kcontrol、codec `reg_val` **只写不可回读**;幅度即 Playback Volume(0-255)、动态仅 DRE_EN;**真实的按输出口响度分级在玩家态 `config.json`(lock_vol 55/43、default_vol 20/15、warn_vol 34/28),可读**;③ USB DAC 模式 = `is_a_peripheral=1` + gadget(pid=0x0004)(当前 `is_a_peripheral=0`,state=not attached → 非 DAC 模式);④ CPU 温度、运行时采样率/DSD **无干净只读接口**(采样率/DSD 因 `/proc/asound` 缺失+codec reg 只写+`current_samplerate` 未导出而 **Unsupported**;温度因无 thermal_zone 而不可读),均标记 MEOW_ERR_NOENT。
**API / 暴露**(`meow_sys.h` + 三端复用,同 meow_settings):`meow_sys_devattr_refresh(&out)`、`meow_devattr_set(field,value)`(白名单)、`meow_devattr_enum_label(field,idx,buf,len)`;MeowPanel `GET/POST /api/device`;CLI `meowcli device [set]`。
**安全**:白名单写(out.port 1-4、vol、filter/nos/dre/dop/mute、bt.powered);禁写 0/5 端口;禁写 codec `write_reg_val`(保留为调试钩子);volume 读用跟踪值。
**附 B:line-out 与 gain(2026-08-29 实机更新,无实测保守默认)**
- **`out.gain`(高/低)= 播放器应用层数字增益**,选 `ot_devices.json``VOLUMES.HW.Gains` 的 HDB/LDB(实机仅暴露高/低两档,MDB 未暴露;框架与曲线本有 HDB/MDB/LDB 三档)。选择值存 `user.ini`(位置式 struct + 自定义完整性字 `0x0134fe6e`,读不干净、写有完整性风险)→ **MeowOS 只读标记 `Unsupported`(MEOW_ERR_NOENT)**,不设可写;`ot_devices.json` 增益曲线作只读信息展示(标注"工厂校准,非当前选择态")。**增益(输出电平曲线) ≠ 音量上限(lock_vol)**,二者独立相乘叠加。
- **`out.port=1`(line-out,3.5mm 同口)**:给功放/台式机的满幅固定电平。**保守默认**:MeowOS 切到 line-out 后**不响应音量键**、**不套用 lock_vol 上限**(`out.vol_max_headset` 不作用于 line-out),UI 标注"固定电平输出";仅当用户在设置里显式开启"line-out 可调"时才放开。**该行为未实测**(无功放设备),待补:切 line-out 后音量键是否仍生效、音量滑杆是否影响输出、lock_vol 是否绕过——测后再松开约束。
- **刷新触发**:用户可能经 HibyOS 切增益档 / 切输出口,MeowOS 需在这两个事件后全量重抓 `meow_sys_refresh()`(与"每次进 MeowOS 抓一遍"同逻辑),勿只靠 1s 轻刷。