/*
 * Copyright (c) 2006-2022, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2021-08-20     BruceOu      first implementation
 */

#include <stdio.h>
#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>

#define GD32H7_USE_EVAL

#ifdef GD32H7_USE_EVAL
#include "gd32h759i_eval.h"
#endif


#define GD32H7_USART_DMA_TEST
#define GD32H7_USART_TX_DMA_TEST
//#define GD32H7_GPIO_TEST
//#define GD32H7_I2C_EEPROM_TEST
//#define GD32H7_ADC_DMA_TEST
//#define GD32H7_HWTIMER_TEST
//#define GD32H7_SPI_TEST


#ifdef GD32H7_GPIO_TEST
/* defined the LED2 pin: PA6 */
#define LED2_PIN GET_PIN(A, 6)
#endif

#ifdef GD32H7_I2C_EEPROM_TEST
#include "at24cxx.h"
rt_uint8_t buf[16];
#define BUFFER_SIZE    256
uint8_t i2c_24c02_test(void);
#endif

#ifdef GD32H7_ADC_DMA_TEST
#define ADC_DEV_NAME        "adc2" 
#define ADC_DEV_CHANNEL     5
#endif

#ifdef GD32H7_ADC_DMA_TEST
static int adc_vol_sample(void);
#endif

#ifdef GD32H7_HWTIMER_TEST
static int hwtimer_sample(void);
#endif

#ifdef GD32H7_SPI_TEST
#define BUS_NAME     "spi0"
#define SPI_NAME     "spi00"

uint8_t send_id = 0x9F;
uint8_t WREN = 0x06;
uint8_t WRITE = 0x02;
uint8_t READ = 0x03;
uint8_t SE = 0x20;
uint8_t recei_id[4] = {0};
uint8_t  tx_buffer[200];
uint8_t  rx_buffer[200];

static void spi_sample(void);
#endif

#ifdef GD32H7_USART_TX_DMA_TEST
#ifndef RT_SERIAL_USING_TX_DMA
#error "RT_SERIAL_USING_TX_DMA should be defined in rtconfig.h"
#endif
static int uart_data_sample(int argc, char *argv[]);
#endif

int main(void)
{

#ifdef GD32H7_USE_EVAL
    gd_eval_led_init(LED1);
#endif

#ifdef GD32H7_GPIO_TEST
    /* set LED1 pin mode to output */
    rt_pin_mode(LED2_PIN, PIN_MODE_OUTPUT);
#endif

#ifdef GD32H7_USART_DMA_TEST
    rt_device_t uart0_dev = rt_device_find(RT_CONSOLE_DEVICE_NAME);
    rt_device_open(uart0_dev,  RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_DMA_RX);
#endif

#ifdef GD32H7_I2C_EEPROM_TEST
    struct rt_i2c_bus_device *i2c0_dev;
    i2c0_dev = rt_i2c_bus_device_find("i2c1");
    if(i2c_24c02_test() != 0){
        rt_kprintf("I2C-AT24C02 test passed!\n\r");
    }
#endif

#ifdef GD32H7_HWTIMER_TEST
    hwtimer_sample();
#endif

#ifdef GD32H7_SPI_TEST
    spi_sample();
#endif

#ifdef GD32H7_USART_TX_DMA_TEST
    uart_data_sample(0, 0);
#endif

    while (1)
    {
#ifdef GD32H7_USE_EVAL
        gd_eval_led_toggle(LED1);
        rt_thread_mdelay(500);
#endif

#ifdef GD32H7_GPIO_TEST
        rt_pin_write(LED2_PIN, PIN_HIGH);
        rt_thread_mdelay(500);
        rt_pin_write(LED2_PIN, PIN_LOW);
        rt_thread_mdelay(500);
#endif
        
#ifdef GD32H7_ADC_DMA_TEST
        adc_vol_sample();
#endif
        
#if !defined (GD32H7_USE_EVAL) && !defined (GD32H7_GPIO_TEST)
        rt_thread_mdelay(1000);
#endif
    }

    return RT_EOK;
}



#ifdef GD32H7_I2C_EEPROM_TEST

