Files
lucky-cat/docs/architecture-and-flow-mermaid.md
T

10 KiB

Architecture And Flow Diagrams

This document captures the current project architecture and major runtime flows in Mermaid format. The diagrams reflect the implementation in the repository, not older planning notes.

Layered Architecture

flowchart TB
    Main["main/app_main"]
    App["app_composition\nstartup sequencing and wiring"]
    CP["control_plane\npolicy, lifecycle, workers, retry/backoff"]
    Domain["domain\nbusiness contracts, adapters, semantic mapping"]
    Platform["platform\nhardware, transport, storage, display, audio"]
    HW["ESP32-S3 hardware\nLCD, audio codec, GPIO, Wi-Fi, flash"]

    Main --> App
    App --> CP
    CP --> Domain
    Domain --> Platform
    Platform --> HW

Component Responsibility Map

flowchart LR
    subgraph AppComposition["app_composition"]
        Boot["Plan A boot sequence"]
        Wire["Runtime wiring"]
    end

    subgraph ControlPlane["control_plane"]
        Connectivity["Connectivity bootstrap and Wi-Fi policy"]
        Workers["Runtime worker ownership"]
        Events["System event dispatch"]
        MultimodalPolicy["Multimodal session policy"]
        Fortune["Daily fortune policy"]
        RemoteLog["Remote log service"]
        FactoryCli["Factory CLI diagnostics"]
    end

    subgraph Domain["domain"]
        ExpressionMap["LCD expression semantic mapping"]
        RuntimeAdapters["Runtime facade adapters"]
        Direction["Direction and calibration model"]
        FortuneDomain["Birth profile and fortune contracts"]
        UserConfig["LAN user config routes"]
    end

    subgraph Platform["platform"]
        LCD["ST7789 direct LCD backend"]
        Audio["ES8311 audio pipeline"]
        Network["Wi-Fi, BLE provisioning, HTTP, WebSocket"]
        Storage["NVS, LittleFS, LogFS"]
        GPIO["GPIO, stepper, console UART"]
    end

    Boot --> Connectivity
    Boot --> Workers
    Wire --> Workers
    Connectivity --> RuntimeAdapters
    Workers --> Events
    Workers --> RemoteLog
    MultimodalPolicy --> RuntimeAdapters
    Fortune --> FortuneDomain
    Events --> ExpressionMap
    FactoryCli --> RemoteLog
    RuntimeAdapters --> LCD
    RuntimeAdapters --> Audio
    RuntimeAdapters --> Network
    RuntimeAdapters --> Storage
    RuntimeAdapters --> GPIO

Current Boot Sequence

sequenceDiagram
    participant Main as app_main
    participant App as app_composition
    participant CP as control_plane
    participant Domain as domain
    participant Platform as platform

    Main->>App: app_composition_start_default_runtime()
    App->>CP: control_plane_prepare_runtime_storage()
    CP->>Domain: prepare storage through runtime adapters
    Domain->>Platform: NVS / storage initialization

    App->>CP: control_plane_play_boot_sound(timeout)
    CP->>Domain: domain_runtime_multimodal_audio_init()
    Domain->>Platform: ES8311 / I2S / I2C audio init
    CP->>Domain: domain_runtime_behavior_play_prompt_file()
    Domain->>Platform: play prompt file

    App->>CP: control_plane_init_lcd_device()
    CP->>Domain: domain_runtime_init_lcd_device()
    Domain->>Platform: LCD GPIO/SPI/ST7789 init

    App->>CP: control_plane_start_lcd_render_worker()
    CP->>CP: create cp_lcd_render task
    CP->>Domain: domain_runtime_start_lcd_render_loop()
    Domain->>Platform: lcd_direct_start_render_loop()

    App->>CP: control_plane_init()
    CP->>Domain: platform/domain runtime initialization
    Domain->>Platform: stepper, storage, behavior adapters

    App->>CP: control_plane_request_boot_expression()
    CP->>Domain: request DOMAIN_EXPRESSION_IDLE
    Domain->>Platform: queue LCD idle asset sequence

    opt boot turntable calibration enabled
        App->>CP: control_plane_calibrate()
        CP->>Domain: direction calibration policy
        Domain->>Platform: stepper + calibration switch
    end

    App->>CP: control_plane_bootstrap_connectivity()
    CP->>Domain: Wi-Fi init / STA connect / BLE provisioning fallback
    Domain->>Platform: Wi-Fi and provisioning primitives

    App->>CP: control_plane_start_runtime_workers()
    CP->>CP: start model, websocket wait, LCD, Wi-Fi state, events, keys, remote log, fortune

