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>
This commit is contained in:
297
docs/dump functions.txt
Normal file
297
docs/dump functions.txt
Normal file
@@ -0,0 +1,297 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user