#include <stdint.h>
#include <stdbool.h>  
#include "SPIBUS.h"

#ifdef USE_SPI1
#include "mcc_generated_files/spi1.h"  
#endif
#ifdef USE_SPI2
#include "mcc_generated_files/spi2.h"  
#endif
#ifdef USE_SPI3
#include "mcc_generated_files/spi3.h"  
#endif
#ifdef USE_SPI4
#include "mcc_generated_files/spi4.h"  
#endif

extern volatile uint16_t tick;

uint8_t SPIWriteRead(SPIBUS_t * pSPIObj);

#ifdef USE_SPI1
static uint16_t dataSentCount_1;
static uint16_t dataReceivedCount_1;
static uint16_t MaxSize_1; //uint may byte, may word
#endif

#ifdef USE_SPI2
static uint16_t dataSentCount_2;
static uint16_t dataReceivedCount_2;
static uint16_t MaxSize_2; //uint may byte, may word
#endif


#ifdef USE_SPI3
static uint16_t dataSentCount_3;
static uint16_t dataReceivedCount_3;
static uint16_t MaxSize_3; //uint may byte, may word
#endif

#ifdef USE_SPI4
static uint16_t dataSentCount_4;
static uint16_t dataReceivedCount_4;
static uint16_t MaxSize_4; //uint may byte, may word
#endif


//SPI_Poll_t POLL_InMain = 0;
SPI_Poll_t POLL_InMain ={0,0,0,0};
#ifdef USE_SPI1 
uint8_t LowerLayer_spi_ReturnResult1 = 1; //means continue
#endif
#ifdef USE_SPI2 
uint8_t LowerLayer_spi_ReturnResult2 = 1; //means continue
#endif
#ifdef USE_SPI3 
uint8_t LowerLayer_spi_ReturnResult3 = 1; //means continue
#endif
#ifdef USE_SPI4 
uint8_t LowerLayer_spi_ReturnResult4 = 1; //means continue
#endif

