Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4a0570706f | |||
| 9ac8fdface | |||
| 33c92d1352 | |||
| 8d05815773 | |||
| fff7657fea | |||
| 52c4dd08f9 |
@@ -4,12 +4,14 @@
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
artifacts/runs/
|
||||
artifacts/mode-profiles/
|
||||
artifacts/server/
|
||||
artifacts/tmp/
|
||||
artifacts/self-repair/
|
||||
artifacts/*.log
|
||||
tmp/*.log
|
||||
.codex_tmp/
|
||||
/build/
|
||||
firmware/t2g/Seat_Controller_demo/Tests/manual_hil/logs/
|
||||
firmware/t2g/Seat_Controller_demo/Tests/manual_hil/seat_function_runtime/
|
||||
tools/zcan/seat_function_runtime/
|
||||
|
||||
@@ -1,9 +1,18 @@
|
||||
.PHONY: validate test dev dev-lan
|
||||
.PHONY: validate test dev dev-lan can-protocol-generate can-protocol-check can-read-trans can-read-trans-test
|
||||
|
||||
validate:
|
||||
CAN_READ_TRANS_BUILD_DIR ?= build/can_read_trans
|
||||
CAN_READ_TRANS_CANFD_ROOT ?= /home/orin/project511/project-code/canfd
|
||||
|
||||
can-protocol-generate:
|
||||
python tools/generate_can_semantic_protocol.py
|
||||
|
||||
can-protocol-check:
|
||||
python tools/generate_can_semantic_protocol.py --check
|
||||
|
||||
validate: can-protocol-check
|
||||
python tools/validate_repository.py
|
||||
|
||||
test:
|
||||
test: can-protocol-check
|
||||
PYTHONPATH=src:domains/seat/src python -m unittest discover -s domains/seat/tests -p 'test_*.py'
|
||||
PYTHONPATH=src:domains/seat/src python -m unittest discover -s tests -p 'test_*.py'
|
||||
|
||||
@@ -12,3 +21,12 @@ dev:
|
||||
|
||||
dev-lan:
|
||||
PYTHONPATH=src:domains/seat/src python -m cognitive_agent.server --host 0.0.0.0
|
||||
|
||||
can-read-trans: can-protocol-generate
|
||||
cmake -S tools/can_read_trans -B $(CAN_READ_TRANS_BUILD_DIR) \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCANFD_ROOT=$(CAN_READ_TRANS_CANFD_ROOT)
|
||||
cmake --build $(CAN_READ_TRANS_BUILD_DIR) --parallel
|
||||
|
||||
can-read-trans-test: can-read-trans
|
||||
ctest --test-dir $(CAN_READ_TRANS_BUILD_DIR) --output-on-failure
|
||||
|
||||
@@ -113,6 +113,21 @@ config/gesture/default.yaml
|
||||
|
||||
同一局域网的其他电脑需要体验时,使用 `make dev-lan` 监听全部网络接口。服务启动日志会打印实际 LAN 地址,例如 `http://172.20.10.5:8000`。前端和 API 使用同源访问,不需要 CORS,也不会把 `OPENAI_API_KEY` 发送到浏览器。若没有启用 `.env.auth`,任何可达设备都能触发服务端 GPT 请求,因此未认证的 LAN 模式只应在可信网络内临时演示。
|
||||
|
||||
Linux 上使用 USBCANFD-200U 被动同步 CH1 车辆状态时,使用
|
||||
`zlgcan-linux` 后端。USB 权限、60 MHz/500k/2M 位时序、只读配置和状态接口
|
||||
验证见 [Linux ZLG 车辆状态接入](docs/workflows/linux-zlg-vehicle-state.md)。
|
||||
有线 ZLG 与本机 NanoMQ 无线链路使用相同的通道角色:CAN0 只对应副驾座椅,
|
||||
CAN1 对应空调、车窗、灯光、遮阳帘、主驾座椅等其余车辆状态和控制。车辆控制
|
||||
后端不允许回退到 CAN0;MQTT 主题、原始 CAN 帧 JSON 合约和有线/无线共用安全
|
||||
门禁见同一文档。
|
||||
|
||||
需要在终端独立核对双通道状态或下发一条明确的白名单语义命令时,可构建
|
||||
`can_read_trans`。该程序由同一个 C++ 进程持有 ZLG 设备:CAN0 监听并控制副驾
|
||||
座椅固件原生协议,CAN1 监听并控制其余车辆矩阵协议;默认只监听、默认不启用
|
||||
适配器内部终端电阻,也不提供任意原始帧注入入口。`console --execute` 可在同一
|
||||
设备会话中持续接收状态并交互下发 CAN0/CAN1 白名单命令。构建、命令示例、反馈
|
||||
判定和安全限制见 [can_read_trans 双通道检测与控制](docs/workflows/can-read-trans.md)。
|
||||
|
||||
## 认证与公网体验
|
||||
|
||||
公网演示必须启用 `.env.auth` 中的服务端认证。密码使用 PBKDF2-SHA256 哈希保存;认证成功后签发有有效期的 HMAC 会话 Cookie,Cookie 使用 `HttpOnly` 和 `SameSite=Strict`,经 HTTPS 代理时自动增加 `Secure`。登录失败按来源 IP 限流,GPT 请求按体验账号限制每分钟调用次数。未登录访问页面会跳转 `/login`,未登录 API 请求返回 `401`。
|
||||
|
||||
@@ -56,6 +56,8 @@ const state = {
|
||||
customizeOpen: false,
|
||||
engine: null,
|
||||
runtimeReady: false,
|
||||
enabled: true,
|
||||
disabledReason: "",
|
||||
cameraStatus: "checking",
|
||||
cameraMessage: "正在检测摄像头…",
|
||||
cameraCheckSequence: 0,
|
||||
@@ -114,7 +116,8 @@ function cameraFailureDetails(error) {
|
||||
function syncCameraButtonAvailability() {
|
||||
const button = $("#gestureStartButton");
|
||||
if (!button || state.stream) return;
|
||||
button.disabled = !state.runtimeReady
|
||||
button.disabled = !state.enabled
|
||||
|| !state.runtimeReady
|
||||
|| ["checking", "unavailable", "unsupported"].includes(state.cameraStatus);
|
||||
}
|
||||
|
||||
@@ -693,29 +696,48 @@ function resetMapping() {
|
||||
}
|
||||
|
||||
function openDrawer() {
|
||||
$("#gestureDrawer").classList.add("open");
|
||||
$("#gestureDrawer").setAttribute("aria-hidden", "false");
|
||||
$("#gestureBackdrop").hidden = false;
|
||||
requestAnimationFrame(() => $("#gestureBackdrop").classList.add("visible"));
|
||||
$("#gestureToggleButton").setAttribute("aria-expanded", "true");
|
||||
if (!state.enabled) {
|
||||
notify(state.disabledReason || "当前运行模式未启用手势控制");
|
||||
return false;
|
||||
}
|
||||
const drawer = $("#gestureDrawer");
|
||||
if (!drawer) return false;
|
||||
drawer.classList.add("open");
|
||||
drawer.setAttribute("aria-hidden", "false");
|
||||
document.body.classList.add("gesture-open");
|
||||
return true;
|
||||
}
|
||||
|
||||
function closeDrawer() {
|
||||
stopCamera();
|
||||
$("#gestureDrawer").classList.remove("open");
|
||||
$("#gestureDrawer").setAttribute("aria-hidden", "true");
|
||||
$("#gestureBackdrop").classList.remove("visible");
|
||||
window.setTimeout(() => { $("#gestureBackdrop").hidden = true; }, 240);
|
||||
$("#gestureToggleButton").setAttribute("aria-expanded", "false");
|
||||
const drawer = $("#gestureDrawer");
|
||||
drawer?.classList.remove("open");
|
||||
drawer?.setAttribute("aria-hidden", "true");
|
||||
document.body.classList.remove("gesture-open");
|
||||
}
|
||||
|
||||
function setEnabled(enabled, { reason = "" } = {}) {
|
||||
state.enabled = Boolean(enabled);
|
||||
state.disabledReason = state.enabled ? "" : String(reason || "当前运行模式未启用手势控制");
|
||||
if (!state.enabled) closeDrawer();
|
||||
syncCameraButtonAvailability();
|
||||
const drawer = $("#gestureDrawer");
|
||||
if (drawer) {
|
||||
drawer.dataset.enabled = String(state.enabled);
|
||||
drawer.title = state.disabledReason;
|
||||
}
|
||||
}
|
||||
|
||||
window.CognitiveAgentGesture = {
|
||||
open: openDrawer,
|
||||
close: closeDrawer,
|
||||
isOpen: () => $("#gestureDrawer")?.classList.contains("open") === true,
|
||||
setEnabled,
|
||||
};
|
||||
|
||||
document.addEventListener("DOMContentLoaded", async () => {
|
||||
$("#gestureStartButton").disabled = true;
|
||||
$("#gestureToggleButton")?.addEventListener("click", openDrawer);
|
||||
$("#gestureCloseButton")?.addEventListener("click", closeDrawer);
|
||||
$("#gestureBackdrop")?.addEventListener("click", closeDrawer);
|
||||
$("#gestureStartButton")?.addEventListener("click", toggleCamera);
|
||||
$("#gestureStopButton")?.addEventListener("click", () => state.engine?.setArmed(false));
|
||||
$("#gestureCustomizeButton")?.addEventListener("click", toggleCustomize);
|
||||
|
||||
@@ -9,44 +9,26 @@
|
||||
<link rel="manifest" href="/manifest.webmanifest" />
|
||||
<link rel="icon" href="/icons/app-icon-192.png" />
|
||||
<title>511工程-智能座舱</title>
|
||||
<link rel="stylesheet" href="/styles.css?v=dual-seat-9" />
|
||||
<link rel="stylesheet" href="/console-v2.css?v=sync-layout-26" />
|
||||
<link rel="stylesheet" href="/styles.css?v=dual-seat-16" />
|
||||
<link rel="stylesheet" href="/console-v2.css?v=sync-layout-41" />
|
||||
<link rel="stylesheet" href="/self-extension.css?v=sync-layout-26" />
|
||||
<script src="/vendor/lucide/0.468.0/lucide.min.js" defer></script>
|
||||
<script src="/vendor/three/0.147.0/three.min.js" defer></script>
|
||||
<script src="/vendor/three/0.147.0/fflate.min.js" defer></script>
|
||||
<script src="/vendor/three/0.147.0/FBXLoader.js" defer></script>
|
||||
<script src="/network.js?v=android-pad-1" defer></script>
|
||||
<script src="/app.js?v=dual-seat-85" defer></script>
|
||||
<script type="module" src="/gesture-control.js?v=android-pad-8"></script>
|
||||
<script src="/pwa.js?v=android-pad-2" defer></script>
|
||||
<script src="/console-v2.js?v=sync-layout-26" defer></script>
|
||||
<script src="/network.js?v=android-pad-2" defer></script>
|
||||
<script src="/app.js?v=dual-seat-107" defer></script>
|
||||
<script type="module" src="/gesture-control.js?v=android-pad-9"></script>
|
||||
<script src="/pwa.js?v=android-pad-3" defer></script>
|
||||
<script src="/console-v2.js?v=task-outcome-47" defer></script>
|
||||
<script src="/self-extension.js?v=sync-layout-26" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
<header class="topbar">
|
||||
<div class="brand-block">
|
||||
<span class="brand-mark" aria-hidden="true"><i data-lucide="brain-circuit"></i></span>
|
||||
<div>
|
||||
<h1>Cognitive Agent</h1>
|
||||
<p>CABIN ORCHESTRATION <span>/</span> MULTI-DOMAIN</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="runtime-badges" aria-label="运行环境">
|
||||
<button class="gesture-entry" id="gestureToggleButton" type="button" aria-controls="gestureDrawer" aria-expanded="false">
|
||||
<span class="gesture-entry-dot"></span><i data-lucide="scan-face"></i>手势控制
|
||||
</button>
|
||||
<span class="status-badge neutral connection-badge" id="connectionBadge"><i data-lucide="loader-circle"></i><span>连接中</span></span>
|
||||
<button class="status-badge neutral pwa-badge" id="pwaBadge" type="button" hidden></button>
|
||||
<span class="status-badge neutral" id="executionBadge"><i data-lucide="flask-conical"></i>DRY-RUN</span>
|
||||
<span class="status-badge" id="modelBadge"><i data-lucide="sparkles"></i>模型检测中</span>
|
||||
<span class="status-badge danger" id="hardwareBadge"><i data-lucide="shield-off"></i>硬件检测中</span>
|
||||
<button class="status-badge auth-logout" id="logoutButton" type="button" title="退出登录" aria-label="退出登录" hidden>
|
||||
<i data-lucide="log-out"></i>
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<body class="console-v2">
|
||||
<div class="v2-boot-screen" id="v2BootScreen" role="status" aria-live="polite">
|
||||
<span class="v2-boot-mark" aria-hidden="true"><i></i><i></i><i></i></span>
|
||||
<strong>511工程-智能座舱</strong>
|
||||
<small>正在加载车机控制与实时状态</small>
|
||||
</div>
|
||||
<div class="workspace">
|
||||
<aside class="command-panel">
|
||||
<div class="panel-heading">
|
||||
@@ -126,10 +108,10 @@
|
||||
<div class="field-group">
|
||||
<span class="field-label">执行目标</span>
|
||||
<div class="segmented execution-mode-options" role="group" aria-label="执行目标">
|
||||
<button type="button" class="mode-option active" data-execution-mode="dry_run">
|
||||
<button type="button" class="mode-option" data-execution-mode="dry_run">
|
||||
<i data-lucide="flask-conical"></i>虚拟 CAN
|
||||
</button>
|
||||
<button type="button" class="mode-option" id="hardwareMode" data-execution-mode="hardware" disabled>
|
||||
<button type="button" class="mode-option active" id="hardwareMode" data-execution-mode="hardware">
|
||||
<i data-lucide="radio-tower"></i>真实台架
|
||||
</button>
|
||||
<button type="button" class="mode-option" id="simulationMode" data-execution-mode="simulated_hardware" disabled>
|
||||
@@ -140,6 +122,19 @@
|
||||
<p class="provider-note" id="hardwareAliasNote">所有座椅能力仅控制副驾实体电机、加热与通风执行器</p>
|
||||
</div>
|
||||
|
||||
<div class="field-group" id="vehicleTransportField">
|
||||
<span class="field-label">车辆连接方式</span>
|
||||
<div class="segmented vehicle-transport-options" role="group" aria-label="车辆连接方式">
|
||||
<button type="button" class="mode-option active" data-control-transport="wired_can">
|
||||
<i data-lucide="cable"></i>有线 CAN
|
||||
</button>
|
||||
<button type="button" class="mode-option" data-control-transport="wireless_mqtt">
|
||||
<i data-lucide="wifi"></i>无线 CAN
|
||||
</button>
|
||||
</div>
|
||||
<p class="provider-note" id="vehicleTransportNote">正在检查车辆连接</p>
|
||||
</div>
|
||||
|
||||
<div class="field-group simulation-fault-field" id="simulationFaultField" hidden>
|
||||
<label class="field-label" for="simulationFault">故障注入场景</label>
|
||||
<select id="simulationFault" aria-label="选择模拟硬件故障">
|
||||
@@ -170,47 +165,6 @@
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<div class="example-group">
|
||||
<span class="field-label">示例请求</span>
|
||||
<button type="button" class="example-command featured-example" data-example="副驾座椅通风3档,同时打开空调,温度设为24度,风量3档">
|
||||
<i data-lucide="workflow"></i><span>副驾通风 + 空调 24℃ · 双通道联动</span><i data-lucide="chevron-right"></i>
|
||||
</button>
|
||||
<button type="button" class="example-command" data-example="空调打开,车内温度调到24度,风量3档">
|
||||
<i data-lucide="fan"></i><span>空调 24℃ · 风量 3 档</span><i data-lucide="chevron-right"></i>
|
||||
</button>
|
||||
<button type="button" class="example-command" data-example="天幕透光率调到30%,遮阳帘打开一半">
|
||||
<i data-lucide="panels-top-left"></i><span>天幕透光 30% · 遮阳帘 50%</span><i data-lucide="chevron-right"></i>
|
||||
</button>
|
||||
<button type="button" class="example-command" data-example="打开氛围灯,调成冰蓝色,亮度60%">
|
||||
<i data-lucide="lamp-ceiling"></i><span>冰蓝氛围灯 · 亮度 60%</span><i data-lucide="chevron-right"></i>
|
||||
</button>
|
||||
<button type="button" class="example-command featured-example" data-example="进入观影状态:副驾调整为舒适观影姿态,空调24度、风量2档,天幕调暗,氛围灯换成暖橙色">
|
||||
<i data-lucide="clapperboard"></i><span>跨域观影场景</span><i data-lucide="chevron-right"></i>
|
||||
</button>
|
||||
<button type="button" class="example-command" data-example="副驾有点热,有点闷">
|
||||
<i data-lucide="wind"></i><span>副驾有点热,有点闷</span><i data-lucide="chevron-right"></i>
|
||||
</button>
|
||||
<button type="button" class="example-command" data-example="副驾靠背向后移动5度">
|
||||
<i data-lucide="move-horizontal"></i><span>副驾靠背向后 5°</span><i data-lucide="chevron-right"></i>
|
||||
</button>
|
||||
<button type="button" class="example-command" data-example="副驾调整为零重力模式,要求靠背座椅夹角128度,坐垫脚托夹角133度">
|
||||
<i data-lucide="compass"></i><span>副驾零重力精确夹角</span><i data-lucide="chevron-right"></i>
|
||||
</button>
|
||||
<button type="button" class="example-command" data-example="将当前状态保存为零重力模式">
|
||||
<i data-lucide="bookmark-plus"></i><span>保存当前座椅姿态</span><i data-lucide="chevron-right"></i>
|
||||
</button>
|
||||
<button type="button" class="example-command warning-example" data-example="副驾座椅加热开到三档">
|
||||
<i data-lucide="triangle-alert"></i><span>三档请求(档位虚拟)</span><i data-lucide="chevron-right"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="safety-strip" id="safetyStrip">
|
||||
<i data-lucide="shield-check"></i>
|
||||
<div>
|
||||
<strong id="safetyTitle">虚拟执行边界</strong>
|
||||
<span id="safetyText">四域 CAN 均为 dry-run,实车发送被强制关闭。</span>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<main class="main-panel">
|
||||
@@ -229,20 +183,6 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="pipeline" aria-label="执行链路">
|
||||
<div class="pipeline-step" data-stage="intent_parse"><span>01</span><i data-lucide="message-square-text"></i><b>意图抽取</b></div>
|
||||
<i class="pipeline-arrow" data-lucide="chevron-right"></i>
|
||||
<div class="pipeline-step" data-stage="function_generate"><span>02</span><i data-lucide="file-code-2"></i><b>配置生成</b></div>
|
||||
<i class="pipeline-arrow" data-lucide="chevron-right"></i>
|
||||
<div class="pipeline-step" data-stage="domain_validate"><span>03</span><i data-lucide="badge-check"></i><b>双层校验</b></div>
|
||||
<i class="pipeline-arrow" data-lucide="chevron-right"></i>
|
||||
<div class="pipeline-step" data-stage="compile"><span>04</span><i data-lucide="binary"></i><b>CAN 编译</b></div>
|
||||
<i class="pipeline-arrow" data-lucide="chevron-right"></i>
|
||||
<div class="pipeline-step" data-stage="safety_check"><span>05</span><i data-lucide="shield-check"></i><b>安全门禁</b></div>
|
||||
<i class="pipeline-arrow" data-lucide="chevron-right"></i>
|
||||
<div class="pipeline-step" data-stage="execute"><span>06</span><i data-lucide="radio-tower"></i><b id="executeStageLabel">虚拟执行</b></div>
|
||||
</section>
|
||||
|
||||
<section class="cabin-band" aria-labelledby="cabinStateTitle">
|
||||
<div class="section-title-row cabin-heading">
|
||||
<div class="cabin-title-copy">
|
||||
@@ -261,27 +201,27 @@
|
||||
<header>
|
||||
<span class="domain-icon"><i data-lucide="fan"></i></span>
|
||||
<div><strong>空调</strong><small>CMD 0x1DE · FB 0x404 · CH1</small></div>
|
||||
<span class="device-state" id="climatePower">OFF</span>
|
||||
<span class="device-state" id="climatePower">UNKNOWN</span>
|
||||
</header>
|
||||
<p class="domain-capability-line"><span>可控参数</span>电源 · 温度 · 风量/风向</p>
|
||||
<div class="climate-display">
|
||||
<div class="zone-temperature">
|
||||
<span>主驾</span><strong id="driverTemperature">24<sup>℃</sup></strong>
|
||||
<span>主驾</span><strong id="driverTemperature">--<sup>℃</sup></strong>
|
||||
<small>风向<b id="driverAirDirection">-</b></small>
|
||||
</div>
|
||||
<div class="airflow-visual" id="airflowVisual" data-level="0" aria-label="空调风量">
|
||||
<i></i><i></i><i></i><i></i><i></i><i></i><i></i>
|
||||
</div>
|
||||
<div class="zone-temperature passenger-temperature">
|
||||
<span>副驾</span><strong id="passengerTemperature">24<sup>℃</sup></strong>
|
||||
<span>副驾</span><strong id="passengerTemperature">--<sup>℃</sup></strong>
|
||||
<small>风向<b id="passengerAirDirection">-</b></small>
|
||||
</div>
|
||||
</div>
|
||||
<dl class="domain-readouts">
|
||||
<div><dt>风量</dt><dd id="fanLevel">0 档</dd></div>
|
||||
<div><dt>循环</dt><dd id="cycleMode">外循环</dd></div>
|
||||
<div><dt>A/C</dt><dd id="acState">关闭</dd></div>
|
||||
<div><dt>前除霜</dt><dd id="defrostState">关闭</dd></div>
|
||||
<div><dt>风量</dt><dd id="fanLevel">未知</dd></div>
|
||||
<div><dt>循环</dt><dd id="cycleMode">未知</dd></div>
|
||||
<div><dt>A/C</dt><dd id="acState">未知</dd></div>
|
||||
<div><dt>前除霜</dt><dd id="defrostState">未知</dd></div>
|
||||
</dl>
|
||||
</article>
|
||||
|
||||
@@ -308,17 +248,17 @@
|
||||
<header>
|
||||
<span class="domain-icon"><i data-lucide="panels-top-left"></i></span>
|
||||
<div><strong>遮阳帘</strong><small>CMD 0x431 · FB 0x41A · CH1</small></div>
|
||||
<span class="device-state" id="roofState">READY</span>
|
||||
<span class="device-state" id="roofState">UNKNOWN</span>
|
||||
</header>
|
||||
<p class="domain-capability-line"><span>可控参数</span>开关 / 停止 · 位置</p>
|
||||
<div class="domain-summary-visual shade-summary-visual" aria-hidden="true">
|
||||
<span>闭合</span><i><b id="shadePositionMeter"></b></i><span>打开</span>
|
||||
</div>
|
||||
<dl class="domain-readouts">
|
||||
<div><dt>遮阳帘</dt><dd id="shadePositionValue">0%</dd></div>
|
||||
<div><dt>动作</dt><dd id="shadeMotionState">停止</dd></div>
|
||||
<div><dt>遮阳帘</dt><dd id="shadePositionValue">未知</dd></div>
|
||||
<div><dt>动作</dt><dd id="shadeMotionState">未知</dd></div>
|
||||
<div><dt>初始化</dt><dd id="shadeInitializedState">未知</dd></div>
|
||||
<div><dt>热保护</dt><dd id="shadeThermalState">正常</dd></div>
|
||||
<div><dt>热保护</dt><dd id="shadeThermalState">未知</dd></div>
|
||||
</dl>
|
||||
</article>
|
||||
|
||||
@@ -326,7 +266,7 @@
|
||||
<header>
|
||||
<span class="domain-icon"><i data-lucide="lamp-ceiling"></i></span>
|
||||
<div><strong>车内灯光</strong><small>INTERIOR / AMBIENT · CH1</small></div>
|
||||
<span class="device-state" id="ambientPower">OFF</span>
|
||||
<span class="device-state" id="ambientPower">UNKNOWN</span>
|
||||
</header>
|
||||
<p class="domain-capability-line"><span>可控参数</span>阅读灯 · 氛围亮度 · 色号</p>
|
||||
<div class="domain-summary-visual ambient-summary-visual" aria-hidden="true">
|
||||
@@ -334,9 +274,9 @@
|
||||
<span data-ambient-zone="rear"><i id="ambientRearMeter"></i><b>后排</b></span>
|
||||
</div>
|
||||
<dl class="domain-readouts">
|
||||
<div><dt>氛围灯</dt><dd id="ambientMode">关闭</dd></div>
|
||||
<div><dt>室内/阅读灯</dt><dd id="interiorLightPower">关闭</dd></div>
|
||||
<div><dt>氛围亮度</dt><dd id="ambientBrightness">0 / 0</dd></div>
|
||||
<div><dt>氛围灯</dt><dd id="ambientMode">未知</dd></div>
|
||||
<div><dt>室内/阅读灯</dt><dd id="interiorLightPower">未知</dd></div>
|
||||
<div><dt>氛围亮度</dt><dd id="ambientBrightness">- / -</dd></div>
|
||||
<div><dt>氛围色号</dt><dd id="ambientColorIndex">- / -</dd></div>
|
||||
</dl>
|
||||
</article>
|
||||
@@ -345,7 +285,7 @@
|
||||
<header>
|
||||
<span class="domain-icon"><i data-lucide="gallery-vertical-end"></i></span>
|
||||
<div><strong>车窗</strong><small>CMD 0x431 · FB 0x388 · CH1</small></div>
|
||||
<span class="device-state" id="windowState">READY</span>
|
||||
<span class="device-state" id="windowState">UNKNOWN</span>
|
||||
</header>
|
||||
<p class="domain-capability-line"><span>可控参数</span>四窗独立 · 开/关/停 · 位置</p>
|
||||
<div class="domain-summary-visual window-summary-visual" aria-hidden="true">
|
||||
@@ -355,18 +295,18 @@
|
||||
<span data-window-meter="rear_right"><i></i><b>右后</b></span>
|
||||
</div>
|
||||
<dl class="domain-readouts">
|
||||
<div><dt>左前窗</dt><dd id="frontLeftWindow">0%</dd></div>
|
||||
<div><dt>右前窗</dt><dd id="frontRightWindow">0%</dd></div>
|
||||
<div><dt>左后窗</dt><dd id="rearLeftWindow">0%</dd></div>
|
||||
<div><dt>右后窗</dt><dd id="rearRightWindow">0%</dd></div>
|
||||
<div><dt>左前窗</dt><dd id="frontLeftWindow">未知</dd></div>
|
||||
<div><dt>右前窗</dt><dd id="frontRightWindow">未知</dd></div>
|
||||
<div><dt>左后窗</dt><dd id="rearLeftWindow">未知</dd></div>
|
||||
<div><dt>右后窗</dt><dd id="rearRightWindow">未知</dd></div>
|
||||
</dl>
|
||||
</article>
|
||||
|
||||
<article class="domain-panel lighting-panel" data-domain-panel="front_light" data-device-channel="ch1">
|
||||
<header>
|
||||
<span class="domain-icon"><i data-lucide="car-front"></i></span>
|
||||
<div><strong>前大灯</strong><small>FRONT LIGHT · SWITCH</small></div>
|
||||
<span class="device-state" id="frontLightState">OFF</span>
|
||||
<div><strong>前大灯</strong><small>FB 0x38A · CH1</small></div>
|
||||
<span class="device-state" id="frontLightState">UNKNOWN</span>
|
||||
</header>
|
||||
<p class="domain-capability-line"><span>可控参数</span>近/远光 · 雾灯 · 转向灯</p>
|
||||
<div class="domain-summary-visual lighting-summary-visual" aria-hidden="true">
|
||||
@@ -376,10 +316,10 @@
|
||||
<span data-light-meter="turnSignalState"><i></i><b>转向</b></span>
|
||||
</div>
|
||||
<dl class="domain-readouts">
|
||||
<div><dt>近光灯</dt><dd id="lowBeamState">关闭</dd></div>
|
||||
<div><dt>远光灯</dt><dd id="highBeamState">关闭</dd></div>
|
||||
<div><dt>雾灯</dt><dd id="fogLightState">关闭</dd></div>
|
||||
<div><dt>转向灯</dt><dd id="turnSignalState">关闭</dd></div>
|
||||
<div><dt>近光灯</dt><dd id="lowBeamState">未知</dd></div>
|
||||
<div><dt>远光灯</dt><dd id="highBeamState">未知</dd></div>
|
||||
<div><dt>雾灯</dt><dd id="fogLightState">未知</dd></div>
|
||||
<div><dt>转向灯</dt><dd id="turnSignalState">未知</dd></div>
|
||||
</dl>
|
||||
</article>
|
||||
|
||||
@@ -463,11 +403,6 @@
|
||||
<div class="dynamic-mode-state" data-dynamic-mode>
|
||||
<i data-lucide="waves"></i><span>动态模式</span><b>未运行</b>
|
||||
</div>
|
||||
<div class="thermal-states">
|
||||
<span data-function="ventilation"><i data-lucide="wind"></i>通风 <b>--</b></span>
|
||||
<span data-function="heating"><i data-lucide="flame"></i>加热 <b>--</b></span>
|
||||
<span data-function="massage"><i data-lucide="waves"></i>按摩 <b>--</b></span>
|
||||
</div>
|
||||
<div class="motion-state-grid" aria-live="polite"></div>
|
||||
</article>
|
||||
<article class="seat-card" data-seat="driver">
|
||||
@@ -563,7 +498,6 @@
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<div class="gesture-backdrop" id="gestureBackdrop" hidden></div>
|
||||
<aside class="gesture-drawer" id="gestureDrawer" aria-hidden="true" aria-labelledby="gestureDrawerTitle">
|
||||
<header class="gesture-drawer-header">
|
||||
<div>
|
||||
@@ -633,6 +567,51 @@
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div class="mode-editor-backdrop" id="modeEditorBackdrop" hidden>
|
||||
<section class="mode-editor" role="dialog" aria-modal="true" aria-labelledby="modeEditorTitle" aria-describedby="modeEditorDescription">
|
||||
<div class="mode-editor-setup">
|
||||
<header class="mode-editor-header">
|
||||
<div>
|
||||
<span>MODE WORKFLOW</span>
|
||||
<h2 id="modeEditorTitle">编辑功能模式</h2>
|
||||
<p id="modeEditorDescription">执行后生成 CAN 控制指令流;完成后永久保存到当前模式卡片。</p>
|
||||
</div>
|
||||
<button id="modeEditorClose" type="button" aria-label="关闭模式编辑器"><i data-lucide="x"></i></button>
|
||||
</header>
|
||||
<div class="mode-editor-inputs">
|
||||
<label class="mode-editor-field mode-editor-name-field" for="modeEditorName">
|
||||
<span>模式名称</span>
|
||||
<input id="modeEditorName" maxlength="64" autocomplete="off" placeholder="输入模式名称" />
|
||||
</label>
|
||||
<label class="mode-editor-field mode-editor-instruction-field" for="modeEditorInstruction">
|
||||
<span>自然语言指令</span>
|
||||
<textarea id="modeEditorInstruction" maxlength="1000" rows="3" placeholder="例如:空调24度、风量2档,打开遮阳帘"></textarea>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<section class="mode-editor-flow" aria-live="polite">
|
||||
<header>
|
||||
<span><i data-lucide="workflow"></i>CAN 控制指令流</span>
|
||||
<div class="mode-editor-flow-tools">
|
||||
<b id="modeEditorFlowCount">尚未生成</b>
|
||||
<button id="modeEditorFlowExpand" type="button" aria-expanded="false" aria-label="展开 CAN 控制指令区域" title="展开 CAN 控制指令区域">
|
||||
<i data-lucide="maximize-2"></i>
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
<div class="mode-editor-flow-preview empty" id="modeEditorFlowPreview">
|
||||
<p>点击“执行”后,这里会显示由后端生成的 CAN 控制指令流。</p>
|
||||
</div>
|
||||
</section>
|
||||
<p class="mode-editor-status" id="modeEditorStatus">修改自然语言后需要重新执行,才能点击完成永久保存。</p>
|
||||
<footer class="mode-editor-actions">
|
||||
<button id="modeEditorCancel" type="button">取消</button>
|
||||
<button class="mode-editor-execute" id="modeEditorExecute" type="button"><i data-lucide="play"></i><span>执行</span></button>
|
||||
<button class="mode-editor-complete" id="modeEditorComplete" type="button" disabled><i data-lucide="save"></i><span>完成</span></button>
|
||||
</footer>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div class="toast" id="toast" role="status" aria-live="polite"></div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<meta name="color-scheme" content="light" />
|
||||
<title>登录 · Cognitive Agent</title>
|
||||
<link rel="stylesheet" href="/login.css" />
|
||||
<script src="/network.js?v=android-pad-1" defer></script>
|
||||
<script src="/network.js?v=android-pad-2" defer></script>
|
||||
<script src="/login.js" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -12,30 +12,11 @@
|
||||
return { ...state };
|
||||
}
|
||||
|
||||
function renderBadge() {
|
||||
const badge = document.querySelector("#connectionBadge");
|
||||
if (!badge) return;
|
||||
const presentation = {
|
||||
connecting: ["neutral", "loader-circle", "连接中"],
|
||||
online: ["", "wifi", "服务已连接"],
|
||||
degraded: ["warning", "wifi-low", "连接不稳定"],
|
||||
offline: ["danger", "wifi-off", "服务已断开"],
|
||||
}[state.status];
|
||||
badge.className = `status-badge connection-badge ${presentation[0]}`.trim();
|
||||
badge.innerHTML = `<i data-lucide="${presentation[1]}"></i><span>${presentation[2]}</span>`;
|
||||
badge.title = state.lastError || presentation[2];
|
||||
window.lucide?.createIcons?.({
|
||||
attrs: { "aria-hidden": "true" },
|
||||
nodes: [badge],
|
||||
});
|
||||
}
|
||||
|
||||
function publish(status, error = null) {
|
||||
const changed = state.status !== status || state.lastError !== error;
|
||||
state.status = status;
|
||||
state.lastError = error;
|
||||
if (status === "online") state.lastSuccessAt = new Date().toISOString();
|
||||
renderBadge();
|
||||
if (!changed) return;
|
||||
const detail = snapshot();
|
||||
listeners.forEach((listener) => listener(detail));
|
||||
@@ -110,7 +91,6 @@
|
||||
|
||||
function startMonitoring() {
|
||||
if (probeTimer !== null) return;
|
||||
renderBadge();
|
||||
probe();
|
||||
probeTimer = window.setInterval(probe, 10000);
|
||||
window.addEventListener("online", () => {
|
||||
|
||||
@@ -4,12 +4,8 @@
|
||||
}
|
||||
|
||||
function showUpdate(registration) {
|
||||
const badge = document.querySelector("#pwaBadge");
|
||||
if (!badge) return;
|
||||
badge.hidden = false;
|
||||
badge.innerHTML = '<i data-lucide="refresh-cw"></i><span>发现更新</span>';
|
||||
badge.onclick = () => registration.waiting?.postMessage({ type: "SKIP_WAITING" });
|
||||
window.lucide?.createIcons?.({ attrs: { "aria-hidden": "true" }, nodes: [badge] });
|
||||
notify("检测到前端更新,正在刷新页面");
|
||||
registration.waiting?.postMessage({ type: "SKIP_WAITING" });
|
||||
}
|
||||
|
||||
async function register() {
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
.console-v2[data-module="self-extension"] .v2-control-section,
|
||||
.console-v2[data-module="self-extension"] .v2-config-section,
|
||||
.console-v2[data-module="self-extension"] .v2-sidebar > .v2-sidebar-footer:not(.v2-extension-footer),
|
||||
.console-v2[data-module="self-extension"] .v2-operation-shell,
|
||||
.console-v2[data-module="self-extension"] .v2-output-shell {
|
||||
|
||||
@@ -718,7 +718,7 @@
|
||||
}
|
||||
|
||||
function isPhysicalVehicleSource(value) {
|
||||
return ["physical_can", "physical_can_ch0", "physical_can_ch1", "physical_partial"].includes(value);
|
||||
return ["physical_can", "physical_can_ch0", "physical_can_ch1", "wireless_mqtt_ch0", "wireless_mqtt_ch1", "physical_partial"].includes(value);
|
||||
}
|
||||
|
||||
function containsAuthoritativePhysicalCh1State(value) {
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
const CACHE_VERSION = "cognitive-agent-pad-v178";
|
||||
const CACHE_VERSION = "cognitive-agent-pad-v210";
|
||||
const SHELL_CACHE = `${CACHE_VERSION}-shell`;
|
||||
const RUNTIME_CACHE = `${CACHE_VERSION}-runtime`;
|
||||
const APP_SHELL = [
|
||||
"/",
|
||||
"/index.html",
|
||||
"/styles.css?v=dual-seat-9",
|
||||
"/network.js?v=android-pad-1",
|
||||
"/app.js?v=dual-seat-85",
|
||||
"/gesture-control.js?v=android-pad-8",
|
||||
"/pwa.js?v=android-pad-2",
|
||||
"/console-v2.css?v=sync-layout-26",
|
||||
"/console-v2.js?v=sync-layout-26",
|
||||
"/styles.css?v=dual-seat-16",
|
||||
"/network.js?v=android-pad-2",
|
||||
"/app.js?v=dual-seat-107",
|
||||
"/gesture-control.js?v=android-pad-9",
|
||||
"/pwa.js?v=android-pad-3",
|
||||
"/console-v2.css?v=sync-layout-41",
|
||||
"/console-v2.js?v=task-outcome-47",
|
||||
"/self-extension.css?v=sync-layout-26",
|
||||
"/self-extension.js?v=sync-layout-26",
|
||||
"/assets/pets/self-extension-cat.png?v=3",
|
||||
|
||||
|
Before Width: | Height: | Size: 230 KiB |
|
Before Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 278 KiB |
|
Before Width: | Height: | Size: 43 KiB |
|
Before Width: | Height: | Size: 182 KiB |
|
Before Width: | Height: | Size: 191 KiB |
|
Before Width: | Height: | Size: 68 KiB |
|
Before Width: | Height: | Size: 68 KiB |
|
Before Width: | Height: | Size: 87 KiB |
|
Before Width: | Height: | Size: 86 KiB |
|
Before Width: | Height: | Size: 161 KiB |
|
Before Width: | Height: | Size: 171 KiB |
|
Before Width: | Height: | Size: 187 KiB |
|
Before Width: | Height: | Size: 167 KiB |
|
Before Width: | Height: | Size: 248 KiB |
|
Before Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 63 KiB |
|
Before Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 149 KiB |
|
Before Width: | Height: | Size: 66 KiB |
|
Before Width: | Height: | Size: 466 KiB |
|
Before Width: | Height: | Size: 214 KiB |
|
Before Width: | Height: | Size: 146 KiB |
|
Before Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 190 KiB |
|
Before Width: | Height: | Size: 187 KiB |
|
Before Width: | Height: | Size: 186 KiB |
|
Before Width: | Height: | Size: 190 KiB |
|
Before Width: | Height: | Size: 185 KiB |
|
Before Width: | Height: | Size: 185 KiB |
|
Before Width: | Height: | Size: 185 KiB |
|
Before Width: | Height: | Size: 193 KiB |
|
Before Width: | Height: | Size: 193 KiB |
|
Before Width: | Height: | Size: 190 KiB |
|
Before Width: | Height: | Size: 74 KiB |
|
Before Width: | Height: | Size: 87 KiB |
|
Before Width: | Height: | Size: 193 KiB |
|
Before Width: | Height: | Size: 192 KiB |
|
Before Width: | Height: | Size: 195 KiB |
|
Before Width: | Height: | Size: 183 KiB |
|
Before Width: | Height: | Size: 186 KiB |
|
Before Width: | Height: | Size: 182 KiB |
|
Before Width: | Height: | Size: 182 KiB |
|
Before Width: | Height: | Size: 190 KiB |
|
Before Width: | Height: | Size: 190 KiB |
|
Before Width: | Height: | Size: 182 KiB |
|
Before Width: | Height: | Size: 192 KiB |
|
Before Width: | Height: | Size: 190 KiB |
|
Before Width: | Height: | Size: 190 KiB |
|
Before Width: | Height: | Size: 182 KiB |
|
Before Width: | Height: | Size: 183 KiB |
|
Before Width: | Height: | Size: 188 KiB |
|
Before Width: | Height: | Size: 196 KiB |
|
Before Width: | Height: | Size: 197 KiB |
|
Before Width: | Height: | Size: 90 KiB |
|
Before Width: | Height: | Size: 68 KiB |
|
Before Width: | Height: | Size: 80 KiB |
|
Before Width: | Height: | Size: 85 KiB |
|
Before Width: | Height: | Size: 189 KiB |
|
Before Width: | Height: | Size: 85 KiB |
|
Before Width: | Height: | Size: 188 KiB |
|
Before Width: | Height: | Size: 189 KiB |
|
Before Width: | Height: | Size: 189 KiB |
|
Before Width: | Height: | Size: 187 KiB |
|
Before Width: | Height: | Size: 187 KiB |
|
Before Width: | Height: | Size: 71 KiB |
|
Before Width: | Height: | Size: 84 KiB |
|
Before Width: | Height: | Size: 188 KiB |
|
Before Width: | Height: | Size: 189 KiB |
|
Before Width: | Height: | Size: 187 KiB |
|
Before Width: | Height: | Size: 187 KiB |
|
Before Width: | Height: | Size: 187 KiB |
|
Before Width: | Height: | Size: 190 KiB |
|
Before Width: | Height: | Size: 190 KiB |
|
Before Width: | Height: | Size: 190 KiB |
|
Before Width: | Height: | Size: 190 KiB |
|
Before Width: | Height: | Size: 68 KiB |
|
Before Width: | Height: | Size: 80 KiB |
|
Before Width: | Height: | Size: 73 KiB |
|
Before Width: | Height: | Size: 86 KiB |
@@ -0,0 +1,433 @@
|
||||
{
|
||||
"schema": "cognitive-agent-can-semantic-protocol/v1",
|
||||
"version": "1.0.0",
|
||||
"description": "Single source of truth for CAN0/CAN1 semantic commands and transport metadata. Frame encoders and feedback algorithms remain named special handlers when they require stateful closed-loop behavior.",
|
||||
"channels": {
|
||||
"0": {
|
||||
"name": "passenger_seat_can",
|
||||
"frame_format": "classic_can",
|
||||
"bitrate": 500000
|
||||
},
|
||||
"1": {
|
||||
"name": "vehicle_body_can",
|
||||
"frame_format": "mixed",
|
||||
"arbitration_bitrate": 500000,
|
||||
"data_bitrate": 2000000
|
||||
}
|
||||
},
|
||||
"rules": [
|
||||
{
|
||||
"id": "can0.seat.position",
|
||||
"channel": 0,
|
||||
"domain": "seat",
|
||||
"capabilities": [
|
||||
"seat.set_longitudinal_position",
|
||||
"seat.set_cushion_tilt",
|
||||
"seat.set_backrest_recline",
|
||||
"seat.set_legrest_height"
|
||||
],
|
||||
"help": "seat passenger <horizontal|basin|backrest|legrest> position <0-100>",
|
||||
"patterns": [
|
||||
[
|
||||
{"literal": "seat"},
|
||||
{"literal": "passenger"},
|
||||
{"enum": "axis", "values": ["horizontal", "longitudinal", "basin", "height", "backrest", "legrest"]},
|
||||
{"literal": "position"},
|
||||
{"integer": "position_pct", "minimum": 0, "maximum": 100}
|
||||
]
|
||||
],
|
||||
"frames": [
|
||||
{
|
||||
"key": "move",
|
||||
"frame_id": "0x300",
|
||||
"format": "classic_can",
|
||||
"brs": false,
|
||||
"dlc": 8,
|
||||
"template_kind": "can0_motion_fields",
|
||||
"base_payload_hex": "00 10 00 00 00 00 00 00",
|
||||
"fields": {
|
||||
"opcode": {"start_bit": 0, "bit_length": 8, "absolute": 1, "home_zero": 11},
|
||||
"motor": {"start_bit": 8, "bit_length": 2, "values": {"horizontal": 0, "longitudinal": 0, "basin": 1, "height": 1, "backrest": 2, "legrest": 3}},
|
||||
"protocol_version": {"start_bit": 12, "bit_length": 2, "constant": 1},
|
||||
"sequence": {"start_bit": 16, "bit_length": 16, "runtime_allocated": true},
|
||||
"param_a": {"start_bit": 32, "bit_length": 16, "scale": 100, "home_key": 19282},
|
||||
"param_b": {"start_bit": 48, "bit_length": 16, "absolute_timeout_ms": 30000, "home_timeout_s": 120}
|
||||
},
|
||||
"repeat": {"kind": "fixed", "count": 1, "period_ms": 0},
|
||||
"feedback_ids": ["0x301", "0x302"],
|
||||
"feedback_policy": "ack_then_motor_terminal"
|
||||
}
|
||||
],
|
||||
"special_handler": "can0_absolute_position",
|
||||
"evidence": "passenger_firmware_hil_verified"
|
||||
},
|
||||
{
|
||||
"id": "can0.seat.relative",
|
||||
"channel": 0,
|
||||
"domain": "seat",
|
||||
"capabilities": [
|
||||
"seat.set_longitudinal_position",
|
||||
"seat.set_cushion_tilt",
|
||||
"seat.set_backrest_recline",
|
||||
"seat.set_legrest_height"
|
||||
],
|
||||
"help": "seat passenger <axis> relative <direction> <1-100>",
|
||||
"patterns": [
|
||||
[{"literal": "seat"}, {"literal": "passenger"}, {"enum": "axis", "values": ["horizontal", "longitudinal"]}, {"literal": "relative"}, {"enum": "direction", "values": ["forward", "backward"]}, {"integer": "delta_pct", "minimum": 1, "maximum": 100}],
|
||||
[{"literal": "seat"}, {"literal": "passenger"}, {"enum": "axis", "values": ["basin", "height"]}, {"literal": "relative"}, {"enum": "direction", "values": ["up", "down"]}, {"integer": "delta_pct", "minimum": 1, "maximum": 100}],
|
||||
[{"literal": "seat"}, {"literal": "passenger"}, {"literal": "backrest"}, {"literal": "relative"}, {"enum": "direction", "values": ["forward", "backward"]}, {"integer": "delta_pct", "minimum": 1, "maximum": 100}],
|
||||
[{"literal": "seat"}, {"literal": "passenger"}, {"literal": "legrest"}, {"literal": "relative"}, {"enum": "direction", "values": ["up", "down"]}, {"integer": "delta_pct", "minimum": 1, "maximum": 100}]
|
||||
],
|
||||
"frames": [
|
||||
{
|
||||
"key": "move",
|
||||
"frame_id": "0x300",
|
||||
"format": "classic_can",
|
||||
"brs": false,
|
||||
"dlc": 8,
|
||||
"template_kind": "can0_relative_closed_loop_or_timed_fallback",
|
||||
"base_payload_hex": "03 10 00 00 00 00 00 00",
|
||||
"fields": {
|
||||
"closed_loop_opcode": 1,
|
||||
"timed_fallback_opcode": 3,
|
||||
"timed_fallback_max_delta_pct": 15,
|
||||
"direction_values": {"increase": 1, "decrease": 2}
|
||||
},
|
||||
"repeat": {"kind": "fixed", "count": 1, "period_ms": 0},
|
||||
"feedback_ids": ["0x301", "0x302"],
|
||||
"feedback_policy": "fresh_position_then_ack_then_motor_terminal"
|
||||
}
|
||||
],
|
||||
"special_handler": "can0_relative_position",
|
||||
"evidence": "passenger_firmware_hil_verified"
|
||||
},
|
||||
{
|
||||
"id": "can0.seat.thermal",
|
||||
"channel": 0,
|
||||
"domain": "seat",
|
||||
"capabilities": ["seat.set_ventilation", "seat.set_heating"],
|
||||
"help": "seat passenger <vent|heat> <off|low|medium|high>",
|
||||
"patterns": [
|
||||
[{"literal": "seat"}, {"literal": "passenger"}, {"enum": "feature", "values": ["vent", "heat"]}, {"enum": "level", "values": ["off", "low", "medium", "high"]}]
|
||||
],
|
||||
"frames": [
|
||||
{
|
||||
"key": "thermal_mode",
|
||||
"frame_id": "0x3CE",
|
||||
"format": "classic_can",
|
||||
"brs": false,
|
||||
"dlc": 8,
|
||||
"template_kind": "can0_heating_mode_optional",
|
||||
"base_payload_hex": "10 00 00 00 00 00 00 00",
|
||||
"repeat": {"kind": "fixed", "count": 1, "period_ms": 0},
|
||||
"feedback_ids": ["0x4FA"],
|
||||
"optional_when": "heating_on"
|
||||
},
|
||||
{
|
||||
"key": "thermal_control",
|
||||
"frame_id": "0x29E",
|
||||
"format": "classic_can",
|
||||
"brs": false,
|
||||
"dlc": 8,
|
||||
"template_kind": "can0_thermal_bit_fields",
|
||||
"base_payload_hex": "00 00 00 00 00 00 00 00",
|
||||
"repeat": {"kind": "fixed", "count": 1, "period_ms": 0},
|
||||
"feedback_ids": ["0x4FA"],
|
||||
"feedback_policy": "thermal_state_match"
|
||||
}
|
||||
],
|
||||
"special_handler": "can0_thermal_preserve_peer_feature",
|
||||
"evidence": "passenger_firmware_hil_verified"
|
||||
},
|
||||
{
|
||||
"id": "can0.seat.dynamic",
|
||||
"channel": 0,
|
||||
"domain": "seat",
|
||||
"capabilities": ["seat.start_dynamic_mode", "seat.stop_dynamic_mode"],
|
||||
"help": "seat passenger dynamic <rocking-horse|cradle|stop>",
|
||||
"patterns": [
|
||||
[{"literal": "seat"}, {"literal": "passenger"}, {"literal": "dynamic"}, {"enum": "mode", "values": ["rocking-horse", "cradle", "stop"]}],
|
||||
[{"literal": "seat"}, {"literal": "passenger"}, {"literal": "dynamic"}, {"literal": "start"}, {"enum": "mode", "values": ["rocking-horse", "cradle"]}]
|
||||
],
|
||||
"frames": [
|
||||
{
|
||||
"key": "dynamic",
|
||||
"frame_id": "0x300",
|
||||
"format": "classic_can",
|
||||
"brs": false,
|
||||
"dlc": 8,
|
||||
"template_kind": "can0_dynamic_fields",
|
||||
"base_payload_hex": "0E 10 00 00 00 00 00 00",
|
||||
"fields": {"start_opcode": 14, "stop_opcode": 15, "mode_values": {"rocking-horse": 1, "cradle": 2, "stop": 0}},
|
||||
"repeat": {"kind": "fixed", "count": 1, "period_ms": 0},
|
||||
"feedback_ids": ["0x301", "0x306"],
|
||||
"feedback_policy": "ack_then_dynamic_state"
|
||||
}
|
||||
],
|
||||
"special_handler": "can0_dynamic_mode",
|
||||
"evidence": "passenger_firmware_hil_verified"
|
||||
},
|
||||
{
|
||||
"id": "can1.door.rear_lock",
|
||||
"channel": 1,
|
||||
"domain": "door",
|
||||
"capabilities": ["door.set_rear_lock"],
|
||||
"help": "door rear <lock|unlock>",
|
||||
"patterns": [[{"literal": "door"}, {"literal": "rear"}, {"enum": "state", "values": ["lock", "unlock"]}]],
|
||||
"frames": [{"key": "command", "frame_id": "0x32B", "format": "classic_can", "brs": false, "dlc": 8, "template_kind": "bit_fields", "base_payload_hex": "0A 00 00 00 00 00 00 00", "fields": {"state": {"start_bit": 14, "bit_length": 2, "values": {"lock": 1, "unlock": 2}}}, "repeat": {"kind": "fixed", "count": 1, "period_ms": 0}, "feedback_ids": ["0x407"], "feedback_policy": "rear_lock_state_match"}],
|
||||
"evidence": "matrix_candidate_with_feedback"
|
||||
},
|
||||
{
|
||||
"id": "can1.window.motion",
|
||||
"channel": 1,
|
||||
"domain": "window",
|
||||
"capabilities": ["window.set_motion"],
|
||||
"help": "window <all|front|rear|front-left|front-right|rear-left|rear-right> <open|close|stop>",
|
||||
"patterns": [[{"literal": "window"}, {"enum": "target", "values": ["all", "front", "rear", "front-left", "front-right", "rear-left", "rear-right"]}, {"enum": "motion", "values": ["open", "close", "stop"]}]],
|
||||
"frames": [{"key": "command", "frame_id": "0x431", "format": "can_fd", "brs": true, "dlc": 8, "template_kind": "window_motion_bit_fields", "base_payload_hex": "00 00 00 00 00 00 00 00", "fields": {"starts": [48, 56, 51, 59], "motion_values": {"open": 1, "close": 2, "stop": 3}}, "repeat": {"kind": "fixed", "count": 3, "period_ms": 100}, "feedback_ids": ["0x388"], "feedback_policy": "window_state_match"}],
|
||||
"evidence": "vehicle_trace_verified"
|
||||
},
|
||||
{
|
||||
"id": "can1.window.position",
|
||||
"channel": 1,
|
||||
"domain": "window",
|
||||
"capabilities": ["window.set_position"],
|
||||
"help": "window <front-left|front-right|rear-left|rear-right> position <0-100>",
|
||||
"patterns": [[{"literal": "window"}, {"enum": "target", "values": ["front-left", "front-right", "rear-left", "rear-right"]}, {"literal": "position"}, {"integer": "position_pct", "minimum": 0, "maximum": 100}]],
|
||||
"frames": [{"key": "command", "frame_id": "0x431", "format": "can_fd", "brs": true, "dlc": 8, "template_kind": "window_feedback_closed_loop", "base_payload_hex": "00 00 00 00 00 00 00 00", "repeat": {"kind": "special", "count": 1, "period_ms": 0}, "feedback_ids": ["0x388"], "feedback_policy": "fresh_position_then_motion_then_stop"}],
|
||||
"special_handler": "window_position"
|
||||
},
|
||||
{
|
||||
"id": "can1.climate.power",
|
||||
"channel": 1,
|
||||
"domain": "climate",
|
||||
"capabilities": ["climate.set_power", "climate.set_ac"],
|
||||
"help": "ac <on|off>",
|
||||
"patterns": [[{"literal": "ac"}, {"enum": "state", "values": ["on", "off"]}]],
|
||||
"frames": [{"key": "command", "frame_id": "0x1DE", "format": "classic_can", "brs": false, "dlc": 8, "template_kind": "bit_fields", "base_payload_hex": "00 00 00 00 00 00 00 00", "fields": {"state": {"start_bit": 28, "bit_length": 2, "values": {"on": 1, "off": 2}}}, "repeat": {"kind": "fixed", "count": 3, "period_ms": 100}, "feedback_ids": ["0x404"], "feedback_policy": "climate_power_match"}],
|
||||
"evidence": "matrix_and_vehicle_trace_verified"
|
||||
},
|
||||
{
|
||||
"id": "can1.climate.fan",
|
||||
"channel": 1,
|
||||
"domain": "climate",
|
||||
"capabilities": ["climate.set_fan_level"],
|
||||
"help": "ac fan <1-7>",
|
||||
"patterns": [[{"literal": "ac"}, {"literal": "fan"}, {"integer": "level", "minimum": 1, "maximum": 7}]],
|
||||
"frames": [{"key": "command", "frame_id": "0x1DE", "format": "classic_can", "brs": false, "dlc": 8, "template_kind": "bit_fields", "base_payload_hex": "00 00 00 00 00 00 00 00", "fields": {"level": {"start_bit": 4, "bit_length": 4}}, "repeat": {"kind": "fixed", "count": 3, "period_ms": 100}, "feedback_ids": ["0x404"], "feedback_policy": "climate_fan_match"}],
|
||||
"evidence": "matrix_and_vehicle_trace_verified"
|
||||
},
|
||||
{
|
||||
"id": "can1.climate.mode",
|
||||
"channel": 1,
|
||||
"domain": "climate",
|
||||
"capabilities": ["climate.set_outlet_mode"],
|
||||
"help": "ac mode <face|face-feet|feet|feet-defrost|defrost|face-feet-defrost|face-defrost>",
|
||||
"patterns": [[{"literal": "ac"}, {"literal": "mode"}, {"enum": "mode", "values": ["face", "face-feet", "feet", "feet-defrost", "defrost", "face-feet-defrost", "face-defrost"]}]],
|
||||
"frames": [{"key": "command", "frame_id": "0x1DE", "format": "classic_can", "brs": false, "dlc": 8, "template_kind": "bit_fields", "base_payload_hex": "00 00 00 00 00 00 00 00", "fields": {"mode": {"start_bit": 0, "bit_length": 4, "values": {"face": 1, "face-feet": 2, "feet": 3, "feet-defrost": 4, "defrost": 5, "face-feet-defrost": 6, "face-defrost": 7}}}, "repeat": {"kind": "fixed", "count": 3, "period_ms": 100}, "feedback_ids": ["0x404"], "feedback_policy": "climate_mode_match"}],
|
||||
"evidence": "matrix_and_vehicle_trace_verified"
|
||||
},
|
||||
{
|
||||
"id": "can1.climate.temperature",
|
||||
"channel": 1,
|
||||
"domain": "climate",
|
||||
"capabilities": ["climate.set_temperature"],
|
||||
"help": "ac temp <driver|passenger|rear> <18-32>",
|
||||
"patterns": [[{"literal": "ac"}, {"literal": "temp"}, {"enum": "target", "values": ["driver", "passenger", "rear"]}, {"integer": "temperature_c", "minimum": 18, "maximum": 32}]],
|
||||
"frames": [
|
||||
{"key": "front", "frame_id": "0x1DE", "format": "classic_can", "brs": false, "dlc": 8, "template_kind": "climate_temperature", "base_payload_hex": "00 00 00 00 00 00 00 00", "fields": {"starts": {"driver": 32, "passenger": 40}}, "repeat": {"kind": "fixed", "count": 3, "period_ms": 100}, "feedback_ids": ["0x404"], "feedback_policy": "climate_temperature_match"},
|
||||
{"key": "rear", "frame_id": "0x1DE", "format": "classic_can", "brs": false, "dlc": 8, "template_kind": "climate_temperature", "base_payload_hex": "00 00 00 00 00 00 00 00", "fields": {"starts": {"rear": 48}}, "repeat": {"kind": "fixed", "count": 1, "period_ms": 100}, "feedback_ids": ["0x404"], "feedback_policy": "climate_temperature_match"}
|
||||
],
|
||||
"evidence": "matrix_and_vehicle_trace_verified"
|
||||
},
|
||||
{
|
||||
"id": "can1.climate.control",
|
||||
"channel": 1,
|
||||
"domain": "climate",
|
||||
"capabilities": ["climate.set_control_mode"],
|
||||
"help": "ac control <manual|auto>",
|
||||
"patterns": [[{"literal": "ac"}, {"literal": "control"}, {"enum": "mode", "values": ["manual", "auto"]}]],
|
||||
"frames": [{"key": "command", "frame_id": "0x1DE", "format": "classic_can", "brs": false, "dlc": 8, "template_kind": "bit_fields", "base_payload_hex": "00 00 00 00 00 00 00 00", "fields": {"mode": {"start_bit": 16, "bit_length": 2, "values": {"manual": 1, "auto": 2}}}, "repeat": {"kind": "fixed", "count": 3, "period_ms": 100}, "feedback_ids": ["0x404"], "feedback_policy": "climate_control_match"}],
|
||||
"evidence": "matrix_and_vehicle_trace_verified"
|
||||
},
|
||||
{
|
||||
"id": "can1.climate.cycle",
|
||||
"channel": 1,
|
||||
"domain": "climate",
|
||||
"capabilities": ["climate.set_cycle_mode"],
|
||||
"help": "ac cycle <internal|external>",
|
||||
"patterns": [[{"literal": "ac"}, {"literal": "cycle"}, {"enum": "mode", "values": ["internal", "external"]}]],
|
||||
"frames": [{"key": "command", "frame_id": "0x1DE", "format": "classic_can", "brs": false, "dlc": 8, "template_kind": "bit_fields", "base_payload_hex": "00 00 00 00 00 00 00 00", "fields": {"mode": {"start_bit": 19, "bit_length": 2, "values": {"internal": 1, "external": 2}}}, "repeat": {"kind": "fixed", "count": 3, "period_ms": 100}, "feedback_ids": ["0x404"], "feedback_policy": "climate_cycle_match"}],
|
||||
"evidence": "matrix_and_vehicle_trace_verified"
|
||||
},
|
||||
{
|
||||
"id": "can1.outlet.switch",
|
||||
"channel": 1,
|
||||
"domain": "outlet",
|
||||
"capabilities": ["outlet.set_switch_state"],
|
||||
"help": "outlet <driver-left|driver-right|passenger-left|passenger-right> <open|close>",
|
||||
"patterns": [[{"literal": "outlet"}, {"enum": "target", "values": ["driver-left", "driver-right", "passenger-left", "passenger-right"]}, {"enum": "state", "values": ["open", "close"]}]],
|
||||
"frames": [{
|
||||
"key": "command", "frame_id": "0x4EF", "format": "can_fd", "brs": true, "dlc": 8, "template_kind": "static_variant", "base_payload_hex": "00 00 00 00 00 00 00 00",
|
||||
"payload_variants": {
|
||||
"driver-left:open": "02 FF FF FF FF 01 FF FF",
|
||||
"driver-left:close": "02 FF FF FF FF 02 FF FF",
|
||||
"driver-right:open": "02 FF FF FF FF 04 FF FF",
|
||||
"driver-right:close": "02 FF FF FF FF 08 FF FF",
|
||||
"passenger-left:open": "03 FF FF FF FF 01 00 00",
|
||||
"passenger-left:close": "03 FF FF FF FF 02 00 00",
|
||||
"passenger-right:open": "03 FF FF FF FF 04 00 00",
|
||||
"passenger-right:close": "03 FF FF FF FF 08 00 00"
|
||||
},
|
||||
"repeat": {"kind": "fixed", "count": 3, "period_ms": 100}, "feedback_ids": ["0x4BB", "0x37B"], "feedback_policy": "outlet_switch_state_match"
|
||||
}],
|
||||
"evidence": "vehicle_differential_trace_verified"
|
||||
},
|
||||
{
|
||||
"id": "can1.outlet.percent",
|
||||
"channel": 1,
|
||||
"domain": "outlet",
|
||||
"capabilities": ["outlet.set_position_percent"],
|
||||
"help": "outlet <target> percent <0-100> <0-100>",
|
||||
"patterns": [[{"literal": "outlet"}, {"enum": "target", "values": ["driver-left", "driver-right", "passenger-left", "passenger-right"]}, {"literal": "percent"}, {"integer": "horizontal_pct", "minimum": 0, "maximum": 100}, {"integer": "vertical_pct", "minimum": 0, "maximum": 100}]],
|
||||
"frames": [{"key": "command", "frame_id": "0x4EF", "format": "can_fd", "brs": true, "dlc": 8, "template_kind": "outlet_calibrated_coordinates", "base_payload_hex": "00 FF FF FF FF 00 00 00", "repeat": {"kind": "fixed", "count": 3, "period_ms": 100}, "feedback_ids": ["0x2F5", "0x37B"], "feedback_policy": "outlet_position_match"}],
|
||||
"special_handler": "outlet_percent_to_calibrated_position"
|
||||
},
|
||||
{
|
||||
"id": "can1.outlet.position",
|
||||
"channel": 1,
|
||||
"domain": "outlet",
|
||||
"capabilities": ["outlet.set_calibrated_position"],
|
||||
"help": "outlet <target> position <-128..126> <-128..126>",
|
||||
"patterns": [[{"literal": "outlet"}, {"enum": "target", "values": ["driver-left", "driver-right", "passenger-left", "passenger-right"]}, {"literal": "position"}, {"integer": "horizontal_value", "minimum": -128, "maximum": 126}, {"integer": "vertical_value", "minimum": -128, "maximum": 126}]],
|
||||
"frames": [{"key": "command", "frame_id": "0x4EF", "format": "can_fd", "brs": true, "dlc": 8, "template_kind": "outlet_calibrated_coordinates", "base_payload_hex": "00 FF FF FF FF 00 00 00", "repeat": {"kind": "fixed", "count": 3, "period_ms": 100}, "feedback_ids": ["0x2F5", "0x37B"], "feedback_policy": "outlet_position_match"}],
|
||||
"special_handler": "outlet_calibrated_position"
|
||||
},
|
||||
{
|
||||
"id": "can1.seat.driver_thermal",
|
||||
"channel": 1,
|
||||
"domain": "seat",
|
||||
"capabilities": ["seat.set_driver_ventilation_native", "seat.set_driver_heating_native"],
|
||||
"help": "seat driver <vent|heat> <off|low|high>",
|
||||
"patterns": [[{"literal": "seat"}, {"literal": "driver"}, {"enum": "feature", "values": ["vent", "heat"]}, {"enum": "level", "values": ["off", "low", "high"]}]],
|
||||
"frames": [{"key": "command", "frame_id": "0x431", "format": "can_fd", "brs": true, "dlc": 8, "template_kind": "driver_seat_thermal", "base_payload_hex": "00 00 00 00 00 00 00 00", "repeat": {"kind": "fixed", "count": 3, "period_ms": 100}, "feedback_ids": ["0x4FA"], "feedback_policy": "driver_seat_thermal_match"}],
|
||||
"evidence": "vehicle_trace_verified"
|
||||
},
|
||||
{
|
||||
"id": "can1.seat.driver_massage",
|
||||
"channel": 1,
|
||||
"domain": "seat",
|
||||
"capabilities": ["seat.set_driver_massage_native"],
|
||||
"help": "seat driver massage <off|strength weak|medium|strong|mode wave|pulse|stretch|slack|relax>",
|
||||
"patterns": [
|
||||
[{"literal": "seat"}, {"literal": "driver"}, {"literal": "massage"}, {"literal": "off"}],
|
||||
[{"literal": "seat"}, {"literal": "driver"}, {"literal": "massage"}, {"literal": "strength"}, {"enum": "strength", "values": ["weak", "medium", "strong"]}],
|
||||
[{"literal": "seat"}, {"literal": "driver"}, {"literal": "massage"}, {"literal": "mode"}, {"enum": "mode", "values": ["wave", "pulse", "stretch", "slack", "relax"]}]
|
||||
],
|
||||
"frames": [{"key": "command", "frame_id": "0x4C1", "format": "can_fd", "brs": true, "dlc": 8, "template_kind": "driver_seat_massage", "base_payload_hex": "12 00 00 00 00 00 00 00", "repeat": {"kind": "fixed", "count": 3, "period_ms": 100}, "feedback_ids": ["0x4FA"], "feedback_policy": "driver_seat_massage_match"}],
|
||||
"evidence": "vehicle_trace_verified"
|
||||
},
|
||||
{
|
||||
"id": "can1.seat.driver_axis",
|
||||
"channel": 1,
|
||||
"domain": "seat",
|
||||
"capabilities": ["seat.set_driver_axis_native"],
|
||||
"help": "seat driver <horizontal|height|backrest|basin> <direction|stop> [100-2000]",
|
||||
"patterns": [
|
||||
[{"literal": "seat"}, {"literal": "driver"}, {"enum": "axis", "values": ["horizontal", "backrest"]}, {"enum": "direction", "values": ["forward", "backward"]}],
|
||||
[{"literal": "seat"}, {"literal": "driver"}, {"enum": "axis", "values": ["horizontal", "backrest"]}, {"enum": "direction", "values": ["forward", "backward"]}, {"integer": "duration_ms", "minimum": 100, "maximum": 2000}],
|
||||
[{"literal": "seat"}, {"literal": "driver"}, {"enum": "axis", "values": ["height", "basin"]}, {"enum": "direction", "values": ["up", "down"]}],
|
||||
[{"literal": "seat"}, {"literal": "driver"}, {"enum": "axis", "values": ["height", "basin"]}, {"enum": "direction", "values": ["up", "down"]}, {"integer": "duration_ms", "minimum": 100, "maximum": 2000}],
|
||||
[{"literal": "seat"}, {"literal": "driver"}, {"enum": "axis", "values": ["horizontal", "height", "backrest", "basin"]}, {"literal": "stop"}]
|
||||
],
|
||||
"frames": [
|
||||
{"key": "motion", "frame_id": "0x4C1", "format": "can_fd", "brs": true, "dlc": 8, "template_kind": "driver_seat_axis", "base_payload_hex": "05 00 00 00 00 00 00 00", "repeat": {"kind": "duration_ceiling", "count": 0, "period_ms": 100, "default_duration_ms": 500}, "feedback_ids": ["0x494"], "feedback_policy": "activity_then_forced_stop"},
|
||||
{"key": "stop", "frame_id": "0x4C1", "format": "can_fd", "brs": true, "dlc": 8, "template_kind": "static", "base_payload_hex": "05 00 00 00 00 00 00 00", "repeat": {"kind": "fixed", "count": 3, "period_ms": 100}, "feedback_ids": ["0x494"], "feedback_policy": "submitted_stop"}
|
||||
],
|
||||
"special_handler": "driver_seat_axis"
|
||||
},
|
||||
{
|
||||
"id": "can1.seat.driver_memory",
|
||||
"channel": 1,
|
||||
"domain": "seat",
|
||||
"capabilities": ["seat.set_driver_position_native", "seat.recall_driver_memory_native"],
|
||||
"help": "seat driver position <1-3> | seat driver memory recall <1-3>",
|
||||
"patterns": [
|
||||
[{"literal": "seat"}, {"literal": "driver"}, {"literal": "position"}, {"integer": "slot", "minimum": 1, "maximum": 3}],
|
||||
[{"literal": "seat"}, {"literal": "driver"}, {"literal": "memory"}, {"literal": "recall"}, {"integer": "slot", "minimum": 1, "maximum": 3}]
|
||||
],
|
||||
"frames": [{"key": "sequence", "frame_id": "0x4C1", "format": "can_fd", "brs": true, "dlc": 8, "template_kind": "learned_driver_memory_pair", "base_payload_hex": "16 00 00 00 00 00 00 00", "repeat": {"kind": "sequence", "count": 20, "period_ms": 50}, "feedback_ids": ["0x494"], "feedback_policy": "fresh_initialized_status_then_post_status"}],
|
||||
"special_handler": "driver_seat_memory_recall"
|
||||
},
|
||||
{
|
||||
"id": "can1.light.indoor",
|
||||
"channel": 1,
|
||||
"domain": "light",
|
||||
"capabilities": ["interior_light.set_indoor_power"],
|
||||
"help": "light indoor <on|off>",
|
||||
"patterns": [[{"literal": "light"}, {"literal": "indoor"}, {"enum": "state", "values": ["on", "off"]}]],
|
||||
"frames": [{"key": "command", "frame_id": "0x4F5", "format": "can_fd", "brs": true, "dlc": 8, "template_kind": "reading_light_all", "base_payload_hex": "00 00 03 FF FF 00 00 00", "repeat": {"kind": "fixed", "count": 3, "period_ms": 100}, "feedback_ids": ["0x42E"], "feedback_policy": "indoor_light_match"}],
|
||||
"evidence": "vehicle_trace_verified"
|
||||
},
|
||||
{
|
||||
"id": "can1.light.reading_all",
|
||||
"channel": 1,
|
||||
"domain": "light",
|
||||
"capabilities": ["interior_light.set_reading_power"],
|
||||
"help": "light reading all <on|off>",
|
||||
"patterns": [[{"literal": "light"}, {"literal": "reading"}, {"literal": "all"}, {"enum": "state", "values": ["on", "off"]}]],
|
||||
"frames": [{"key": "command", "frame_id": "0x4F5", "format": "can_fd", "brs": true, "dlc": 8, "template_kind": "reading_light_all", "base_payload_hex": "00 00 03 FF FF 00 00 00", "repeat": {"kind": "fixed", "count": 3, "period_ms": 100}, "feedback_ids": ["0x42E"], "feedback_policy": "indoor_light_match"}],
|
||||
"evidence": "vehicle_trace_verified"
|
||||
},
|
||||
{
|
||||
"id": "can1.light.ambient_power",
|
||||
"channel": 1,
|
||||
"domain": "light",
|
||||
"capabilities": ["ambient_light.set_power"],
|
||||
"help": "light ambient <on|off>",
|
||||
"patterns": [[{"literal": "light"}, {"literal": "ambient"}, {"enum": "state", "values": ["on", "off"]}]],
|
||||
"frames": [{"key": "command", "frame_id": "0x3FC", "format": "can_fd", "brs": true, "dlc": 8, "template_kind": "static_variant", "base_payload_hex": "00 00 00 00 00 00 00 00", "payload_variants": {"on": "00 36 00 75 00 80 00 00", "off": "00 31 00 75 00 80 00 00"}, "repeat": {"kind": "fixed", "count": 3, "period_ms": 100}, "feedback_ids": ["0x42E"], "feedback_policy": "ambient_power_match"}],
|
||||
"evidence": "vehicle_trace_verified"
|
||||
},
|
||||
{
|
||||
"id": "can1.light.ambient_color",
|
||||
"channel": 1,
|
||||
"domain": "light",
|
||||
"capabilities": ["ambient_light.set_color_index"],
|
||||
"help": "light ambient color <1-127>",
|
||||
"patterns": [[{"literal": "light"}, {"literal": "ambient"}, {"literal": "color"}, {"integer": "color_index", "minimum": 1, "maximum": 127}]],
|
||||
"frames": [{"key": "command", "frame_id": "0x3FC", "format": "can_fd", "brs": true, "dlc": 8, "template_kind": "ambient_color", "base_payload_hex": "00 30 00 75 00 00 00 00", "repeat": {"kind": "fixed", "count": 3, "period_ms": 100}, "feedback_ids": ["0x42E"], "feedback_policy": "ambient_color_match"}],
|
||||
"evidence": "vehicle_trace_verified"
|
||||
},
|
||||
{
|
||||
"id": "can1.light.ambient_brightness",
|
||||
"channel": 1,
|
||||
"domain": "light",
|
||||
"capabilities": ["ambient_light.set_brightness_level"],
|
||||
"help": "light ambient brightness <1-5>",
|
||||
"patterns": [[{"literal": "light"}, {"literal": "ambient"}, {"literal": "brightness"}, {"integer": "brightness_level", "minimum": 1, "maximum": 5}]],
|
||||
"frames": [{"key": "command", "frame_id": "0x3FC", "format": "can_fd", "brs": true, "dlc": 8, "template_kind": "ambient_brightness", "base_payload_hex": "00 30 00 75 00 00 00 00", "repeat": {"kind": "fixed", "count": 3, "period_ms": 100}, "feedback_ids": ["0x42E"], "feedback_policy": "ambient_brightness_match"}],
|
||||
"evidence": "vehicle_trace_verified"
|
||||
},
|
||||
{
|
||||
"id": "can1.shade.motion",
|
||||
"channel": 1,
|
||||
"domain": "roof",
|
||||
"capabilities": ["roof.set_shade_motion"],
|
||||
"help": "shade <open|close|half|stop>",
|
||||
"patterns": [[{"literal": "shade"}, {"enum": "motion", "values": ["open", "close", "half", "stop"]}]],
|
||||
"frames": [{"key": "command", "frame_id": "0x431", "format": "classic_can", "brs": false, "dlc": 8, "template_kind": "static_variant", "base_payload_hex": "00 00 00 00 00 00 00 00", "payload_variants": {"open": "10 00 00 00 00 00 00 00", "close": "20 00 00 00 00 00 00 00", "half": "30 00 00 00 00 00 00 00", "stop": "40 00 00 00 00 00 00 00"}, "repeat": {"kind": "fixed", "count": 1, "period_ms": 0}, "feedback_ids": ["0x41A"], "feedback_policy": "shade_position_or_stop_submission"}],
|
||||
"special_handler": "shade_preset"
|
||||
},
|
||||
{
|
||||
"id": "can1.shade.position",
|
||||
"channel": 1,
|
||||
"domain": "roof",
|
||||
"capabilities": ["roof.set_shade_position"],
|
||||
"help": "shade position <0-100>",
|
||||
"patterns": [[{"literal": "shade"}, {"literal": "position"}, {"integer": "position_pct", "minimum": 0, "maximum": 100}]],
|
||||
"frames": [{"key": "command", "frame_id": "0x431", "format": "classic_can", "brs": false, "dlc": 8, "template_kind": "shade_feedback_closed_loop", "base_payload_hex": "40 00 00 00 00 00 00 00", "repeat": {"kind": "special", "count": 1, "period_ms": 0}, "feedback_ids": ["0x41A"], "feedback_policy": "fresh_position_then_motion_then_stop"}],
|
||||
"special_handler": "shade_position"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
# Read-only vehicle-state synchronization through ZLG's Linux VCI SDK.
|
||||
# Keep the approval token unset: hardware transmit remains locked.
|
||||
COGNITIVE_AGENT_VEHICLE_CAN_ENABLED=true
|
||||
COGNITIVE_AGENT_VEHICLE_CAN_BACKEND=zlgcan-linux
|
||||
COGNITIVE_AGENT_VEHICLE_CAN_CHANNEL=1
|
||||
COGNITIVE_AGENT_VEHICLE_CAN_REQUIRED_CHANNEL=1
|
||||
COGNITIVE_AGENT_VEHICLE_CAN_ARBITRATION_BITRATE=500000
|
||||
COGNITIVE_AGENT_VEHICLE_CAN_DATA_BITRATE=2000000
|
||||
COGNITIVE_AGENT_VEHICLE_CAN_TERMINATION_ENABLED=false
|
||||
COGNITIVE_AGENT_ZLGCAN_DEVICE_TYPE=33
|
||||
COGNITIVE_AGENT_ZLGCAN_DEVICE_INDEX=0
|
||||
COGNITIVE_AGENT_ZLGCAN_LINUX_LIBRARY=/home/orin/project511/project-code/canfd/libusbcanfd.so
|
||||
COGNITIVE_AGENT_SHARED_CAN_RUNTIME_ENABLED=false
|
||||
|
||||
# Local NanoMQ wireless dual-CAN relay: CAN0 is the passenger seat; CAN1 is the
|
||||
# rest of the vehicle. The local relay is executable by default; set the MQTT
|
||||
# approval flag below to true and configure the shared approval token when a
|
||||
# deployment needs an additional server-side transmit gate.
|
||||
COGNITIVE_AGENT_VEHICLE_MQTT_ENABLED=true
|
||||
COGNITIVE_AGENT_VEHICLE_MQTT_APPROVAL_TOKEN_REQUIRED=false
|
||||
COGNITIVE_AGENT_VEHICLE_MQTT_HOST=127.0.0.1
|
||||
COGNITIVE_AGENT_VEHICLE_MQTT_PORT=1883
|
||||
COGNITIVE_AGENT_VEHICLE_MQTT_CONDITION_TOPIC=n7/n7-headunit/can/state
|
||||
COGNITIVE_AGENT_VEHICLE_MQTT_CONTROL_TOPIC=n7/n7-headunit/can/command
|
||||
COGNITIVE_AGENT_VEHICLE_MQTT_QOS=1
|
||||
@@ -0,0 +1,24 @@
|
||||
# Linux USBCANFD-200U wired dual-channel N7 runtime.
|
||||
COGNITIVE_AGENT_VEHICLE_CAN_ENABLED=true
|
||||
COGNITIVE_AGENT_VEHICLE_CAN_BACKEND=zlgcan-linux
|
||||
COGNITIVE_AGENT_VEHICLE_CAN_CHANNEL=1
|
||||
COGNITIVE_AGENT_VEHICLE_CAN_REQUIRED_CHANNEL=1
|
||||
COGNITIVE_AGENT_VEHICLE_CAN_ARBITRATION_BITRATE=500000
|
||||
COGNITIVE_AGENT_VEHICLE_CAN_DATA_BITRATE=2000000
|
||||
COGNITIVE_AGENT_VEHICLE_CAN_TERMINATION_ENABLED=false
|
||||
|
||||
COGNITIVE_AGENT_WIRED_PASSENGER_CAN_ENABLED=true
|
||||
COGNITIVE_AGENT_SEAT_CAN_BACKEND=zlgcan-linux
|
||||
COGNITIVE_AGENT_SEAT_CAN_CHANNEL=0
|
||||
COGNITIVE_AGENT_SEAT_CAN_BITRATE=500000
|
||||
COGNITIVE_AGENT_SEAT_CAN_TERMINATION_ENABLED=false
|
||||
COGNITIVE_AGENT_SEAT_AUTO_FLASH_ENABLED=false
|
||||
COGNITIVE_AGENT_SEAT_POSITION_SYNC_ENABLED=false
|
||||
|
||||
COGNITIVE_AGENT_ZLGCAN_DEVICE_TYPE=33
|
||||
COGNITIVE_AGENT_ZLGCAN_DEVICE_INDEX=0
|
||||
COGNITIVE_AGENT_ZLGCAN_LINUX_LIBRARY=/home/orin/project511/project-code/canfd/libusbcanfd.so
|
||||
COGNITIVE_AGENT_SHARED_CAN_RUNTIME_ENABLED=false
|
||||
|
||||
# Local supervised bench only. Keep token approval enabled for shared/remote use.
|
||||
COGNITIVE_AGENT_HARDWARE_APPROVAL_TOKEN_REQUIRED=false
|
||||