#include <stdint.h>
#include <stdbool.h>  
#include "I2CBUS.h"
#define NULL ((void*)0)
#ifdef USE_I2C1
#include "mcc_generated_files/i2c1_master.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);

typedef struct {
    uint8_t *readData;
    size_t readLen;
    size_t bytesWritten; // Track bytes transmitted  because MCC callback will be called every Interrupt, 
    size_t bytesToWrite; // Total bytes to write  because MCC callback will be called every Interrupt.
} i2c_context_t; 

#ifdef USE_I2C1

static uint8_t ReTry_1;
static uint16_t Delay_1 = 0;

static volatile bool ErrorOccur_1;
static volatile i2c_context_t ctx_1;
static i2c1_operations_t i2cErrorCallback_1(void *ptr);
static i2c1_operations_t writeCallbackWithRead_1(void *ptr);
#endif




#ifdef USE_I2C2
static uint8_t ReTry_2;
static uint16_t Delay_2 = 0;
static volatile bool ErrorOccur_2;
static volatile i2c_context_t ctx_2;
static i2c2_operations_t i2cErrorCallback_2(void *ptr);
static i2c2_operations_t writeCallbackWithRead_2(void *ptr);
#endif

#ifdef USE_I2C3
static uint8_t ReTry_3;
static uint16_t Delay_3 = 0;
static volatile bool ErrorOccur_3;
static volatile i2c_context_t ctx_3;
static i2c3_operations_t i2cErrorCallback_3(void *ptr);
static i2c3_operations_t writeCallbackWithRead_3(void *ptr);
#endif

