//#include <stdint.h>
//#include <stdbool.h>  
#include <xc.h>
#include "I2CBUS.h"
#define NULL ((void*)0)
#ifdef USE_I2C1
#include "mcc_generated_files/i2c_host/i2c1.h"  
#endif
#ifdef USE_I2C2
#include "mcc_generated_files/i2c2_master.h"  
#endif
#ifdef USE_I2C3
#include "mcc_generated_files/i2c3_master.h"  
#endif
#ifdef USE_I2C4
#include "mcc_generated_files/i2c4_master.h"  
#endif

extern volatile uint16_t tick;
#define I2C_DEVICE_TIMEOUT 50   //MAX=65535 ms, now it is 50ms, actually it is 500*1/100k=5ms when scl=100k, it is 500*1/400k=1.25msms when scl=400k, 
#define I2C_MAX_RE_TRY     8    //Max 255
uint8_t I2CWriteRead(I2CBUS_t * pI2CObj);


#ifdef USE_I2C1
static uint8_t ReTry_1;
static uint16_t Delay_1 = 0;
#endif




#ifdef USE_I2C2
static uint8_t ReTry_2;
static uint16_t Delay_2 = 0;
#endif

#ifdef USE_I2C3
static uint8_t ReTry_3;
static uint16_t Delay_3 = 0;
#endif

#ifdef USE_I2C4
static uint8_t ReTry_4;
static uint16_t Delay_4 = 0;
#endif



/**
 * I2C Write-only/ Read-only/ Write-first and then read   Function
 * @param pI2CObj --- I2C Bus object
 * 
 * @return 
 * 0: Success
 * 1: Continue
 * negative: fail
 */
