Files
HC_APTBS/Services/IKwpService.cs
LucianoDev 827b811b39 feat: developer tools page, auto-test orchestrator, BIP display, tests redesign
Bundles several feature streams that have been iterating on the working tree:

- Developer Tools page (Debug-only via DEVELOPER_TOOLS symbol): hosts the
  identification card, manual KWP write + transaction log, ROM/EEPROM dump
  card with progress banner and completion message, persisted custom-commands
  library, persisted EEPROM passwords library. New service primitives:
  IKwpService.SendRawCustomAsync / ReadEepromAsync / ReadRomEepromAsync.
  Persistence mirrors the Clients XML pattern in two new files
  (custom_commands.xml, eeprom_passwords.xml).
- Auto-test orchestrator (IAutoTestOrchestrator + AutoTestState): linear
  K-Line read -> unlock -> bench-on -> test sequence with snackbar UI and
  progress dialog VM, gated on dashboard alarms.
- BIP-STATUS display: BipDisplayViewModel + BipDisplayView, RAM read at
  0x0106 via IKwpService.ReadBipStatusAsync; status definitions in
  BipStatusDefinition.
- Tests page redesign: TestSectionCard + PhaseTileView replacing the old
  TestPlanView/TestRunningView/TestDoneView/TestPreconditionsView/
  TestSectionView controls and their VMs.
- Pump command sliders: Fluent thick-track style with overhang thumb,
  click-anywhere-and-drag, mouse-wheel adjustment.
- Window startup: app.manifest declares PerMonitorV2 DPI awareness,
  MainWindow installs a WM_GETMINMAXINFO hook in OnSourceInitialized and
  maximizes there (after the hook is in place) so the app fits the work
  area exactly on any display configuration.
- Misc: PercentToPixelsConverter, seed_aliases.py one-shot pump-alias
  importer, tools/Import-BipStatus.ps1, kline_eeprom_spec.md and
  dump-functions reference docs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-07 13:59:50 +02:00

