# 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 ```mermaid 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 ```mermaid 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 ```mermaid 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 ```mermaid 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 ```mermaid 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 ```mermaid 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 ```mermaid 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 ```mermaid 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 ```mermaid 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 ```mermaid 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 ```mermaid 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 ```