uint8_t i2c_24c02_test(void)
{
    at24cxx_device_t ati2c;
    ati2c = at24cxx_init("i2c1", 0x00);
    
    if (ati2c != NULL)
    {
       rt_kprintf("\r\n Found eeprom \r\n");
    
    }
    uint16_t i;
    uint8_t i2c_buffer_write[BUFFER_SIZE];
    uint8_t i2c_buffer_read[BUFFER_SIZE];

    rt_kprintf("\r\n I2C-AT24C02 writing...\r\n");

    /* initialize i2c_buffer_write */
    for(i = 0; i < BUFFER_SIZE; i++) {
        i2c_buffer_write[i] = i;
    }
    /* EEPROM data write */
    if(at24cxx_page_write(ati2c,0x00,i2c_buffer_write, BUFFER_SIZE) == RT_EOK) {
           rt_kprintf("I2C-AT24C02 Finish writing...\r\n");
    }
    
    rt_kprintf("I2C-AT24C02 reading...\r\n");
    /* EEPROM data read */
    if(at24cxx_page_read(ati2c,0x00,i2c_buffer_read, BUFFER_SIZE) == RT_EOK) {
           rt_kprintf("I2C-AT24C02 Finish reading...\r\n");
    }
    
    /* compare the read buffer and write buffer */
    for(i = 0; i < BUFFER_SIZE; i++) {
        if(i2c_buffer_read[i] != i2c_buffer_write[i]) {
            rt_kprintf("0x%02X ", i2c_buffer_read[i]);
            rt_kprintf("\r\n rr:data read and write aren't matching.\n\r");
            return 0;
        }
    }
    return 1;
}
#endif

#ifdef GD32H7_ADC_DMA_TEST
static int adc_vol_sample(void)
{
    rt_adc_device_t adc_dev;
    rt_uint32_t value, vol;
    rt_err_t ret = RT_EOK;

    adc_dev = (rt_adc_device_t)rt_device_find(ADC_DEV_NAME);
    if (adc_dev == RT_NULL)
    {
        rt_kprintf("adc sample run failed! can't find %s device!\n", ADC_DEV_NAME);
        return RT_ERROR;
    }

    ret = rt_adc_enable(adc_dev, ADC_DEV_CHANNEL);

    value = rt_adc_read(adc_dev, ADC_DEV_CHANNEL);
    rt_kprintf("the value is :%d \n", value);

    ret = rt_adc_disable(adc_dev, ADC_DEV_CHANNEL);

    return ret;
}
#endif

#ifdef GD32H7_HWTIMER_TEST

static rt_err_t timeout_cb(rt_device_t dev, rt_size_t size)
{
    rt_kprintf("this is hwtimer timeout callback fucntion!\n");
    rt_kprintf("tick is :%d !\n", rt_tick_get());

    return 0;
}

static int hwtimer_sample(void)
{
    rt_err_t ret = RT_EOK;
    rt_hwtimerval_t timeout_s;
    rt_device_t hw_dev = RT_NULL;
    rt_hwtimer_mode_t mode;
    rt_uint32_t freq = 10000;

    hw_dev = rt_device_find("timer0");
    if (hw_dev == RT_NULL)
    {
        rt_kprintf("hwtimer sample run failed! can't find %s device!\n", hw_dev);
        return RT_ERROR;
    }

    ret = rt_device_open(hw_dev, RT_DEVICE_OFLAG_RDWR);
    if (ret != RT_EOK)
    {
        rt_kprintf("open %s device failed!\n", hw_dev);
        return ret;
    }

    rt_device_set_rx_indicate(hw_dev, timeout_cb);

    rt_device_control(hw_dev, HWTIMER_CTRL_FREQ_SET, &freq);

    mode = HWTIMER_MODE_PERIOD;
    ret = rt_device_control(hw_dev, HWTIMER_CTRL_MODE_SET, &mode);
    if (ret != RT_EOK)
    {
        rt_kprintf("set mode failed! ret is :%d\n", ret);
        return ret;
    }

    timeout_s.sec = 5;
    timeout_s.usec = 0;
    if (rt_device_write(hw_dev, 0, &timeout_s, sizeof(timeout_s)) != sizeof(timeout_s))
    {
        rt_kprintf("set timeout value failed\n");
        return RT_ERROR;
    }

    rt_thread_mdelay(3500);

    rt_device_read(hw_dev, 0, &timeout_s, sizeof(timeout_s));
    rt_kprintf("Read: Sec = %d, Usec = %d\n", timeout_s.sec, timeout_s.usec);
    return ret;
}
#endif

