diff --git a/PlasmaNew/replica/MatrixPortalPlasma/MatrixPortalPlasma.ino b/PlasmaNew/replica/MatrixPortalPlasma/MatrixPortalPlasma.ino index 8cece91..9d4b718 100644 --- a/PlasmaNew/replica/MatrixPortalPlasma/MatrixPortalPlasma.ino +++ b/PlasmaNew/replica/MatrixPortalPlasma/MatrixPortalPlasma.ino @@ -47,6 +47,12 @@ static int demoScreen = 0; static uint32_t lastDemoStep = 0; static const uint32_t DEMO_MS = 2800; +// Panel test (DOWN button): cycle the diagnostic patterns. +static bool testRunning = false; +static int testPattern = 0; +static uint32_t lastTestStep = 0; +static const uint32_t TEST_MS = 1200; + // ---- helpers ------------------------------------------------------------- static bool frameHasFlash = false; @@ -120,6 +126,7 @@ void loop() { bool up = digitalRead(BUTTON_UP); if (upPrev == HIGH && up == LOW) { // pressed demoRunning = !demoRunning; + testRunning = false; if (demoRunning) { demoScreen = 0; feedDemoScreen(0); demoScreen = 1; lastDemoStep = millis(); } else { display.reset(); } } @@ -129,19 +136,26 @@ void loop() { static bool downPrev = HIGH; bool down = digitalRead(BUTTON_DOWN); if (downPrev == HIGH && down == LOW) { // pressed + testRunning = !testRunning; demoRunning = false; - display.showTestPattern(); + if (testRunning) { testPattern = 0; display.showTestPattern(0); lastTestStep = millis(); } + else { display.reset(); } } downPrev = down; #endif - // 3) Advance the demo on its timer. + // 3) Advance the demo / test on their timers. uint32_t now = millis(); if (demoRunning && now - lastDemoStep >= DEMO_MS) { feedDemoScreen(demoScreen); demoScreen = (demoScreen + 1) % plasmaDemoCount; lastDemoStep = now; } + if (testRunning && now - lastTestStep >= TEST_MS) { + testPattern = (testPattern + 1) % PlasmaDisplay::TEST_PATTERN_COUNT; + display.showTestPattern(testPattern); + lastTestStep = now; + } // 4) Blink phase for flashing pixels. if (now - lastBlink >= BLINK_MS) { diff --git a/PlasmaNew/replica/MatrixPortalPlasma/PlasmaDisplay.cpp b/PlasmaNew/replica/MatrixPortalPlasma/PlasmaDisplay.cpp index db762f7..e2c0a31 100644 --- a/PlasmaNew/replica/MatrixPortalPlasma/PlasmaDisplay.cpp +++ b/PlasmaNew/replica/MatrixPortalPlasma/PlasmaDisplay.cpp @@ -32,8 +32,25 @@ void PlasmaDisplay::setOrientation(Orientation o) { dirty_ = true; } -void PlasmaDisplay::showTestPattern() { - for (int i = 0; i < WIDTH * HEIGHT; ++i) pixels_[i] = PIX_LIT; +// The real display's power-on test (JP1 jumper 5, firmware $B888) runs through +// several drawing sequences — solid, border+grid, and more — to expose dead +// dots and addressing faults. These stand in for that; the sketch cycles them. +static bool testDot(int index, int x, int y) { + switch (index) { + case 0: return true; // all on + case 1: return x == 0 || x == PlasmaDisplay::WIDTH - 1 || // frame + y == 0 || y == PlasmaDisplay::HEIGHT - 1 || + (x % 16) == 0 || (y % 8) == 0; // + grid + case 2: return ((y / 2) % 2) == 0; // horizontal stripes + case 3: return ((x / 4) % 2) == 0; // vertical stripes + default: return (((x / 8) + (y / 8)) % 2) == 0; // checkerboard + } +} + +void PlasmaDisplay::showTestPattern(int index) { + for (int y = 0; y < HEIGHT; ++y) + for (int x = 0; x < WIDTH; ++x) + pixels_[y * WIDTH + x] = testDot(index, x, y) ? PIX_LIT : 0; dirty_ = true; } diff --git a/PlasmaNew/replica/MatrixPortalPlasma/PlasmaDisplay.h b/PlasmaNew/replica/MatrixPortalPlasma/PlasmaDisplay.h index 208e143..7b96d39 100644 --- a/PlasmaNew/replica/MatrixPortalPlasma/PlasmaDisplay.h +++ b/PlasmaNew/replica/MatrixPortalPlasma/PlasmaDisplay.h @@ -25,10 +25,13 @@ class PlasmaDisplay { PlasmaDisplay(); + static const int TEST_PATTERN_COUNT = 5; // JP1 jumper-5 diagnostic patterns + void reset(); // power-on: dark glass, home cursor void feed(uint8_t b); // one received wire byte void feed(const uint8_t *buf, size_t n); - void showTestPattern(); // all dots lit (JP1 jumper 5) + void showTestPattern() { showTestPattern(0); } // all dots lit + void showTestPattern(int index); // JP1 jumper 5: solid/grid/stripes/checker void setOrientation(Orientation o); // JP1 jumper 4 const uint8_t *frame() const { return pixels_; } diff --git a/PlasmaNew/replica/README.md b/PlasmaNew/replica/README.md index 9c477d5..3b9eeb3 100644 --- a/PlasmaNew/replica/README.md +++ b/PlasmaNew/replica/README.md @@ -66,7 +66,9 @@ display listens), exactly as the cockpit drove the real panel. - **UP** — toggle the built-in **firmware demonstration** (the real 10-screen PLASMADOT demo, `demo_screens.h`, extracted from the ROM). -- **DOWN** — the **panel test pattern** (all dots lit; a dead-dot check). +- **DOWN** — toggle the **panel test**: cycles diagnostic patterns (solid, + border+grid, horizontal/vertical stripes, checkerboard) to expose dead dots + and addressing faults — the multi-pattern sequence the real firmware runs. - **Power-on** briefly lights every dot (confirms both panels), then clears. ## Files diff --git a/src/VPlasma.App/MainForm.cs b/src/VPlasma.App/MainForm.cs index 63c7334..73ea1cd 100644 --- a/src/VPlasma.App/MainForm.cs +++ b/src/VPlasma.App/MainForm.cs @@ -30,8 +30,10 @@ internal sealed class MainForm : Form private readonly System.Windows.Forms.Timer _uiTimer = new() { Interval = 500 }; private readonly System.Windows.Forms.Timer _demoTimer = new() { Interval = 2800 }; + private readonly System.Windows.Forms.Timer _testTimer = new() { Interval = 1200 }; private int _selfTestPage; private int _demoScreen; + private int _testPattern; // ---- config panel controls ------------------------------------------- private readonly ComboBox _portBox = new() { Width = 168, DropDownStyle = ComboBoxStyle.DropDownList }; @@ -118,6 +120,7 @@ internal sealed class MainForm : Form _jp5.CheckedChanged += (_, _) => ApplyTestPattern(); _jp6.CheckedChanged += (_, _) => ApplyDemo(); _demoTimer.Tick += (_, _) => StepDemo(); + _testTimer.Tick += (_, _) => StepTestPattern(); // Default straps: jumper 2 installed = 9600 (the game's rate). Jumper 4 // unstrapped = horizontal (the normal cockpit orientation). @@ -130,6 +133,7 @@ internal sealed class MainForm : Form { _uiTimer.Dispose(); _demoTimer.Dispose(); + _testTimer.Dispose(); _service.Dispose(); _pipeService.Dispose(); }; @@ -288,16 +292,25 @@ internal sealed class MainForm : Form { if (_jp5.Checked) { - _device.ShowTestPattern(); - PrependLog("Jumper 5 installed — panel test pattern (all dots lit)"); + PrependLog("Jumper 5 installed — panel test (cycling diagnostic patterns)"); + _testPattern = 0; + _device.ShowTestPattern(0); + _testTimer.Start(); } else { + _testTimer.Stop(); _device.Reset(); PrependLog("Jumper 5 removed — test pattern cleared"); } } + private void StepTestPattern() + { + _testPattern = (_testPattern + 1) % VPlasmaDevice.TestPatternCount; + _device.ShowTestPattern(_testPattern); + } + private void ApplyDemo() { if (_jp6.Checked) diff --git a/src/VPlasma.Core/Device/VPlasmaDevice.cs b/src/VPlasma.Core/Device/VPlasmaDevice.cs index 6a7620d..1eafc98 100644 --- a/src/VPlasma.Core/Device/VPlasmaDevice.cs +++ b/src/VPlasma.Core/Device/VPlasmaDevice.cs @@ -197,21 +197,41 @@ public sealed class VPlasmaDevice FlushEvents(); } + /// Number of diagnostic patterns the JP1 jumper-5 test cycles. + public const int TestPatternCount = 5; + + /// Show the first test pattern (all dots lit). + public void ShowTestPattern() => ShowTestPattern(0); + /// - /// Light every dot — the panel test pattern JP1 jumper 5 runs at power-on - /// (the firmware's dead-dot check). Clear it with . + /// Paint diagnostic pattern (0..-1). The real display's power-on test (JP1 + /// jumper 5, firmware $B888) runs through several drawing + /// sequences — a solid fill, a border+grid, and more, each held briefly — + /// to expose dead dots and addressing faults; these stand in for that. /// - public void ShowTestPattern() + public void ShowTestPattern(int index) { lock (_sync) { - for (int i = 0; i < _pixels.Length; ++i) - _pixels[i] = PixelLit; + for (int y = 0; y < Height; ++y) + for (int x = 0; x < Width; ++x) + _pixels[y * Width + x] = TestDot(index, x, y) ? PixelLit : (byte)0; _dirty = true; } FlushEvents(); } + private static bool TestDot(int index, int x, int y) => index switch + { + 0 => true, // all on + 1 => x == 0 || x == Width - 1 || y == 0 || y == Height - 1 // frame + || x % 16 == 0 || y % 8 == 0, // + grid + 2 => (y / 2) % 2 == 0, // horizontal stripes + 3 => (x / 4) % 2 == 0, // vertical stripes + _ => ((x / 8) + (y / 8)) % 2 == 0, // checkerboard + }; + /// Feed received wire bytes. public void OnReceived(byte[] buffer, int count) {