initial commit
This commit is contained in:
17
.claude/settings.json
Normal file
17
.claude/settings.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"hooks": {
|
||||
"PreToolUse": [
|
||||
{
|
||||
"matcher": "Edit|Write",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "python3 -c \"\nimport sys, json\ndata = json.load(sys.stdin)\nfp = data.get('tool_input', {}).get('file_path', '')\nif 'PcanBasic.cs' in fp or '/old_source/' in fp or 'old_source/' in fp:\n print(json.dumps({'decision': 'block', 'reason': 'PROTECTED FILE: PcanBasic.cs is a vendor file and old_source/ is archived reference. Neither should be modified.'}))\n sys.exit(1)\n\"",
|
||||
"timeout": 5,
|
||||
"statusMessage": "Checking protected files..."
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
28
.claude/settings.local.json
Normal file
28
.claude/settings.local.json
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(dotnet:*)",
|
||||
"Bash(xargs ls:*)",
|
||||
"Bash(ls \"C:\\\\Users\\\\herli\\\\Documents\\\\ClaudeProjects\\\\HC_APTBS\\\\Resources\\\\Native\"\" 2>/dev/null || echo \"Directory not found \")",
|
||||
"Bash(grep -r \"PumpId\\\\|Pump.*Selector\\\\|PumpCombo\" /c/Users/herli/Documents/ClaudeProjects/HC_APTBS --include=*.cs --include=*.xaml)",
|
||||
"Bash(grep -r \"Pumps\\\\|PumpID\" /c/Users/herli/Documents/ClaudeProjects/HC_APTBS/old_source --include=*.cs --include=*.xaml)",
|
||||
"Bash(grep -r \"GetDevices\\\\|GetPorts\\\\|SerialPort\\\\|FindPort\\\\|ListPorts\" /c/Users/herli/Documents/ClaudeProjects/HC_APTBS/old_source --include=*.cs)",
|
||||
"Bash(grep -l \"PumpDefinition\\\\|BenchConfiguration\" /c/Users/herli/Documents/ClaudeProjects/HC_APTBS/Models/*.cs)",
|
||||
"Bash(find C:/Users/herli/Documents/ClaudeProjects/HC_APTBS/old_source -name *.xml -o -name *.dat -o -name *.data)",
|
||||
"Bash(find C:/Users/herli/Documents/ClaudeProjects/HC_APTBS/old_source -name data.herlic -o -name data* -type f)",
|
||||
"Bash(mkdir -p \"C:/Users/herli/.HC_APTBS/config\")",
|
||||
"Bash(cp \"C:/Users/herli/AppData/Roaming/Local/ConfigH/nuevaconfig.xml\" \"C:/Users/herli/.HC_APTBS/config/pumps.xml\")",
|
||||
"Bash(xargs grep:*)",
|
||||
"Bash(grep -r \"KlineKeys\\\\|class.*Kline\" C:UsersherliDocumentsClaudeProjectsHC_APTBS --include=*.cs)",
|
||||
"Bash(grep -r \"DetectKLinePort\\\\|GetKLinePort\" C:UsersherliDocumentsClaudeProjectsHC_APTBS --include=*.cs)",
|
||||
"Bash(python3)",
|
||||
"Bash(ls \"C:\\\\Users\\\\herli\\\\.claude\\\\settings\"*)",
|
||||
"Bash(find \"C:\\\\Users\\\\herli\\\\Documents\\\\ClaudeProjects\\\\HC_APTBS\" -name \"*.cs\" -not -path \"*/old_source/*\" -not -path \"*/obj/*\" -not -path \"*/bin/*\" -exec wc -l {} +)",
|
||||
"Skill(update-config)",
|
||||
"Skill(update-config:*)",
|
||||
"Bash(echo \"exit: $?\")",
|
||||
"Bash(python3 -c ':*)",
|
||||
"Bash(python3 -c \"import json; f=open\\('C:/Users/herli/Documents/ClaudeProjects/HC_APTBS/.claude/settings.json'\\); d=json.load\\(f\\); print\\('Valid JSON'\\); print\\('Hook command:', d['hooks']['PreToolUse'][0]['hooks'][0]['command'][:50]+'...'\\)\")"
|
||||
]
|
||||
}
|
||||
}
|
||||
20
.claude/skills/build.md
Normal file
20
.claude/skills/build.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# Build HC_APTBS
|
||||
|
||||
Build the WPF application targeting Windows x64.
|
||||
|
||||
## Steps
|
||||
|
||||
1. Run the build from the solution root:
|
||||
|
||||
```bash
|
||||
dotnet build -r win-x64 "C:/Users/herli/Documents/ClaudeProjects/HC_APTBS/HC_APTBS.slnx"
|
||||
```
|
||||
|
||||
2. Parse the output:
|
||||
- If the build **succeeds**: report the number of warnings (if any) and confirm success.
|
||||
- If the build **fails**: list each error with file path and line number, then suggest fixes.
|
||||
|
||||
## Notes
|
||||
- Always use `-r win-x64` — native DLLs (`PCANBasic.dll`, `ftd2xx.dll`) are x64 Windows binaries.
|
||||
- SDK version is pinned in `global.json`. Do not modify it.
|
||||
- There is no test project. Build success is the only automated check.
|
||||
69
.claude/skills/kwp-review.md
Normal file
69
.claude/skills/kwp-review.md
Normal 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
|
||||
74
.claude/skills/protocol-ref.md
Normal file
74
.claude/skills/protocol-ref.md
Normal file
@@ -0,0 +1,74 @@
|
||||
# VP44 Protocol Reference
|
||||
|
||||
Quick reference for hardware protocol constants used in HC_APTBS. Consult this before modifying any protocol-related code.
|
||||
|
||||
---
|
||||
|
||||
## DFI encoding (EEPROM address 0x0044 on VP44 ECU)
|
||||
|
||||
**Read (raw byte → DFI value):**
|
||||
```csharp
|
||||
dfi = (sbyte)raw * 3.0 / 256.0
|
||||
```
|
||||
|
||||
**Write (DFI value → raw byte):**
|
||||
```csharp
|
||||
raw = (sbyte)((dfi * 256.0f) / 3.0f)
|
||||
// If raw == 0, use 1 — the ECU rejects zero
|
||||
```
|
||||
|
||||
**Checksum:**
|
||||
```csharp
|
||||
checksum = (byte)(0 - (byte)rawValue)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## IIR low-pass filter (PcanAdapter.PassFilterUpdate)
|
||||
|
||||
```csharp
|
||||
result = Math.Round(prev + alpha * (value - prev), 4)
|
||||
```
|
||||
|
||||
Used to smooth CAN bus sensor readings. The `alpha` coefficient controls responsiveness vs. noise rejection.
|
||||
|
||||
---
|
||||
|
||||
## OEM legitimation (PcanAdapter.Connect)
|
||||
|
||||
```csharp
|
||||
token = (20120378UL << 32) | 21200UL
|
||||
```
|
||||
|
||||
Sent as a CAN frame to authenticate with the bench controller. Without this, the bench ignores all commands.
|
||||
|
||||
---
|
||||
|
||||
## K-Line / KWP timing
|
||||
|
||||
**Inter-byte delay** (`KW1281Connection.SendPacket`):
|
||||
```csharp
|
||||
Thread.Sleep(5) // after each byte — KWP protocol requirement, NOT a workaround
|
||||
```
|
||||
|
||||
**5-baud slow-init** (`KwpCommon.WakeUp`):
|
||||
- Bit-bangs the ECU address at 5 baud on the K-Line
|
||||
- Sleep durations in WakeUp are protocol-mandated — do not change
|
||||
|
||||
**Session lifetime**:
|
||||
- One `FtdiInterface` open/close per KWP operation
|
||||
- ECU expects a fresh session per dialog — do not pool connections
|
||||
|
||||
---
|
||||
|
||||
## CAN bus (PCAN-Basic, 500 kbps)
|
||||
|
||||
- Channel: `PCAN_USBBUS1`
|
||||
- Baud: `PCAN_BAUD_500K`
|
||||
- Read thread polls with `Thread.Sleep(2)` in `DrainMessageQueue` (known debt)
|
||||
|
||||
---
|
||||
|
||||
## Caution
|
||||
|
||||
Do not change any of these values without understanding the hardware protocol specification. Incorrect values can cause ECU communication failures or bench malfunction.
|
||||
Reference in New Issue
Block a user