text: /**
   * @file disp_spi.c
   *
   */
  
  /*********************
   *      INCLUDES
   *********************/
  #include "esp_system.h"
  #include "driver/gpio.h"
  #include "driver/spi_master.h"
  
  #include <string.h>
  
  #include <freertos/FreeRTOS.h>
  #include <freertos/semphr.h>
  #include <freertos/task.h>
  
  #include "lvgl/lvgl.h"
  
  #include "disp_spi.h"
  #include "disp_driver.h"
  
  #include "../lvgl_driver.h"
  
  /*********************
   *      DEFINES
   *********************/
   #if CONFIG_LVGL_TFT_DISPLAY_SPI_HSPI == 1
   #define TFT_SPI_HOST HSPI_HOST
   #else
   #define TFT_SPI_HOST VSPI_HOST
   #endif
  
  /**********************
   *      TYPEDEFS
   **********************/
  
  /**********************
   *  STATIC PROTOTYPES
   **********************/
  static void IRAM_ATTR spi_ready (spi_transaction_t *trans);
  
  /**********************
   *  STATIC VARIABLES
   **********************/
  static spi_device_handle_t spi;
  static volatile bool spi_trans_in_progress;
  static volatile bool spi_color_sent;
  static transaction_cb_t chained_post_cb;
  
  /**********************
   *      MACROS
   **********************/
  
  /**********************
   *   GLOBAL FUNCTIONS
   **********************/
  void disp_spi_add_device_config(spi_host_device_t host, spi_device_interface_config_t *devcfg)
  {
      chained_post_cb=devcfg->post_cb;
      devcfg->post_cb=spi_ready;
      esp_err_t ret=spi_bus_add_device(host, devcfg, &spi);
      assert(ret==ESP_OK);
  }
  
  void disp_spi_add_device(spi_host_device_t host)
  {
      spi_device_interface_config_t devcfg={
  #if CONFIG_LVGL_TFT_DISPLAY_CONTROLLER == TFT_CONTROLLER_HX8357
              .clock_speed_hz=26*1000*1000,           //Clock out at 26 MHz
  #elif CONFIG_LVGL_TFT_DISPLAY_CONTROLLER == TFT_CONTROLLER_ST7789
              .clock_speed_hz=24*1000*1000,           //Clock out at 24 MHz
  #elif CONFIG_LVGL_TFT_DISPLAY_CONTROLLER == TFT_CONTROLLER_ILI9486
              .clock_speed_hz=24*1000*1000,           //Clock out at 24 MHz
  #else
              .clock_speed_hz=40*1000*1000,           //Clock out at 40 MHz
  #endif
  
  #if CONFIG_LVGL_TFT_DISPLAY_CONTROLLER == TFT_CONTROLLER_ST7789
              .mode=2,                                //SPI mode 2
  #else
  	    .mode=0,				    // SPI mode 0
  #endif
  	    .spics_io_num=DISP_SPI_CS,              //CS pin
              .queue_size=1,
              .pre_cb=NULL,
              .post_cb=NULL,
              .flags = SPI_DEVICE_HALFDUPLEX
      };
  
      disp_spi_add_device_config(host, &devcfg);
  }
  
  void disp_spi_init(void)
  {
  
      esp_err_t ret;
  
      spi_bus_config_t buscfg={
  #if 1 /* Set the if value to 0 on m5stack */
              .miso_io_num=-1,
  #else
              .miso_io_num= 19,
  #endif
              .mosi_io_num=DISP_SPI_MOSI,
              .sclk_io_num=DISP_SPI_CLK,
              .quadwp_io_num=-1,
              .quadhd_io_num=-1,
  #if CONFIG_LVGL_TFT_DISPLAY_CONTROLLER == TFT_CONTROLLER_ILI9341
              .max_transfer_sz = DISP_BUF_SIZE * 2,
  #elif CONFIG_LVGL_TFT_DISPLAY_CONTROLLER == TFT_CONTROLLER_ST7789
              .max_transfer_sz = DISP_BUF_SIZE * 2,
  #elif CONFIG_LVGL_TFT_DISPLAY_CONTROLLER == TFT_CONTROLLER_ILI9488
              .max_transfer_sz = DISP_BUF_SIZE * 3,
  #elif CONFIG_LVGL_TFT_DISPLAY_CONTROLLER == TFT_CONTROLLER_HX8357
              .max_transfer_sz = DISP_BUF_SIZE * 2
  #elif CONFIG_LVGL_TFT_DISPLAY_CONTROLLER == TFT_CONTROLLER_ILI9486
              .max_transfer_sz = DISP_BUF_SIZE * 2,
  #endif
      };
  
      //Initialize the SPI bus
      ret=spi_bus_initialize(TFT_SPI_HOST, &buscfg, 1);
      assert(ret==ESP_OK);
  
      //Attach the LCD to the SPI bus
      disp_spi_add_device(TFT_SPI_HOST);
  }
  
  void disp_spi_send_data(uint8_t * data, uint16_t length)
  {
      if (length == 0) return;           //no need to send anything
  
      while(spi_trans_in_progress);
  
      spi_transaction_t t = {
          .length = length * 8, // transaction length is in bits
          .tx_buffer = data
      };
  
      spi_trans_in_progress = true;
      spi_color_sent = false;             //Mark the "lv_flush_ready" NOT needs to be called in "spi_ready"
      spi_device_queue_trans(spi, &t, portMAX_DELAY);
  //	spi_transaction_t *ta = &t;
  //	spi_device_get_trans_result(spi,&ta, portMAX_DELAY);
  }
  
  void disp_spi_send_colors(uint8_t * data, uint16_t length)
  {
      if (length == 0) {
  	return;
      }
  
      while(spi_trans_in_progress);
  
      spi_transaction_t t = {
          .length = length * 8, // transaction length is in bits
          .tx_buffer = data
      };
      
      spi_trans_in_progress = true;
      spi_color_sent = true;              //Mark the "lv_flush_ready" needs to be called in "spi_ready"
      spi_device_queue_trans(spi, &t, portMAX_DELAY);
  //	spi_transaction_t *ta = &t;
  //	spi_device_get_trans_result(spi,&ta, portMAX_DELAY);
  }
  
  
  bool disp_spi_is_busy(void)
  {
      return spi_trans_in_progress;
  }
  
  /**********************
   *   STATIC FUNCTIONS
   **********************/
  
  static void IRAM_ATTR spi_ready (spi_transaction_t *trans)
  {
      spi_trans_in_progress = false;
  
      lv_disp_t * disp = lv_refr_get_disp_refreshing();
      if(spi_color_sent) lv_disp_flush_ready(&disp->driver);
      if(chained_post_cb) chained_post_cb(trans);
  }
  