#ifdef GD32H7_SPI_TEST

static void spi_sample(void)
{
    uint8_t address[4] = {0x20,00,00,04};
    uint8_t waddress[4] = {0x02,00,00,04};
    uint8_t raddress[4] = {0x03,00,00,04};
    
    static struct rt_spi_device *spi_dev = RT_NULL;
    struct rt_spi_configuration cfg;
    
    for(int i = 0; i < 200; i ++){
            tx_buffer[i] = i;
        }
    
    spi_dev = (struct rt_spi_device *)rt_malloc(sizeof(struct rt_spi_device));
//    rt_hw_spi_device_attach(BUS_NAME, SPI_NAME, GET_PIN(A, 4));
    rt_spi_bus_attach_device_cspin(spi_dev, SPI_NAME, BUS_NAME, GET_PIN(A, 4), RT_NULL);

    cfg.data_width = 8;
    cfg.mode   = RT_SPI_MASTER | RT_SPI_MODE_0 | RT_SPI_MSB;
    cfg.max_hz =  2 *1000 *1000;

    spi_dev = (struct rt_spi_device *)rt_device_find(SPI_NAME);
    spi_dev->bus->owner = spi_dev;
    if (RT_NULL == spi_dev)
    {
        rt_kprintf("spi sample run failed! can't find %s device!\n", SPI_NAME);
    }
    rt_spi_configure(spi_dev, &cfg);


    /* READ FLASH ID */
    rt_spi_send_then_recv((struct rt_spi_device *)spi_dev, (uint8_t *)&send_id, 1,(uint8_t *)recei_id, 3);
    rt_kprintf("use rt_spi_transfer_message() read gd25q ID is:%x,%x,%x\n", recei_id[0], recei_id[1],recei_id[2]);

    /* WRITE ENABLE */
    rt_spi_transfer((struct rt_spi_device *)spi_dev, (uint8_t *)&WREN,(uint8_t *)recei_id, 1);

    /* ERASE SECTOR */
    rt_spi_transfer((struct rt_spi_device *)spi_dev, (uint8_t *)address,(uint8_t *)recei_id, 4);
    rt_thread_mdelay(100);

    /* WRITE ENABLE */
    rt_spi_transfer((struct rt_spi_device *)spi_dev, (uint8_t *)&WREN,(uint8_t *)recei_id, 1);

    /* WRITE TO PAGE */
    rt_spi_send_then_send((struct rt_spi_device *)spi_dev, (uint8_t *)waddress, 4,(uint8_t *)tx_buffer, 200);
    rt_thread_mdelay(50);

    /* READ TO BUFFER */
    rt_spi_send_then_recv((struct rt_spi_device *)spi_dev, (uint8_t *)raddress, 4,(uint8_t *)rx_buffer, 200);
    rt_thread_mdelay(20);

    if(memcpy(rx_buffer, tx_buffer, 200)) {
        rt_kprintf("spi flash write and read test success.\r\n");
    } else {
        rt_kprintf("spi flash write and read test failed.\r\n");
    }

//    for(int i = 0; i < 200; i ++){
//        rt_kprintf("%d:  %x\n  ", i, rx_buffer[i]);
//    }
}

#endif

#ifdef GD32H7_USART_TX_DMA_TEST
#define SAMPLE_UART_NAME                 "uart2"

struct rx_msg
{
    rt_device_t dev;
    rt_size_t size;
};

static struct rt_messagequeue rx_mq;

static struct rt_semaphore rx_sem_test;
static rt_device_t serial_test;

