// display_test -- basic function check for the MA-40 display on an RP2350.
//
// Panel:  Waveshare 1.47" IPS LCD, ST7789 controller, 172x320, SPI.
// Board:  RP2350, compiled with the Arduino-Pico (Earle Philhower) core.
//         (Tools > Board > Raspberry Pi Pico/RP2040/RP2350 > your RP2350 board)
//
// Wiring (RP2350 GPIO -> display pin):
//   GP1  -> CS
//   GP2  -> SCLK   (SPI0 SCK)
//   GP3  -> MOSI   (SPI0 TX)
//   GP4  -> DC
//   GP5  -> RST
//   GP24 -> backlight PWM (TFT_PWM)
//   (GP12/GP13 are the I2C pins -- unused by this test)
//
// What it does: lights the backlight, then loops forever through a set of
// visual checks -- solid color fills, RGB color bars, an edge/border test,
// text, rotation, and a backlight fade. Each step is announced on Serial
// (115200) so you can tell where it dies if the panel stays dark.

#include <Adafruit_GFX.h>
#include <Adafruit_ST7789.h>
#include <SPI.h>

// --- Pin assignments ---
#define TFT_CS    1
#define TFT_SCK   2   // SPI0 SCK
#define TFT_MOSI  3   // SPI0 TX
#define TFT_DC    4
#define TFT_RST   5
#define TFT_BL    24  // backlight, PWM-capable

// --- Panel geometry ---
#define TFT_WIDTH   172
#define TFT_HEIGHT  320

// Hardware SPI on SPI0; CS/DC/RST are handled by the library.
Adafruit_ST7789 tft = Adafruit_ST7789(&SPI, TFT_CS, TFT_DC, TFT_RST);

#define STEP_MS 1500  // how long each test stays on screen

static void banner(const char *msg) {
  Serial.print("[display_test] ");
  Serial.println(msg);
}

void setup() {
  Serial.begin(115200);
  delay(2000);  // give USB serial a moment to enumerate
  banner("boot");

  // Backlight full on first, so we can see anything the panel does.
  pinMode(TFT_BL, OUTPUT);
  analogWrite(TFT_BL, 255);

  // Route SPI0 to the pins the display is actually wired to. Must happen
  // before tft.init() calls SPI.begin().
  SPI.setSCK(TFT_SCK);
  SPI.setTX(TFT_MOSI);

  // init(172, 320) tells the library the panel size; it applies the required
  // column offset (34) so the image lands correctly on this cut of the ST7789.
  tft.init(TFT_WIDTH, TFT_HEIGHT);
  tft.setSPISpeed(40000000);  // 40 MHz -- safe for bring-up; raise later if clean
  tft.setRotation(0);         // portrait, 172 wide x 320 tall
  tft.fillScreen(ST77XX_BLACK);
  banner("init OK");
}

// Full-screen fills: verifies basic communication and color order.
static void testFills() {
  struct { const char *name; uint16_t c; } fills[] = {
    { "fill RED",   ST77XX_RED },
    { "fill GREEN", ST77XX_GREEN },
    { "fill BLUE",  ST77XX_BLUE },
    { "fill WHITE", ST77XX_WHITE },
    { "fill BLACK", ST77XX_BLACK },
  };
  for (auto &f : fills) {
    banner(f.name);
    tft.fillScreen(f.c);
    delay(STEP_MS);
  }
}

// Horizontal color bars: quick check for stuck lines / wrong geometry.
static void testColorBars() {
  banner("color bars");
  const uint16_t bars[] = {
    ST77XX_RED, ST77XX_YELLOW, ST77XX_GREEN, ST77XX_CYAN,
    ST77XX_BLUE, ST77XX_MAGENTA, ST77XX_WHITE, ST77XX_BLACK,
  };
  const int n = sizeof(bars) / sizeof(bars[0]);
  const int h = tft.height() / n;
  for (int i = 0; i < n; i++) {
    tft.fillRect(0, i * h, tft.width(), h, bars[i]);
  }
  delay(STEP_MS * 2);
}

// 1px border + corner markers + crosshair: verifies the column/row offsets
// are right and no edge pixels are cut off.
static void testEdges() {
  banner("edge/offset test");
  tft.fillScreen(ST77XX_BLACK);
  tft.drawRect(0, 0, tft.width(), tft.height(), ST77XX_WHITE);
  tft.drawLine(0, 0, tft.width() - 1, tft.height() - 1, ST77XX_RED);
  tft.drawLine(tft.width() - 1, 0, 0, tft.height() - 1, ST77XX_RED);
  tft.fillCircle(tft.width() / 2, tft.height() / 2, 20, ST77XX_GREEN);
  delay(STEP_MS * 2);
}

// Text rendering at a few sizes.
static void testText() {
  banner("text test");
  tft.fillScreen(ST77XX_BLACK);
  tft.setTextWrap(false);
  tft.setCursor(8, 10);
  tft.setTextColor(ST77XX_CYAN);
  tft.setTextSize(2);
  tft.println("MA-40");
  tft.setCursor(8, 40);
  tft.setTextColor(ST77XX_WHITE);
  tft.setTextSize(1);
  tft.println("display_test OK");
  tft.setCursor(8, 60);
  tft.setTextSize(3);
  tft.setTextColor(ST77XX_YELLOW);
  tft.println("12345");
  delay(STEP_MS * 2);
}

// Cycle all four rotations with a label so orientation is easy to confirm.
static void testRotation() {
  for (uint8_t r = 0; r < 4; r++) {
    banner("rotation");
    tft.setRotation(r);
    tft.fillScreen(ST77XX_BLACK);
    tft.drawRect(0, 0, tft.width(), tft.height(), ST77XX_WHITE);
    tft.setCursor(10, 10);
    tft.setTextColor(ST77XX_GREEN);
    tft.setTextSize(2);
    tft.print("rot ");
    tft.print(r);
    delay(STEP_MS);
  }
  tft.setRotation(0);
}

// Fade the backlight down and back up to prove the PWM pin works.
static void testBacklight() {
  banner("backlight fade");
  tft.fillScreen(ST77XX_WHITE);
  for (int b = 255; b >= 0; b -= 5) { analogWrite(TFT_BL, b); delay(15); }
  for (int b = 0; b <= 255; b += 5) { analogWrite(TFT_BL, b); delay(15); }
}

void loop() {
  testFills();
  testColorBars();
  testEdges();
  testText();
  testRotation();
  testBacklight();
  banner("cycle complete, restarting");
}
