Files
HC_APTBS/docs/dump functions.txt
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

297 lines
12 KiB
Plaintext

public bool DumpRom(int firstAddress, int lastAddress)
{
const ushort BLOCK_SIZE = 0x0100; // 256 bytes per block
const byte MAX_CHUNK = 13; // protocol limit
const bool DEBUG = true;
if (firstAddress < 0 || lastAddress < 0 || lastAddress < firstAddress)
{
Logger.Write("ReadRomEepromBlock: invalid address range.");
return false;
}
// Number of 0x0100 blocks touched by the requested range
int numBlocks = ((lastAddress - firstAddress) / BLOCK_SIZE) + 1;
// Fresh buffer for this dump
var packets2 = new List<byte>(numBlocks * BLOCK_SIZE);
Logger.Write($"ROM EEPROM BIN dump start: 0x{firstAddress:X4} .. 0x{lastAddress:X4}");
try
{
int addr = firstAddress;
while (addr <= lastAddress)
{
ushort blockBase = (ushort)(addr & 0xFF00);
if (DEBUG)
Logger.Write($"===== ROM EEPROM block base 0x{blockBase:X4} =====");
// Last address we may read inside this current 0x0100 block
int blockEnd = blockBase + BLOCK_SIZE - 1;
// Do not read past:
// 1) requested lastAddress
// 2) current block end
int maxReadableAbs = Math.Min(lastAddress, blockEnd);
while (addr <= maxReadableAbs)
{
int remaining = maxReadableAbs - addr + 1;
byte len = (byte)Math.Min(MAX_CHUNK, remaining);
var chunk = ReadRomEeprom((ushort)addr, len);
// Safety: if the ECU returns fewer bytes than requested, don't infinite-loop
if (chunk == null || chunk.Count == 0)
{
Logger.Write($"ReadRomEeprom returned 0 bytes at 0x{addr:X4}");
return false;
}
packets2.AddRange(chunk);
if (DEBUG)
//Logger.Write($"{addr:X4}: " + string.Join(" ", chunk.Select(b => b.ToString("X2"))));
// Advance by what was actually received
addr += chunk.Count;
}
// Move to next block if still not finished
if (addr <= lastAddress)
{
addr = blockBase + BLOCK_SIZE;
}
}
KeepAlive();
string fileName = $"rom_eeprom_dump_{firstAddress:X4}-{lastAddress:X4}.bin";
File.WriteAllBytes(fileName, packets2.ToArray());
Logger.Write($"ROM EEPROM BIN dump done: {packets2.Count} bytes -> {fileName}");
return true;
}
catch (Exception ex)
{
Logger.Write($"ReadRomEepromBlock failed: {ex.Message}");
return false;
}
}
public bool DumpEeprom(int startAddress, int endAddress)
{
const ushort BLOCK_SIZE = 0x0100; // logical block stride
const ushort VALID_BYTES_PER_BLOCK = 0x00C0; // EEPROM valid region: 0x0000..0x00BF
const byte MAX_CHUNK = 13; // protocol limit / safe chunk size
if (startAddress < 0 || endAddress < 0 || endAddress < startAddress)
{
Logger.Write("ReadEepromBlock: invalid address range.");
return false;
}
// Fresh buffer for this dump
var packets2 = new List<byte>();
Logger.Write($"EEPROM BIN dump start: 0x{startAddress:X4} .. 0x{endAddress:X4}");
try
{
// Walk absolute address range, but only read valid EEPROM bytes inside each 0x0100 block
int addr = startAddress;
while (addr <= endAddress)
{
ushort blockBase = (ushort)(addr & 0xFF00); // start of current 0x0100 block
ushort offsetInBlock = (ushort)(addr & 0x00FF);
// If current address is outside valid EEPROM region of this block, skip to next block
if (offsetInBlock >= VALID_BYTES_PER_BLOCK)
{
addr = blockBase + BLOCK_SIZE;
continue;
}
// Last valid absolute address inside this block
int blockValidEndAbs = blockBase + VALID_BYTES_PER_BLOCK - 1;
// Do not read past:
// 1) requested endAddress
// 2) valid EEPROM end within this block
int maxReadableAbs = Math.Min(endAddress, blockValidEndAbs);
while (addr <= maxReadableAbs)
{
int remaining = maxReadableAbs - addr + 1;
byte len = (byte)Math.Min(MAX_CHUNK, remaining);
var chunk = ReadEeprom((ushort)addr, len);
if (chunk == null || chunk.Count == 0)
{
Logger.Write($"ReadEeprom returned 0 bytes at 0x{addr:X4}");
return false;
}
packets2.AddRange(chunk);
float progress = 1.0f * (addr - startAddress) / (endAddress - startAddress);
Logger.Write($"Progress{progress:P1}");
//Logger.Write(string.Join(" ", chunk.Select(b => $"0x{b:X2}")));
// Safety: advance by what was actually received
addr += chunk.Count;
}
// Move to next block if needed
if (addr <= endAddress)
{
addr = (blockBase + BLOCK_SIZE);
}
}
KeepAlive();
string fileName = $"eeprom_dump_{startAddress:X4}-{endAddress:X4}.bin";
File.WriteAllBytes(fileName, packets2.ToArray());
Logger.Write($"EEPROM BIN dump done: {packets2.Count} bytes -> {fileName}");
return true;
}
catch (Exception ex)
{
Logger.Write($"ReadEepromBlock failed: {ex.Message}");
return false;
}
}
public bool DumpAllEeprom()
{
int startAddress = 0x0000;
int endAddress = 0x0000; //0x00BF
const ushort VALID_BYTES_PER_BLOCK = 0x00C0; // EEPROM valid region: 0x0000..0x00BF
const byte MAX_CHUNK = 13; // protocol limit / safe chunk size
if (startAddress < 0 || endAddress < 0 || endAddress < startAddress)
{
Logger.Write("ReadEepromBlock: invalid address range.");
return false;
}
// Fresh buffer for this dump
var packets2 = new List<byte>();
Logger.Write($"EEPROM BIN dump start: 0x{startAddress:X4} .. 0x{endAddress:X4}");
try
{
// Walk absolute address range, but only read valid EEPROM bytes inside each 0x0100 block
int addr = startAddress;
while (addr <= endAddress)
{
ushort blockBase = (ushort)(addr & 0xFF00); // start of current 0x0100 block
ushort offsetInBlock = (ushort)(addr & 0x00FF);
// Last valid absolute address inside this block
int blockValidEndAbs = blockBase + VALID_BYTES_PER_BLOCK - 1;
// Do not read past:
// 1) requested endAddress
// 2) valid EEPROM end within this block
int maxReadableAbs = Math.Min(endAddress, blockValidEndAbs);
while (addr <= maxReadableAbs)
{
int remaining = maxReadableAbs - addr + 1;
byte len = (byte)Math.Min(MAX_CHUNK, remaining);
var chunk = ReadEeprom((ushort)addr, len);
if (chunk == null || chunk.Count == 0)
{
Logger.Write($"ReadEeprom returned 0 bytes at 0x{addr:X4}");
return false;
}
packets2.AddRange(chunk);
float progress = 1.0f * (addr - startAddress) / (endAddress - startAddress);
Logger.Write($"Progress{progress:P1}");
//Logger.Write(string.Join(" ", chunk.Select(b => $"0x{b:X2}")));
// Safety: advance by what was actually received
addr += chunk.Count;
}
}
packets2.AddRange(new byte[16]);
packets2.AddRange(Enumerable.Repeat((byte)0xFF, 7));
var oemzone = SendCustom(new List<byte> { 0x18, 0x00, 0x00, 0x82, 0x33 });
oemzone = oemzone.Where(b => !b.IsAckNak).ToList();
var newbytes = oemzone[0].Body;
newbytes.RemoveRange(0,4);
packets2.AddRange(newbytes);
/*oemzone = SendCustom(new List<byte> { 0x18, 0x00, 0x00, 0x00, 0x00 });
oemzone = oemzone.Where(b => !b.IsAckNak).ToList();
newbytes = oemzone[0].Body;
packets2.AddRange(newbytes);
oemzone = SendCustom(new List<byte> { 0x18, 0x00, 0x00, 0x9F, 0xFF });
oemzone = oemzone.Where(b => !b.IsAckNak).ToList();
newbytes = oemzone[0].Body;
packets2.AddRange(newbytes);
oemzone = SendCustom(new List<byte> { 0x18, 0x00, 0x00, 0xD7, 0x01 });
oemzone = oemzone.Where(b => !b.IsAckNak).ToList();
newbytes = oemzone[0].Body;
packets2.AddRange(newbytes);
oemzone = SendCustom(new List<byte> { 0x18, 0x00, 0x00, 0xFF, 0xFC });
oemzone = oemzone.Where(b => !b.IsAckNak).ToList();
newbytes = oemzone[0].Body;
packets2.AddRange(newbytes);*/
oemzone = SendCustom(new List<byte> { 0x18, 0x00, 0x01, 0x6A, 0x89 });
oemzone = oemzone.Where(b => !b.IsAckNak).ToList();
newbytes = oemzone[0].Body;
newbytes.RemoveRange(0, 4);
packets2.AddRange(newbytes);
oemzone = SendCustom(new List<byte> { 0x18, 0x00, 0x02, 0x2E, 0x10 });
oemzone = oemzone.Where(b => !b.IsAckNak).ToList();
newbytes = oemzone[0].Body;
newbytes.RemoveRange(0, 4);
packets2.AddRange(newbytes);
oemzone = SendCustom(new List<byte> { 0x18, 0x00, 0x03, 0xFF, 0xFF });
oemzone = oemzone.Where(b => !b.IsAckNak).ToList();
newbytes = oemzone[0].Body;
newbytes.RemoveRange(0, 4);
packets2.AddRange(newbytes);
oemzone = SendCustom(new List<byte> { 0x18, 0x00, 0x04, 0xC7, 0xAE });
oemzone = oemzone.Where(b => !b.IsAckNak).ToList();
newbytes = oemzone[0].Body;
newbytes.RemoveRange(0, 4);
packets2.AddRange(newbytes);
KeepAlive();
string fileName = $"eeprom_dump_{startAddress:X4}-{0x00FF:X4}.bin";
File.WriteAllBytes(fileName, packets2.ToArray());
Logger.Write($"EEPROM BIN dump done: {packets2.Count} bytes -> {fileName}");
return true;
}
catch (Exception ex)
{
Logger.Write($"ReadEepromBlock failed: {ex.Message}");
return false;
}
}