#include "system/includes.h"
#include "media/includes.h"
#include "asm/spi.h"
#include "generic/log.h"

#if 0
/*
    [[[ README ]]]
    1. 本spi测试demo提供了spi.c的API使用例程，测试方式为两个spi的环回测试。
    spi1设置为主机模式，spi2设置为从机模式，spi1发送数据到spi2，然后接收spi2
    原样返回的数据，然后比较发送出去的数据与接收的数据是否一致，一致则说明
    验证通过。
    2. 本demo涉及BYTE收发测试及DMA收发测试，通过宏SPI_TEST_MODE选择。另外
    demo还涉及到spi中断中调用可用于中断的spi API的使用。
    3. spi.c的API不包含CS引脚，CS由API以外控制。
    4. 请在board_xxx.c中定义配置结构体，例如用到spi1，需要定义spi1_p_data，
    否则编译出错。
    5. spi的DMA地址需要4字节对齐。
    6. 虽然spi.c的API带有spi0，但在有挂spi flash的芯片上使用可能会出问题，
    避免使用spi0。

*/

#define SPI1_CS_OUT() \
    do { \
        JL_PORTB->DIR &= ~BIT(4); \
        JL_PORTB->DIE |= BIT(4); \
        JL_PORTB->PU &= ~BIT(4); \
        JL_PORTB->PD &= ~BIT(4); \
    } while(0)
#define SPI1_CS_L()     (JL_PORTB->OUT &= ~BIT(4))
#define SPI1_CS_H()     (JL_PORTB->OUT |= BIT(4))

#define SPI2_CS_IN() \
    do { \
        JL_PORTA->DIR |= BIT(3); \
        JL_PORTA->DIE |= BIT(3); \
        JL_PORTA->PU &= ~BIT(3); \
        JL_PORTA->PD &= ~BIT(3); \
    } while (0)
#define SPI2_READ_CS()     (JL_PORTA->IN & BIT(3))

static u8 slave_dir = 1;
static u8 spi1_send_buf[100] __attribute__((aligned(4)));
static u8 spi1_recv_buf[100] __attribute__((aligned(4)));
static u8 spi2_send_buf[100] __attribute__((aligned(4)));
static u8 spi2_recv_buf[100] __attribute__((aligned(4)));

static spi_dev spi1_hdl = 1;
static spi_dev spi2_hdl = 2;

#define SPI_TEST_BYTE_MODE      0x01
#define SPI_TEST_DMA_MODE       0x02
//测试模式选择
#define SPI_TEST_MODE           SPI_TEST_BYTE_MODE

static void my_put_u8hex(u8 b)
{
    u8 dat;
    dat = b / 16;
    if (dat >= 0 && dat <= 9) {
        putchar('0' + dat);
    } else {
        putchar('A' + dat - 10);
    }
    dat = b % 16;
    if (dat >= 0 && dat <= 9) {
        putchar('0' + dat);
    } else {
        putchar('A' + dat - 10);
    }
    putchar(' ');
}

//中断函数，需以下特殊声明
__attribute__((interrupt("")))
static void spi2_isr()
{
    static int i = 0;
    if (spi_get_pending(spi2_hdl)) {
        spi_clear_pending(spi2_hdl);
        if (SPI2_READ_CS()) {
            return;
        }
#if SPI_TEST_MODE == SPI_TEST_BYTE_MODE
        if (slave_dir == 1) {
            spi2_recv_buf[i] = spi_recv_byte_for_isr(spi2_hdl);
            spi_send_byte_for_isr(spi2_hdl, spi2_recv_buf[i]);
            i >= 100 ? i = 0 : i++;
            slave_dir = 0;
        } else {
            slave_dir = 1;
        }
#elif SPI_TEST_MODE == SPI_TEST_DMA_MODE
        if (slave_dir == 1) {
            spi_dma_set_addr_for_isr(spi2_hdl, spi2_recv_buf, 100, 0);
            slave_dir = 0;
        } else {
            slave_dir = 1;
        }
#endif
    }
}

#if 1  //仅用于spi demo，正式工程请放到board_xxx.c文件中
/* const struct spi_platform_data spi0_p_data = { */
/* .port = 'A', */
/* .mode = SPI_MODE_BIDIR_1BIT, */
/* .clk = 1000000, */
/* .role = SPI_ROLE_MASTER, */
/* }; */

const struct spi_platform_data spi1_p_data = {
    .port = 'A',
    .mode = SPI_MODE_BIDIR_1BIT,
    .clk = 1000000,
    .role = SPI_ROLE_MASTER,
};

const struct spi_platform_data spi2_p_data = {
    .port = 'A',
    .mode = SPI_MODE_BIDIR_1BIT,
    .clk = 1000000,
    .role = SPI_ROLE_SLAVE,
};
#endif


void spi_test_main()
{
    int i;
    int err;

    spi_open(spi1_hdl);
    spi_open(spi2_hdl);
    spi_set_ie(spi2_hdl, 1);
    //配置中断优先级，中断函数
    request_irq(IRQ_SPI2_IDX, 3, spi2_isr, 0);

    SPI1_CS_OUT();
    SPI2_CS_IN();
    SPI1_CS_H();
    for (i = 0; i < 100; i++) {
        spi1_send_buf[i] = i % 26 + 'A';
        spi1_recv_buf[i] = 0;
    }
    puts(">>> spi test start\n");
#if SPI_TEST_MODE == SPI_TEST_BYTE_MODE
    SPI1_CS_L();
    for (i = 0; i < 100; i++) {
        err = spi_send_byte(spi1_hdl, spi1_send_buf[i]);
        if (err) {
            puts("spi1 byte send timeout\n");
            break;
        }
        delay(100);
        spi1_recv_buf[i] = spi_recv_byte(spi1_hdl, &err);
        if (err) {
            puts("spi1 byte recv timeout\n");
            break;
        }
        delay(100);
    }
    SPI1_CS_H();
#elif SPI_TEST_MODE == SPI_TEST_DMA_MODE
    spi_dma_set_addr_for_isr(spi2_hdl, spi2_recv_buf, 100, 1);
    SPI1_CS_L();
    err = spi_dma_send(spi1_hdl, spi1_send_buf, 100);
    if (err < 0) {
        puts("spi1 dma send timeout\n");
        goto __out_dma;
    }
    //delay(100);
    err = spi_dma_recv(spi1_hdl, spi1_recv_buf, 100);
    if (err < 0) {
        puts("spi1 dma recv timeout\n");
        goto __out_dma;
    }
    //delay(100);
__out_dma:
    SPI1_CS_H();
#endif
    puts("<<< spi test end\n");

    puts("\nspi master receivce buffer:\n");
    for (i = 0; i < 100; i++) {
        //my_put_u8hex(spi1_recv_buf[i]);
        putchar(spi1_recv_buf[i]), putchar(0x20);
        if (i % 16 == 15) {
            putchar('\n');
        }
    }
    if (i % 16) {
        putchar('\n');
    }

    if (!memcmp(spi1_send_buf, spi1_recv_buf, 100)) {
        puts("\nspi test pass\n");
    } else {
        puts("\nspi test fail\n");
    }

    spi_close(spi1_hdl);
    spi_close(spi2_hdl);
}
#endif