Runtime Worker Topology

flowchart TB
    Start["control_plane_start_runtime_workers()"]

    Start --> ModelQueue["ensure model command queue"]
    Start --> ModelTask["cp_model_cmd"]
    Start --> WsWait["WebSocket wait task"]
    Start --> LcdTask["cp_lcd_render"]
    Start --> WifiTask["cp_wifi_state"]
    Start --> EventTask["cp_system_event"]
    Start --> KeyTask["cp_key_input"]
    Start --> RemoteLogTask["cp_remote_log"]
    Start --> FortuneTask["cp_fortune\nif FORTUNE_ENABLE"]

    KeyTask --> EventTask
    EventTask --> LcdTask
    WsWait --> Multimodal["multimodal client/runtime"]
    Multimodal --> ModelTask
    Multimodal --> Audio["audio capture/playback"]
    WifiTask --> LcdTask
    RemoteLogTask --> LogServer["remote log server"]
    FortuneTask --> FortuneApi["daily fortune API"]

Connectivity Bootstrap Flow

flowchart TD
    Start["control_plane_bootstrap_connectivity"]
    InitWiFi["domain_runtime_network_wifi_init(seed credentials)"]
    HasCreds{"saved Wi-Fi credentials?"}
    StaConnect["connect STA with feedback"]
    StaOk{"STA connected?"}
    KeepCreds{"error keeps credentials?"}
    ClearCreds["clear saved Wi-Fi credentials"]
    ResolvePop["resolve provisioning PoP\nserial number preferred"]
    HasPop{"PoP available?"}
    BleProv["start BLE provisioning"]
    Done["return ESP_OK"]
    Error["return error"]

    Start --> InitWiFi --> HasCreds
    HasCreds -- yes --> StaConnect --> StaOk
    StaOk -- yes --> Done
    StaOk -- no --> KeepCreds
    KeepCreds -- yes --> Done
    KeepCreds -- no --> ClearCreds --> ResolvePop
    HasCreds -- no --> ResolvePop
    ResolvePop --> HasPop
    HasPop -- yes --> BleProv --> Done
    HasPop -- no --> Error

LCD Expression Flow

flowchart LR
    CP["control_plane policy/event"]
    DomainReq["domain_runtime_request_expression()"]
    Resolve["domain_resolve_expression_platform_request()"]
    Catalog["domain expression catalog\nIDLE, WIFI_DISCONNECTED,\nSERVER_ERROR, MUYU, CHOUQIAN, WUXING"]
    PlatformReq["platform_lcd_request_presentation()"]
    Pending["lcd_direct pending request"]
    Render["cp_lcd_render loop"]
    Draw["draw RLE asset frame\nfrom /littlefs/lcd"]
    Panel["ST7789 panel"]

    CP --> DomainReq --> Resolve --> Catalog --> PlatformReq --> Pending --> Render --> Draw --> Panel

    Draw --> Delay["vTaskDelay(frame_ms)"]
    Delay --> Render

Key And Local Event Flow

flowchart TD
    GPIO["GPIO edge interrupt\nPTT GPIO15 / SW2 GPIO45"]
    IsrQueue["key IRQ queue"]
    KeyTask["cp_key_input\ndebounce and click state machine"]
    SystemQueue["system event queue"]
    EventTask["cp_system_event"]
    PttState["PTT active state"]
    Chouqian["SW2 short press\nDOMAIN_EXPRESSION_CHOUQIAN"]
    Wuxing["SW2 double click\nDOMAIN_EXPRESSION_WUXING"]
    Muyu["PTT double click\nDOMAIN_EXPRESSION_MUYU"]

    GPIO --> IsrQueue --> KeyTask --> SystemQueue --> EventTask
    EventTask --> PttState
    EventTask --> Chouqian
    EventTask --> Wuxing
    EventTask --> Muyu

