#include <SPI.h>
#include "driver/spi_master.h"
#include "esp_flash.h"
#include "esp_flash_spi_init.h"
#include "sea_esp32_qspi.h"
// https://github.com/espressif/esp-idf/issues/9924
// Declare spi as a global variable
spi_device_handle_t spi;

typedef struct {
    uint32_t addr;
    uint8_t param[4];
    uint8_t len;
} lcd_cmd_t;

void lcd_init() {
  esp_err_t ret;
 spi_bus_config_t buscfg = {
      .data0_io_num = 6,
      .data1_io_num = 7,
      .sclk_io_num = 4,
      .data2_io_num = 15,
      .data3_io_num = 16,
      .max_transfer_sz = 64,
      // .flags = SPICOMMON_BUSFLAG_MASTER | SPICOMMON_BUSFLAG_QUAD |
      //          SPICOMMON_BUSFLAG_GPIO_PINS,
      .flags = SPICOMMON_BUSFLAG_MASTER | SPICOMMON_BUSFLAG_GPIO_PINS,
  };

  spi_device_interface_config_t devcfg = {
      .command_bits = 8,
      .address_bits = 24,
      // .dummy_bits=1,
      .mode = SPI_MODE0,
      .clock_speed_hz = SPI_MASTER_FREQ_8M,
      .spics_io_num = 5,
      .flags = SPI_DEVICE_HALFDUPLEX,
      .queue_size = 3,

      // .pre_cb=lcd_spi_pre_transfer_callback,  //Specify pre-transfer callback
      // to handle D/C line
  };
  pinMode(4, OUTPUT); digitalWrite(4, HIGH);
  pinMode(5, OUTPUT); digitalWrite(5, HIGH);
  pinMode(6, OUTPUT); digitalWrite(6, HIGH);
  pinMode(7, OUTPUT); digitalWrite(7, HIGH);
  pinMode(15, OUTPUT); digitalWrite(15, HIGH);
  pinMode(16, OUTPUT); digitalWrite(16, HIGH);
  ret = spi_bus_initialize(SPI3_HOST, &buscfg, SPI_DMA_CH_AUTO);
  ESP_ERROR_CHECK(ret);
  ret = spi_bus_add_device(SPI3_HOST, &devcfg, &spi);
  ESP_ERROR_CHECK(ret);


}

static void lcd_send_cmd(uint32_t cmd, uint8_t *dat, uint32_t len) {
  spi_transaction_t t;
  memset(&t, 0, sizeof(t));
  t.flags = (SPI_TRANS_MULTILINE_CMD | SPI_TRANS_MULTILINE_ADDR);
  t.cmd = 0x02;
  t.addr = cmd;
  t.length = 8 * len;
  if (len != 0) {
    t.tx_buffer = dat;
  } else {
    t.tx_buffer = NULL;
  }
  spi_device_polling_transmit(spi, &t);
}

void lcd_address_set(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) {
  lcd_cmd_t t[3] = {
      {0x2a00, {x1 >> 8, x1, x2 >> 8, x2}, 0x04},
      {0x2b00, {y1 >> 8, y1, y2 >> 8, y2}, 0x04},
      {0x2c00, {0x00}, 0x00},
  };
  for (uint32_t i = 0; i < 3; i++) {
    lcd_send_cmd(t[i].addr, t[i].param, t[i].len);
  }
}

void lcd_push_colors(uint16_t x, uint16_t y, uint16_t width, uint16_t hight,
                     uint16_t *data) {

  size_t len = width * hight * 2;
  lcd_address_set(x, y, x + width - 1, y + hight - 1);

  /***********4 line***********/
  Serial.println("len : " + String(len));
  spi_transaction_t t;
  memset(&t, 0, sizeof(t));
  t.flags = (SPI_TRANS_MODE_QIO /* | SPI_TRANS_MODE_DIOQIO_ADDR */);
  t.cmd = 0x32;
  t.addr = 0x002C00;
  t.tx_buffer = (uint8_t *)data;
  t.length = 16 * len;
  Serial.println("t.length : " + String(t.length));
  ESP_ERROR_CHECK(spi_device_queue_trans(spi, &t , portMAX_DELAY));
}

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  Serial.println("Hello, ESP32-S3!");
  printf("ESP32 SDK version: %s\n", ESP.getSdkVersion());
  lcd_init();
}

void loop() {
  // put your main code here, to run repeatedly:
  //doSPI();
  uint8_t pippo[] = "abcdefghijklmnopqrstuvwxyz1234567890";
  //lcd_send_cmd(0xaaaa, pippo, 6);
  lcd_push_colors(10, 10, 2, 2, (uint16_t *)pippo);
  delay(1000); // this speeds up the simulation
}

#define PIN_SPI3_MOSI 4
#define PIN_SPI3_MISO 5
#define PIN_SPI3_CLK  6
#define PIN_SPI3_D2   7
#define PIN_SPI3_D3  15
#define PIN_SPI3_CS  16


void doSPI()
{
  uint8_t data1[2]={42,33};
  uint8_t data2[2] = {0, 0};
  Serial.begin(115200);
  SeaTrans.begin();
  SeaTrans.write(0, data1, 2);
  SeaTrans.read(0, data2, 2);
  Serial.printf("%d %d\r\n",data2[0],data2[1]);
}
esp:0
esp:1
esp:2
esp:3
esp:4
esp:5
esp:6
esp:7
esp:8
esp:9
esp:10
esp:11
esp:12
esp:13
esp:14
esp:15
esp:16
esp:17
esp:18
esp:19
esp:20
esp:21
esp:35
esp:36
esp:37
esp:38
esp:39
esp:40
esp:41
esp:42
esp:45
esp:46
esp:47
esp:48
esp:3V3.1
esp:3V3.2
esp:RST
esp:5V
esp:GND.1
esp:GND.2
esp:TX
esp:RX
esp:GND.3
esp:GND.4
led1:A
led1:C
led3:A
led3:C
led4:A
led4:C
led2:A
led2:C
led5:A
led5:C
led6:A
led6:C