uint8_t SPIWriteRead(SPIBUS_t * pSPIObj) {
    uint8_t retR;
    switch (pSPIObj->SPI_Peripheral_No) {
        case 1:
#ifdef USE_SPI1
            if ((1 == LowerLayer_spi_ReturnResult1)&&(0 == POLL_InMain.SPI1_Polling)) //let main loop call forever
            {
                POLL_InMain.SPI1_Polling = 1;
                LowerLayer_spi_ReturnResult1 = SPIWriteRead_lowLayer(pSPIObj);
                if ((0 == LowerLayer_spi_ReturnResult1) || (-1 == LowerLayer_spi_ReturnResult1)) {
                    //success or fail
                    POLL_InMain.SPI1_Polling = 0; //stop main loop call forever
                    retR = LowerLayer_spi_ReturnResult1;
                    LowerLayer_spi_ReturnResult1 = 1; //for next time call me : both LowerLayer_spi_ReturnResult1==1 and POLL_InMain==0
                    return retR;
                }
            }
            retR = LowerLayer_spi_ReturnResult1;
            if ((0 == LowerLayer_spi_ReturnResult1) || (-1 == LowerLayer_spi_ReturnResult1)) {
                //success or fail                
                LowerLayer_spi_ReturnResult1 = 1; //for next time call me : both LowerLayer_spi_ReturnResult1==1 and POLL_InMain==0
            }
            return retR;
#else
            return -1; //error
#endif
            break;
        case 2:
#ifdef USE_SPI2
            if ((1 == LowerLayer_spi_ReturnResult2)&&(0 == POLL_InMain.SPI2_Polling)) //let main loop call forever
            {
                POLL_InMain.SPI2_Polling = 1;
                LowerLayer_spi_ReturnResult2 = SPIWriteRead_lowLayer(pSPIObj);
                if ((0 == LowerLayer_spi_ReturnResult2) || (-1 == LowerLayer_spi_ReturnResult2)) {
                    //success or fail
                    POLL_InMain.SPI2_Polling = 0; //stop main loop call forever
                    retR = LowerLayer_spi_ReturnResult2;
                    LowerLayer_spi_ReturnResult2 = 1; //for next time call me : both LowerLayer_spi_ReturnResult2==1 and POLL_InMain==0
                    return retR;
                }
            }
            retR = LowerLayer_spi_ReturnResult2;
            if ((0 == LowerLayer_spi_ReturnResult2) || (-1 == LowerLayer_spi_ReturnResult2)) {
                //success or fail                
                LowerLayer_spi_ReturnResult2 = 1; //for next time call me : both LowerLayer_spi_ReturnResult2==1 and POLL_InMain==0
            }
            return retR;
#else
            return -1; //error
#endif
            break;
        case 3:
#ifdef USE_SPI3
            if ((1 == LowerLayer_spi_ReturnResult3)&&(0 == POLL_InMain.SPI3_Polling)) //let main loop call forever
            {
                POLL_InMain.SPI3_Polling = 1;
                LowerLayer_spi_ReturnResult3 = SPIWriteRead_lowLayer(pSPIObj);
                if ((0 == LowerLayer_spi_ReturnResult3) || (-1 == LowerLayer_spi_ReturnResult3)) {
                    //success or fail
                    POLL_InMain.SPI3_Polling = 0; //stop main loop call forever
                    retR = LowerLayer_spi_ReturnResult3;
                    LowerLayer_spi_ReturnResult3 = 1; //for next time call me : both LowerLayer_spi_ReturnResult3==1 and POLL_InMain==0
                    return retR;
                }
            }
            retR = LowerLayer_spi_ReturnResult3;
            if ((0 == LowerLayer_spi_ReturnResult3) || (-1 == LowerLayer_spi_ReturnResult3)) {
                //success or fail
                LowerLayer_spi_ReturnResult3 = 1; //for next time call me : both LowerLayer_spi_ReturnResult3==1 and POLL_InMain==0
            }
            return retR;
#else
            return -1; //error
#endif
            break;
        case 4:
#ifdef USE_SPI4
            if ((1 == LowerLayer_spi_ReturnResult4)&&(0 == POLL_InMain.SPI4_Polling)) //let main loop call forever
            {
                POLL_InMain.SPI4_Polling = 1;
                LowerLayer_spi_ReturnResult4 = SPIWriteRead_lowLayer(pSPIObj);
                if ((0 == LowerLayer_spi_ReturnResult4) || (-1 == LowerLayer_spi_ReturnResult4)) {
                    //success or fail
                    POLL_InMain.SPI4_Polling = 0; //stop main loop call forever
                    retR = LowerLayer_spi_ReturnResult4;
                    LowerLayer_spi_ReturnResult4 = 1; //for next time call me : both LowerLayer_spi_ReturnResult4==1 and POLL_InMain==0
                    return retR;
                }
            }
            retR = LowerLayer_spi_ReturnResult4;
            if ((0 == LowerLayer_spi_ReturnResult4) || (-1 == LowerLayer_spi_ReturnResult4)) {
                //success or fail
                LowerLayer_spi_ReturnResult4 = 1; //for next time call me : both LowerLayer_spi_ReturnResult4==1 and POLL_InMain==0
            }
            return retR;
#else
            return -1; //error
#endif            
    }
    return 1;
}

/**
 * SPI Write-only/ Read-only/ Write and read   Function
 * @param pI2CObj --- I2C Bus object
 * 
 * @return 
 * 0: Success
 * 1: Continue
 * negative: fail
 */
