// SPDX-License-Identifier: MIT
// Copyright (c) 2026 heypcb.ai
//
// SummonExodia — the EXODIA ESP32-C6 card's first sketch.
//
// Board: "ESP32C6 Dev Module" (Arduino-ESP32 3.x), USB CDC On Boot: Enabled.
// Library: Adafruit NeoPixel.
//
// The four SK6812MINI-E LEDs sit behind the card face: index 0-2 are the
// level stars (left to right), index 3 is the DARK orb. Their power is
// switched by GPIO22 (off at boot, and keep it off in deep sleep); their data
// is GPIO8 through a 3.3 V -> 5 V translator.

#include <Adafruit_NeoPixel.h>

constexpr int PIX_DATA = 8;    // GPIO8, pulled up on the board (boot strap)
constexpr int PIX_POWER = 22;  // high = LEDs powered
constexpr int VBAT_SENSE = 3;  // VBAT / 2
constexpr int BOOT_BUTTON = 9; // pressed = LOW
constexpr int NUM_PIX = 4;
constexpr int ORB = 3;

Adafruit_NeoPixel pix(NUM_PIX, PIX_DATA, NEO_GRB + NEO_KHZ800);

void summon() {
  pix.clear();
  pix.show();
  for (int star = 0; star < 3; star++) {            // the level stars, one by one
    for (int b = 0; b <= 255; b += 15) {
      pix.setPixelColor(star, pix.Color(b, b / 10, 0));
      pix.show();
      delay(12);
    }
    delay(250);
  }
  for (int b = 0; b <= 255; b += 3) {                // then the DARK orb wakes
    pix.setPixelColor(ORB, pix.Color(b / 2, 0, b));
    pix.show();
    delay(10);
  }
}

void obliterate() {                                  // all five pieces: you win
  for (int k = 0; k < 6; k++) {
    for (int i = 0; i < NUM_PIX; i++) pix.setPixelColor(i, pix.Color(255, 200, 80));
    pix.show();
    delay(60);
    pix.clear();
    pix.show();
    delay(60);
  }
  summon();
}

void setup() {
  Serial.begin(115200);
  pinMode(BOOT_BUTTON, INPUT_PULLUP);
  pinMode(PIX_POWER, OUTPUT);
  digitalWrite(PIX_POWER, HIGH);
  delay(5);
  pix.begin();
  pix.setBrightness(80);
  summon();
}

void loop() {
  // the orb breathes
  static uint32_t t0 = millis();
  float phase = (millis() - t0) / 1000.0f;
  uint8_t b = 90 + 90 * sinf(phase * 2.0f);
  pix.setPixelColor(ORB, pix.Color(b / 2, 0, b));
  pix.show();

  static uint32_t lastReport = 0;
  if (millis() - lastReport > 2000) {
    lastReport = millis();
    // The divider halves VBAT. With USB in and no cell, this reads the charger's
    // own output (about 4.2 V, and it wanders), so it cannot tell you a cell is
    // missing; on battery alone it is the cell's voltage.
    uint32_t mv = analogReadMilliVolts(VBAT_SENSE) * 2;
    Serial.printf("VBAT %lu mV\n", (unsigned long)mv);
  }

  if (digitalRead(BOOT_BUTTON) == LOW) {
    Serial.println("Exodia, obliterate!");
    obliterate();
    while (digitalRead(BOOT_BUTTON) == LOW) delay(10);
  }
  delay(20);
}
