#include <Arduino.h>
#include <SPI.h>
#include "image.h"

#define EPD_WIDTH  800
#define EPD_HEIGHT 480
#define IMG_W      480   // portrait image dimensions
#define IMG_H      800
#define PIN_SCK  18
#define PIN_MOSI 23
#define PIN_CS    5
#define PIN_DC   17
#define PIN_RST  16
#define PIN_BUSY  4

static uint8_t row_buf[EPD_WIDTH / 2];

void wait_busy() { while (digitalRead(PIN_BUSY) == LOW) delay(5); }

void send_command(uint8_t cmd) {
    digitalWrite(PIN_DC, LOW);
    digitalWrite(PIN_CS, LOW);
    SPI.transfer(cmd);
    digitalWrite(PIN_CS, HIGH);
}

void send_data(uint8_t data) {
    digitalWrite(PIN_DC, HIGH);
    digitalWrite(PIN_CS, LOW);
    SPI.transfer(data);
    digitalWrite(PIN_CS, HIGH);
}

void epd_reset() {
    digitalWrite(PIN_RST, HIGH); delay(20);
    digitalWrite(PIN_RST, LOW);  delay(2);
    digitalWrite(PIN_RST, HIGH); delay(20);
}

void epd_init() {
    epd_reset();
    wait_busy();
    delay(30);
    send_command(0xAA);
    send_data(0x49); send_data(0x55); send_data(0x20);
    send_data(0x08); send_data(0x09); send_data(0x18);
    send_command(0x01); send_data(0x3F);
    send_command(0x00); send_data(0x5F); send_data(0x69);
    send_command(0x03);
    send_data(0x00); send_data(0x54); send_data(0x00); send_data(0x44);
    send_command(0x05);
    send_data(0x40); send_data(0x1F); send_data(0x1F); send_data(0x2C);
    send_command(0x06);
    send_data(0x6F); send_data(0x1F); send_data(0x17); send_data(0x49);
    send_command(0x08);
    send_data(0x6F); send_data(0x1F); send_data(0x1F); send_data(0x22);
    send_command(0x30); send_data(0x03);
    send_command(0x50); send_data(0x3F);
    send_command(0x60); send_data(0x02); send_data(0x00);
    send_command(0x61);
    send_data(0x03); send_data(0x20); send_data(0x01); send_data(0xE0);
    send_command(0x84); send_data(0x01);
    send_command(0xE3); send_data(0x2F);
    send_command(0x04);
    wait_busy();
}

void epd_sleep() {
    send_command(0x02); send_data(0x00); wait_busy();
    send_command(0x07); send_data(0xA5);
}

void show_image() {
    send_command(0x10);
    digitalWrite(PIN_DC, HIGH);
    digitalWrite(PIN_CS, LOW);

    // 90° CW rotation: display(x,y) → portrait(IMG_W-1-y, x)
    // Portrait image is IMG_W×IMG_H, IMAGE_ROW = IMG_W/2 bytes per portrait row.
    for (int y = 0; y < EPD_HEIGHT; y++) {
        int pcol = (IMG_W - 1) - y;
        for (int x = 0; x < EPD_WIDTH; x++) {
            uint32_t bidx = (uint32_t)x * IMAGE_ROW + pcol / 2;
            uint8_t b = pgm_read_byte(&IMAGE_DATA[bidx]);
            uint8_t code = (pcol & 1) ? (b & 0x0F) : (b >> 4);
            if (x & 1)
                row_buf[x / 2] = (row_buf[x / 2] & 0xF0) | code;
            else
                row_buf[x / 2] = (code << 4) | (row_buf[x / 2] & 0x0F);
        }
        SPI.writeBytes(row_buf, sizeof(row_buf));
    }
    digitalWrite(PIN_CS, HIGH);

    send_command(0x04); wait_busy();
    send_command(0x12); send_data(0x00); wait_busy();
}

void setup() {
    Serial.begin(115200);
    Serial.println("pictureFrame");

    pinMode(PIN_CS,   OUTPUT);
    pinMode(PIN_DC,   OUTPUT);
    pinMode(PIN_RST,  OUTPUT);
    pinMode(PIN_BUSY, INPUT);

    SPI.begin(PIN_SCK, -1, PIN_MOSI, PIN_CS);
    SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0));

    epd_init();
    show_image();
    epd_sleep();
    Serial.println("Done.");
}

void loop() {
    delay(60000);
}
