feat(can): 添加跨通道CAN突发发送功能支持多电机同步驱动
- 新增 /can/send_burst HTTP接口,支持一次SPI事务批量发送多帧CAN消息 - 实现canFdSendBurst函数,通过0xC7 SPI类型实现背靠背装载各通道邮箱 - 添加canBurstCapacity函数计算单次突发最大帧数限制 - 突发发送期间暂停can_feedback_task避免SPI抢占冲突 refactor(can_feedback_task): 改造为周期查询+事件消费模式 - 0xC4/0xC5从GD32主动推送改为ESP32周期查询(250ms/1s) - 0xC6/0xD2仍保留事件驱动推送模式,由任务消费处理 - 消除OTA期间GD32悬空按铃导致的超时刷屏问题 - 电机OTA期间也暂停任务避免与0xD1抢夺SPI资源 perf(ota_relay): 增加重发次数上限提升传输可靠性 - 将kMaxDataSends从3次增加到5次,提高数据包传输成功率 chore(version): 更新固件版本号至0.3.78 - 版本查询checkVersionWait移到tickInFlight释放后异步触发 - 避免/motor/version请求拖长tick导致tickStuck误报通道闪黄
This commit is contained in:
+39
-2
@@ -111,8 +111,45 @@ export async function abortTask() {
|
||||
}
|
||||
|
||||
export function bindEvents() {
|
||||
els.connectBtn.addEventListener('click', connectBle);
|
||||
els.disconnectBtn.addEventListener('click', disconnectBle);
|
||||
if (els.bleConnectToggle) {
|
||||
// launch 风格按钮:用 click 而非 change 触发——navigator.bluetooth.requestDevice
|
||||
// 必须在 user gesture 内调用,change 事件不被识别为 user gesture,会报
|
||||
// "Must be handling a user gesture to show a permission request."
|
||||
// preventDefault 阻止 label 默认勾选,checked 由 setConnectionState 按实际结果驱动。
|
||||
els.bleConnectToggle.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
if (state._bleConnecting) return; // 连接进行中,忽略重复点击
|
||||
var btn = document.querySelector('.ble-launch-btn');
|
||||
if (state.server) {
|
||||
els.bleConnectToggle.checked = false;
|
||||
if (btn) btn.setAttribute('data-ble-state', 'idle');
|
||||
disconnectBle(); // → resetUiAfterDisconnect 置 idle
|
||||
} else {
|
||||
state._bleConnecting = true;
|
||||
els.bleConnectToggle.checked = true; // 即时视觉反馈
|
||||
if (btn) btn.setAttribute('data-ble-state', 'connecting');
|
||||
// 连接结束后按实际结果收口:成功→connected / 失败→idle
|
||||
// 不依赖 state.js 的 setConnectionState(ES 模块子导入可能被浏览器缓存为旧版)
|
||||
connectBle().finally(() => {
|
||||
state._bleConnecting = false;
|
||||
var b = document.querySelector('.ble-launch-btn');
|
||||
if (b) b.setAttribute('data-ble-state', state.server ? 'connected' : 'idle');
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 兜底:自动断开(onDisconnected)、重连等路径绕过 click handler,
|
||||
// 用轮询同步 data-ble-state,确保按钮状态始终与 state.server 一致。
|
||||
setInterval(function() {
|
||||
if (state._bleConnecting) return; // 连接中不干扰
|
||||
var btn = document.querySelector('.ble-launch-btn');
|
||||
if (!btn || !btn.offsetParent) return; // 按钮不可见(WiFi 模式)时跳过
|
||||
var expected = state.server ? 'connected' : 'idle';
|
||||
if (btn.getAttribute('data-ble-state') !== expected) {
|
||||
btn.setAttribute('data-ble-state', expected);
|
||||
}
|
||||
}, 800);
|
||||
}
|
||||
els.autoFlashBtn.addEventListener('click', autoFlash);
|
||||
els.abortBtn.addEventListener('click', abortTask);
|
||||
// 上传区事件由 app.js 的 setupSharedUploadZone 统一处理
|
||||
|
||||
+10
-4
@@ -38,8 +38,7 @@ export const state = {
|
||||
|
||||
export const $ = (id) => document.getElementById(id);
|
||||
export const els = {
|
||||
connectBtn: $('connectBtn'),
|
||||
disconnectBtn: $('disconnectBtn'),
|
||||
bleConnectToggle: $('bleConnectToggle'),
|
||||
autoFlashBtn: $('autoFlashBtn'),
|
||||
abortBtn: $('abortBtn'),
|
||||
uploadZone: $('uploadZone'),
|
||||
@@ -129,8 +128,15 @@ export function setConnectionState(connected) {
|
||||
}
|
||||
if (els.gattState) els.gattState.textContent = connected ? 'GATT 已就绪' : '未就绪';
|
||||
}
|
||||
els.connectBtn.disabled = connected;
|
||||
els.disconnectBtn.disabled = !connected;
|
||||
// launch 风格按钮:checked 与 data-ble-state 由连接结果驱动
|
||||
// connecting 态由点击时设置;此处仅在连接结束(成功→connected / 失败→idle)时收口
|
||||
if (els.bleConnectToggle) {
|
||||
if (els.bleConnectToggle.checked !== connected) {
|
||||
els.bleConnectToggle.checked = !!connected;
|
||||
}
|
||||
}
|
||||
var btn = document.querySelector('.ble-launch-btn');
|
||||
if (btn) btn.setAttribute('data-ble-state', connected ? 'connected' : 'idle');
|
||||
els.autoFlashBtn.disabled = !idle;
|
||||
els.abortBtn.disabled = !state.uploading;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user