#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/spi_master.h"
#include "driver/gpio.h"
#include "stdint.h"

#define EVE_CS 		GPIO_NUM_5
#define LED_BUILTIN GPIO_NUM_2
#define EVE_PDN		GPIO_NUM_4
#define EVE_SCK		GPIO_NUM_18
#define EVE_MISO	GPIO_NUM_19
#define EVE_MOSI	GPIO_NUM_23

spi_device_handle_t EVE_spi_device = {0};
spi_device_handle_t EVE_spi_device_simple = {0};
spi_transaction_t EVE_spi_transaction = {0};

volatile uint8_t EVE_dma_busy;

static inline void EVE_cs_set(void)
{
	gpio_set_level(EVE_CS, 0); /* make EVE listening */
}

static inline void EVE_cs_clear(void)
{
	gpio_set_level(EVE_CS, 1); /* tell EVE to stop listening */
}

static void eve_spi_post_transfer_callback(spi_transaction_t *trans)
{
	EVE_cs_clear();
	EVE_dma_busy = 0;
}

void EVE_SPI_Init(void)
{
	spi_bus_config_t buscfg  = {0}; 
	spi_device_interface_config_t devcfg  = {0};
	spi_device_interface_config_t devcfg_simple  = {0};

	buscfg.mosi_io_num =EVE_MOSI;
	buscfg.miso_io_num = EVE_MISO;
	buscfg.sclk_io_num = EVE_SCK;
	buscfg.quadwp_io_num = -1;
	buscfg.quadhd_io_num = -1;
	buscfg.max_transfer_sz= 4088;

	devcfg.clock_speed_hz = 16 * 1000 * 1000;	//Clock = 16 MHz
	devcfg.mode = 0;							//SPI mode 0
	devcfg.spics_io_num = -1;					//CS pin operated by app
	devcfg.queue_size = 7;						// we need only one transaction in the que
	devcfg.address_bits = 24;
	devcfg.command_bits = 0;					//command operated by app
	devcfg.post_cb = (transaction_cb_t)eve_spi_post_transfer_callback;

	spi_bus_initialize(HSPI_HOST, &buscfg, 1);

	spi_bus_add_device(HSPI_HOST, &devcfg, &EVE_spi_device);

	devcfg_simple.clock_speed_hz = 10 * 1000 * 1000;	//Clock = 16 MHz
	devcfg_simple.mode = 0;							//SPI mode 0
	devcfg_simple.spics_io_num = -1;					//CS pin operated by app
	devcfg_simple.queue_size = 7;						// we need only one transaction in the que
	devcfg_simple.address_bits = 0;
	devcfg_simple.command_bits = 0;					//command operated by app

	spi_bus_add_device(HSPI_HOST, &devcfg_simple, &EVE_spi_device_simple);
}

void loop(void* arg)
{
	static uint16_t led = 0;
	static uint8_t led_state = 0;
    while(1) {
        led++;
        if(led > 39)
        {
            led = 0;
            if(led_state)
            {
                led_state = 0;
                gpio_set_level(LED_BUILTIN, 0);
            }
            else
            {
                led_state = 42;
                gpio_set_level(LED_BUILTIN, 1);
            }
        }

        #if 1
                spi_transaction_t trans;
                trans.length = 8;
                trans.rxlength = 0;
                trans.flags = SPI_TRANS_USE_TXDATA;

                trans.tx_data[0] = 0x55;
                EVE_cs_set();
                spi_device_transmit(EVE_spi_device_simple, &trans);
                EVE_cs_clear();
        #endif

        #if 1
                uint32_t data = __builtin_bswap32(0xdeadbeef);
                spi_transaction_t trans3;
                trans3.length = 32;
                trans3.rxlength = 0;
                trans3.flags = 0;
                trans3.tx_buffer = &data;
                EVE_cs_set();
        //		spi_device_transmit(EVE_spi_device_simple, &trans3);
        //		spi_device_transmit(EVE_spi_device_simple, &trans3);
                spi_device_transmit(EVE_spi_device_simple, &trans3);
                spi_device_transmit(EVE_spi_device_simple, &trans3);
                EVE_cs_clear();
        #endif

        #if 1
                uint32_t EVE_dma_buffer[1025];

                EVE_dma_buffer[1] = 0x12345678;
                EVE_dma_buffer[2] = 0x12345678;
                EVE_dma_buffer[3] = 0x12345678;
                EVE_dma_buffer[4] = 0x12345678;

                spi_transaction_t trans2;
                trans2.length = 43 * 4 * 8;
                trans2.rxlength = 0;
                trans2.flags = 0;
                trans2.addr = 0x00b02578;
                trans2.tx_buffer = (uint8_t *) &EVE_dma_buffer[1];
                EVE_cs_set();
                spi_device_queue_trans(EVE_spi_device, &trans2, portMAX_DELAY);
        //		EVE_cs_clear();
        #endif
    
        vTaskDelay(pdMS_TO_TICKS(10));
    }
    vTaskDelete(NULL);
}

void app_main() {
    gpio_config_t cfg = {0};
    cfg.intr_type = GPIO_INTR_DISABLE;
    cfg.mode = GPIO_MODE_OUTPUT;
    cfg.pin_bit_mask = BIT(EVE_CS) | BIT(EVE_PDN) | BIT(LED_BUILTIN);
    cfg.pull_down_en = 0;
    cfg.pull_up_en = 0;
    gpio_config(&cfg);

    gpio_set_level(EVE_CS, 0);
    gpio_set_level(EVE_PDN, 0);
    gpio_set_level(LED_BUILTIN, 1);

    EVE_SPI_Init();
    esp_timer_init();
    xTaskCreate(loop, "loop", 8192, NULL, 10, NULL);
}