#ifdef USE_I2C4
static uint8_t ReTry_4;
static uint16_t Delay_4 = 0;
static volatile bool ErrorOccur_4;
static volatile i2c_context_t ctx_4;
static i2c4_operations_t i2cErrorCallback_4(void *ptr);
static i2c4_operations_t writeCallbackWithRead_4(void *ptr);
#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:
            //transactionDone_1=false;
            ErrorOccur_1=false;
            //prepare all I2C1 transaction REQUEST (TRB))
            if (1 == pI2CObj->I2C_Peripheral_No) {
#ifdef USE_I2C1      
                
                Delay_1 = 0;
                ReTry_1 = 0;
                while (!I2C1_Open(pI2CObj->I2CAddr[pI2CObj->PresentSeqNo])); 
                //pI2CObj->SuccessWR = pI2CObj->SuccessWR |(1U<<pI2CObj->PresentSeqNo);
                ctx_1.readData=pI2CObj->pReadData[pI2CObj->PresentSeqNo];
                ctx_1.readLen=pI2CObj->QTY4Read[pI2CObj->PresentSeqNo];
                ctx_1.bytesWritten=0;
                ctx_1.bytesToWrite=pI2CObj->QTY4Write[pI2CObj->PresentSeqNo];
                I2C1_SetWriteCollisionCallback(i2cErrorCallback_1,NULL);
                I2C1_SetDataNackCallback(i2cErrorCallback_1,NULL);
                I2C1_SetAddressNackCallback(i2cErrorCallback_1, NULL); // Handle NACK errors
                I2C1_SetTimeoutCallback(i2cErrorCallback_1,NULL);
                
                
                if (pI2CObj->QTY4Write[pI2CObj->PresentSeqNo] > 0) {
                    //writing exists
                    if (pI2CObj->QTY4Read[pI2CObj->PresentSeqNo] > 0) {
                        //both writing and reading
                        
                        I2C1_SetDataCompleteCallback(writeCallbackWithRead_1, (void*) &ctx_1);                                                  
                        I2C1_SetBuffer(pI2CObj->pWriteData[pI2CObj->PresentSeqNo], pI2CObj->QTY4Write[pI2CObj->PresentSeqNo]);
                        I2C1_MasterWrite(); // Non-blocking (interrupt-driven)
                    } else {
                        //no reading, so only writing                           
                        I2C1_SetBuffer(pI2CObj->pWriteData[pI2CObj->PresentSeqNo], pI2CObj->QTY4Write[pI2CObj->PresentSeqNo]);
                        I2C1_MasterWrite(); // Non-blocking (interrupt-driven)                        
                    }

                } else {
                    //no writing
                    if (pI2CObj->QTY4Read[pI2CObj->PresentSeqNo] > 0) {
                        //only reading    
                        I2C1_SetBuffer(pI2CObj->pReadData[pI2CObj->PresentSeqNo], pI2CObj->QTY4Read[pI2CObj->PresentSeqNo]);
                        I2C1_MasterRead(); // Non-blocking (interrupt-driven) 
                    } else {
                        //no reading and no reading
                        return 0; //success because no need any action
                    }
                }

                pI2CObj->state=2;  //done?
#else
                return -1;
#endif
            } else if (2 == pI2CObj->I2C_Peripheral_No) {
#ifdef USE_I2C2                
                Delay_2 = 0;
                ReTry_2 = 0;
                while (!I2C2_Open(pI2CObj->I2CAddr[pI2CObj->PresentSeqNo])); 
                ctx_2.readData=pI2CObj->pReadData[pI2CObj->PresentSeqNo];
                ctx_2.readLen=pI2CObj->QTY4Read[pI2CObj->PresentSeqNo];
                ctx_2.bytesWritten=0;
                ctx_2.bytesToWrite=pI2CObj->QTY4Write[pI2CObj->PresentSeqNo];
                
                I2C2_SetWriteCollisionCallback(i2cErrorCallback_2,NULL);
                I2C2_SetDataNackCallback(i2cErrorCallback_2,NULL);
                I2C2_SetAddressNackCallback(i2cErrorCallback_2, NULL); // Handle NACK errors
                I2C2_SetTimeoutCallback(i2cErrorCallback_2,NULL);
                
                if (pI2CObj->QTY4Write[pI2CObj->PresentSeqNo] > 0) {
                    //writing exists
                    if (pI2CObj->QTY4Read[pI2CObj->PresentSeqNo] > 0) {
                        //both writing and reading
                        I2C2_SetDataCompleteCallback(writeCallbackWithRead_2, (void*) &ctx_2);                                                  
                        I2C2_SetBuffer(pI2CObj->pWriteData[pI2CObj->PresentSeqNo], pI2CObj->QTY4Write[pI2CObj->PresentSeqNo]);
                        I2C2_MasterWrite(); // Non-blocking (interrupt-driven)
                    } else {
                        //no reading, so only writing                                                   
                        I2C2_SetBuffer(pI2CObj->pWriteData[pI2CObj->PresentSeqNo], pI2CObj->QTY4Write[pI2CObj->PresentSeqNo]);
                        I2C2_MasterWrite(); // Non-blocking (interrupt-driven)   
                    }

                } else {
                    //no writing
                    if (pI2CObj->QTY4Read[pI2CObj->PresentSeqNo] > 0) {
                        //only reading
                        I2C2_SetBuffer(pI2CObj->pReadData[pI2CObj->PresentSeqNo], pI2CObj->QTY4Read[pI2CObj->PresentSeqNo]);
                        I2C2_MasterRead(); // Non-blocking (interrupt-driven) 
                    } else {
                        //no reading and no reading
                        return 0; //success because no need any action
                    }
                }

                pI2CObj->state=2;  //done?
#else
                return -1;
#endif
            } else if (3 == pI2CObj->I2C_Peripheral_No) {
#ifdef USE_I2C3                    
                Delay_3 = 0;
                ReTry_3 = 0;
                while (!I2C3_Open(pI2CObj->I2CAddr[pI2CObj->PresentSeqNo])); 
                ctx_3.readData=pI2CObj->pReadData[pI2CObj->PresentSeqNo];
                ctx_3.readLen=pI2CObj->QTY4Read[pI2CObj->PresentSeqNo];
                ctx_3.bytesWritten=0;
                ctx_3.bytesToWrite=pI2CObj->QTY4Write[pI2CObj->PresentSeqNo];
                
                I2C3_SetWriteCollisionCallback(i2cErrorCallback_3,NULL);
                I2C3_SetDataNackCallback(i2cErrorCallback_3,NULL);
                I2C3_SetAddressNackCallback(i2cErrorCallback_3, NULL); // Handle NACK errors
                I2C3_SetTimeoutCallback(i2cErrorCallback_3,NULL);
                
                if (pI2CObj->QTY4Write[pI2CObj->PresentSeqNo] > 0) {
                    //writing exists
                    if (pI2CObj->QTY4Read[pI2CObj->PresentSeqNo] > 0) {
                        //both writing and reading
                        I2C3_SetDataCompleteCallback(writeCallbackWithRead_3, (void*) &ctx_3);                                                  
                        I2C3_SetBuffer(pI2CObj->pWriteData[pI2CObj->PresentSeqNo], pI2CObj->QTY4Write[pI2CObj->PresentSeqNo]);
                        I2C3_MasterWrite(); // Non-blocking (interrupt-driven)
                    } else {
                        //no reading, so only writing
                        I2C3_SetBuffer(pI2CObj->pWriteData[pI2CObj->PresentSeqNo], pI2CObj->QTY4Write[pI2CObj->PresentSeqNo]);
                        I2C3_MasterWrite(); // Non-blocking (interrupt-driven)   
                    }

                } else {
                    //no writing
                    if (pI2CObj->QTY4Read[pI2CObj->PresentSeqNo] > 0) {
                        //only reading
                        I2C3_SetBuffer(pI2CObj->pReadData[pI2CObj->PresentSeqNo], pI2CObj->QTY4Read[pI2CObj->PresentSeqNo]);
                        I2C3_MasterRead(); // Non-blocking (interrupt-driven) 
                    } else {
                        //no reading and no reading
                        return 0; //success because no need any action
                    }
                }

                pI2CObj->state=2;  //done?
#else
                return -1;
#endif
            } else if (4 == pI2CObj->I2C_Peripheral_No) {
#ifdef USE_I2C4                     
                Delay_4 = 0;
                ReTry_4 = 0;
                while (!I2C4_Open(pI2CObj->I2CAddr[pI2CObj->PresentSeqNo])); 
                ctx_4.readData=pI2CObj->pReadData[pI2CObj->PresentSeqNo];
                ctx_4.readLen=pI2CObj->QTY4Read[pI2CObj->PresentSeqNo];
                ctx_4.bytesWritten=0;
                ctx_4.bytesToWrite=pI2CObj->QTY4Write[pI2CObj->PresentSeqNo];
                I2C4_SetWriteCollisionCallback(i2cErrorCallback_4,NULL);
                I2C4_SetDataNackCallback(i2cErrorCallback_4,NULL);
                I2C4_SetAddressNackCallback(i2cErrorCallback_4, NULL); // Handle NACK errors
                I2C4_SetTimeoutCallback(i2cErrorCallback_4,NULL);
                
                if (pI2CObj->QTY4Write[pI2CObj->PresentSeqNo] > 0) {
                    //writing exists
                    if (pI2CObj->QTY4Read[pI2CObj->PresentSeqNo] > 0) {
                        //both writing and reading
                        I2C4_SetDataCompleteCallback(writeCallbackWithRead_4, (void*) &ctx_3);                                                  
                        I2C4_SetBuffer(pI2CObj->pWriteData[pI2CObj->PresentSeqNo], pI2CObj->QTY4Write[pI2CObj->PresentSeqNo]);
                        I2C4_MasterWrite(); // Non-blocking (interrupt-driven)
                    } else {
                        //no reading, so only writing
                        I2C4_SetBuffer(pI2CObj->pWriteData[pI2CObj->PresentSeqNo], pI2CObj->QTY4Write[pI2CObj->PresentSeqNo]);
                        I2C4_MasterWrite(); // Non-blocking (interrupt-driven)   
                    }

                } else {
                    //no writing
                    if (pI2CObj->QTY4Read[pI2CObj->PresentSeqNo] > 0) {
                        //only reading
                        I2C4_SetBuffer(pI2CObj->pReadData[pI2CObj->PresentSeqNo], pI2CObj->QTY4Read[pI2CObj->PresentSeqNo]);
                        I2C4_MasterRead(); // Non-blocking (interrupt-driven) 
                    } else {
                        //no reading and no reading
                        return 0; //success because no need any action
                    }
                }

                pI2CObj->state=2;  //done?
#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
                ReTry_1 ++;  
                while (!I2C1_Open(pI2CObj->I2CAddr[pI2CObj->PresentSeqNo])); 
                //pI2CObj->SuccessWR = pI2CObj->SuccessWR |(1U<<pI2CObj->PresentSeqNo);
                ctx_1.readData=pI2CObj->pReadData[pI2CObj->PresentSeqNo];
                ctx_1.readLen=pI2CObj->QTY4Read[pI2CObj->PresentSeqNo]; 
                ctx_1.bytesWritten=0;
                ctx_1.bytesToWrite=pI2CObj->QTY4Write[pI2CObj->PresentSeqNo];
                
                I2C1_SetWriteCollisionCallback(i2cErrorCallback_1,NULL);
                I2C1_SetDataNackCallback(i2cErrorCallback_1,NULL);
                I2C1_SetAddressNackCallback(i2cErrorCallback_1, NULL); // Handle NACK errors
                I2C1_SetTimeoutCallback(i2cErrorCallback_1,NULL);
                
                if (pI2CObj->QTY4Write[pI2CObj->PresentSeqNo] > 0) {
                    //writing exists
                    if (pI2CObj->QTY4Read[pI2CObj->PresentSeqNo] > 0) {
                        //both writing and reading
                        
                        I2C1_SetDataCompleteCallback(writeCallbackWithRead_1, (void*) &ctx_1);                                                  
                        I2C1_SetBuffer(pI2CObj->pWriteData[pI2CObj->PresentSeqNo], pI2CObj->QTY4Write[pI2CObj->PresentSeqNo]);
                        I2C1_MasterWrite(); // Non-blocking (interrupt-driven)
                    } else {
                        //no reading, so only writing    
                        
                        I2C1_SetBuffer(pI2CObj->pWriteData[pI2CObj->PresentSeqNo], pI2CObj->QTY4Write[pI2CObj->PresentSeqNo]);
                        I2C1_MasterWrite(); // Non-blocking (interrupt-driven)                        
                    }

                } else {
                    //no writing
                    if (pI2CObj->QTY4Read[pI2CObj->PresentSeqNo] > 0) {
                        //only reading   
                        
                        I2C1_SetBuffer(pI2CObj->pReadData[pI2CObj->PresentSeqNo], pI2CObj->QTY4Read[pI2CObj->PresentSeqNo]);
                        I2C1_MasterRead(); // Non-blocking (interrupt-driven) 
                    } else {
                        //no reading and no reading
                        return 0; //success because no need any action
                    }
                }

                pI2CObj->state=2;  //done?
#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
                ReTry_2 ++;  
                while (!I2C2_Open(pI2CObj->I2CAddr)); 
                //pI2CObj->SuccessWR = pI2CObj->SuccessWR |(1U<<pI2CObj->PresentSeqNo);
                ctx_2.readData=pI2CObj->pReadData[pI2CObj->PresentSeqNo];
                ctx_2.readLen=pI2CObj->QTY4Read[pI2CObj->PresentSeqNo];  
                ctx_2.bytesWritten=0;
                ctx_2.bytesToWrite=pI2CObj->QTY4Write[pI2CObj->PresentSeqNo];
                
                I2C2_SetWriteCollisionCallback(i2cErrorCallback_2,NULL);
                I2C2_SetDataNackCallback(i2cErrorCallback_2,NULL);
                I2C2_SetAddressNackCallback(i2cErrorCallback_2, NULL); // Handle NACK errors
                I2C2_SetTimeoutCallback(i2cErrorCallback_2,NULL);
                
                if (pI2CObj->QTY4Write[pI2CObj->PresentSeqNo] > 0) {
                    //writing exists
                    if (pI2CObj->QTY4Read[pI2CObj->PresentSeqNo] > 0) {
                        //both writing and reading
                        I2C2_SetDataCompleteCallback(writeCallbackWithRead_2, (void*) &ctx_2);  
                    }                    
                    I2C2_SetBuffer(pI2CObj->pWriteData[pI2CObj->PresentSeqNo], pI2CObj->QTY4Write[pI2CObj->PresentSeqNo]);
                    I2C2_MasterWrite(); // Non-blocking (interrupt-driven)

                } else {
                    //no writing
                    if (pI2CObj->QTY4Read[pI2CObj->PresentSeqNo] > 0) {
                        //only reading                                               
                        I2C2_SetBuffer(pI2CObj->pReadData[pI2CObj->PresentSeqNo], pI2CObj->QTY4Read[pI2CObj->PresentSeqNo]);
                        I2C2_MasterRead(); // Non-blocking (interrupt-driven) 
                    } else {
                        //no reading and no reading
                        pI2CObj->state==0;
                        return 0; //success because no need any action
                    }
                }

                pI2CObj->state=2;  //done?
#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
                ReTry_3 ++;  
                while (!I2C3_Open(pI2CObj->I2CAddr)); 
                //pI2CObj->SuccessWR = pI2CObj->SuccessWR |(1U<<pI2CObj->PresentSeqNo);
                ctx_3.readData=pI2CObj->pReadData[pI2CObj->PresentSeqNo];
                ctx_3.readLen=pI2CObj->QTY4Read[pI2CObj->PresentSeqNo]; 
                ctx_3.bytesWritten=0;
                ctx_3.bytesToWrite=pI2CObj->QTY4Write[pI2CObj->PresentSeqNo];
                
                I2C3_SetWriteCollisionCallback(i2cErrorCallback_3,NULL);
                I2C3_SetDataNackCallback(i2cErrorCallback_3,NULL);
                I2C3_SetAddressNackCallback(i2cErrorCallback_3, NULL); // Handle NACK errors
                I2C3_SetTimeoutCallback(i2cErrorCallback_3,NULL);
                
                if (pI2CObj->QTY4Write[pI2CObj->PresentSeqNo] > 0) {
                    //writing exists
                    if (pI2CObj->QTY4Read[pI2CObj->PresentSeqNo] > 0) {
                        //both writing and reading
                        I2C3_SetDataCompleteCallback(writeCallbackWithRead_3, (void*) &ctx_3);  
                    }
                    I2C3_SetBuffer(pI2CObj->pWriteData[pI2CObj->PresentSeqNo], pI2CObj->QTY4Write[pI2CObj->PresentSeqNo]);
                    I2C3_MasterWrite(); // Non-blocking (interrupt-driven)

                } else {
                    //no writing
                    if (pI2CObj->QTY4Read[pI2CObj->PresentSeqNo] > 0) {
                        //only reading                                               
                        I2C3_SetBuffer(pI2CObj->pReadData[pI2CObj->PresentSeqNo], pI2CObj->QTY4Read[pI2CObj->PresentSeqNo]);
                        I2C3_MasterRead(); // Non-blocking (interrupt-driven) 
                    } else {
                        //no reading and no reading
                        pI2CObj->state==0;
                        return 0; //success because no need any action
                    }
                }

                pI2CObj->state=2;  //done?
#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
                ReTry_4 ++;  
                while (!I2C4_Open(pI2CObj->I2CAddr)); 
                ctx_4.readData=pI2CObj->pReadData[pI2CObj->PresentSeqNo];
                ctx_4.readLen=pI2CObj->QTY4Read[pI2CObj->PresentSeqNo];   
                ctx_4.bytesWritten=0;
                ctx_4.bytesToWrite=pI2CObj->QTY4Write[pI2CObj->PresentSeqNo];
                
                I2C4_SetWriteCollisionCallback(i2cErrorCallback_4,NULL);
                I2C4_SetDataNackCallback(i2cErrorCallback_4,NULL);
                I2C4_SetAddressNackCallback(i2cErrorCallback_4, NULL); // Handle NACK errors
                I2C4_SetTimeoutCallback(i2cErrorCallback_4,NULL);
                
                if (pI2CObj->QTY4Write[pI2CObj->PresentSeqNo] > 0) {
                    //writing exists
                    if (pI2CObj->QTY4Read[pI2CObj->PresentSeqNo] > 0) {
                        //both writing and reading
                        I2C4_SetDataCompleteCallback(writeCallbackWithRead_4, (void*) &ctx_4);  
                    }
                    I2C4_SetBuffer(pI2CObj->pWriteData[pI2CObj->PresentSeqNo], pI2CObj->QTY4Write[pI2CObj->PresentSeqNo]);
                    I2C4_MasterWrite(); // Non-blocking (interrupt-driven)

                } else {
                    //no writing
                    if (pI2CObj->QTY4Read[pI2CObj->PresentSeqNo] > 0) {
                        //only reading                                               
                        I2C4_SetBuffer(pI2CObj->pReadData[pI2CObj->PresentSeqNo], pI2CObj->QTY4Read[pI2CObj->PresentSeqNo]);
                        I2C4_MasterRead(); // Non-blocking (interrupt-driven) 
                    } else {
                        //no reading and no reading
                        pI2CObj->state==0;
                        return 0; //success because no need any action
                    }
                }

                pI2CObj->state=2;  //done?
#else
                return -1;
#endif
            }
            break;
        case 2:
            //Done?
            if (1 == pI2CObj->I2C_Peripheral_No) {
#ifdef USE_I2C1                                                 
                if (ErrorOccur_1 == true) {                    
                    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
                    }
                }
                if (I2C1_BUSY != I2C1_Close())
                {
                    //finish transaction and success
                    pI2CObj->state = 0;                        
                    return 0; //success
                }                     
                return 1; //continue