215 lines
12 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using HC_APTBS.Models;
namespace HC_APTBS.Services
{
/// <summary>
/// Provides KWP2000 / KW1281 diagnostics operations over the ISO K-Line
/// via an FTDI USB-to-K-Line adapter.
/// </summary>
public interface IKwpService
{
// ── Session lifecycle ─────────────────────────────────────────────────────
/// <summary>Current state of the persistent K-Line session.</summary>
KLineConnectionState KLineState { get; }
/// <summary>
/// Raised whenever the K-Line session state transitions.
/// Fires on a background thread; consumers must marshal to the UI thread.
/// </summary>
event Action<KLineConnectionState>? KLineStateChanged;
/// <summary>
/// Opens a persistent K-Line session: performs 5-baud slow-init,
/// reads ECU info, then starts a background keep-alive loop (~1 s interval).
/// </summary>
/// <param name="port">FTDI serial number or COM port identifier.</param>
/// <param name="ct">Cancellation token.</param>
Task ConnectAsync(string port, CancellationToken ct = default);
/// <summary>
/// Stops the keep-alive loop, sends EndCommunication to the ECU,
/// and disposes the FTDI interface.
/// </summary>
void Disconnect();
// ── Progress reporting ────────────────────────────────────────────────────
/// <summary>
/// Raised during long operations to report completion percentage and a status message.
/// Always marshalled to the UI thread by the implementation.
/// </summary>
event Action<int, string>? ProgressChanged;
// ── Full ECU read ─────────────────────────────────────────────────────────
/// <summary>
/// Connects to the pump ECU over K-Line and reads all available identification data,
/// fault codes, DFI value, serial number, and software versions.
/// </summary>
/// <param name="port">FTDI serial number or COM port identifier.</param>
/// <param name="pumpVersion">KWP protocol variant (0=V1, 1=V2, 2=V3/V4).</param>
/// <param name="ct">Cancellation token.</param>
/// <returns>
/// Dictionary with keys from <see cref="HC_APTBS.Models.KlineKeys"/>.
/// The <c>result</c> key is "1" on success, "0" on failure.
/// </returns>
Task<Dictionary<string, string>> ReadAllInfoAsync(
string port, int pumpVersion, CancellationToken ct = default);
// ── DTC operations ────────────────────────────────────────────────────────
/// <summary>Reads all current diagnostic trouble codes from the ECU.</summary>
/// <param name="port">FTDI serial number or COM port identifier.</param>
/// <param name="ct">Cancellation token.</param>
/// <returns>Formatted fault code string, or "No fault codes".</returns>
Task<string> ReadFaultCodesAsync(string port, CancellationToken ct = default);
/// <summary>Clears all diagnostic trouble codes and returns the post-clear state.</summary>
/// <param name="port">FTDI serial number or COM port identifier.</param>
/// <param name="ct">Cancellation token.</param>
/// <returns>Post-clear fault code string.</returns>
Task<string> ClearFaultCodesAsync(string port, CancellationToken ct = default);
// ── DFI calibration ───────────────────────────────────────────────────────
/// <summary>Reads the current DFI calibration angle from EEPROM address 0x0044.</summary>
/// <param name="port">FTDI serial number or COM port identifier.</param>
/// <param name="ct">Cancellation token.</param>
/// <returns>DFI value in degrees as a formatted string.</returns>
Task<string> ReadDfiAsync(string port, CancellationToken ct = default);
/// <summary>
/// Writes a new DFI calibration angle to EEPROM address 0x0044.
/// </summary>
/// <param name="port">FTDI serial number or COM port identifier.</param>
/// <param name="dfi">Target DFI angle (degrees, range ±1.45°).</param>
/// <param name="version">KWP protocol variant (selects the authentication password).</param>
/// <param name="ct">Cancellation token.</param>
/// <returns>Verified DFI value read back from EEPROM after the write.</returns>
Task<string> WriteDfiAsync(
string port, float dfi, int version, CancellationToken ct = default);
/// <summary>
/// Writes DFI to EEPROM, then triggers a pump power cycle via
/// <see cref="PumpDisconnectRequested"/> / <see cref="PumpReconnectRequested"/>
/// to activate the new calibration.
/// </summary>
Task<string> WriteDfiAndRestartAsync(
string port, float dfi, int version, CancellationToken ct = default);
// ── Device detection ──────────────────────────────────────────────────────
/// <summary>
/// Enumerates connected FTDI USB devices and returns the serial number of the
/// first one found, or <see langword="null"/> if none are connected.
/// </summary>
string? DetectKLinePort();
/// <summary>
/// The FTDI serial number of the device that is currently holding an open
/// K-Line session, or <see langword="null"/> when no session is active.
/// </summary>
string? ConnectedPort { get; }
// ── Mid-read notifications ────────────────────────────────────────────
/// <summary>
/// Raised during <see cref="ReadAllInfoAsync"/> as soon as the pump identifier
/// string has been read from ROM, before the full read completes.
/// Fires on a background thread; consumers must marshal to the UI thread.
/// </summary>
event Action<string>? PumpIdentified;
/// <summary>
/// Raised during <see cref="ReadAllInfoAsync"/> when the DFI calibration
/// value has been read from EEPROM. Parameter is the DFI angle in degrees.
/// Fires on a background thread; consumers must marshal to the UI thread.
/// </summary>
event Action<double>? DfiRead;
// ── Fast immobilizer unlock ───────────────────────────────────────────────
/// <summary>
/// Attempts a fast immobilizer unlock by sending a KWP custom command
/// over an existing K-Line session. The RAM address byte written by the
/// command is selected by <paramref name="unlockType"/>: <c>1</c> → <c>0xA8</c>,
/// <c>2</c> → <c>0xE8</c>. Any other value is rejected and returns
/// <see langword="false"/>.
/// </summary>
/// <param name="unlockType">Pump unlock variant (1 or 2).</param>
/// <returns>
/// <see langword="true"/> when the command was acknowledged,
/// <see langword="false"/> on NAK, no active session, or unsupported type.
/// </returns>
Task<bool> TryFastUnlockAsync(int unlockType);
// ── Raw custom KWP packet (developer use) ─────────────────────────────────
/// <summary>
/// Sends a raw KWP1281 custom packet over the persistent K-Line session and
/// returns the bytes of every response packet. The supplied <paramref name="payload"/>
/// is the title byte plus body — framing (length + counter + end byte) is added
/// by the lower-level transport.
///
/// <para>Returns an empty list when no session is active or the send fails.
/// Used by the Developer Tools page; never called from production paths.</para>
/// </summary>
/// <param name="payload">Packet bytes excluding length/counter/end framing.</param>
/// <param name="ct">Cancellation token.</param>
/// <returns>Each response packet's full byte sequence (length…end inclusive).</returns>
Task<IReadOnlyList<byte[]>> SendRawCustomAsync(byte[] payload, CancellationToken ct = default);
/// <summary>
/// Reads <paramref name="count"/> bytes from EEPROM starting at <paramref name="address"/>
/// over the persistent K-Line session (KWP <c>ReadEeprom</c> command 0x19).
/// Returns an empty list when no session is active or the ECU returns NAK.
/// Used by the Developer Tools page's dumper; max 13 bytes per call.
/// </summary>
Task<IReadOnlyList<byte>> ReadEepromAsync(ushort address, byte count, CancellationToken ct = default);
/// <summary>
/// Reads <paramref name="count"/> bytes from ROM/EEPROM starting at <paramref name="address"/>
/// over the persistent K-Line session (KWP <c>ReadRomEeprom</c> command 0x03).
/// Valid range 0x00000x9FFF. Returns an empty list when no session is active or
/// the ECU returns NAK. Used by the Developer Tools page's dumper; max 13 bytes per call.
/// </summary>
Task<IReadOnlyList<byte>> ReadRomEepromAsync(ushort address, byte count, CancellationToken ct = default);
// ── BIP status ────────────────────────────────────────────────────────────
/// <summary>
/// Reads the 16-bit BIP status word from ECU RAM address <c>0x0106</c>
/// (<c>ADR-S_BIP_HW_UW</c>) over the persistent K-Line session.
/// Returns <see langword="null"/> when no session is active or if the read fails.
/// </summary>
/// <param name="ct">Cancellation token.</param>
Task<ushort?> ReadBipStatusAsync(CancellationToken ct = default);
/// <summary>
/// Raised after a successful <see cref="ReadBipStatusAsync"/> call with the
/// raw 16-bit BIP status word. Fires on a background thread;
/// consumers must marshal to the UI thread.
/// </summary>
event Action<ushort>? BipStatusRead;
// ── Power cycle callbacks ─────────────────────────────────────────────────
/// <summary>
/// Raised when the service needs the bench to cut power to the pump
/// (e.g. after a DFI write) before reconnecting.
/// </summary>
event Action? PumpDisconnectRequested;
/// <summary>
/// Raised after <see cref="PumpDisconnectRequested"/> when the service needs
/// the bench to restore power and re-establish the K-Line session.
/// </summary>
event Action? PumpReconnectRequested;
}
}