feat: restore bench section UI with controls, PID RPM ramp, flowmeter charts, and fix CAN IDs
Restore the full bench control panel from the old source with MVVM architecture: - Two-column left panel layout: bench info displays (RPM with target/voltage, temps, pressures, Q-flow, pump live values) and user commands (direction toggle, start/stop with RPM popup and quick-select buttons, oil pump toggle, turn downcounter with CAN send) - PID RPM ramp controller (BenchPidController) with bumpless startup, anti-windup, and derivative-on-measurement for smooth motor speed transitions - Real-time flowmeter charts (LiveChartsCore) for Q-Delivery and Q-Over with tolerance band overlays - Bench/pump CAN liveness detection in PcanAdapter (receive-only IDs) - K-Line connection status indicator (placeholder) - Periodic relay bitmask sender (~21ms) and ElectronicMsg keepalive start on CAN connect, pump sender starts immediately on pump load Fix critical CAN message ID bug: default bench XML values were incorrectly converted from old source (decimal-notation hex parsed as actual hex digits, e.g. "10" -> "A" instead of keeping "10" which parses as 0x10). Corrected all IDs to match hardware: 0x10, 0x11, 0x13, 0x14, 0x15, 0x50, 0x51, 0x55. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -48,11 +48,27 @@ namespace HC_APTBS.Infrastructure.Pcan
|
||||
private AutoResetEvent? _receiveEvent;
|
||||
private volatile bool _stopRead = true;
|
||||
|
||||
// ── Liveness tracking ────────────────────────────────────────────────────
|
||||
|
||||
private const int LivenessTimeoutMs = 500;
|
||||
private HashSet<uint> _benchMessageIds = new();
|
||||
private HashSet<uint> _pumpMessageIds = new();
|
||||
private DateTime _lastBenchFrameUtc = DateTime.MinValue;
|
||||
private DateTime _lastPumpFrameUtc = DateTime.MinValue;
|
||||
private bool _benchAlive;
|
||||
private bool _pumpAlive;
|
||||
|
||||
// ── ICanService ──────────────────────────────────────────────────────────
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event Action<string, bool>? StatusChanged;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event Action<bool>? BenchLivenessChanged;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event Action<bool>? PumpLivenessChanged;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public TPCANStatus CurrentStatus { get; private set; } = TPCANStatus.PCAN_ERROR_OK;
|
||||
|
||||
@@ -186,6 +202,18 @@ namespace HC_APTBS.Infrastructure.Pcan
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void RegisterBenchMessageIds(IReadOnlyCollection<uint> ids)
|
||||
{
|
||||
_benchMessageIds = new HashSet<uint>(ids);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void RegisterPumpMessageIds(IReadOnlyCollection<uint> ids)
|
||||
{
|
||||
_pumpMessageIds = new HashSet<uint>(ids);
|
||||
}
|
||||
|
||||
// ── ICanService: transmit ─────────────────────────────────────────────────
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -289,6 +317,9 @@ namespace HC_APTBS.Infrastructure.Pcan
|
||||
EmitStatusChanged(status);
|
||||
}
|
||||
|
||||
// Check liveness timeouts.
|
||||
CheckLivenessTimeout();
|
||||
|
||||
// Configurable polling interval to avoid pegging the CPU.
|
||||
// Typical value: 2–50 ms depending on operational phase.
|
||||
Thread.Sleep(2);
|
||||
@@ -336,6 +367,27 @@ namespace HC_APTBS.Infrastructure.Pcan
|
||||
|
||||
if (!snapshot.TryGetValue(frame.ID, out var parameters)) return;
|
||||
|
||||
// Track liveness for bench and pump frame groups.
|
||||
var now = DateTime.UtcNow;
|
||||
if (_benchMessageIds.Contains(frame.ID))
|
||||
{
|
||||
_lastBenchFrameUtc = now;
|
||||
if (!_benchAlive)
|
||||
{
|
||||
_benchAlive = true;
|
||||
BenchLivenessChanged?.Invoke(true);
|
||||
}
|
||||
}
|
||||
if (_pumpMessageIds.Contains(frame.ID))
|
||||
{
|
||||
_lastPumpFrameUtc = now;
|
||||
if (!_pumpAlive)
|
||||
{
|
||||
_pumpAlive = true;
|
||||
PumpLivenessChanged?.Invoke(true);
|
||||
}
|
||||
}
|
||||
|
||||
byte[] data = frame.DATA;
|
||||
|
||||
foreach (var param in parameters)
|
||||
@@ -472,6 +524,27 @@ namespace HC_APTBS.Infrastructure.Pcan
|
||||
return raw;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if bench or pump frame reception has timed out and fires
|
||||
/// liveness events on transition from alive to dead.
|
||||
/// </summary>
|
||||
private void CheckLivenessTimeout()
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
|
||||
if (_benchAlive && (now - _lastBenchFrameUtc).TotalMilliseconds > LivenessTimeoutMs)
|
||||
{
|
||||
_benchAlive = false;
|
||||
BenchLivenessChanged?.Invoke(false);
|
||||
}
|
||||
|
||||
if (_pumpAlive && (now - _lastPumpFrameUtc).TotalMilliseconds > LivenessTimeoutMs)
|
||||
{
|
||||
_pumpAlive = false;
|
||||
PumpLivenessChanged?.Invoke(false);
|
||||
}
|
||||
}
|
||||
|
||||
// ── IIR low-pass filter ───────────────────────────────────────────────────
|
||||
|
||||
/// <summary>
|
||||
|
||||
Reference in New Issue
Block a user