#else
                pI2CObj->state = 0;
                return -1;
#endif
            } else if (2 == pI2CObj->I2C_Peripheral_No) {
#ifdef USE_I2C2      
                if (ErrorOccur_2 == true) {                    
                    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
                    }
                }
                if (I2C2_BUSY != I2C2_Close()) {
                    pI2CObj->state = 0;                    
                    return 0; //success
                }                                
                return 1; //continue
#else
                pI2CObj->state = 0;
                return -1;
#endif
            } else if (3 == pI2CObj->I2C_Peripheral_No) {
#ifdef USE_I2C3 
                if (ErrorOccur_3 == true) {                    
                    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
                    }
                }
                if (I2C3_BUSY != I2C3_Close()) {
                    pI2CObj->state = 0;                    
                    return 0; //success
                }                                
                return 1; //continue
#else
                pI2CObj->state = 0;
                return -1;
#endif
            } else if (4 == pI2CObj->I2C_Peripheral_No) {
#ifdef USE_I2C4 
                if (ErrorOccur_4 == true) {                    
                    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
                    }
                }
                if (I2C4_BUSY != I2C4_Close()) {
                    pI2CObj->state = 0;                    
                    return 0; //success
                }                                
                return 1; //continue
#else           
                pI2CObj->state = 0;
                return -1;
