docs: 补充核心分层中文注释

This commit is contained in:
chenjintao
2026-09-29 18:18:44 +08:00
parent a77471a7b1
commit 9fd01bb61b
81 changed files with 1189 additions and 112 deletions
+90 -36
View File
@@ -15,6 +15,24 @@
extern "C" {
#endif
/*
* Domain 层调用与所有权概览 / Domain call flow and ownership overview
*
* domain 是业务语义的唯一所有者:方向、校准、电池等级、配网协议、表情映射、
* 用户资料、运势和 OTA 响应解析均在此定义。它只通过 platform facade 使用硬件原语,
* 不把 platform 类型暴露给 control_plane。
* Domain is the single owner of business semantics and consumes hardware only
* through the platform facade without leaking platform types upward.
*
* control_plane -> domain facade -> domain service/adapter -> platform facade
*
* store/service 状态以 domain 内部快照或下层持久化为事实来源;回调携带的临时数据
* 只在调用期间有效。阻塞接口的 timeout 包含锁等待和下层操作的完整调用方预算。
* Stores and service snapshots are SSOTs. Callback payloads are temporary, and
* blocking timeouts cover lock acquisition plus all lower-layer work.
*/
/* 方向轴与校准策略属于 domain 语义,GPIO/步进相位等硬件细节不得进入这些结构。 */
typedef struct {
float initial_angle;
int rotate_speed_us;
@@ -29,6 +47,7 @@ typedef struct {
int settle_delay_ms;
} domain_direction_calibration_t;
/* 电池原始采样由 platform 提供,domain 负责充电、等级、有效性和抑制语义。 */
typedef enum {
DOMAIN_BATTERY_CHARGE_UNKNOWN = 0,
DOMAIN_BATTERY_CHARGE_NOT_CHARGING,
@@ -58,22 +77,22 @@ typedef struct {
int64_t last_valid_sample_time_ms;
} domain_battery_status_t;
/** Initialize the battery measurement domain. Idempotent and thread-safe. */
/** 幂等且线程安全地初始化电池领域。 / Initialize the battery domain idempotently and thread-safely. */
esp_err_t domain_battery_init(void);
/** Acquire and process one battery sample without applying product policy. */
/** 获取并处理一次电池采样,不执行产品策略。 / Process one battery sample without product policy. */
esp_err_t domain_battery_sample(void);
/** Copy the latest battery SSOT snapshot into `out_status`. */
/** 复制最新电池 SSOT 快照。 / Copy the latest battery SSOT snapshot into `out_status`. */
esp_err_t domain_battery_get_status(domain_battery_status_t *out_status);
/** Enter the configured board deep-sleep state; a successful call does not return. */
/** 进入板级深睡,成功时不返回。 / Enter configured deep sleep; success does not return. */
esp_err_t domain_battery_prepare_shutdown(void);
/** Return true when the current boot resumed through a deep-sleep wake source. */
/** 当前启动来自深睡唤醒源时返回 true。 / Return true after a deep-sleep wake. */
bool domain_battery_woke_from_deep_sleep(void);
/** Release low-power GPIO holds after accepting a deep-sleep wake. */
/** 接受唤醒后释放低功耗 GPIO 保持。 / Release low-power GPIO holds after wake. */
void domain_battery_complete_wakeup(void);
typedef enum {
@@ -84,6 +103,7 @@ typedef enum {
DOMAIN_WIFI_PROMPT_WIFI_CONFIG,
} domain_wifi_prompt_id_t;
/* Wi-Fi 行为钩子使用 domain 提示语义,具体音频文件映射留在适配实现中。 */
typedef struct {
void (*set_keep_awake)(bool keep_awake);
esp_err_t (*play_prompt)(domain_wifi_prompt_id_t prompt);
@@ -98,6 +118,7 @@ typedef enum {
DOMAIN_MULTIMODAL_TRANSPORT_EVENT_BINARY_MESSAGE,
} domain_multimodal_transport_event_type_t;
/* 回调 payload 仅在回调期间有效;跨任务保存前必须复制。 */
typedef struct {
domain_multimodal_transport_event_type_t type;
const uint8_t *data;
@@ -202,6 +223,7 @@ typedef enum {
DOMAIN_EXPRESSION_TRIGGER_FACTORY_LCD_TEST,
} domain_expression_trigger_t;
/* 表情请求表达业务意图;资源目录、帧序列和图标位置由 domain 适配器映射。 */
typedef struct {
domain_expression_id_t id;
domain_expression_trigger_t trigger;
@@ -228,20 +250,22 @@ float domain_get_current_angle(void);
void domain_set_current_angle(float angle);
int domain_get_rotate_speed_us(void);
/**
* @brief Rotate to an absolute direction angle.
* @brief 旋转到绝对方向角。 / Rotate to an absolute direction angle.
*
* 非正 timeout 使用 domain 默认值;预算覆盖状态锁获取和电机运动全过程。
* `timeout_ms <= 0` uses the default domain timeout. The timeout is the total
* caller-visible budget, including state-lock acquisition and motor movement.
*/
esp_err_t domain_rotate_to_angle_with_timeout(float target_angle, int timeout_ms);
esp_err_t domain_apply_rotation_delta(float delta);
/** Release stepper holding current; the next movement re-energizes automatically. */
/** 释放电机保持电流,下次运动自动重新励磁。 / Release hold; next movement re-energizes. */
esp_err_t domain_direction_release_motor_hold(int timeout_ms);
void domain_set_calibration(const domain_direction_calibration_t *config);
bool domain_get_calibration(domain_direction_calibration_t *out_config);
/**
* @brief Run direction calibration.
* @brief 执行方向校准。 / Run direction calibration.
*
* 非正 timeout 使用默认校准预算,包含锁等待、分步运动、开关稳定等待和释放扫描。
* `timeout_ms <= 0` uses the default calibration timeout. The timeout is the
* total caller-visible budget, including state-lock acquisition, movement
* steps, switch settle delays, and release sweep.
@@ -254,8 +278,9 @@ esp_err_t domain_runtime_multimodal_transport_start(
domain_multimodal_transport_event_callback_t cb,
void *user_data);
/**
* @brief Stop the multimodal transport with bounded teardown.
* @brief 有界停止多模态传输。 / Stop multimodal transport with bounded teardown.
*
* 负超时无效,零发起异步停止,正数等待到边界后由下层执行确定性兜底。
* `timeout_ms < 0` is invalid, zero requests asynchronous stop, and positive
* values wait up to the bound before lower layers apply deterministic fallback.
*/
@@ -272,7 +297,7 @@ esp_err_t domain_runtime_multimodal_audio_start_uplink(
void *user_data);
/**
* @brief Stop multimodal uplink capture/stream with bounded teardown.
* @brief 有界停止多模态上行采集和流发送。 / Stop uplink capture/stream with bounded teardown.
*
* `timeout_ms < 0` is invalid, zero requests asynchronous stop, and positive
* values wait up to the bound before lower layers apply deterministic fallback.
@@ -280,11 +305,12 @@ esp_err_t domain_runtime_multimodal_audio_start_uplink(
esp_err_t domain_runtime_multimodal_audio_stop_uplink(int timeout_ms);
bool domain_runtime_multimodal_audio_is_uplink_running(void);
bool domain_runtime_multimodal_audio_is_initialized(void);
/** Gate speaker output while preserving the microphone capture path. */
/** 保留麦克风采集,仅控制扬声器输出。 / Gate speaker output while preserving capture. */
esp_err_t domain_runtime_multimodal_audio_set_speaker_output_enabled(bool enabled);
/**
* @brief Start local MultiNet detection for the Chinese phrase "喵掌柜".
* @brief 启动“喵掌柜”本地 MultiNet 检测。 / Start local MultiNet detection for "喵掌柜".
*
* 回调运行在 domain 推理任务中,必须有界且不可阻塞;相同回调的重复启动幂等。
* The callback runs in the domain inference task and must be bounded and
* non-blocking. Repeated start with the same callback is idempotent.
*/
@@ -326,8 +352,10 @@ typedef enum {
} domain_runtime_auth_record_t;
/**
* @brief Domain-owned device-auth persistence port, backed by platform blobs.
* @brief domain 拥有、由 platform blob 支撑的设备认证持久化端口。
* Domain-owned device-auth persistence port backed by platform blobs.
*
* domain 只拥有记录槽、存储键映射和旧版迁移边界;调用方拥有序列化 schema。
* The domain facade owns only the auth record slots, storage key mapping, and
* legacy migration boundary. Callers own the serialized record schema and pass
* opaque bytes. `load_record` returns `ESP_ERR_NOT_FOUND` when no record exists
@@ -342,10 +370,11 @@ esp_err_t domain_runtime_auth_store_save_record(domain_runtime_auth_record_t rec
size_t len);
/* ------------------------------------------------------------------------- */
/* Daily fortune: user birth profile + server-computed daily result. */
/* Owned by the domain layer; see docs/adr/0002-daily-fortune-contracts.md. */
/* 每日运势:用户出生资料 + 服务端计算结果。 / Daily fortune profile + result. */
/* 契约属于 domain;详见 docs/adr/0002-daily-fortune-contracts.md。 */
/* ------------------------------------------------------------------------- */
/* 固定容量使资料可直接序列化进 NVS;长度包含结尾 NUL,修改需考虑旧记录兼容。 */
#define DOMAIN_BIRTH_PLACE_MAX_LEN 64
#define DOMAIN_BIRTH_RESIDENCE_MAX_LEN 64
#define DOMAIN_BIRTH_MBTI_MAX_LEN 8
@@ -364,6 +393,7 @@ typedef struct {
bool valid;
} domain_birth_profile_t;
/* 运势字段容量同时约束服务端 JSON 校验和持久化结构布局。 */
#define DOMAIN_FORTUNE_BAZI_MAX_LEN 64
#define DOMAIN_FORTUNE_ELEMENT_MAX_LEN 8
#define DOMAIN_FORTUNE_DIRECTION_MAX_LEN 16
@@ -382,8 +412,9 @@ typedef struct {
typedef void (*domain_birth_profile_observer_t)(const domain_birth_profile_t *profile, void *user_data);
/**
* @brief Persist / query the user birth profile (NVS-backed via the platform store).
* @brief 持久化或查询用户出生资料。 / Persist or query the user birth profile.
*
* set 校验并持久化后在锁外通知观察者;get 在无有效记录时返回 false。存储是 SSOT。
* `set` requires a valid profile, persists it, then notifies the registered
* observer with a snapshot (invoked outside any lock). `get` returns false when
* no valid profile has been stored. Storage is the single source of truth; no
@@ -393,21 +424,25 @@ esp_err_t domain_birth_profile_store_set(const domain_birth_profile_t *profile);
bool domain_birth_profile_store_get(domain_birth_profile_t *out_profile);
/**
* @brief Persist / query the most recent daily fortune result.
* @brief 持久化或查询最近一次每日运势。 / Persist or query the latest daily fortune result.
*/
esp_err_t domain_fortune_result_store_set(const domain_fortune_result_t *result);
bool domain_fortune_result_store_get(domain_fortune_result_t *out_result);
esp_err_t domain_fortune_result_store_clear(void);
/**
* @brief Register the single observer notified when a new birth profile is
* stored (e.g. submitted over the LAN configuration page). Pass NULL to clear it. The
* callback must be lightweight (it runs in the caller's context).
* @brief 注册出生资料更新的唯一观察者。 / Register the single birth-profile observer.
*
* 新资料持久化后在调用方上下文通知,例如 LAN 配置页面提交;传 NULL 清除。
* The callback runs in the caller's context after persistence and must be lightweight.
*/
void domain_runtime_register_birth_profile_observer(domain_birth_profile_observer_t cb, void *user_data);
/**
* @brief Wall-clock time synchronization, bridged to the platform SNTP
* @brief 桥接到 platform SNTP 的墙上时钟同步。 / Wall-clock synchronization.
*
* set_timezone 仅设置本地时间转换;start 幂等启动 SNTP 并应用时区;网络就绪后调用。
* Bridged to the platform SNTP
* primitive. `set_timezone` applies local-time conversion without
* network access. `start` is idempotent and also applies the process
* time zone (`posix_tz`, e.g. "CST-8"); `is_synced` reports whether the
@@ -417,6 +452,7 @@ esp_err_t domain_runtime_time_set_timezone(const char *posix_tz);
esp_err_t domain_runtime_time_sync_start(const char *sntp_server, const char *posix_tz);
bool domain_runtime_time_is_synced(void);
/* mDNS 主机名按值复制到服务状态,容量包含结尾 NUL。 */
#define DOMAIN_USER_CONFIG_HOSTNAME_MAX_LEN 32
typedef struct {
@@ -431,8 +467,9 @@ typedef struct {
} domain_user_config_server_state_t;
/**
* @brief Start the domain-owned user profile and fortune web application.
* @brief 启动 domain 拥有的资料与运势 Web 应用。 / Start the domain-owned user web app.
*
* platform 只提供有界 HTTP 传输;路由、JSON、校验和页面属于 domain;重复启动幂等。
* The platform supplies only the bounded raw HTTP transport. This domain
* service owns the routes, JSON semantics, validation, and embedded page.
* Start is idempotent while the service is starting or running.
@@ -441,7 +478,7 @@ esp_err_t domain_user_config_server_start(
const domain_user_config_server_config_t *config);
/**
* @brief Stop the user configuration server with bounded teardown.
* @brief 有界停止用户配置服务。 / Stop the user configuration server with bounded teardown.
*
* `timeout_ms < 0` is invalid, zero requests asynchronous stop, and positive
* values wait up to the bound before the platform applies deterministic
@@ -452,8 +489,9 @@ esp_err_t domain_user_config_server_get_state(
domain_user_config_server_state_t *out_state);
/**
* @brief POST domain JSON data through the lower-layer HTTPS transport adapter.
* @brief 通过下层 HTTPS 适配器 POST domain JSON。 / POST domain JSON via HTTPS adapter.
*
* 可选设备 ID 和 bearer token 被映射为请求头;响应写入调用方缓冲并以 NUL 结尾。
* Optional `device_id` is sent as X-Device-Id and optional `bearer_token` is
* sent as Authorization: Bearer <token>. The response body is written to the
* caller-owned buffer and NUL-terminated on success. A completed HTTP exchange
@@ -475,6 +513,7 @@ esp_err_t domain_runtime_post_json(const char *url,
size_t *out_response_body_len,
int *out_status);
/* OTA 固定容量是响应校验和任务间快照复制边界;SHA-256 为64位十六进制。 */
#define DOMAIN_OTA_VERSION_MAX_LEN 32
#define DOMAIN_OTA_URL_MAX_LEN 2048
#define DOMAIN_OTA_SHA256_HEX_LEN 64
@@ -534,7 +573,7 @@ esp_err_t domain_runtime_ota_get_memory_headroom(domain_ota_memory_headroom_t *o
void domain_runtime_restart(void);
/**
* @brief Console (UART) line-transport primitives, bridged to the platform.
* @brief 桥接到 platform 的串口行传输原语。 / Console line transport bridged to platform.
*
* `read_bytes` returns bytes read (0 on timeout, <0 on error). A zero timeout
* polls once; negative timeouts are invalid and return <0. Used by the factory
@@ -551,6 +590,7 @@ void domain_runtime_wifi_portal_set_behavior_hooks(const domain_wifi_behavior_ho
esp_err_t domain_runtime_wifi_portal_init_defaults(const char *seed_ssid, const char *seed_password);
bool domain_runtime_wifi_portal_has_saved_credentials(void);
/* SSID 容量包含 NUL;最多保存10个候选,返回顺序即后续连接优先级。 */
#define DOMAIN_WIFI_SSID_MAX_LEN 33
#define DOMAIN_WIFI_SAVED_NETWORK_MAX_COUNT 10
@@ -559,7 +599,7 @@ typedef struct {
char ssids[DOMAIN_WIFI_SAVED_NETWORK_MAX_COUNT][DOMAIN_WIFI_SSID_MAX_LEN];
} domain_wifi_saved_networks_t;
/** Copy saved SSIDs in persistent priority order. Passwords are not exposed. */
/** 按持久化优先级复制 SSID,不暴露密码。 / Copy saved SSIDs in priority order. */
esp_err_t domain_runtime_wifi_portal_get_saved_networks(
domain_wifi_saved_networks_t *out_networks);
bool domain_runtime_wifi_portal_sta_is_connected(void);
@@ -567,7 +607,9 @@ esp_err_t domain_runtime_wifi_portal_start_config_ap(const char *ssid_prefix);
bool domain_runtime_wifi_connect_error_keeps_credentials(esp_err_t err);
/**
* @brief Connect STA using stored credentials with explicit timeout.
* @brief 以明确超时使用已存凭据连接 STA。 / Connect STA using stored credentials.
*
* 非正超时使用默认值;STA 已连接时幂等返回 `ESP_OK`;超时或连接错误会明确返回失败。
*
* Semantics:
* - `timeout_ms <= 0`: use default timeout.
@@ -576,7 +618,9 @@ bool domain_runtime_wifi_connect_error_keeps_credentials(esp_err_t err);
*/
esp_err_t domain_runtime_wifi_portal_connect_sta(int timeout_ms);
/**
* @brief Validate candidate credentials before replacing persisted Wi-Fi state.
* @brief 替换持久化状态前先验证候选凭据。 / Validate credentials before persistence.
*
* 有界连接试验失败时保留原凭据;只有试验成功才提交新凭据。
*
* The previous credentials remain available when the bounded connection trial
* fails. A successful trial commits only the new credentials.
@@ -587,12 +631,13 @@ esp_err_t domain_runtime_wifi_portal_connect_sta_with_credentials(
int timeout_ms);
esp_err_t domain_runtime_wifi_portal_reconnect_sta(int timeout_ms);
esp_err_t domain_runtime_wifi_portal_stop_sta(void);
/** Apply standby Wi-Fi power save, or restore the configured active policy. */
/** 应用待机 Wi-Fi 省电或恢复活动策略。 / Apply standby Wi-Fi power save or restore policy. */
esp_err_t domain_runtime_wifi_portal_set_light_standby(bool standby);
bool domain_runtime_is_network_connect_error(esp_err_t err);
esp_err_t domain_runtime_wifi_portal_save_credentials(const char *ssid, const char *password);
esp_err_t domain_runtime_wifi_portal_clear_saved_credentials(void);
/* 小程序配网容量包含 NUL,并对应 BLE 写入 payload 的校验边界。 */
#define DOMAIN_WIFI_PROVISIONING_SSID_MAX_LEN DOMAIN_WIFI_SSID_MAX_LEN
#define DOMAIN_WIFI_PROVISIONING_PASSWORD_MAX_LEN 65
@@ -627,7 +672,7 @@ typedef enum {
DOMAIN_WIFI_PROVISIONING_STATUS_FAIL_CONNECT,
} domain_wifi_provisioning_status_t;
/** Start the fixed TalkingQ mini-program BLE provisioning protocol. */
/** 启动固定 TalkingQ 小程序 BLE 配网协议。 / Start the TalkingQ BLE provisioning protocol. */
esp_err_t domain_runtime_mini_program_provisioning_start(
domain_wifi_provisioning_event_callback_t callback,
void *user_data);
@@ -636,24 +681,28 @@ esp_err_t domain_runtime_mini_program_provisioning_notify(
esp_err_t domain_runtime_mini_program_provisioning_stop(int timeout_ms);
esp_err_t domain_runtime_init_lcd_device(void);
/** Set LCD backlight PWM brightness from 0 to 100 percent. */
/** 设置0到100%的 LCD PWM 背光。 / Set LCD PWM backlight from 0 to 100 percent. */
esp_err_t domain_runtime_set_lcd_backlight_brightness(uint8_t brightness_percent);
void domain_runtime_start_lcd_render_loop(void);
/**
* @brief Stop LCD render loop with bounded teardown.
* @brief 有界停止 LCD 渲染循环。 / Stop LCD render loop with bounded teardown.
*
* 负超时无效;零只发起异步停止;正值等待到预算结束,再由下层执行确定性兜底。
* `timeout_ms < 0` is invalid, zero requests asynchronous stop, and positive
* values wait up to the bound before lower layers apply deterministic fallback.
*/
esp_err_t domain_runtime_stop_lcd_render_loop(int timeout_ms);
/** Map the domain battery snapshot to persistent LCD status overlays. */
/** 将电池快照映射为持久 LCD 状态层。 / Map battery snapshot to persistent LCD overlays. */
esp_err_t domain_runtime_update_battery_overlay(const domain_battery_status_t *status);
esp_err_t domain_runtime_request_expression(const domain_expression_request_t *request);
/**
* @brief Preload assets for an expression without changing the active display.
* @brief 预热表情资源而不改变当前显示。 / Preload expression assets without display changes.
*
* 用于即将播放的资源型表情。请求会被复制,LCD 渲染任务在帧间执行预热,调用方等待结果;
* 不支持或非资源型表情返回明确错误。
*
* Intended for asset-backed expressions that are likely to play soon. The
* request is copied, the LCD render task performs the preload between display
@@ -663,9 +712,14 @@ esp_err_t domain_runtime_request_expression(const domain_expression_request_t *r
esp_err_t domain_runtime_preheat_expression(const domain_expression_request_t *request);
/**
* @brief Request an expression and block until its finite asset sequence
* @brief 请求表情并阻塞到有限资源序列结束或超时。 /
* Request an expression and block until its finite asset sequence
* completes, or @p timeout_ms elapses.
*
* 用于财富旋转开场等有限演示。入队失败返回底层错误;播放未在预算内结束返回
* `ESP_ERR_TIMEOUT`(调用方可自行继续);LCD 未运行返回 `ESP_ERR_INVALID_STATE`。
* `repeat_count == 0` 表示无限循环,因此本接口最终必然超时。
*
* Intended for finite presentations such as the wealth spin intro. Returns the
* underlying request error if queuing fails, ESP_ERR_TIMEOUT if playback does
* not finish within the timeout (the caller may proceed anyway), or