uint8_t SPIWriteRead_lowLayer(SPIBUS_t * pSPIObj) {
    int16_t i;
    switch (pSPIObj->state) {
        case 0:
            //prepare all spi ans transmit Data including dummy data, 
            //Actually Transmit and receiver Array is equal size.
            //So Actually we defined equal size array in pSPIObj
            if (1 == pSPIObj->SPI_Peripheral_No) {
#ifdef USE_SPI1      
                dataSentCount_1 = 0;
                dataReceivedCount_1 = 0;
                MaxSize_1 = (pSPIObj->QTY4Read[pSPIObj->PresentSeqNo] > pSPIObj->QTY4Write[pSPIObj->PresentSeqNo]) ? pSPIObj->QTY4Read[pSPIObj->PresentSeqNo] : pSPIObj->QTY4Write[pSPIObj->PresentSeqNo];
                if (pSPIObj->Use16bitsBus) {
                    //16 bits
                    //pic18 has no 16 bits
                } else {
                    //8 bits
                    if (pSPIObj->QTY4Write[pSPIObj->PresentSeqNo] < MaxSize_1) {
                        if (pSPIObj->DummyDataAllOne & (1U << pSPIObj->PresentSeqNo)) {
                            //All 1 for dummy data
                            for (i = pSPIObj->QTY4Write[pSPIObj->PresentSeqNo]; i < MaxSize_1; i++) {
                                pSPIObj->pWriteData[pSPIObj->PresentSeqNo][i] = 0xFF;
                            }
                        } else {
                            //All 0 for dummy data
                            for (i = pSPIObj->QTY4Write[pSPIObj->PresentSeqNo]; i < MaxSize_1; i++) {
                                pSPIObj->pWriteData[pSPIObj->PresentSeqNo][i] = 0x0;
                            }
                        }
                    }
                    //transmit ---8 bits bus
                    (pSPIObj->set_CS[pSPIObj->PresentSeqNo])(true);
                    //(pSPIObj->set_CS + pSPIObj->PresentSeqNo)(true);                   
                    
                    //at most, 20 bytes
                    for (i=1;20;i++)
                    {
                        pSPIObj->pReadData[pSPIObj->PresentSeqNo][dataReceivedCount_1++]=SPI1_ExchangeByte(pSPIObj->pWriteData[pSPIObj->PresentSeqNo][dataSentCount_1++]);
                        if (dataReceivedCount_1>=MaxSize_1) break;
                    }                    
                }
                if ((MaxSize_1 == dataSentCount_1) && (MaxSize_1 == dataReceivedCount_1)) {
                    //done all transmit/receive
                    pSPIObj->set_CS[pSPIObj->PresentSeqNo](false);
                    //(pSPIObj->set_CS + pSPIObj->PresentSeqNo)(false);
                    return 0; //success
                }
                pSPIObj->state++;
                return 1;
#else
                return -1;
#endif
            } else if (2 == pSPIObj->SPI_Peripheral_No) {
#ifdef USE_SPI2   
                dataSentCount_2 = 0;
                dataReceivedCount_2 = 0;
                MaxSize_2 = (pSPIObj->QTY4Read[pSPIObj->PresentSeqNo] > pSPIObj->QTY4Write[pSPIObj->PresentSeqNo]) ? pSPIObj->QTY4Read[pSPIObj->PresentSeqNo] : pSPIObj->QTY4Write[pSPIObj->PresentSeqNo];
                if (pSPIObj->Use16bitsBus) {
                    //16 bits
                    //no 16 bits for pic18 spi
                } else {
                    //8 bits
                    if (pSPIObj->QTY4Write[pSPIObj->PresentSeqNo] < MaxSize_2) {
                        if (pSPIObj->DummyDataAllOne & (1U << pSPIObj->PresentSeqNo)) {
                            //All 1 for dummy data
                            for (i = pSPIObj->QTY4Write[pSPIObj->PresentSeqNo]; i < MaxSize_2; i++) {
                                pSPIObj->pWriteData[pSPIObj->PresentSeqNo][i] = 0xFF;
                            }
                        } else {
                            //All 0 for dummy data
                            for (i = pSPIObj->QTY4Write[pSPIObj->PresentSeqNo]; i < MaxSize_2; i++) {
                                pSPIObj->pWriteData[pSPIObj->PresentSeqNo][i] = 0x0;
                            }
                        }
                    }
                    //transmit ---8 bits bus
                    pSPIObj->set_CS[pSPIObj->PresentSeqNo](true);
                    //(pSPIObj->set_CS + pSPIObj->PresentSeqNo)(true);
                    //at most, 20 bytes
                    for (i=1;20;i++)
                    {
                        pSPIObj->pReadData[pSPIObj->PresentSeqNo][dataReceivedCount_2++]=SPI2_ExchangeByte(pSPIObj->pWriteData[pSPIObj->PresentSeqNo][dataSentCount_2++]);
                        if (dataReceivedCount_2>=MaxSize_2) break;
                    }       
                }
                if ((MaxSize_2 == dataSentCount_2) && (MaxSize_2 == dataReceivedCount_2)) {
                    //done all transmit/receive
                    //pSPIObj->set_CS[pSPIObj->PresentSeqNo](false);
                    (pSPIObj->set_CS + pSPIObj->PresentSeqNo)(false);
                    return 0; //success
                }
                pSPIObj->state++;
                return 1;
#else
                return -1;
#endif
            } else if (3 == pSPIObj->SPI_Peripheral_No) {
#ifdef USE_SPI3   
                dataSentCount_3 = 0;
                dataReceivedCount_3 = 0;
                MaxSize_3 = (pSPIObj->QTY4Read[pSPIObj->PresentSeqNo] > pSPIObj->QTY4Write[pSPIObj->PresentSeqNo]) ? pSPIObj->QTY4Read[pSPIObj->PresentSeqNo] : pSPIObj->QTY4Write[pSPIObj->PresentSeqNo];
                if (pSPIObj->Use16bitsBus) {
                    //16 bits
                    //no 16 bits spi for pic18
                } else {
                    //8 bits
                    if (pSPIObj->QTY4Write[pSPIObj->PresentSeqNo] < MaxSize_3) {
                        if (pSPIObj->DummyDataAllOne & (1U << pSPIObj->PresentSeqNo)) {
                            //All 1 for dummy data
                            for (i = pSPIObj->QTY4Write[pSPIObj->PresentSeqNo]; i < MaxSize_3; i++) {
                                pSPIObj->pWriteData[pSPIObj->PresentSeqNo][i] = 0xFF;
                            }
                        } else {
                            //All 0 for dummy data
                            for (i = pSPIObj->QTY4Write[pSPIObj->PresentSeqNo]; i < MaxSize_3; i++) {
                                pSPIObj->pWriteData[pSPIObj->PresentSeqNo][i] = 0x0;
                            }
                        }
                    }
                    //transmit ---8 bits bus
                    pSPIObj->set_CS[pSPIObj->PresentSeqNo](true);
                    //(pSPIObj->set_CS + pSPIObj->PresentSeqNo)(true);
                    //at most, 20 bytes
                    for (i=1;20;i++)
                    {
                        pSPIObj->pReadData[pSPIObj->PresentSeqNo][dataReceivedCount_3++]=SPI3_ExchangeByte(pSPIObj->pWriteData[pSPIObj->PresentSeqNo][dataSentCount_3++]);
                        if (dataReceivedCount_3>=MaxSize_3) break;
                    }  
                }
                if ((MaxSize_3 == dataSentCount_3) && (MaxSize_3 == dataReceivedCount_3)) {
                    //done all transmit/receive
                    //pSPIObj->set_CS[pSPIObj->PresentSeqNo](false);
                    (pSPIObj->set_CS + pSPIObj->PresentSeqNo)(false);
                    return 0; //success
                }
                pSPIObj->state++;
                return 1;
#else
                return -1;
#endif
            } else if (4 == pSPIObj->SPI_Peripheral_No) {
#ifdef USE_SPI4 
                dataSentCount_4 = 0;
                dataReceivedCount_4 = 0;
                MaxSize_4 = (pSPIObj->QTY4Read[pSPIObj->PresentSeqNo] > pSPIObj->QTY4Write[pSPIObj->PresentSeqNo]) ? pSPIObj->QTY4Read[pSPIObj->PresentSeqNo] : pSPIObj->QTY4Write[pSPIObj->PresentSeqNo];
                if (pSPIObj->Use16bitsBus) {
                    //16 bits
                    //no 16 bits spi for pic18
                } else {
                    //8 bits
                    if (pSPIObj->QTY4Write[pSPIObj->PresentSeqNo] < MaxSize_4) {
                        if (pSPIObj->DummyDataAllOne & (1U << pSPIObj->PresentSeqNo)) {
                            //All 1 for dummy data
                            for (i = pSPIObj->QTY4Write[pSPIObj->PresentSeqNo]; i < MaxSize_4; i++) {
                                pSPIObj->pWriteData[pSPIObj->PresentSeqNo][i] = 0xFF;
                            }
                        } else {
                            //All 0 for dummy data
                            for (i = pSPIObj->QTY4Write[pSPIObj->PresentSeqNo]; i < MaxSize_4; i++) {
                                pSPIObj->pWriteData[pSPIObj->PresentSeqNo][i] = 0x0;
                            }
                        }
                    }
                    //transmit ---8 bits bus
                    pSPIObj->set_CS[pSPIObj->PresentSeqNo](true);
                    //(pSPIObj->set_CS + pSPIObj->PresentSeqNo)(true);
                    //at most, 20 bytes
                    for (i=1;20;i++)
                    {
                        pSPIObj->pReadData[pSPIObj->PresentSeqNo][dataReceivedCount_4++]=SPI4_ExchangeByte(pSPIObj->pWriteData[pSPIObj->PresentSeqNo][dataSentCount_4++]);
                        if (dataReceivedCount_4>=MaxSize_4) break;
                    }  
                }
                if ((MaxSize_4 == dataSentCount_4) && (MaxSize_4 == dataReceivedCount_4)) {
                    //done all transmit/receive
                    //pSPIObj->set_CS[pSPIObj->PresentSeqNo](false);
                    (pSPIObj->set_CS + pSPIObj->PresentSeqNo)(false);
                    return 0; //success
                }
                pSPIObj->state++;
                return 1;
#else                
                return -1;
#endif
            }
            break;
        case 1:
            //Transmit/receiving continuously
            if (1 == pSPIObj->SPI_Peripheral_No) {
#ifdef USE_SPI1                
                if (pSPIObj->Use16bitsBus) {
                    //16 bits
                    //no 16 bits spi for pic18

                } else {
                    //8 bits
                    //transmit ---8 bits bus
                    
                    //At most, we transmit 20 bytes
                    for (i=1;20;i++)
                    {
                        pSPIObj->pReadData[pSPIObj->PresentSeqNo][dataReceivedCount_1++]=SPI1_ExchangeByte(pSPIObj->pWriteData[pSPIObj->PresentSeqNo][dataSentCount_1++]);
                        if (dataReceivedCount_1>=MaxSize_1) break;
                    }   
                    if (MaxSize_1 == dataSentCount_1) {                        
                        pSPIObj->set_CS[pSPIObj->PresentSeqNo](false);
                        //(pSPIObj->set_CS + pSPIObj->PresentSeqNo)(false);
                        pSPIObj->state = 0;
                        return 0; //success
                    }
                    
                }
                return 1; //continue
#else
                pSPIObj->state = 0;
                return -1; //Fail
#endif
            } else if (2 == pSPIObj->SPI_Peripheral_No) {
#ifdef USE_SPI2
                if (pSPIObj->Use16bitsBus) {
                    //16 bits
                    //no 16 bits spi for pic18
                    

                } else {
                    //8 bits
                    //transmit ---8 bits bus                                       
                    //At most, we transmit 20 bytes
                    for (i=1;20;i++)
                    {
                        pSPIObj->pReadData[pSPIObj->PresentSeqNo][dataReceivedCount_2++]=SPI2_ExchangeByte(pSPIObj->pWriteData[pSPIObj->PresentSeqNo][dataSentCount_2++]);
                        if (dataReceivedCount_2>=MaxSize_2) break;
                    }   
                    if (MaxSize_2 == dataSentCount_2) {                        
                        pSPIObj->set_CS[pSPIObj->PresentSeqNo](false);
                        //(pSPIObj->set_CS + pSPIObj->PresentSeqNo)(false);
                        pSPIObj->state = 0;
                        return 0; //success
                    }
                    
                }
                return 1; //continue
#else
                pSPIObj->state = 0;
                return -1; //Fail
#endif                
            } else if (3 == pSPIObj->SPI_Peripheral_No) {
#ifdef USE_SPI3
                if (pSPIObj->Use16bitsBus) {
                    //16 bits
                    //no 16 bits spi for pic18
                    
                } else {
                    //8 bits
                    //transmit ---8 bits bus
                    //At most, we transmit 20 bytes
                    for (i=1;20;i++)
                    {
                        pSPIObj->pReadData[pSPIObj->PresentSeqNo][dataReceivedCount_3++]=SPI3_ExchangeByte(pSPIObj->pWriteData[pSPIObj->PresentSeqNo][dataSentCount_3++]);
                        if (dataReceivedCount_3>=MaxSize_3) break;
                    }   
                    if (MaxSize_3 == dataSentCount_3) {                        
                        pSPIObj->set_CS[pSPIObj->PresentSeqNo](false);
                        //(pSPIObj->set_CS + pSPIObj->PresentSeqNo)(false);
                        pSPIObj->state = 0;
                        return 0; //success
                    }
                    
                }
                return 1; //continue
#else
                pSPIObj->state = 0;
                return -1; //Fail
#endif                
            } else if (4 == pSPIObj->SPI_Peripheral_No) {
#ifdef USE_SPI4
                if (pSPIObj->Use16bitsBus) {
                    //16 bits
                    //no 16 bits spi for pic18

                } else {
                    //8 bits
                    //transmit ---8 bits bus
                    
                    //At most, we transmit 20 bytes
                    for (i=1;20;i++)
                    {
                        pSPIObj->pReadData[pSPIObj->PresentSeqNo][dataReceivedCount_4++]=SPI4_ExchangeByte(pSPIObj->pWriteData[pSPIObj->PresentSeqNo][dataSentCount_4++]);
                        if (dataReceivedCount_4>=MaxSize_4) break;
                    }   
                    
                    if (MaxSize_4 == dataSentCount_4) {                        
                        pSPIObj->set_CS[pSPIObj->PresentSeqNo](false);
                        //(pSPIObj->set_CS + pSPIObj->PresentSeqNo)(false);
                        pSPIObj->state = 0;
                        return 0; //success
                    }
                    
                }
                return 1; //continue
#else
                pSPIObj->state = 0;
                return -1; //Fail
#endif               
            }

    }
    return 1;
}




