void __ISR(_I2C_1_VECTOR, ipl3) _SlaveI2CHandler(void) {
    unsigned char temp;
    static unsigned int dIndex;

    // check for MASTER and Bus events and respond accordingly
    if (IFS1bits.I2C1MIF) {
        mI2C1MClearIntFlag();
        return;
    }
    if (IFS1bits.I2C1BIF) {//bus collision, reset I2C state machine
        I2Cstate = 0;
        mI2C1BClearIntFlag();
        return;
    }

    // handle the incoming message
    if ((I2C1STATbits.R_W == 0) && (I2C1STATbits.D_A == 0)) {
        // reset any state variables needed by a message sequence
        // perform a dummy read
        temp = SlaveReadI2C1();
        I2C1CONbits.SCLREL = 1; // release the clock
        I2Cstate = 0;
    } else if ((I2C1STATbits.R_W == 0) && (I2C1STATbits.D_A == 1)) {//data received, input to slave
        WDTCount = 0;
        WriteTimer1(0);
        
        // writing data to our module
        I2CDataIn = SlaveReadI2C1();
        I2C1CONbits.SCLREL = 1; // release clock stretch bit

        if (I2Cstate == 0 && I2CDataIn != ADDR_CLR_I2C_STATE) {
            I2Cstate = 1;
            I2C_request = I2CDataIn;
        } else if (I2Cstate == 1) {
            switch (I2C_request) {
                case ADDR_M3_PWM:
                    M3_Dir = I2CDataIn >> 7 & 0x01;//take top bit                    
                    
                    if (((Status2 & M3_CUR) && (config1 & CUR_SENSE_EN)) || (config1 & MOTOR_HALT)) {
                        M3_PWM = 0;
                    } else {
                        if (I2CDataIn & 0x80) {
                            mPORTBClearBits(BIT_13);
                                M3_PWM = (((int) ((~I2CDataIn) + 1)) << 4);
                            
                        } else {
                            
                            mPORTBSetBits(BIT_13);
                            
                            M3_PWM = ((int) I2CDataIn) << 4;
                        }
                    }
                    SetDCOC4PWM(M3_PWM);
                    break;
                case ADDR_M4_PWM:
                    M4_Dir = I2CDataIn >> 7 & 0x01;//take top bit                    
                    
                    if (((Status2 & M4_CUR) && (config1 & CUR_SENSE_EN)) || (config1 & MOTOR_HALT)) {
                        M4_PWM = 0;
                    } else {
                        if (I2CDataIn & 0x80) {
                            mPORTBClearBits(BIT_14);
                            M4_PWM = (((int) ((~I2CDataIn) + 1)) << 4);

                        } else {
                            mPORTBSetBits(BIT_14);
                            M4_PWM = ((int) I2CDataIn) << 4;
                        }
                    }
                    SetDCOC5PWM(M4_PWM);
                    break;
                case ADDR_M5_PWM:
                    M5_Dir = I2CDataIn >> 7 & 0x01;//take top bit                    
                    
                    if (((Status2 & M5_CUR) && (config1 & CUR_SENSE_EN)) || (config1 & MOTOR_HALT)) {
                        M5_PWM = 0;
                    } else {
                        if (I2CDataIn & 0x80) {
                            mPORTBClearBits(BIT_15);
                            M5_PWM = (((int) ((~I2CDataIn) + 1)) << 4);

                        } else {
                            mPORTBSetBits(BIT_15);
                            M5_PWM = ((int) I2CDataIn) << 4;
                        }
                    }
                    SetDCOC3PWM(M5_PWM);
                    break;
                case ADDR_M6_PWM:
                    M6_Dir = I2CDataIn >> 7 & 0x01;//take top bit                    
                    
                    if (((Status2 & M6_CUR) && (config1 & CUR_SENSE_EN)) || (config1 & MOTOR_HALT)) {
                        M6_PWM = 0;
                    } else {
                        if (I2CDataIn & 0x80) {
                            mPORTBClearBits(BIT_11);
                            M6_PWM = (((int) ((~I2CDataIn) + 1)) << 4);

                        } else {
                            mPORTBSetBits(BIT_11);
                            M6_PWM = ((int) I2CDataIn) << 4;
                        }
                    }
                    SetDCOC2PWM(M6_PWM);
                    break;
                case ADDR_M7_PWM:
                    M7_Dir = I2CDataIn >> 7 & 0x01;//take top bit                    
                    
                    if (((Status2 & M7_CUR) && (config1 & CUR_SENSE_EN)) || (config1 & MOTOR_HALT)) {
                        M7_PWM = 0;
                    } else {
                        if (I2CDataIn & 0x80) {
                            mPORTBClearBits(BIT_7);
                            M7_PWM = (((int) ((~I2CDataIn) + 1)) << 4);

                        } else {
                            mPORTBSetBits(BIT_7);
                            M7_PWM = ((int) I2CDataIn) << 4;
                        }
                    }
                    SetDCOC1PWM(M7_PWM);
                    break;
                case ADDR_Config1:
                    config1 = I2CDataIn;
                    if (config1 & MOTOR_HALT) {
                        SetDCOC1PWM(0);
                        SetDCOC2PWM(0);
                        SetDCOC3PWM(0);
                        SetDCOC4PWM(0);
                        SetDCOC5PWM(0);
                    } else {
                        SetDCOC1PWM(M7_PWM);
                        SetDCOC2PWM(M6_PWM);
                        SetDCOC3PWM(M5_PWM);
                        SetDCOC4PWM(M3_PWM);
                        SetDCOC5PWM(M4_PWM);
                    }
                    break;
                default:
                    break;

            }
            I2Cstate = 0;
        }


    } else if ((I2C1STATbits.R_W == 1) && (I2C1STATbits.D_A == 0)) {
/**
 * Function Name: SI2C1Interrupt
 * Description : This is the ISR for I2C1 Slave interrupt.
 */
void __ISR(_I2C_1_VECTOR, ipl3) _SlaveI2CHandler(void)
{
    // TODO : Find the right i2cBusConnection
    I2cBusConnection* i2cBusConnection = NULL;

    // last byte received is address and not data
    char isData = I2C1STATbits.D_A;
    char read = I2C1STATbits.R_W;
    char isStart = I2C1STATbits.S;
    char isSclRelease = I2C1CONbits.SCLREL;
    char readBufferFull = I2C1STATbits.RBF;

    // check for MASTER and Bus events and respond accordingly
    if (IFS0bits.I2C1MIF == 1) {
        mI2C1MClearIntFlag();
        return;
    }
    if (IFS0bits.I2C1BIF == 1) {
        mI2C1BClearIntFlag();
        return;
    }
    StreamLink* i2cStreamLink = getI2cStreamLink();

    // handle the incoming message

    // Master want to write and send the address
    if (isStart && !read && !isData && readBufferFull) {
        // R/W bit = 0 --> indicates data transfer is input to slave
        // D/A bit = 0 --> indicates last byte was address

        // reset any state variables needed by a message sequence
        // perform a dummy read of the address
        portableSlaveReadI2C(i2cBusConnection);
        
        // release the clock to restart I2C
        portableSlaveClockRelease(i2cBusConnection);
    }
    // Master WRITE (InputStream)
    else if (isStart && !read && isData && readBufferFull) {
        // R/W bit = 0 --> indicates data transfer is input to slave
        // D/A bit = 1 --> indicates last byte was data
        int data = portableSlaveReadI2C(i2cBusConnection);
        Buffer* i2cSlaveInputBuffer = i2cStreamLink->inputBuffer;
        OutputStream* outputStream = getOutputStream(i2cSlaveInputBuffer);
        // Read data from the Master
        append(outputStream, data);
        // for debug support
        appendI2cDebugInputChar(data);
  
        // release the clock to restart I2C
        portableSlaveClockRelease(i2cBusConnection);
    }
    // Master send the address and want to read
    else if (isStart && read && !isData) {
        // R/W bit = 1 --> indicates data transfer is output from slave
        // D/A bit = 0 --> indicates last byte was address
        portableSlaveReadI2C(i2cBusConnection);
        
        Buffer* i2cSlaveOutputBuffer = i2cStreamLink->outputBuffer;
        // Get an inputStream to read the buffer to send to the master
        InputStream* i2cInputStream = getInputStream(i2cSlaveOutputBuffer);

        // There is available data
        if (i2cInputStream->availableData(i2cInputStream)) {
            char c = i2cInputStream->readChar(i2cInputStream);
            // for debug support
            appendI2cDebugOutputChar(c);
            portableSlaveWriteI2C(i2cBusConnection, c);
        } else {
            portableSlaveWriteI2C(i2cBusConnection, I2C_SLAVE_NO_DATA_IN_READ_BUFFER);
        } 
    }
    // Master want to read
    else if (isStart && read && isData && !isSclRelease) {

        // R/W bit = 1 --> indicates data transfer is output from slave
        // D/A bit = 1 --> indicates last byte was data
        Buffer* i2cSlaveOutputBuffer = i2cStreamLink->outputBuffer;
        // Get an inputStream to read the buffer to send to the master
        InputStream* i2cInputStream = getInputStream(i2cSlaveOutputBuffer);

        // There is available data
        if (i2cInputStream->availableData(i2cInputStream)) {
            char c = i2cInputStream->readChar(i2cInputStream);
            // for debug support
            appendI2cDebugInputChar(c);
            // we send it to the master
            portableSlaveWriteI2C(i2cBusConnection, c);
        } else {
            // There is no data, we send it to the master
            portableSlaveWriteI2C(i2cBusConnection, I2C_SLAVE_NO_DATA_IN_READ_BUFFER);
        }
    }
    // finally clear the slave interrupt flag
    mI2C1SClearIntFlag();
}