static rt_err_t uart_input(rt_device_t dev, rt_size_t size)
{
    struct rx_msg msg;
    rt_err_t result;
    msg.dev = dev;
    msg.size = size;

    result = rt_mq_send(&rx_mq, &msg, sizeof(msg));
    if ( result == -RT_EFULL)
    {
        rt_kprintf("message queue full!\n");
    }
    return result;
}

static rt_err_t uart_tx_complete(rt_device_t dev, void *buffer)
{
    rt_err_t result = RT_EOK;

    rt_kprintf("uart_tx_complete!\n");

    return result;
}

#if 0
static void serial_thread_entry(void *parameter)
{
    struct rx_msg msg;
    rt_err_t result;
    rt_uint32_t rx_length;
    static char rx_buffer[RT_SERIAL_RB_BUFSZ + 1];

    while (1)
    {
        rt_memset(&msg, 0, sizeof(msg));

        result = rt_mq_recv(&rx_mq, &msg, sizeof(msg), RT_WAITING_FOREVER);
        if (result > 0)
        {

            rx_length = rt_device_read(msg.dev, 0, rx_buffer, msg.size);
            rx_buffer[rx_length] = '\0';

            rt_device_write(serial_test, 0, rx_buffer, rx_length);

            rt_thread_mdelay(20);
        }
    }
}

#else
static void serial_thread_entry(void *parameter)
{
    struct rx_msg msg;
    rt_err_t result;
    rt_uint32_t rx_length;
    static char rx_buffer[RT_SERIAL_RB_BUFSZ + 1];

    while (1)
    {
        rt_memset(&msg, 0, sizeof(msg));

        result = rt_mq_recv(&rx_mq, &msg, sizeof(msg), RT_WAITING_FOREVER);
        if (result > 0)
        {

            rx_length = rt_device_read(msg.dev, 0, rx_buffer, msg.size);
            rx_buffer[rx_length] = '\0';

            rt_device_write(serial_test, 0, rx_buffer, rx_length);

            rt_thread_mdelay(20);
            rt_kprintf("%s\n",rx_buffer);
//            rt_thread_mdelay(100);

            rt_device_close(serial_test);
            rt_kprintf("close usart2\n");
//            rt_device_control(serial_test, RT_DEVICE_CTRL_CLR_INT, RT_NULL);
//            break;
            
            rt_thread_mdelay(100);
            
            serial_test = rt_device_find(SAMPLE_UART_NAME);
            rt_device_open(serial_test, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_DMA_RX | RT_DEVICE_FLAG_DMA_TX);
            rt_kprintf("open usart2\n");
            rt_thread_mdelay(100);
        }
    }
}
#endif

static int uart_data_sample(int argc, char *argv[])
{
    rt_err_t ret = RT_EOK;
    char uart_name[RT_NAME_MAX];
    __ALIGNED(4) static char str[32] = "hello RT-Thread!\r\n";
    static char msg_pool[256] = {0};

    if (argc == 2)
    {
        rt_strncpy(uart_name, argv[1], RT_NAME_MAX);
    }
    else
    {
        rt_strncpy(uart_name, SAMPLE_UART_NAME, RT_NAME_MAX);
    }

    serial_test = rt_device_find(SAMPLE_UART_NAME);
    if (!serial_test)
    {
        rt_kprintf("find %s failed!\n", SAMPLE_UART_NAME);
        return RT_ERROR;
    }

    rt_mq_init(&rx_mq, "rx_mq", msg_pool, sizeof(struct rx_msg), sizeof(msg_pool), RT_IPC_FLAG_FIFO);

    rt_device_open(serial_test, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_DMA_RX | RT_DEVICE_FLAG_DMA_TX);

    rt_device_set_rx_indicate(serial_test, uart_input);
    
    rt_device_set_tx_complete(serial_test, uart_tx_complete);

    rt_device_write(serial_test, 0, str, (strlen(str) - 1));

    rt_thread_mdelay(5);

    rt_thread_t thread = rt_thread_create("serial2", serial_thread_entry, RT_NULL, 2048, 25, 10);

    if (thread != RT_NULL)
    {
        rt_kprintf("serial2 thread has been created. \r\n");
        rt_thread_startup(thread);
    }
    else
    {
        ret = RT_ERROR;
    }

    return ret;
}
#endif
