feat: redesign dashboard with Fluent KPI tiles, connection strip, and devices column
- Replace LCD-style readings with a 3×2 KPI tile grid (Fluent card surfaces, 52pt values) - Add persistent top connection strip with horizontal chips + pump name badge - Add elapsed test timer (DispatcherTimer, mm:ss) to Test Summary card - Restyle Test Summary and Active Alarms with Fluent brushes/iconography - Add Devices column (CAN / K-Line / Bench tiles) between KPI grid and test/alarms - Enumerates attached PCAN USB channels via PCAN_ATTACHED_CHANNELS API - Enumerates FTDI K-Line adapters via existing FtdiInterface helpers - Click to connect/disconnect; confirmation dialog when session active or test running - Hover tint: blue = will connect, red = will disconnect; Bench row is read-only stub - Extend ICanService with SelectedChannel + EnumerateAttachedChannels() - Expose IKwpService.ConnectedPort for active session device tracking - Add DeviceRow button style with MultiDataTrigger hover colour logic - Add 30+ new localization keys (ES + EN) for KPI labels, devices, confirmations Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -31,7 +31,7 @@ namespace HC_APTBS.Infrastructure.Pcan
|
||||
|
||||
// ── State ────────────────────────────────────────────────────────────────
|
||||
|
||||
private readonly TPCANHandle _channel;
|
||||
private TPCANHandle _channel;
|
||||
private TPCANBaudrate _baudrate;
|
||||
private readonly IAppLogger _log;
|
||||
|
||||
@@ -75,6 +75,19 @@ namespace HC_APTBS.Infrastructure.Pcan
|
||||
/// <inheritdoc/>
|
||||
public bool IsConnected => !_stopRead;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public TPCANHandle SelectedChannel
|
||||
{
|
||||
get => _channel;
|
||||
set
|
||||
{
|
||||
if (IsConnected)
|
||||
throw new System.InvalidOperationException(
|
||||
"Cannot change the CAN channel while connected. Call Disconnect() first.");
|
||||
_channel = value;
|
||||
}
|
||||
}
|
||||
|
||||
// ── Construction ─────────────────────────────────────────────────────────
|
||||
|
||||
/// <summary>
|
||||
@@ -91,6 +104,45 @@ namespace HC_APTBS.Infrastructure.Pcan
|
||||
_log = logger;
|
||||
}
|
||||
|
||||
// ── ICanService: discovery ────────────────────────────────────────────────
|
||||
|
||||
/// <inheritdoc/>
|
||||
public System.Collections.Generic.IReadOnlyList<AttachedPcanChannel> EnumerateAttachedChannels()
|
||||
{
|
||||
var result = new System.Collections.Generic.List<AttachedPcanChannel>();
|
||||
try
|
||||
{
|
||||
var countStatus = PCANBasic.GetValue(
|
||||
PCANBasic.PCAN_NONEBUS,
|
||||
TPCANParameter.PCAN_ATTACHED_CHANNELS_COUNT,
|
||||
out uint count,
|
||||
sizeof(uint));
|
||||
|
||||
if (countStatus != TPCANStatus.PCAN_ERROR_OK || count == 0)
|
||||
return result;
|
||||
|
||||
var buffer = new TPCANChannelInformation[count];
|
||||
var infoStatus = PCANBasic.GetValue(
|
||||
PCANBasic.PCAN_NONEBUS,
|
||||
TPCANParameter.PCAN_ATTACHED_CHANNELS,
|
||||
buffer);
|
||||
|
||||
if (infoStatus != TPCANStatus.PCAN_ERROR_OK)
|
||||
return result;
|
||||
|
||||
foreach (var ch in buffer)
|
||||
{
|
||||
if (ch.device_type == TPCANDevice.PCAN_USB)
|
||||
result.Add(new AttachedPcanChannel(ch.channel_handle, ch.device_name ?? $"PCAN-USB ({ch.channel_handle:X})"));
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.Warning(LogId, $"EnumerateAttachedChannels failed: {ex.Message}");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// ── ICanService: lifecycle ────────────────────────────────────────────────
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
||||
Reference in New Issue
Block a user