refactor(motor): P1 拆分 main.js + 收敛连接/总线状态机
R4 外提 scope/ota/seq/conn-poll;R5 waitVersion/queryNodeIdParam 下沉 transport;R6 ecat-bus 单点 bootstrap;R7 toast-stack + utils 去重。 main.js 4647→~1894 行。?v= 已 bump 20260924a。
This commit is contained in:
+24
-56
@@ -18,6 +18,10 @@
|
||||
import {
|
||||
getDeviceIp, saveDeviceIp, getBaseUrl as baseUrlFromIp
|
||||
} from "./base-url.js";
|
||||
import {
|
||||
runEcatBootstrap, repairEcatDc, getEcatAdapterOrDefault,
|
||||
ECAT_DEFAULT_ADAPTER,
|
||||
} from "./ecat-bus.js";
|
||||
|
||||
var CH_NAME = "dcu-device-link";
|
||||
var ESP32_FAIL_ONLINE = 3; /* 连续失败 ≥3 判离线 */
|
||||
@@ -28,7 +32,8 @@ var ecatDcGuardBusy = false; /* DC/周期自愈 in-flight */
|
||||
var LS_ECAT_PERIOD = "dcu_ecat_period_ms";
|
||||
var LS_ECAT_SPIN = "dcu_ecat_spin";
|
||||
var LS_ECAT_ADAPTER = "dcu_ecat_adapter";
|
||||
var DEFAULT_ECAT_ADAPTER = "I210";
|
||||
/* R6:网卡默认常量只在 ecat-bus.js 定义;此处 re-export 保持旧 import 路径可用 */
|
||||
var DEFAULT_ECAT_ADAPTER = ECAT_DEFAULT_ADAPTER;
|
||||
|
||||
function nowMs() { return Date.now(); }
|
||||
|
||||
@@ -45,7 +50,7 @@ function readAdapter() {
|
||||
var s = localStorage.getItem(LS_ECAT_ADAPTER);
|
||||
if (s && s.trim()) return s.trim();
|
||||
} catch (_) {}
|
||||
return DEFAULT_ECAT_ADAPTER;
|
||||
return getEcatAdapterOrDefault();
|
||||
}
|
||||
|
||||
function writeAdapter(substr) {
|
||||
@@ -165,13 +170,8 @@ function createOwner() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 开总线:health →(未就绪则)status →(未开则)open 网卡 → motor/start 进 OP + 起 PDO 循环。
|
||||
* 与 motor/transport-ecat ensureOpen/ensureStarted 同源,由外壳 Owner 在
|
||||
* 控制台启动时强制执行,用户不必先去电机页把链路切到 EtherCAT。
|
||||
*
|
||||
* 已健康(bus_open + loop)时**直接复用**,不打 motor/start:
|
||||
* 那条路由会先 loop_stop 再重进 OP,和电机页探测撞车时会假超时
|
||||
* (横幅 signal timed out)并平白增加 SSC 楔死风险。
|
||||
* 开总线:R6 —— 策略只在 js/common/ecat-bus.js(health→open→motor/start,
|
||||
* DC 250µs,已健康则复用)。外壳 Owner 启动时强制执行,用户不必先去电机页。
|
||||
*/
|
||||
function bootstrapEcatBus() {
|
||||
if (stopped || ecatBusBusy) return;
|
||||
@@ -182,47 +182,22 @@ function createOwner() {
|
||||
ecatBusNextTryAt = now + ECAT_BUS_RETRY_MS;
|
||||
|
||||
var adapter = readAdapter();
|
||||
var body = {};
|
||||
var period = null;
|
||||
var spin = null;
|
||||
try {
|
||||
var v = parseFloat(localStorage.getItem(LS_ECAT_PERIOD));
|
||||
/* 无显式值 / 值过慢 → 固定 0.25ms。1ms+DC 会让发送出口回到 ~1s。 */
|
||||
if (v > 0 && v <= 0.5) body.period_ms = v;
|
||||
else body.period_ms = 0.25;
|
||||
period = parseFloat(localStorage.getItem(LS_ECAT_PERIOD));
|
||||
var sp = localStorage.getItem(LS_ECAT_SPIN);
|
||||
if (sp === "0") body.spin = false;
|
||||
else if (sp === "1") body.spin = true;
|
||||
} catch (_) { body.period_ms = 0.25; }
|
||||
/* EtherCAT 控制必须 DC SYNC0≈PDO 周期,且周期应保持 250µs 档 */
|
||||
{
|
||||
var per = Number(body.period_ms) || 0.25;
|
||||
if (per > 0.5) per = 0.25;
|
||||
body.period_ms = per;
|
||||
var us = Math.round(per * 1000);
|
||||
if (us < 250) us = 250;
|
||||
body.dc_cycle_us = us;
|
||||
body.dc_shift_us = 0;
|
||||
}
|
||||
if (sp === "0") spin = false;
|
||||
else if (sp === "1") spin = true;
|
||||
} catch (_) {}
|
||||
|
||||
ecatPost("native/health", {}, 3000).then(function (h) {
|
||||
if (h && h.ok && h.bus_open && h.loop) {
|
||||
ecatBusReady = true;
|
||||
return null; /* 已在跑:跳过 open + motor/start */
|
||||
}
|
||||
return ecatPost("status", {}, 6000).then(function (st) {
|
||||
var open = !!(st && st.ok);
|
||||
return open ? Promise.resolve(st)
|
||||
: ecatPost("open", { substr: adapter }, 20000);
|
||||
}).then(function (r) {
|
||||
if (r && r.ok === false) {
|
||||
throw new Error((r.log && r.log.join(" / ")) || "open 失败");
|
||||
}
|
||||
return ecatPost("motor/start", body, 30000);
|
||||
});
|
||||
runEcatBootstrap({
|
||||
ecatPost: ecatPost,
|
||||
adapter: adapter,
|
||||
period_ms: period,
|
||||
spin: spin,
|
||||
}).then(function (r) {
|
||||
if (r && r.ok === false) {
|
||||
throw new Error((r.log && r.log.join(" / ")) || "motor/start 失败");
|
||||
}
|
||||
if (r) ecatBusReady = true;
|
||||
if (r && r.ok) ecatBusReady = true;
|
||||
}).catch(function () {
|
||||
/* 网线没插/从站未上电:退避后由 pollEcat 再触发 */
|
||||
}).then(function () {
|
||||
@@ -250,18 +225,10 @@ function createOwner() {
|
||||
if (e.busOpen && e.loop) ecatBusReady = true;
|
||||
else if (ecatBusReady && !e.busOpen) ecatBusReady = false; /* 总线掉了 → 允许重开 */
|
||||
publish();
|
||||
/* 自愈:DC/周期被配错时发送出口秒级 —— 2s 轮询里拉回 250µs */
|
||||
/* 自愈:DC/周期被配错时发送出口秒级 —— R6 单点 repairEcatDc */
|
||||
if (e.busOpen && e.loop && !ecatDcGuardBusy) {
|
||||
ecatDcGuardBusy = true;
|
||||
ecatPost("native/health", {}, 2000).then(function (h) {
|
||||
if (!h || !h.ok) return null;
|
||||
var dcs = Number(h.dc_cycle_us);
|
||||
var per = Number(h.period_ms);
|
||||
if (h.dc === 1 && dcs === 250 && (h.period_ms == null || Math.abs(per - 0.25) < 0.001)) return null;
|
||||
return ecatPost("motor/start", {
|
||||
period_ms: 0.25, dc_cycle_us: 250, dc_shift_us: 0
|
||||
}, 30000);
|
||||
}).catch(function () {}).then(function () {
|
||||
repairEcatDc(ecatPost).catch(function () {}).then(function () {
|
||||
ecatDcGuardBusy = false;
|
||||
});
|
||||
}
|
||||
@@ -410,4 +377,5 @@ try {
|
||||
|
||||
deviceLink = createClient();
|
||||
export { deviceLink, ecatPost, readAdapter as getEcatAdapter, writeAdapter as setEcatAdapter };
|
||||
export { ECAT_DEFAULT_ADAPTER };
|
||||
export default deviceLink;
|
||||
|
||||
Reference in New Issue
Block a user