uint8_t I2CWriteRead(I2CBUS_t * pI2CObj) {
    
    switch (pI2CObj->state) {
        case 0:            
            if (1 == pI2CObj->I2C_Peripheral_No) {
#ifdef USE_I2C1      
                
                Delay_1 = 0;
                ReTry_1 = 0;
                
                
                if (pI2CObj->QTY4Write[pI2CObj->PresentSeqNo] > 0) {
                    //writing exists
                    if (pI2CObj->QTY4Read[pI2CObj->PresentSeqNo] > 0) {
                        //both writing and reading
                        if (I2C1_WriteRead(pI2CObj->I2CAddr[pI2CObj->PresentSeqNo],pI2CObj->pWriteData[pI2CObj->PresentSeqNo], pI2CObj->QTY4Write[pI2CObj->PresentSeqNo], 
                                           pI2CObj->pReadData[pI2CObj->PresentSeqNo], pI2CObj->QTY4Read[pI2CObj->PresentSeqNo])) {
                            pI2CObj->state=2;  //done?
                            return 1; 
                        }
                    } else {
                        //no reading, so only writing                           
                        if (I2C1_Write(/*uint16_t address*/pI2CObj->I2CAddr[pI2CObj->PresentSeqNo], /*uint8_t *data*/pI2CObj->pWriteData[pI2CObj->PresentSeqNo], /*size_t dataLength*/pI2CObj->QTY4Write[pI2CObj->PresentSeqNo])) {
                            pI2CObj->state=2;  //done?
                            return 1; 
                        }
                    }

                } else {
                    //no writing
                    if (pI2CObj->QTY4Read[pI2CObj->PresentSeqNo] > 0) {
                        //only reading    
                        if (I2C1_Read(/*uint16_t address*/pI2CObj->I2CAddr[pI2CObj->PresentSeqNo], /*uint8_t *data*/pI2CObj->pReadData[pI2CObj->PresentSeqNo], pI2CObj->QTY4Read[pI2CObj->PresentSeqNo])) {
                            pI2CObj->state=2;  //done?
                            return 1; 
                        }
                    } else {
                        //no reading and no reading
                        return 0; //success because no need any action
                    }
                }

                
#else
                return -1;
#endif
            } else if (2 == pI2CObj->I2C_Peripheral_No) {
#ifdef USE_I2C2                
                Delay_2 = 0;
                ReTry_2 = 0;
                
                if (pI2CObj->QTY4Write[pI2CObj->PresentSeqNo] > 0) {
                    //writing exists
                    if (pI2CObj->QTY4Read[pI2CObj->PresentSeqNo] > 0) {
                        //both writing and reading
                        if (I2C2_WriteRead(pI2CObj->I2CAddr[pI2CObj->PresentSeqNo],pI2CObj->pWriteData[pI2CObj->PresentSeqNo], pI2CObj->QTY4Write[pI2CObj->PresentSeqNo], 
                                           pI2CObj->pReadData[pI2CObj->PresentSeqNo], pI2CObj->QTY4Read[pI2CObj->PresentSeqNo])) {
                            pI2CObj->state=2;  //done?
                            return 1; 
                        }
                    } else {
                        //no reading, so only writing                                                   
                        if (I2C2_Write(/*uint16_t address*/pI2CObj->I2CAddr[pI2CObj->PresentSeqNo], /*uint8_t *data*/pI2CObj->pWriteData[pI2CObj->PresentSeqNo], /*size_t dataLength*/pI2CObj->QTY4Write[pI2CObj->PresentSeqNo])) {
                            pI2CObj->state=2;  //done?
                            return 1; 
                        }   
                    }

                } else {
                    //no writing
                    if (pI2CObj->QTY4Read[pI2CObj->PresentSeqNo] > 0) {
                        //only reading
                        if (I2C2_Read(/*uint16_t address*/pI2CObj->I2CAddr[pI2CObj->PresentSeqNo], /*uint8_t *data*/pI2CObj->pReadData[pI2CObj->PresentSeqNo], pI2CObj->QTY4Read[pI2CObj->PresentSeqNo])) {
                            pI2CObj->state=2;  //done?
                            return 1; 
                        }
                    } else {
                        //no reading and no reading
                        return 0; //success because no need any action
                    }
                }                
#else
                return -1;
#endif
            } else if (3 == pI2CObj->I2C_Peripheral_No) {
#ifdef USE_I2C3                    
                Delay_3 = 0;
                ReTry_3 = 0;
                
                if (pI2CObj->QTY4Write[pI2CObj->PresentSeqNo] > 0) {
                    //writing exists
                    if (pI2CObj->QTY4Read[pI2CObj->PresentSeqNo] > 0) {
                        //both writing and reading
                        if (I2C3_WriteRead(pI2CObj->I2CAddr[pI2CObj->PresentSeqNo],pI2CObj->pWriteData[pI2CObj->PresentSeqNo], pI2CObj->QTY4Write[pI2CObj->PresentSeqNo], 
                                           pI2CObj->pReadData[pI2CObj->PresentSeqNo], pI2CObj->QTY4Read[pI2CObj->PresentSeqNo])) {
                            pI2CObj->state=2;  //done?
                            return 1; 
                        }
                    } else {
                        //no reading, so only writing
                        if (I2C3_Write(/*uint16_t address*/pI2CObj->I2CAddr[pI2CObj->PresentSeqNo], /*uint8_t *data*/pI2CObj->pWriteData[pI2CObj->PresentSeqNo], /*size_t dataLength*/pI2CObj->QTY4Write[pI2CObj->PresentSeqNo])) {
                            pI2CObj->state=2;  //done?
                            return 1; 
                        }  
                    }

                } else {
                    //no writing
                    if (pI2CObj->QTY4Read[pI2CObj->PresentSeqNo] > 0) {
                        //only reading
                        if (I2C3_Read(/*uint16_t address*/pI2CObj->I2CAddr[pI2CObj->PresentSeqNo], /*uint8_t *data*/pI2CObj->pReadData[pI2CObj->PresentSeqNo], pI2CObj->QTY4Read[pI2CObj->PresentSeqNo])) {
                            pI2CObj->state=2;  //done?
                            return 1; 
                        }
                    } else {
                        //no reading and no reading
                        return 0; //success because no need any action
                    }
                }
#else
                return -1;
#endif
            } else if (4 == pI2CObj->I2C_Peripheral_No) {
#ifdef USE_I2C4                     
                Delay_4 = 0;
                ReTry_4 = 0;
                if (pI2CObj->QTY4Write[pI2CObj->PresentSeqNo] > 0) {
                    //writing exists
                    if (pI2CObj->QTY4Read[pI2CObj->PresentSeqNo] > 0) {
                        //both writing and reading
                        if (I2C4_WriteRead(pI2CObj->I2CAddr[pI2CObj->PresentSeqNo],pI2CObj->pWriteData[pI2CObj->PresentSeqNo], pI2CObj->QTY4Write[pI2CObj->PresentSeqNo], 
                                           pI2CObj->pReadData[pI2CObj->PresentSeqNo], pI2CObj->QTY4Read[pI2CObj->PresentSeqNo])) {
                            pI2CObj->state=2;  //done?
                            return 1; 
                        }
                    } else {
                        //no reading, so only writing
                        if (I2C4_Write(/*uint16_t address*/pI2CObj->I2CAddr[pI2CObj->PresentSeqNo], /*uint8_t *data*/pI2CObj->pWriteData[pI2CObj->PresentSeqNo], /*size_t dataLength*/pI2CObj->QTY4Write[pI2CObj->PresentSeqNo])) {
                            pI2CObj->state=2;  //done?
                            return 1; 
                        }     
                    }

                } else {
                    //no writing
                    if (pI2CObj->QTY4Read[pI2CObj->PresentSeqNo] > 0) {
                        //only reading
                        if (I2C4_Read(/*uint16_t address*/pI2CObj->I2CAddr[pI2CObj->PresentSeqNo], /*uint8_t *data*/pI2CObj->pReadData[pI2CObj->PresentSeqNo], pI2CObj->QTY4Read[pI2CObj->PresentSeqNo])) {
                            pI2CObj->state=2;  //done?
                            return 1; 
                        }
                    } else {
                        //no reading and no reading
                        return 0; //success because no need any action
                    }
                }
#else                
                return -1;
#endif
            }
            return 1; //continue
            break;
        case 1:
            //re-try?
            if (1 == pI2CObj->I2C_Peripheral_No) {
#ifdef USE_I2C1      
                
                Delay_1++;
                if (Delay_1<10) return 1;  //continue , that is 10ms delay               
                
                if (pI2CObj->QTY4Write[pI2CObj->PresentSeqNo] > 0) {
                    //writing exists
                    if (pI2CObj->QTY4Read[pI2CObj->PresentSeqNo] > 0) {
                        //both writing and reading
                        if (I2C1_WriteRead(pI2CObj->I2CAddr[pI2CObj->PresentSeqNo],pI2CObj->pWriteData[pI2CObj->PresentSeqNo], pI2CObj->QTY4Write[pI2CObj->PresentSeqNo], 
                                           pI2CObj->pReadData[pI2CObj->PresentSeqNo], pI2CObj->QTY4Read[pI2CObj->PresentSeqNo])) {
                            pI2CObj->state=2;  //done?
                            ReTry_1 ++; 
                            return 1; 
                        }
                    } else {
                        //no reading, so only writing    
                        if (I2C1_Write(/*uint16_t address*/pI2CObj->I2CAddr[pI2CObj->PresentSeqNo], /*uint8_t *data*/pI2CObj->pWriteData[pI2CObj->PresentSeqNo], /*size_t dataLength*/pI2CObj->QTY4Write[pI2CObj->PresentSeqNo])) {
                            pI2CObj->state=2;  //done?
                            ReTry_1 ++; 
                            return 1; 
                        }                      
                    }

                } else {
                    //no writing
                    if (pI2CObj->QTY4Read[pI2CObj->PresentSeqNo] > 0) {
                        //only reading   
                        if (I2C1_Read(/*uint16_t address*/pI2CObj->I2CAddr[pI2CObj->PresentSeqNo], /*uint8_t *data*/pI2CObj->pReadData[pI2CObj->PresentSeqNo], pI2CObj->QTY4Read[pI2CObj->PresentSeqNo])) {
                            pI2CObj->state=2;  //done?
                            ReTry_1 ++; 
                            return 1; 
                        }
                    } else {
                        //no reading and no reading
                        return 0; //success because no need any action
                    }
                }

                Delay_1=254;  //avoid overflow
#else
                return -1;
#endif
            }
            else if (2 == pI2CObj->I2C_Peripheral_No) {
#ifdef USE_I2C2                     
                Delay_2++;
                if (Delay_2<10) return 1;  //continue , that is 10ms delay                                               
                if (pI2CObj->QTY4Write[pI2CObj->PresentSeqNo] > 0) {
                    //writing exists
                    if (pI2CObj->QTY4Read[pI2CObj->PresentSeqNo] > 0) {
                        //both writing and reading
                        if (I2C2_WriteRead(pI2CObj->I2CAddr[pI2CObj->PresentSeqNo],pI2CObj->pWriteData[pI2CObj->PresentSeqNo], pI2CObj->QTY4Write[pI2CObj->PresentSeqNo], 
                                           pI2CObj->pReadData[pI2CObj->PresentSeqNo], pI2CObj->QTY4Read[pI2CObj->PresentSeqNo])) {
                            pI2CObj->state=2;  //done?
                            ReTry_2 ++;  
                            return 1; 
                        }
                    } 
                    else
                    {
                        //only writing
                        if (I2C2_Write(/*uint16_t address*/pI2CObj->I2CAddr[pI2CObj->PresentSeqNo], /*uint8_t *data*/pI2CObj->pWriteData[pI2CObj->PresentSeqNo], /*size_t dataLength*/pI2CObj->QTY4Write[pI2CObj->PresentSeqNo])) {
                            pI2CObj->state=2;  //done?
                            ReTry_2 ++;  
                            return 1; 
                        }  
                    }
                    

                } else {
                    //no writing
                    if (pI2CObj->QTY4Read[pI2CObj->PresentSeqNo] > 0) {
                        //only reading                                               
                        if (I2C2_Read(/*uint16_t address*/pI2CObj->I2CAddr[pI2CObj->PresentSeqNo], /*uint8_t *data*/pI2CObj->pReadData[pI2CObj->PresentSeqNo], pI2CObj->QTY4Read[pI2CObj->PresentSeqNo])) {
                            pI2CObj->state=2;  //done?
                            ReTry_2 ++;  
                            return 1; 
                        }
                    } else {
                        //no reading and no reading
                        pI2CObj->state==0;
                        return 0; //success because no need any action
                    }
                }

                Delay_2=254; //avoid overflow
#else
                return -1;
#endif
            }
            else if (3 == pI2CObj->I2C_Peripheral_No) {
#ifdef USE_I2C3                     
                Delay_3++;
                if (Delay_3<10) return 1;  //continue , that is 10ms delay                                
                if (pI2CObj->QTY4Write[pI2CObj->PresentSeqNo] > 0) {
                    //writing exists
                    if (pI2CObj->QTY4Read[pI2CObj->PresentSeqNo] > 0) {
                        //both writing and reading
                        if (I2C3_WriteRead(pI2CObj->I2CAddr[pI2CObj->PresentSeqNo],pI2CObj->pWriteData[pI2CObj->PresentSeqNo], pI2CObj->QTY4Write[pI2CObj->PresentSeqNo], 
                                           pI2CObj->pReadData[pI2CObj->PresentSeqNo], pI2CObj->QTY4Read[pI2CObj->PresentSeqNo])) {
                            pI2CObj->state=2;  //done?
                            ReTry_3 ++;   
                            return 1; 
                        } 
                    }
                    else {
                        //only writing
                        if (I2C3_Write(/*uint16_t address*/pI2CObj->I2CAddr[pI2CObj->PresentSeqNo], /*uint8_t *data*/pI2CObj->pWriteData[pI2CObj->PresentSeqNo], /*size_t dataLength*/pI2CObj->QTY4Write[pI2CObj->PresentSeqNo])) {
                            pI2CObj->state=2;  //done?
                            ReTry_3 ++;  
                            return 1; 
                        }  
                    }
                    
                } else {
                    //no writing
                    if (pI2CObj->QTY4Read[pI2CObj->PresentSeqNo] > 0) {
                        //only reading                                               
                        if (I2C3_Read(/*uint16_t address*/pI2CObj->I2CAddr[pI2CObj->PresentSeqNo], /*uint8_t *data*/pI2CObj->pReadData[pI2CObj->PresentSeqNo], pI2CObj->QTY4Read[pI2CObj->PresentSeqNo])) {
                            pI2CObj->state=2;  //done?
                            ReTry_3 ++;  
                            return 1; 
                        }
                    } else {
                        //no reading and no reading
                        pI2CObj->state==0;
                        return 0; //success because no need any action
                    }
                }
                Delay_3=254; //avoid overflow
#else
                return -1;
#endif
            }
            else if (4 == pI2CObj->I2C_Peripheral_No) {
#ifdef USE_I2C4                     
                Delay_4++;
                if (Delay_4<10) return 1;  //continue , that is 10ms delay
                if (pI2CObj->QTY4Write[pI2CObj->PresentSeqNo] > 0) {
                    //writing exists
                    if (pI2CObj->QTY4Read[pI2CObj->PresentSeqNo] > 0) {
                        //both writing and reading
                        if (I2C4_WriteRead(pI2CObj->I2CAddr[pI2CObj->PresentSeqNo],pI2CObj->pWriteData[pI2CObj->PresentSeqNo], pI2CObj->QTY4Write[pI2CObj->PresentSeqNo], 
                                           pI2CObj->pReadData[pI2CObj->PresentSeqNo], pI2CObj->QTY4Read[pI2CObj->PresentSeqNo])) {
                            pI2CObj->state=2;  //done?
                            ReTry_4 ++;  
                            return 1; 
                        } 
                    }
                    else {
                        //Only writing
                        if (I2C4_Write(/*uint16_t address*/pI2CObj->I2CAddr[pI2CObj->PresentSeqNo], /*uint8_t *data*/pI2CObj->pWriteData[pI2CObj->PresentSeqNo], /*size_t dataLength*/pI2CObj->QTY4Write[pI2CObj->PresentSeqNo])) {
                            pI2CObj->state=2;  //done?
                            ReTry_4 ++;  
                            return 1; 
                        }  
                    }
                    

                } else {
                    //no writing
                    if (pI2CObj->QTY4Read[pI2CObj->PresentSeqNo] > 0) {
                        //only reading                                               
                        if (I2C4_Read(/*uint16_t address*/pI2CObj->I2CAddr[pI2CObj->PresentSeqNo], /*uint8_t *data*/pI2CObj->pReadData[pI2CObj->PresentSeqNo], pI2CObj->QTY4Read[pI2CObj->PresentSeqNo])) {
                            pI2CObj->state=2;  //done?
                            ReTry_4 ++;  
                            return 1; 
                        }
                    } else {
                        //no reading and no reading
                        pI2CObj->state==0;
                        return 0; //success because no need any action
                    }
                }

                Delay_4=254; //avoid overflow
#else
                return -1;
#endif
            }
            break;
        case 2:
            //Done?
            if (1 == pI2CObj->I2C_Peripheral_No) {
#ifdef USE_I2C1  
                if (I2C1_IsBusy()) return 1;
                if (I2C1_ErrorGet()!=I2C_ERROR_NONE)  {
                    //Error created
                    if (ReTry_1 >= I2C_MAX_RE_TRY) {
                        pI2CObj->state = 0;                        
                        return (-1); //fail
                    } else {
                        ReTry_1++;
                        Delay_1=0;
                        pI2CObj->state = 1;                        
                        return 1; //continue
                    }
                }                                   
                pI2CObj->state = 0; 
                return 0; //success
#else
                pI2CObj->state = 0;
                return -1;
#endif
            } else if (2 == pI2CObj->I2C_Peripheral_No) {
#ifdef USE_I2C2      
                if (I2C2_IsBusy()) return 1;
                if (I2C2_ErrorGet()!=I2C_ERROR_NONE)  {
                    //Error created
                    if (ReTry_2 >= I2C_MAX_RE_TRY) {
                        pI2CObj->state = 0;                        
                        return (-1); //fail
                    } else {
                        ReTry_2++;
                        Delay_2=0;
                        pI2CObj->state = 1;                        
                        return 1; //continue
                    }
                }                                   
                pI2CObj->state = 0; 
                return 0; //success
#else
                pI2CObj->state = 0;
                return -1;
#endif
            } else if (3 == pI2CObj->I2C_Peripheral_No) {
#ifdef USE_I2C3 
                if (I2C3_IsBusy()) return 1;
                if (I2C3_ErrorGet()!=I2C_ERROR_NONE)  {
                    //Error created
                    if (ReTry_3 >= I2C_MAX_RE_TRY) {
                        pI2CObj->state = 0;                        
                        return (-1); //fail
                    } else {
                        ReTry_3++;
                        Delay_3=0;
                        pI2CObj->state = 1;                        
                        return 1; //continue
                    }
                }                                   
                pI2CObj->state = 0; 
                return 0; //success
#else
                pI2CObj->state = 0;
                return -1;
#endif
            } else if (4 == pI2CObj->I2C_Peripheral_No) {
#ifdef USE_I2C4 
                if (I2C4_IsBusy()) return 1;
                if (I2C4_ErrorGet()!=I2C_ERROR_NONE)  {
                    //Error created
                    if (ReTry_4 >= I2C_MAX_RE_TRY) {
                        pI2CObj->state = 0;                        
                        return (-1); //fail
                    } else {
                        ReTry_4++;
                        Delay_4=0;
                        pI2CObj->state = 1;                        
                        return 1; //continue
                    }
                }                                   
                pI2CObj->state = 0; 
                return 0; //success
#else           
                pI2CObj->state = 0;
                return -1;
#endif
            }
            
    }
    return 1;
}