#endif
            }
            
    }
    return 1;
}


#ifdef USE_I2C1  
static i2c1_operations_t writeCallbackWithRead_1(void *ptr) {
    
    volatile i2c_context_t * ctx_1=(volatile i2c_context_t *)ptr;   
    ctx_1->bytesWritten++;
    if (ctx_1->bytesWritten < ctx_1->bytesToWrite) {        
        return I2C1_CONTINUE;
    }
    I2C1_SetBuffer(ctx_1->readData, ctx_1->readLen);
    //I2C1_SetDataCompleteCallback(NULL,NULL);  //otherwise, it still call my old callback
    I2C1_SetDataCompleteCallback(I2C1_CallbackReturnStop,NULL);  //otherwise, it still call my old callback. We use I2C1_CallbackReturnStop replace
                                                                 //NULL, Please see I2C1_open() function. Actually NULL Works.
    // Restart and read
    return I2C1_RESTART_READ;
    
}

static i2c1_operations_t i2cErrorCallback_1(void *ptr) {    
    ErrorOccur_1=true;  
    //I2C1_Close(); // Release bus
    while(I2C1_BUSY == I2C1_Close());
    return I2C1_STOP; // Terminate transaction
}

#endif

#ifdef USE_I2C2  
static i2c2_operations_t writeCallbackWithRead_2(void *ptr) {
    
    volatile i2c_context_t * ctx_2=(volatile i2c_context_t *)ptr;   
    
    ctx_2->bytesWritten++;
    if (ctx_2->bytesWritten < ctx_2->bytesToWrite) {        
        return I2C2_CONTINUE;
    }
    I2C2_SetBuffer(ctx_2->readData, ctx_2->readLen);
    //I2C2_SetDataCompleteCallback(NULL,NULL);  //otherwise, it still call my old callback
    I2C2_SetDataCompleteCallback(I2C2_CallbackReturnStop,NULL);  //otherwise, it still call my old callback. We use I2C2_CallbackReturnStop replace
                                                                 //NULL, Please see I2C1_open() function. Actually NULL Works.
    // Restart and read
    return I2C2_RESTART_READ;
    
}

