From bd063bfef86fb7bc733054f89a317154339ce466 Mon Sep 17 00:00:00 2001 From: David Montero Crespo Date: Thu, 6 Aug 2026 04:59:14 +0200 Subject: [PATCH] fix(epaper): correct vertical orientation for Y-decrement transposed panels A panel driven with a Y-decrement entry mode through the rotation-1 transpose (BadgeOS on the Badger 2350) rendered upside-down: its text read vertically flipped. The transpose was calibrated against the standard Y-increment (GxEPD2 / raw-SSD1680) path, where the source index maps to display row via Wn-1-x; under Y-decrement the source axis ends up flipped, so map it straight (x) to the display row for that case. Gated on the same yTopIsHigh signal already used for the RAM read, so Y-increment panels are byte-for-byte unchanged. Verified: the BadgeOS factory menu now renders upright ("BadgeOS" title + app icons readable). 23 decoder/epaper tests still pass. --- frontend/src/simulation/displays/SSD168xDecoder.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/frontend/src/simulation/displays/SSD168xDecoder.ts b/frontend/src/simulation/displays/SSD168xDecoder.ts index 9d3b6592..1604640c 100644 --- a/frontend/src/simulation/displays/SSD168xDecoder.ts +++ b/frontend/src/simulation/displays/SSD168xDecoder.ts @@ -344,12 +344,23 @@ export class SSD168xDecoder { // Transposed (rotation 1): native actual width = H. Inverse of // Adafruit_GFX rotation 1: native(x_raw,y_raw) -> display(xd=y_raw, // yd=Wn-1-x_raw), Wn = true native width = H. + // + // Under a Y-decrement entry mode (BadgeOS) the source axis ends up + // vertically flipped in the display versus the standard Y-increment + // (GxEPD2 / raw-SSD1680) path this transpose was calibrated against, so + // the whole image renders upside-down (its text reads flipped). Map the + // source index straight to the display row for the Y-decrement case; + // Y-increment panels keep the Wn-1-x mapping and are byte-for-byte + // unchanged. const out = new Uint8Array(W * H).fill(fill); const Wn = H; for (let ny = 0; ny < nh; ny++) { if (ny >= W) break; const s = ny * nw; - for (let x = 0; x < Wn; x++) out[(Wn - 1 - x) * W + ny] = src[s + x]; + for (let x = 0; x < Wn; x++) { + const dispRow = yTopIsHigh ? x : Wn - 1 - x; + out[dispRow * W + ny] = src[s + x]; + } } return out; }