Multimodal Runtime Flow

sequenceDiagram
    participant CP as control_plane
    participant Domain as domain
    participant Platform as platform
    participant WS as WebSocket server
    participant Audio as ES8311 audio path
    participant LCD as LCD expression

    CP->>Domain: prepare multimodal start
    CP->>Domain: register event callback
    CP->>Domain: register downstream audio callback
    CP->>CP: start multimodal watchdog task
    CP->>Domain: control_plane_multimodal_start()
    Domain->>Platform: open WebSocket transport
    Platform->>WS: connect and send Start directive

    WS-->>Platform: connected / task events
    Platform-->>Domain: multimodal events
    Domain-->>CP: event callback

    WS-->>Platform: downstream audio binary
    Platform-->>Domain: downstream audio callback
    Domain-->>CP: control_plane_downstream_audio_bridge()
    CP->>Audio: play downstream audio

    alt transport/task/output error while STA connected
        CP->>LCD: request DOMAIN_EXPRESSION_SERVER_ERROR
    end

    alt server responding starts
        CP->>Audio: stop uplink if running
    end

Remote Logging Flow

flowchart TD
    EspLog["ESP_LOGx / printf log"]
    Hook["esp_log_set_vprintf hook"]
    Filter["filter by CONFIG_TQ_REMOTE_LOG_MIN_LEVEL"]
    RamQueue["RAM queue\nCONFIG_TQ_REMOTE_LOG_QUEUE_LEN"]
    FlushTimer["periodic flush\nCONFIG_TQ_REMOTE_LOG_FLUSH_INTERVAL_MS"]
    LogFS["/logfs/remote_logs\nLittleFS persistent queue"]
    StaReady{"STA connected\nand realtime path idle?"}
    Upload["HTTP POST JSON batch\nCONFIG_TQ_REMOTE_LOG_ENDPOINT"]
    Server["remote_log_receiver.py\n/opt/logTools/logs"]
    Backoff["exponential retry backoff"]
    DropOld["trim old files\nCONFIG_TQ_REMOTE_LOG_MAX_FILES"]
    CoreDump["detect flash coredump\nupload metadata report"]

    EspLog --> Hook --> Filter --> RamQueue
    RamQueue --> FlushTimer --> LogFS --> DropOld
    LogFS --> StaReady
    CoreDump --> StaReady
    StaReady -- yes --> Upload --> Server
    StaReady -- no --> Backoff --> StaReady
    Upload -- fail --> Backoff
    Upload -- success --> Delete["delete uploaded local file"]

Daily Fortune Flow

flowchart TD
    Task["cp_fortune task"]
    WaitTime["wait for local time / next midnight / refresh request"]
    WaitNetwork["wait for STA and multimodal readiness"]
    Date["resolve local date"]
    Fetch["control_plane_refresh_daily_fortune(date)"]
    DomainFortune["domain fortune APIs\nbirth profile + fortune result"]
    Http["HTTPS fortune API"]
    Persist["persist fortune result"]
    Notify["notify observers / UI configuration server"]
    Retry["retry delay on failure"]

    Task --> WaitTime --> WaitNetwork --> Date --> Fetch
    Fetch --> DomainFortune --> Http
    Http -- success --> Persist --> Notify --> WaitTime
    Http -- failure --> Retry --> WaitTime

Factory CLI Diagnostics Flow

flowchart LR
    UART["UART0 serial input"]
    CLI["factory CLI parser"]
    Identity["identity / auth commands"]
    LogStatus["log status"]
    LogFlush["log flush"]
    LogClear["log clear"]
    RemoteLog["control_plane_remote_log_*"]
    UARTOut["UART0 JSON/OK/ERROR output"]

    UART --> CLI
    CLI --> Identity --> UARTOut
    CLI --> LogStatus --> RemoteLog --> UARTOut
    CLI --> LogFlush --> RemoteLog --> UARTOut
    CLI --> LogClear --> RemoteLog --> UARTOut