#include "tft.h"

static struct tft_config tft_cfg;
static bool tft_data_mode = false;
static int dma_chan;

void tft_set_dc_cs(bool dc, bool cs) {
    sleep_us(1);
    gpio_put_masked((1u << tft_cfg.gpio_dc) | (1u << tft_cfg.gpio_cs), !!dc << tft_cfg.gpio_dc | !!cs << tft_cfg.gpio_cs);
    sleep_us(1);
}

void tft_write_cmd(PIO pio, uint sm, const uint8_t *cmd, size_t count) {
    tft_wait_idle(pio, sm);
    tft_set_dc_cs(0, 0);
    tft_put(pio, sm, *cmd++);
    if (count >= 2) {
        tft_wait_idle(pio, sm);
        tft_set_dc_cs(1, 0);
        for (size_t i = 0; i < count - 1; ++i) {
            tft_put(pio, sm, *cmd++);
        }
    }
    tft_wait_idle(pio, sm);
    tft_set_dc_cs(1, 1);
}

void lcd_init(PIO pio, uint sm, const uint8_t *init_seq) {
    const uint8_t *cmd = init_seq;
    while (*cmd) {
        tft_write_cmd(pio, sm, cmd + 2, *cmd);
        sleep_ms(*(cmd + 1) * 5);
//        sleep_ms(200);
        cmd += *cmd + 2;
    }
}

void tft_start_pixels(PIO pio, uint sm) {
    const uint8_t cmd = 0x2c; // RAMWR
    tft_write_cmd(pio, sm, &cmd, 1);
    tft_set_dc_cs(1, 0);
}

void tft_init(const struct tft_config* config, int dma_channel) {
	memcpy(&tft_cfg, config, sizeof(tft_cfg));
	dma_chan = dma_channel;

    gpio_init(tft_cfg.gpio_cs);
    gpio_init(tft_cfg.gpio_dc);
    gpio_init(tft_cfg.gpio_rst);
    gpio_init(tft_cfg.gpio_bl);
    gpio_set_dir(tft_cfg.gpio_cs, GPIO_OUT);
    gpio_set_dir(tft_cfg.gpio_dc, GPIO_OUT);
    gpio_set_dir(tft_cfg.gpio_rst, GPIO_OUT);
    gpio_set_dir(tft_cfg.gpio_bl, GPIO_OUT);

    gpio_put(tft_cfg.gpio_cs, 1);
    gpio_put(tft_cfg.gpio_rst, 1);
    lcd_init(tft_cfg.pio, tft_cfg.sm, st7789_init_seq);
    gpio_put(tft_cfg.gpio_bl, 1);
}
void tft_fill(uint16_t color) {
    uint32_t color_left = ((uint32_t)color) << 16;
    uint32_t two = 0;
    two |= color_left;
    two |= color;
    uint32_t pix_buf[320*480/4]; 
	for(size_t i = 0; i < 320*480/4; i++) {
		pix_buf[i] = two;
	}
    dma_channel_set_read_addr(dma_chan, pix_buf, true);
}