feat(ble): 完善BLE OTA架构并优化性能
- 实现BLE OTA数据路径分离:添加ble_ota_data.cpp处理重排序/工作线程/DATA_IN, 和ble_ota_host.cpp处理GATT/GAP/广播/主机功能 - 将滑动ACK窗口从32增大到64,实测Windows WebBT环境下固件传输速度提升约10% (从40KB/s提升到44KB/s),内存消耗约30KB重排序缓冲区 - 优化调试日志级别,将OTA相关信息从INFO调整为DBG以减少日志冗余 refactor(can): 改进CAN反馈监听机制 - 将CAN反馈任务从1Hz主动轮询模式改为被动事件监听模式, 使用SpiMaster::takeEvent()替代主动发送0xC1轮询请求 - 更新相关头文件注释说明架构变更,将"周期性轮询"改为"被动接收推送" - 修改调试日志级别,将暂停/恢复状态日志从INFO调整为DBG
This commit is contained in:
+26
-24
@@ -2,8 +2,9 @@
|
||||
* can_monitor.js - CAN 接收监控(独立页 can_monitor.html 与 can.html 右侧抽屉共用)
|
||||
*/
|
||||
import { showToast } from './common/toast.js?v=20260717x';
|
||||
import { escapeHtml } from './common/utils.js';
|
||||
|
||||
var state = { fbTimer: null, fbAbortCtrl: null };
|
||||
var state = { fbTimer: null, fbInFlight: false };
|
||||
|
||||
var el = {};
|
||||
|
||||
@@ -27,11 +28,6 @@ function cacheElements() {
|
||||
ids.forEach(function (id) { el[id] = document.getElementById(id); });
|
||||
}
|
||||
|
||||
function sanitize(text) {
|
||||
return String(text == null ? '' : text)
|
||||
.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
||||
}
|
||||
|
||||
function getBaseUrl() {
|
||||
var ip = '';
|
||||
if (el.monIp && el.monIp.value) {
|
||||
@@ -63,15 +59,18 @@ function setConnState(ok, text) {
|
||||
|
||||
// ── 1Hz 轮询 /can/feedback ─────────────────────────────────
|
||||
async function pollFeedback() {
|
||||
if (state.fbAbortCtrl) { try { state.fbAbortCtrl.abort(); } catch (_e) {} }
|
||||
state.fbAbortCtrl = new AbortController();
|
||||
var fbPollTimer = setTimeout(function () { try { state.fbAbortCtrl.abort(); } catch (_e) {} }, 3000);
|
||||
// 防重入:上一次 fetch 未完成则跳过本次 tick,避免并发请求叠加
|
||||
if (state.fbInFlight) return;
|
||||
state.fbInFlight = true;
|
||||
var ac = new AbortController();
|
||||
var timer = setTimeout(function () { ac.abort(); }, 3000);
|
||||
try {
|
||||
var resp = await fetch(getBaseUrl() + '/can/feedback', { signal: state.fbAbortCtrl.signal });
|
||||
var resp = await fetch(getBaseUrl() + '/can/feedback', { signal: ac.signal });
|
||||
if (!resp.ok) return;
|
||||
var data = await resp.json();
|
||||
var channels = data.channels || [];
|
||||
var selectedCh = el.idsnapChannel ? parseInt(el.idsnapChannel.value, 10) : 0;
|
||||
if (!Number.isFinite(selectedCh)) selectedCh = 0;
|
||||
|
||||
for (var i = 0; i < 3; i++) {
|
||||
var ch = channels[i];
|
||||
@@ -84,7 +83,7 @@ async function pollFeedback() {
|
||||
|
||||
var sel = channels[selectedCh];
|
||||
if (sel && sel.valid && sel.entries) {
|
||||
renderIdTable(sel.entries, sel.count || sel.entries.length);
|
||||
renderIdTable(sel.entries);
|
||||
if (el.idsnapStatus) {
|
||||
el.idsnapStatus.textContent = (sel.entries.length) + ' 个 ID';
|
||||
el.idsnapStatus.className = 'pill online';
|
||||
@@ -98,15 +97,16 @@ async function pollFeedback() {
|
||||
el.fbPollStatus.className = 'pill online';
|
||||
}
|
||||
setConnState(true, '已连接');
|
||||
clearTimeout(fbPollTimer);
|
||||
} catch (e) {
|
||||
clearTimeout(fbPollTimer);
|
||||
if (e && e.name === 'AbortError') return;
|
||||
if (el.fbPollStatus) {
|
||||
el.fbPollStatus.textContent = '轮询: 离线';
|
||||
el.fbPollStatus.className = 'pill offline';
|
||||
}
|
||||
setConnState(false, '连接失败');
|
||||
} finally {
|
||||
clearTimeout(timer);
|
||||
state.fbInFlight = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,20 +183,22 @@ function renderIdTable(entries) {
|
||||
tbody.innerHTML = '<tr><td colspan="7" class="status-empty">无数据(CAN 未收到帧)</td></tr>';
|
||||
return;
|
||||
}
|
||||
var html = '';
|
||||
var frag = document.createDocumentFragment();
|
||||
for (var i = 0; i < entries.length; i++) {
|
||||
var e = entries[i];
|
||||
html += '<tr>';
|
||||
html += '<td>' + (i + 1) + '</td>';
|
||||
html += '<td class="mono">' + sanitize(e.id) + '</td>';
|
||||
html += '<td>' + e.dlc + '</td>';
|
||||
html += '<td class="' + (e.fd ? 'flag-on' : 'flag-off') + '">' + (e.fd ? 'Y' : '-') + '</td>';
|
||||
html += '<td class="' + (e.brs ? 'flag-on' : 'flag-off') + '">' + (e.brs ? 'Y' : '-') + '</td>';
|
||||
html += '<td class="' + (e.esi ? 'flag-on' : 'flag-off') + '">' + (e.esi ? 'Y' : '-') + '</td>';
|
||||
html += '<td class="idsnap-data mono">' + sanitize(e.data || '--') + '</td>';
|
||||
html += '</tr>';
|
||||
var tr = document.createElement('tr');
|
||||
tr.innerHTML =
|
||||
'<td>' + (i + 1) + '</td>' +
|
||||
'<td class="mono">' + escapeHtml(e.id) + '</td>' +
|
||||
'<td>' + escapeHtml(e.dlc) + '</td>' +
|
||||
'<td class="' + (e.fd ? 'flag-on' : 'flag-off') + '">' + (e.fd ? 'Y' : '-') + '</td>' +
|
||||
'<td class="' + (e.brs ? 'flag-on' : 'flag-off') + '">' + (e.brs ? 'Y' : '-') + '</td>' +
|
||||
'<td class="' + (e.esi ? 'flag-on' : 'flag-off') + '">' + (e.esi ? 'Y' : '-') + '</td>' +
|
||||
'<td class="idsnap-data mono">' + escapeHtml(e.data || '--') + '</td>';
|
||||
frag.appendChild(tr);
|
||||
}
|
||||
tbody.innerHTML = html;
|
||||
tbody.innerHTML = '';
|
||||
tbody.appendChild(frag);
|
||||
}
|
||||
|
||||
function renderIdTableEmpty() {
|
||||
|
||||
Reference in New Issue
Block a user