#include "spi.h"
#include "tool.h"

#define CS_ENABLE() Dev.CS ? Dev.CS_SET(HIGH) : Dev.CS_SET(LOW)
#define CS_DISABLE() Dev.CS ? Dev.CS_SET(LOW) : Dev.CS_SET(HIGH)

static inline uint8_t spi_RW(SW_Dev_Spi Dev, uint8_t Write_Date) {
    uint8_t i, read_date = 0;
    switch (Dev.MODE) {
        case Mode0:
            for (i = 0; i < 8; i++) {
                if (Write_Date & 0x80)
                    Dev.MOSI_SET(HIGH);
                else
                    Dev.MOSI_SET(LOW);
                Write_Date <<= 1;DELAY1US();
                Dev.SCK_SET(HIGH);
                read_date <<= 1;
                if (Dev.MISO())
                    read_date++;DELAY1US();
                Dev.SCK_SET(LOW);NOP();
            }
            break;
        case Mode1:
            for (i = 0; i < 8; i++) {
                Dev.SCK_SET(HIGH);
                if (Write_Date & 0x80)
                    Dev.MOSI_SET(HIGH);
                else
                    Dev.MOSI_SET(LOW);
                Write_Date <<= 1;DELAY1US();
                Dev.SCK_SET(LOW);
                read_date <<= 1;
                if (Dev.MISO())
                    read_date++;DELAY1US();
            }
            break;
        case Mode2:
            for (i = 0; i < 8; i++) {
                if (Write_Date & 0x80)
                    Dev.MOSI_SET(HIGH);
                else
                    Dev.MOSI_SET(LOW);
                Write_Date <<= 1;DELAY1US();
                Dev.SCK_SET(LOW);
                read_date <<= 1;
                if (Dev.MISO())
                    read_date++;DELAY1US();
                Dev.SCK_SET(HIGH);
            }
            break;
        case Mode3:
            for (i = 0; i < 8; i++) {
                Dev.SCK_SET(LOW);
                if (Write_Date & 0x80)
                    Dev.MOSI_SET(HIGH);
                else
                    Dev.MOSI_SET(LOW);
                Write_Date <<= 1;DELAY1US();
                Dev.SCK_SET(HIGH);
                read_date <<= 1;
                if (Dev.MISO())
                    read_date++;DELAY1US();NOP();
            }
            break;
    }
    return read_date;
}

uint8_t SW_SPI_RW(SW_Dev_Spi Dev, uint8_t Write_Date) {
    uint8_t read_date;
    CS_ENABLE();
    read_date = spi_RW(Dev, Write_Date);
    CS_DISABLE();
    return read_date;
}

void SW_SPI_WL(SW_Dev_Spi Dev, uint8_t *Write_Date, uint32_t Len) {
    CS_ENABLE();
    for (uint32_t i = 0; i < Len; i++)
        spi_RW(Dev, Write_Date[i]);
    CS_DISABLE();
}

void SW_SPI_RL(SW_Dev_Spi Dev, uint8_t *Read_Date, uint32_t Len) {
    CS_ENABLE();
    for (uint32_t i = 0; i < Len; i++)
        Read_Date[i] = spi_RW(Dev, 0xFF);
    CS_DISABLE();
}

void SW_SPI_RWL(SW_Dev_Spi Dev, uint8_t *Read_Date, uint8_t *Write_Date, uint32_t Len) {
    CS_ENABLE();
    for (uint32_t i = 0; i < Len; i++)
        Read_Date[i] = spi_RW(Dev, Write_Date[i]);
    CS_DISABLE();
}

uint16_t SW_SPI_RW16(SW_Dev_Spi Dev, uint16_t Write_Date) {
    Data16_t wdate16, rdate16;
    wdate16.u16 = Write_Date;
    CS_ENABLE();
    if (Dev.ENDIAN) {
        rdate16.u8[0] = spi_RW(Dev, wdate16.u8[0]);
        rdate16.u8[1] = spi_RW(Dev, wdate16.u8[1]);
    } else {
        rdate16.u8[0] = spi_RW(Dev, wdate16.u8[1]);
        rdate16.u8[1] = spi_RW(Dev, wdate16.u8[0]);
    }
    CS_DISABLE();
    return rdate16.u16;
}

