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

#include "config/default/definitions.h"

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,0,0,0};  //let main loop call forever if it is 1. Actualy we used ISR SPI, so no need it, just keep all zero
#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

#ifdef USE_SPI1 
extern volatile bool transferStatus1;  //From SPI callback, true: sucess, false: wait
#endif
#ifdef USE_SPI2 
extern volatile bool transferStatus2;  //From SPI callback, true: sucess, false: wait
#endif
#ifdef USE_SPI3 
extern volatile bool transferStatus3;  //From SPI callback, true: sucess, false: wait
#endif
#ifdef USE_SPI4 
extern volatile bool transferStatus4;  //From SPI callback, true: sucess, false: wait
#endif
/**
 * 
 * @param pSPIObj
 * @return 0: success, plus: continue, negative : fail
 */
uint8_t SPIWriteRead(SPIBUS_t * pSPIObj) {
    uint16_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
                    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++) {
                                ((uint16_t * *) pSPIObj->pWriteData)[pSPIObj->PresentSeqNo][i] = 0xFFFFU;
                            }
                        } else {
                            //All 0 for dummy data
                            for (i = pSPIObj->QTY4Write[pSPIObj->PresentSeqNo]; i < MaxSize_1; i++) {
                                ((uint16_t * *) pSPIObj->pWriteData)[pSPIObj->PresentSeqNo][i] = 0x0;
                            }
                        }
                        //Transmit---16 bits bus
                        pSPIObj->set_CS[pSPIObj->PresentSeqNo](true);
                        
                        if (SERCOM0_SPI_WriteRead((void*)&(pSPIObj->pWriteData)[pSPIObj->PresentSeqNo][0], MaxSize_1*2, (void*)&(pSPIObj->pReadData)[pSPIObj->PresentSeqNo][0], MaxSize_1*2))
                        {
                            pSPIObj->state++;  
                        }
                        
                        

                    }
                } 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);
                    if (SERCOM0_SPI_WriteRead((void*)&(pSPIObj->pWriteData)[pSPIObj->PresentSeqNo][0], MaxSize_1, (void*)&(pSPIObj->pReadData)[pSPIObj->PresentSeqNo][0], MaxSize_1))
                    {
                            pSPIObj->state++;  
                    }
                }
                if(transferStatus1 == true) {
                    //done all transmit/receive
                    transferStatus1=false;
                    //pSPIObj->set_CS[pSPIObj->PresentSeqNo](false);  already did in callback                                        
                    return 0; //success
                }                
                return 1;  //continue
#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
                    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++) {
                                ((uint16_t * *) pSPIObj->pWriteData)[pSPIObj->PresentSeqNo][i] = 0xFFFFU;
                            }
                        } else {
                            //All 0 for dummy data
                            for (i = pSPIObj->QTY4Write[pSPIObj->PresentSeqNo]; i < MaxSize_2; i++) {
                                ((uint16_t * *) pSPIObj->pWriteData)[pSPIObj->PresentSeqNo][i] = 0x0;
                            }
                        }
                        //Transmit---16 bits bus
                        pSPIObj->set_CS[pSPIObj->PresentSeqNo](true);
                        if (SERCOM1_SPI_WriteRead((void*)&(pSPIObj->pWriteData)[pSPIObj->PresentSeqNo][0], MaxSize_2*2, (void*)&(pSPIObj->pReadData)[pSPIObj->PresentSeqNo][0], MaxSize_2*2))
                        {
                            pSPIObj->state++;  
                        }
                    }
                } 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);
                    if (SERCOM1_SPI_WriteRead((void*)&(pSPIObj->pWriteData)[pSPIObj->PresentSeqNo][0], MaxSize_2, (void*)&(pSPIObj->pReadData)[pSPIObj->PresentSeqNo][0], MaxSize_2))
                    {
                            pSPIObj->state++;  
                    }
                    
                }
                if(transferStatus2 == true) {
                    //done all transmit/receive
                    transferStatus2=false;
                    //pSPIObj->set_CS[pSPIObj->PresentSeqNo](false);  already did in callback                                        
                    return 0; //success
                }                
                return 1;  //continue
