feat(config): 优化NimBLE配置以节省内存并提升OTA性能

- 启用BLE连接事件长度优化,允许单CE内传输多包,提升OTA吞吐
- 缩减NimBLE mbuf池配置,单连接OTA场景节省约7KB内存
- 禁用未使用的标准GATT服务,仅保留自定义OTA service,节省8-15KB
- 缩减NimBLE传输缓冲区配置以优化内存使用

refactor(debug_log): 重构环形日志缓冲区API以支持逐条弹出

- 新增ringPopOldest方法,支持弹出最旧日志并从缓冲区移除
- 重构ringDrainJson实现,基于新的逐条弹出机制
- 改进日志转义处理逻辑,支持更多特殊字符转义

perf(tasks): 优化各任务栈大小配置以节省内存

- 将ota_relay任务栈从12288字节缩减至6144字节
- 将ble_ota任务栈从8192字节缩减至4096字节
- 将ble_ota数据工作线程栈从8192字节缩减至4096字节
- 通过栈高水位监控验证实际使用情况,确保安全余量

feat(monitor): 添加任务句柄获取接口以支持系统状态监控

- 为HealthMonitor、OtaRelay、BleOta和WifiOta类添加任务句柄获取方法
- 在任务入口处记录当前任务句柄
- 便于系统状态监控和调试信息收集

feat(status): 扩展系统状态API以提供更详细的内存和任务信息

- 增加内部堆和默认堆的详细统计信息
- 添加各关键任务的栈使用情况监控
- 扩展/system/status端点返回更全面的系统资源使用情况
- 包含最大空闲块、最小空闲内存等关键指标
This commit is contained in:
小龙虾
2026-06-20 00:46:04 +08:00
parent 59c729d77a
commit 3fff959a2b
18 changed files with 701 additions and 103 deletions
+212
View File
@@ -116,6 +116,12 @@ body::before {
text-transform: uppercase; letter-spacing: .06em;
}
.card-head .ico { font-size: 15px; }
.card-head-btn {
margin-left: auto;
padding: 4px 10px;
position: relative;
z-index: 2;
}
.card-body { padding: 16px 18px; }
.card.collapsed .card-body { display: none; }
.card-head { cursor: pointer; }
@@ -326,6 +332,211 @@ select option { background: var(--bg-panel); color: var(--text); }
}
.metric .v.highlight { color: var(--accent); }
.status-kv-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 10px;
}
.status-kv {
background: var(--bg-elevated);
border: 1px solid var(--border);
border-radius: var(--radius-sm);
padding: 10px 12px;
}
.status-kv .k {
display: block;
font-size: 10px;
color: var(--text-label);
text-transform: uppercase;
letter-spacing: .08em;
margin-bottom: 4px;
}
.status-kv b {
display: block;
color: var(--text);
font-size: 13px;
font-weight: 700;
word-break: break-word;
font-family: var(--font-mono);
}
.status-section-title { margin-top: 14px; margin-bottom: 8px; font-size: 11px; color: var(--text-label); text-transform: uppercase; letter-spacing: .08em; }
/* ===== 堆概况 ===== */
.heap-group {
background: rgba(255,255,255,0.02);
border: 1px solid var(--border);
border-radius: 8px;
padding: 12px 14px;
margin-bottom: 10px;
}
.heap-group:last-child { margin-bottom: 0; }
.heap-group-title {
font-size: 11px;
font-weight: 600;
color: var(--text-label);
text-transform: uppercase;
letter-spacing: 0.06em;
margin-bottom: 10px;
}
.heap-bar-row {
display: flex;
align-items: center;
gap: 10px;
}
.heap-bar-text {
font-size: 13px;
font-weight: 600;
white-space: nowrap;
min-width: 165px;
color: var(--text);
}
.heap-bar-track {
flex: 1;
height: 14px;
background: rgba(255,255,255,0.06);
border-radius: 7px;
overflow: hidden;
position: relative;
}
.heap-bar-fill {
display: block;
height: 100%;
border-radius: 7px;
background: linear-gradient(90deg, var(--accent), #5eead4);
transition: width .4s ease;
.heap-bar-fill.warn {
background: linear-gradient(90deg, #f59e0b, #d97706);
}
.heap-bar-fill.danger {
background: linear-gradient(90deg, #ef4444, #dc2626);
}
}
.heap-bar-pct {
font-size: 12px;
font-weight: 600;
min-width: 42px;
text-align: right;
font-variant-numeric: tabular-nums;
color: var(--text-dim);
}
.heap-detail-row {
display: flex;
gap: 16px;
font-size: 11px;
color: var(--text-dim);
margin-top: 6px;
padding-top: 6px;
border-top: 1px solid rgba(255,255,255,0.04);
flex-wrap: wrap;
}
.heap-detail-row span {
display: inline-flex;
align-items: center;
gap: 4px;
}
.heap-detail-row b {
color: var(--text);
font-weight: 500;
font-family: var(--font-mono);
font-size: 11px;
}
.status-task-list {
display: grid;
gap: 8px;
}
.status-task {
background: var(--bg-elevated);
border: 1px solid var(--border);
border-radius: var(--radius-sm);
padding: 10px 12px;
}
.status-task-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 10px;
margin-bottom: 8px;
}
.status-task-name {
font-size: 12px;
font-weight: 700;
color: var(--text);
font-family: var(--font-mono);
}
.status-task-ratio {
font-size: 11px;
color: var(--text-dim);
font-family: var(--font-mono);
}
.status-task-bar {
width: 100%;
height: 8px;
border-radius: 999px;
background: var(--bg-input);
overflow: hidden;
margin-bottom: 8px;
}
.status-task-bar-fill {
height: 100%;
border-radius: 999px;
background: linear-gradient(90deg, #22d3ee, #06b6d4);
}
.status-task-bar-fill.warn {
background: linear-gradient(90deg, #f59e0b, #d97706);
}
.status-task-bar-fill.err {
background: linear-gradient(90deg, #ef4444, #dc2626);
}
.status-task-meta {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 8px;
}
.status-task-meta span {
display: block;
font-size: 10px;
color: var(--text-label);
text-transform: uppercase;
letter-spacing: .06em;
}
.status-task-meta b {
display: block;
margin-top: 2px;
color: var(--text);
font-size: 11px;
font-family: var(--font-mono);
}
.status-json {
margin-top: 0;
padding: 12px;
border-radius: var(--radius-sm);
border: 1px solid var(--border);
background: var(--bg-elevated);
color: var(--text-dim);
font-size: 11px;
line-height: 1.6;
max-height: 280px;
overflow: auto;
white-space: pre-wrap;
word-break: break-word;
font-family: var(--font-mono);
}
.status-empty {
padding: 12px;
border: 1px dashed var(--border);
border-radius: var(--radius-sm);
color: var(--text-dim);
font-size: 12px;
}
/* === PRIMARY STATUS BADGES (large) === */
.badge-grid {
display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px;
@@ -662,6 +873,7 @@ code { color: #d3f9ff; font-family: var(--font-mono); }
.container { padding: 16px; }
.header-bar { flex-direction: column; align-items: flex-start; }
.badge-grid, .metric-grid { grid-template-columns: 1fr; }
.status-kv-grid, .status-task-meta { grid-template-columns: 1fr; }
.can-grid { grid-template-columns: 1fr 1fr; }
.btn-row { flex-direction: column; }
}