feat: redesign bench calibration (factor/offset), add Ttank/P2 displays, fix sensor calibration

- Replace P1-P6 rational transfer function with factor/offset model for bench params
- Add explicit rx/tx direction flags in bench XML configuration
- Add T.Tank (BenchTemp) and P2 (AnalogSensor2) to temperature/pressure display
- Apply SensorConfiguration calibration to pressure channels, fix empty sensors.xml fallback
- Add live value labels to flowmeter charts
- Hide pump live values and PSG encoder standalone label
- Add K-Line connection state model, improve KWP service and status displays
- Restructure .claude/skills into subdirectory format

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-14 21:25:30 +02:00
parent 4964806de1
commit 4891eb6812
20 changed files with 881 additions and 185 deletions

View File

@@ -0,0 +1,69 @@
# KWP/FTDI edit checklist
You are about to edit timing-sensitive K-Line communication code in one of:
- `Infrastructure/Kwp/KwpCommon.cs`
- `Infrastructure/Kwp/KW1281Connection.cs`
- `Infrastructure/Kwp/FtdiInterface.cs`
- `Services/Impl/KwpService.cs`
Read the relevant file(s) first, then apply the following checks before and after your edit.
---
## Timing constraints
**`KW1281Connection.SendPacket`** calls `Thread.Sleep(5)` after each byte written.
This is the mandatory KWP inter-byte gap. Do not remove or reduce it.
**`KwpCommon.WakeUp`** implements the 5-baud slow-init sequence.
Any change to Sleep durations here will break ECU connection. Leave it alone unless
you are explicitly fixing a timing bug and have the KW1281 spec in front of you.
---
## FtdiInterface lifetime
`KwpService` constructs a `FtdiInterface` at the start of each operation and disposes it
at the end. This is intentional — the ECU expects a fresh session per dialog.
Do not try to hold `FtdiInterface` open across multiple `KwpService` calls.
`FtdiInterface._buf` is a reused `byte[1]` field for single-byte reads/writes.
Do not allocate a new array inside `ReadByte()` or `WriteByteRaw()`.
---
## Error handling invariant
Every `KwpService` method that opens an `FtdiInterface` must dispose it in all code paths:
```csharp
FtdiInterface? iface = null;
try
{
iface = new FtdiInterface(port, KLineBaudRate);
// ... work ...
}
catch (Exception ex) { /* log */ }
finally { iface?.Dispose(); }
```
If you add a new KwpService method, verify it follows this pattern.
K-Line errors throw `InvalidOperationException` or `TimeoutException`.
Do not catch and swallow these inside the method body — the ViewModel catch block depends on seeing them.
---
## Allocation patterns (known debt — do not worsen)
`KW1281Connection` uses `List<byte>` for packet buffers throughout.
If you want to reduce allocations, convert the entire packet path at once.
Converting one method in isolation creates a mixed pattern that is harder to reason about.
---
## After your edit, verify:
1. Search for `new FtdiInterface` — every occurrence has a matching `finally { iface?.Dispose(); }`
2. `Thread.Sleep(5)` in `SendPacket` is still present
3. `ProgressChanged` is still called with increasing percent values so the progress dialog updates
4. No new `Thread.Sleep`, `Console.Write`, or `Logger.WriteLine` was added inside a per-byte loop