static i2c2_operations_t i2cErrorCallback_2(void *ptr) {    
    ErrorOccur_2=true;  
    while(I2C2_BUSY == I2C2_Close()); // Release bus
    return I2C2_STOP; // Terminate transaction
}
#endif

#ifdef USE_I2C3  
static i2c3_operations_t writeCallbackWithRead_3(void *ptr) {
    
    volatile i2c_context_t * ctx_3=(volatile i2c_context_t *)ptr;   
    ctx_3->bytesWritten++;
    if (ctx_3->bytesWritten < ctx_3->bytesToWrite) {        
        return I2C3_CONTINUE;
    }    
    I2C3_SetBuffer(ctx_3->readData, ctx_3->readLen);
    //I2C3_SetDataCompleteCallback(NULL,NULL);  //otherwise, it still call my old callback
    I2C3_SetDataCompleteCallback(I2C3_CallbackReturnStop,NULL);  //otherwise, it still call my old callback. We use I2C3_CallbackReturnStop replace
                                                                 //NULL, Please see I2C1_open() function. Actually NULL Works.
    // Restart and read
    return I2C3_RESTART_READ;
    
}

static i2c3_operations_t i2cErrorCallback_3(void *ptr) {    
    ErrorOccur_3=true;  
    while(I2C3_BUSY == I2C3_Close()); // Release bus
    return I2C3_STOP; // Terminate transaction
}
#endif

#ifdef USE_I2C4  
static i2c4_operations_t writeCallbackWithRead_4(void *ptr) {
    
    volatile i2c_context_t * ctx_4=(volatile i2c_context_t *)ptr;   
    ctx_4->bytesWritten++;
    if (ctx_4->bytesWritten < ctx_4->bytesToWrite) {        
        return I2C4_CONTINUE;
    }    
    I2C4_SetBuffer(ctx_4->readData, ctx_4->readLen);
    //I2C4_SetDataCompleteCallback(NULL,NULL);  //otherwise, it still call my old callback
    I2C4_SetDataCompleteCallback(I2C4_CallbackReturnStop,NULL);  //otherwise, it still call my old callback. We use I2C4_CallbackReturnStop replace
                                                                 //NULL, Please see I2C4_open() function. Actually NULL Works.
    // Restart and read
    return I2C4_RESTART_READ;
    
}


static i2c4_operations_t i2cErrorCallback_4(void *ptr) {    
    ErrorOccur_4=true;  
    while(I2C4_BUSY == I2C4_Close()); // Release bus
    return I2C4_STOP; // Terminate transaction
}
#endif