#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
                    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++) {
                                ((uint16_t * *) pSPIObj->pWriteData)[pSPIObj->PresentSeqNo][i] = 0xFFFFU;
                            }
                        } else {
                            //All 0 for dummy data
                            for (i = pSPIObj->QTY4Write[pSPIObj->PresentSeqNo]; i < MaxSize_3; i++) {
                                ((uint16_t * *) pSPIObj->pWriteData)[pSPIObj->PresentSeqNo][i] = 0x0;
                            }
                        }
                        //Transmit---16 bits bus
                        pSPIObj->set_CS[pSPIObj->PresentSeqNo](true);
                        if (SERCOM2_SPI_WriteRead((void*)&(pSPIObj->pWriteData)[pSPIObj->PresentSeqNo][0], MaxSize_3*2, (void*)&(pSPIObj->pReadData)[pSPIObj->PresentSeqNo][0], MaxSize_3*2))
                        {
                            pSPIObj->state++;  
                        }

                    }
                } 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);
                    if (SERCOM2_SPI_WriteRead((void*)&(pSPIObj->pWriteData)[pSPIObj->PresentSeqNo][0], MaxSize_3, (void*)&(pSPIObj->pReadData)[pSPIObj->PresentSeqNo][0], MaxSize_3))
                    {
                            pSPIObj->state++;  
                    }
                }
                if(transferStatus3 == true) {
                    //done all transmit/receive
                    transferStatus3=false;
                    //pSPIObj->set_CS[pSPIObj->PresentSeqNo](false);  already did in callback                                        
                    return 0; //success
                }                
                return 1;  //continue
#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
                    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++) {
                                ((uint16_t * *) pSPIObj->pWriteData)[pSPIObj->PresentSeqNo][i] = 0xFFFFU;
                            }
                        } else {
                            //All 0 for dummy data
                            for (i = pSPIObj->QTY4Write[pSPIObj->PresentSeqNo]; i < MaxSize_4; i++) {
                                ((uint16_t * *) pSPIObj->pWriteData)[pSPIObj->PresentSeqNo][i] = 0x0;
                            }
                        }
                        //Transmit---16 bits bus
                        pSPIObj->set_CS[pSPIObj->PresentSeqNo](true);
                        if (SERCOM3_SPI_WriteRead((void*)&(pSPIObj->pWriteData)[pSPIObj->PresentSeqNo][0], MaxSize_4*2, (void*)&(pSPIObj->pReadData)[pSPIObj->PresentSeqNo][0], MaxSize_4*2))
                        {
                            pSPIObj->state++;  
                        }


                    }
                } 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);
                    if (SERCOM3_SPI_WriteRead((void*)&(pSPIObj->pWriteData)[pSPIObj->PresentSeqNo][0], MaxSize_4, (void*)&(pSPIObj->pReadData)[pSPIObj->PresentSeqNo][0], MaxSize_4))
                    {
                            pSPIObj->state++;  
                    }
                }
                if(transferStatus4 == true) {
                    //done all transmit/receive
                    transferStatus4=false;
                    //pSPIObj->set_CS[pSPIObj->PresentSeqNo](false);  already did in callback                                        
                    return 0; //success
                }                
                return 1;  //continue
#else                
                return -1;
#endif
            }
            break;
        case 1:
            //Transmit/receiving continuously, wait for done
            if (1 == pSPIObj->SPI_Peripheral_No) {
#ifdef USE_SPI1                
                if(transferStatus1 == true) {
                    //done all transmit/receive
                    transferStatus1=false;
                    //pSPIObj->set_CS[pSPIObj->PresentSeqNo](false);  already did in callback    
                    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(transferStatus2 == true) {
                    //done all transmit/receive
                    transferStatus2=false;
                    //pSPIObj->set_CS[pSPIObj->PresentSeqNo](false);  already did in callback    
                    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(transferStatus3 == true) {
                    //done all transmit/receive
                    transferStatus3=false;
                    //pSPIObj->set_CS[pSPIObj->PresentSeqNo](false);  already did in callback    
                    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(transferStatus4 == true) {
                    //done all transmit/receive
                    transferStatus4=false;
                    //pSPIObj->set_CS[pSPIObj->PresentSeqNo](false);  already did in callback    
                    pSPIObj->state=0;
                    return 0; //success
                }                
                return 1;  //continue
#else
                pSPIObj->state = 0;
                return -1; //Fail
#endif               
            }

    }
    return 1;    

}

/**
 * SPI Write-only/ Read-only/ Write and read   Function
 * This is only for Non-ISR SPI bus main-loop call forever.  But for PIC32, we used ISR call back.  So no use, we just return 0
 * @param pSPIObj --- SPI Bus object
 * 
 * @return 
 * 0: Success
 * 1: Continue
 * negative: fail
 */
uint8_t SPIWriteRead_lowLayer(SPIBUS_t * pSPIObj) {

    return 0;  
}





