feat(ecat): PDO 快发 ESF1 桌面强制直通,堵死慢发回落

桌面 APP 下 ECAT motor 发送只走 pywebview ESF1→native TCP;
删除桥内 HTTP/JSON 回落。附延迟测量与 pack 自测脚本与规格文档。
This commit is contained in:
cbb
2026-09-21 02:11:49 +08:00
parent 383535bd1d
commit 2c6235d920
13 changed files with 1267 additions and 21 deletions
+14 -7
View File
@@ -174,9 +174,10 @@ if (liveOk) {
typeof ecat.takeNodeIdReport === "function" && ecat.takeNodeIdReport(7) === null);
const dbg = ecat.debug();
check("debug() 暴露 PDO 周期与槽位统计",
dbg && typeof dbg.slots === "number" && dbg.slotsPerPdo === 5 &&
dbg.slotCount === 27 && dbg.scanCycles === 6, JSON.stringify(dbg && {
periodMs: dbg.periodMs, slots: dbg.slots }));
dbg && typeof dbg.slots === "number" && dbg.slotsPerPdo === 9 &&
dbg.slotCount === 27 && dbg.scanCycles === 1, JSON.stringify(dbg && {
periodMs: dbg.periodMs, slots: dbg.slots, slotsPerPdo: dbg.slotsPerPdo,
scanCycles: dbg.scanCycles }));
}
/* ── 10. 代理错误信封可读 ── 指向一个没人监听的端口 */
@@ -259,23 +260,29 @@ section("[8] 快照→契约翻译(构造快照,跑生产代码)");
st.motors[0].config_data === CONFIG_HEX,
`len=${st.motors[0].config_data.length}`);
/* (d) 版本(0x00FF):累积且 seq 递增 —— 上层靠 seq 增长判"这是本次查询的新应答" */
/* (d) 版本(0x00FF):累积且 seq 递增 —— 上层靠 seq 增长判"这是本次查询的新应答"。
* fetchMotorState 对 rx drain 有 DRAIN_MIN_MS 节流;构造用例必须等过节流窗,
* 否则测的是节流而不是版本累积器。 */
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
const VER_HEX = "1A00" + "0200" + "0300" + "0400" + "00".repeat(16);
await sleep(25);
rxFrames = [{ ch: 1, dlc: 24, valid: true, id: (3 << 16) | 0x00FF, data: VER_HEX }];
snap = mkSnap([{ slot: 0, node: 3, ch: 1, online: true, dlc: 48, seq: 503, data: STATUS_HEX }],
{ rx_batch: { count: 1, lost: 0, pending: 0, frames: [] } });
await tp.fetchMotorState();
const v1 = await tp.fetchVersionNode(3);
check("(d) 版本应答被累积", v1 && v1.node === 3 && v1.version === VER_HEX);
await sleep(25);
rxFrames = [{ ch: 1, dlc: 24, valid: true, id: (3 << 16) | 0x00FF, data: VER_HEX }];
snap = mkSnap([{ slot: 0, node: 3, ch: 1, online: true, dlc: 48, seq: 504, data: STATUS_HEX }],
{ rx_batch: { count: 1, lost: 0, pending: 0, frames: [] } });
await tp.fetchMotorState();
const v2 = await tp.fetchVersionNode(3);
check("(d) 再收一次 → seq 递增(上层据此判新应答)", v2.seq === v1.seq + 1,
`${v1.seq} → ${v2.seq}`);
check("(d) 再收一次 → seq 递增(上层据此判新应答)", v2 && v1 && v2.seq === v1.seq + 1,
`${v1 && v1.seq} → ${v2 && v2.seq}`);
/* (e) 节点 ID 应答:取走即清 */
/* (e) 节点 ID 应答:取走即清(同样要等过 DRAIN_MIN_MS) */
await sleep(25);
rxFrames = [{ ch: 1, dlc: 2, valid: true, id: (3 << 16) | 0x0401, data: "0700" }];
snap = mkSnap([{ slot: 0, node: 3, ch: 1, online: true, dlc: 48, seq: 505, data: STATUS_HEX }],
{ rx_batch: { count: 1, lost: 0, pending: 0, frames: [] } });