void SW_SPI_RL16(SW_Dev_Spi Dev, uint16_t *Read_Date, uint32_t Len) {
    Data16_t rdate16;
    CS_ENABLE();
    switch (Dev.ENDIAN) {
        case LTL:
            for (uint32_t i = 0; i < Len; i++) {
                rdate16.u8[0] = spi_RW(Dev, 0xFF);
                rdate16.u8[1] = spi_RW(Dev, 0xFF);
                Read_Date[i] = rdate16.u16;
            }
            break;
        case LTB:
            for (uint32_t i = 0; i < Len; i++) {
                rdate16.u8[0] = spi_RW(Dev, 0xFF);
                rdate16.u8[1] = spi_RW(Dev, 0xFF);
                Read_Date[i] = rdate16.u16;
            }
            break;
        case BTB:
            for (uint32_t i = 0; i < Len; i++) {
                rdate16.u8[1] = spi_RW(Dev, 0xFF);
                rdate16.u8[0] = spi_RW(Dev, 0xFF);
                Read_Date[i] = rdate16.u16;
            }
            break;
        case BTL:
            for (uint32_t i = 0; i < Len; i++) {
                rdate16.u8[1] = spi_RW(Dev, 0xFF);
                rdate16.u8[0] = spi_RW(Dev, 0xFF);
                Read_Date[i] = rdate16.u16;
            }
            break;
    }
    CS_DISABLE();
}

void SW_SPI_WL16(SW_Dev_Spi Dev, uint16_t *Write_Date, uint32_t Len) {
    Data16_t wdate16;
    CS_ENABLE();
    switch (Dev.ENDIAN) {
        case LTL:
            for (uint32_t i = 0; i < Len; i++) {
                wdate16.u16 = Write_Date[i];
                spi_RW(Dev, wdate16.u8[0]);
                spi_RW(Dev, wdate16.u8[1]);
            }
            break;
        case LTB:
            for (uint32_t i = 0; i < Len; i++) {
                wdate16.u16 = Write_Date[i];
                spi_RW(Dev, wdate16.u8[1]);
                spi_RW(Dev, wdate16.u8[0]);
            }
            break;
        case BTB:
            for (uint32_t i = 0; i < Len; i++) {
                wdate16.u16 = Write_Date[i];
                spi_RW(Dev, wdate16.u8[1]);
                spi_RW(Dev, wdate16.u8[0]);
            }
            break;
        case BTL:
            for (uint32_t i = 0; i < Len; i++) {
                wdate16.u16 = Write_Date[i];
                spi_RW(Dev, wdate16.u8[0]);
                spi_RW(Dev, wdate16.u8[1]);
            }
            break;
    }
    CS_DISABLE();
}

void SW_SPI_RWL16(SW_Dev_Spi Dev, uint16_t *Read_Date, uint16_t *Write_Date, uint32_t Len) {
    Data16_t wdate16, rdate16;
    CS_ENABLE();
    switch (Dev.ENDIAN) {
        case LTL:
            for (uint32_t i = 0; i < Len; i++) {
                wdate16.u16 = Write_Date[i];
                rdate16.u8[0] = spi_RW(Dev, wdate16.u8[0]);
                rdate16.u8[1] = spi_RW(Dev, wdate16.u8[1]);
                Read_Date[i] = rdate16.u16;
            }
            break;
        case LTB:
            for (uint32_t i = 0; i < Len; i++) {
                wdate16.u16 = Write_Date[i];
                rdate16.u8[0] = spi_RW(Dev, wdate16.u8[1]);
                rdate16.u8[1] = spi_RW(Dev, wdate16.u8[0]);
                Read_Date[i] = rdate16.u16;
            }
            break;
        case BTB:
            for (uint32_t i = 0; i < Len; i++) {
                wdate16.u16 = Write_Date[i];
                rdate16.u8[1] = spi_RW(Dev, wdate16.u8[1]);
                rdate16.u8[0] = spi_RW(Dev, wdate16.u8[0]);
                Read_Date[i] = rdate16.u16;
            }
            break;
        case BTL:
            for (uint32_t i = 0; i < Len; i++) {
                wdate16.u16 = Write_Date[i];
                rdate16.u8[1] = spi_RW(Dev, wdate16.u8[0]);
                rdate16.u8[0] = spi_RW(Dev, wdate16.u8[1]);
                Read_Date[i] = rdate16.u16;
            }
            break;
    }
    CS_DISABLE();
}