Pulse Oximeter and Heart-Rate Sensor IC for Wearable Health

MAX30100.cpp

Committer:
mcm
Date:
2018-07-13
Revision:
4:b914185995a1
Parent:
3:318e993aaf54

File content as of revision 4:b914185995a1:

/**
 * @brief       MAX30100.c
 * @details     Pulse Oximeter and Heart-Rate Sensor IC for Wearable Health.
 *              Functions file.
 *
 *
 * @return      N/A
 *
 * @author      Manuel Caballero
 * @date        13/July/2018
 * @version     13/July/2018    The ORIGIN
 * @pre         N/A.
 * @warning     N/A
 * @pre         This code belongs to AqueronteBlog ( http://unbarquero.blogspot.com ).
 */

#include "MAX30100.h"


MAX30100::MAX30100 ( PinName sda, PinName scl, uint32_t addr, uint32_t freq )
    : _i2c           ( sda, scl )
    , _MAX30100_Addr ( addr )
{
    _i2c.frequency( freq );
}


MAX30100::~MAX30100()
{
}



/**
 * @brief       MAX30100_ReadInterruptStatus ( MAX30100_vector_data_t* )
 *
 * @details     It gets the interrupt status value.
 *
 * @param[in]    N/A
 *
 * @param[out]   myInterruptStatus:     Interrupt status register.
 *
 *
 * @return       Status of MAX30100_ReadInterruptStatus.
 *
 *
 * @author      Manuel Caballero
 * @date        13/July/2018
 * @version     13/July/2018   The ORIGIN
 * @pre         N/A.
 * @warning     N/A.
 */
MAX30100::MAX30100_status_t  MAX30100::MAX30100_ReadInterruptStatus ( MAX30100_vector_data_t* myInterruptStatus )
{
    char     cmd    =    0;
    uint32_t aux;


    /* Read INTERRUPT STATUS register    */
    cmd      =   MAX30100_INTERRUPT_STATUS;
    aux      =   _i2c.write ( _MAX30100_Addr, &cmd, 1, true );
    aux      =   _i2c.read  ( _MAX30100_Addr, &cmd, 1 );


    /* Parse data   */
    myInterruptStatus->InterruptStatus   =   cmd;



    if ( aux == I2C_SUCCESS )
        return   MAX30100_SUCCESS;
    else
        return   MAX30100_FAILURE;
}



/**
 * @brief       MAX30100_InterrupEnable ( uint8_t )
 *
 * @details     It sets which interrupt is enabled/disabled.
 *
 * @param[in]    myInterruptEnable      Interrupts to be enabled.
 *
 * @param[out]   N/A.
 *
 *
 * @return       Status of MAX30100_InterrupEnable.
 *
 *
 * @author      Manuel Caballero
 * @date        13/July/2018
 * @version     13/July/2018   The ORIGIN
 * @pre         N/A.
 * @warning     N/A.
 */
MAX30100::MAX30100_status_t  MAX30100::MAX30100_InterrupEnable ( uint8_t myInterruptEnable )
{
    char     cmd[]    =  { 0, 0 };
    uint32_t aux;


    /* Read INTERRUPT ENABLE register    */
    cmd[0]   =   MAX30100_INTERRUPT_ENABLE;
    aux      =   _i2c.write ( _MAX30100_Addr, &cmd[0], 1, true );
    aux      =   _i2c.read  ( _MAX30100_Addr, &cmd[1], 1 );

    /* Parse data   */
    cmd[1]  &=  ~( INTERRUPT_ENABLE_ENB_A_FULL_MASK | INTERRUPT_ENABLE_ENB_TEP_RDY_MASK | INTERRUPT_ENABLE_ENB_HR_RDY_MASK | INTERRUPT_ENABLE_ENB_SO2_RDY_MASK );
    cmd[1]  |=   myInterruptEnable;

    /* Update the register   */
    aux      =   _i2c.write ( _MAX30100_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ), false );



    if ( aux == I2C_SUCCESS )
        return   MAX30100_SUCCESS;
    else
        return   MAX30100_FAILURE;
}



/**
 * @brief       MAX30100_ShutdownControl ( MAX30100_mode_configuration_shdn_t )
 *
 * @details     It sets the power mode.
 *
 * @param[in]    myPowerMode            power mode.
 *
 * @param[out]   N/A.
 *
 *
 * @return       Status of MAX30100_ShutdownControl.
 *
 *
 * @author      Manuel Caballero
 * @date        13/July/2018
 * @version     13/July/2018   The ORIGIN
 * @pre         N/A.
 * @warning     N/A.
 */
MAX30100::MAX30100_status_t  MAX30100::MAX30100_ShutdownControl ( MAX30100_mode_configuration_shdn_t myPowerMode )
{
    char     cmd[]    =  { 0, 0 };
    uint32_t aux;


    /* Read MODE CONFIGURATION register    */
    cmd[0]   =   MAX30100_MODE_CONFIGURATION;
    aux      =   _i2c.write ( _MAX30100_Addr, &cmd[0], 1, true );
    aux      =   _i2c.read  ( _MAX30100_Addr, &cmd[1], 1 );

    /* Parse data   */
    cmd[1]  &=  ~MODE_CONFIGURATION_SHDN_MASK;
    cmd[1]  |=   myPowerMode;

    /* Update the register   */
    aux      =   _i2c.write ( _MAX30100_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ), false );



    if ( aux == I2C_SUCCESS )
        return   MAX30100_SUCCESS;
    else
        return   MAX30100_FAILURE;
}



/**
 * @brief       MAX30100_SoftwareReset ( void )
 *
 * @details     It performs a software reset.
 *
 * @param[in]    N/A.
 *
 * @param[out]   N/A.
 *
 *
 * @return       Status of MAX30100_SoftwareReset.
 *
 *
 * @author      Manuel Caballero
 * @date        13/July/2018
 * @version     13/July/2018   The ORIGIN
 * @pre         The RESET bit is cleared automatically back to zero after the reset sequence is completed.
 * @warning     N/A.
 */
MAX30100::MAX30100_status_t  MAX30100::MAX30100_SoftwareReset ( void )
{
    char     cmd[]    =  { 0, 0 };
    uint32_t aux;


    /* Read MODE CONFIGURATION register    */
    cmd[0]   =   MAX30100_MODE_CONFIGURATION;
    aux      =   _i2c.write ( _MAX30100_Addr, &cmd[0], 1, true );
    aux      =   _i2c.read  ( _MAX30100_Addr, &cmd[1], 1 );

    /* Parse data   */
    cmd[1]  &=  ~MODE_CONFIGURATION_RESET_MASK;
    cmd[1]  |=   MODE_CONFIGURATION_RESET_ENABLE;

    /* Update the register   */
    aux      =   _i2c.write ( _MAX30100_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ), false );



    if ( aux == I2C_SUCCESS )
        return   MAX30100_SUCCESS;
    else
        return   MAX30100_FAILURE;
}



/**
 * @brief       MAX30100_TriggerTemperature ( void )
 *
 * @details     It initiates a single temperature reading from the temperature sensor.
 *
 * @param[in]    N/A.
 *
 * @param[out]   N/A.
 *
 *
 * @return       Status of MAX30100_TriggerTemperature.
 *
 *
 * @author      Manuel Caballero
 * @date        13/July/2018
 * @version     13/July/2018   The ORIGIN
 * @pre         This bit is cleared automatically back to zero at the conclusion of the temperature
 *              reading when the bit is set to one in heart rate or SpO2 mode.
 * @warning     N/A.
 */
MAX30100::MAX30100_status_t  MAX30100::MAX30100_TriggerTemperature ( void )
{
    char     cmd[]    =  { 0, 0 };
    uint32_t aux;


    /* Read MODE CONFIGURATION register    */
    cmd[0]   =   MAX30100_MODE_CONFIGURATION;
    aux      =   _i2c.write ( _MAX30100_Addr, &cmd[0], 1, true );
    aux      =   _i2c.read  ( _MAX30100_Addr, &cmd[1], 1 );

    /* Parse data   */
    cmd[1]  &=  ~MODE_CONFIGURATION_TEMP_EN_MASK;
    cmd[1]  |=   MODE_CONFIGURATION_TEMP_EN_ENABLE;

    /* Update the register   */
    aux      =   _i2c.write ( _MAX30100_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ), false );



    if ( aux == I2C_SUCCESS )
        return   MAX30100_SUCCESS;
    else
        return   MAX30100_FAILURE;
}



/**
 * @brief       MAX30100_ModeControl ( MAX30100_mode_configuration_mode_t )
 *
 * @details     It sets the operating state of the MAX30100.
 *
 * @param[in]    myModeControl:       Mode Control.
 *
 * @param[out]   N/A.
 *
 *
 * @return       Status of MAX30100_ModeControl.
 *
 *
 * @author      Manuel Caballero
 * @date        13/July/2018
 * @version     13/July/2018   The ORIGIN
 * @pre         Changing modes does not change any other setting, nor does it erase any previously stored
 *              data inside the data registers.
 * @warning     N/A.
 */
MAX30100::MAX30100_status_t  MAX30100::MAX30100_ModeControl ( MAX30100_mode_configuration_mode_t myModeControl )
{
    char     cmd[]    =  { 0, 0 };
    uint32_t aux;


    /* Read MODE CONFIGURATION register    */
    cmd[0]   =   MAX30100_MODE_CONFIGURATION;
    aux      =   _i2c.write ( _MAX30100_Addr, &cmd[0], 1, true );
    aux      =   _i2c.read  ( _MAX30100_Addr, &cmd[1], 1 );

    /* Parse data   */
    cmd[1]  &=  ~MODE_CONFIGURATION_MODE_MASK;
    cmd[1]  |=   myModeControl;

    /* Update the register   */
    aux      =   _i2c.write ( _MAX30100_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ), false );



    if ( aux == I2C_SUCCESS )
        return   MAX30100_SUCCESS;
    else
        return   MAX30100_FAILURE;
}



/**
 * @brief       MAX30100_SpO2_HighResolution ( MAX30100_spo2_configuration_spo2_hi_res_en_t )
 *
 * @details     It sets the SpO2 ADC resolution is 16-bit with 1.6ms LED pulse width.
 *
 * @param[in]    myRes:                 SpO2 High Resolution Enable.
 *
 * @param[out]   N/A.
 *
 *
 * @return       Status of MAX30100_SpO2_HighResolution.
 *
 *
 * @author      Manuel Caballero
 * @date        13/July/2018
 * @version     13/July/2018   The ORIGIN
 * @pre         N/A.
 * @warning     N/A.
 */
MAX30100::MAX30100_status_t  MAX30100::MAX30100_SpO2_HighResolution ( MAX30100_spo2_configuration_spo2_hi_res_en_t myRes )
{
    char     cmd[]    =  { 0, 0 };
    uint32_t aux;


    /* Read SPO2 CONFIGURATION register    */
    cmd[0]   =   MAX30100_SPO2_CONFIGURATION;
    aux      =   _i2c.write ( _MAX30100_Addr, &cmd[0], 1, true );
    aux      =   _i2c.read  ( _MAX30100_Addr, &cmd[1], 1 );

    /* Parse data   */
    cmd[1]  &=  ~SPO2_CONFIGURATION_SPO2_HI_RES_EN_MASK;
    cmd[1]  |=   myRes;

    /* Update the register   */
    aux      =   _i2c.write ( _MAX30100_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ), false );



    if ( aux == I2C_SUCCESS )
        return   MAX30100_SUCCESS;
    else
        return   MAX30100_FAILURE;
}



/**
 * @brief       MAX30100_SpO2_SampleRateControl ( MAX30100_spo2_configuration_spo2_hi_res_en_t )
 *
 * @details     It defines the effective sampling rate.
 *
 * @param[in]    mySampleRate:          Effective sampling rate.
 *
 * @param[out]   N/A.
 *
 *
 * @return       Status of MAX30100_SpO2_SampleRateControl.
 *
 *
 * @author      Manuel Caballero
 * @date        13/July/2018
 * @version     13/July/2018   The ORIGIN
 * @pre         N/A.
 * @warning     The allowed sample rates for both SpO2 and HR mode are summarized in Table 8 and Table 9 in the Data-sheet.
 *              The user MUST take care of this.
 */
MAX30100::MAX30100_status_t  MAX30100::MAX30100_SpO2_SampleRateControl ( MAX30100_spo2_configuration_spo2_sr_t mySampleRate )
{
    char     cmd[]    =  { 0, 0 };
    uint32_t aux;


    /* Read SPO2 CONFIGURATION register    */
    cmd[0]   =   MAX30100_SPO2_CONFIGURATION;
    aux      =   _i2c.write ( _MAX30100_Addr, &cmd[0], 1, true );
    aux      =   _i2c.read  ( _MAX30100_Addr, &cmd[1], 1 );

    /* Parse data   */
    cmd[1]  &=  ~SPO2_CONFIGURATION_SPO2_SR_MASK;
    cmd[1]  |=   mySampleRate;

    /* Update the register   */
    aux      =   _i2c.write ( _MAX30100_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ), false );



    if ( aux == I2C_SUCCESS )
        return   MAX30100_SUCCESS;
    else
        return   MAX30100_FAILURE;
}



/**
 * @brief       MAX30100_LED_PulseWidthControl ( MAX30100_vector_data_t )
 *
 * @details     It sets the LED pulse width.
 *
 * @param[in]    myLEDWidth:          Pulse width/Resolution.
 *
 * @param[out]   N/A.
 *
 *
 * @return       Status of MAX30100_LED_PulseWidthControl.
 *
 *
 * @author      Manuel Caballero
 * @date        13/July/2018
 * @version     13/July/2018   The ORIGIN
 * @pre         N/A.
 * @warning     The allowed sample rates for both SpO2 and HR mode are summarized in Table 8 and Table 9 in the Data-sheet.
 *              The user MUST take care of this.
 */
MAX30100::MAX30100_status_t  MAX30100::MAX30100_LED_PulseWidthControl ( MAX30100_vector_data_t myLEDWidth )
{
    char     cmd[]    =  { 0, 0 };
    uint32_t aux;


    /* Read SPO2 CONFIGURATION register    */
    cmd[0]   =   MAX30100_SPO2_CONFIGURATION;
    aux      =   _i2c.write ( _MAX30100_Addr, &cmd[0], 1, true );
    aux      =   _i2c.read  ( _MAX30100_Addr, &cmd[1], 1 );

    /* Parse data   */
    cmd[1]  &=  ~SPO2_CONFIGURATION_LED_PW_MASK;
    cmd[1]  |=   myLEDWidth.Resolution;

    /* Update the register   */
    aux      =   _i2c.write ( _MAX30100_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ), false );



    if ( aux == I2C_SUCCESS )
        return   MAX30100_SUCCESS;
    else
        return   MAX30100_FAILURE;
}



/**
 * @brief       MAX30100_Get_LED_PulseWidthControl ( MAX30100_vector_data_t* )
 *
 * @details     It gets the LED pulse width.
 *
 * @param[in]    N/A.
 *
 * @param[out]   myLEDWidth:          Pulse width/Resolution.
 *
 *
 * @return       Status of MAX30100_Get_LED_PulseWidthControl.
 *
 *
 * @author      Manuel Caballero
 * @date        13/July/2018
 * @version     13/July/2018   The ORIGIN
 * @pre         N/A.
 * @warning     N/A.
 */
MAX30100::MAX30100_status_t  MAX30100::MAX30100_Get_LED_PulseWidthControl ( MAX30100_vector_data_t* myLEDWidth )
{
    char     cmd[]    =  { 0, 0 };
    uint32_t aux;


    /* Read SPO2 CONFIGURATION register    */
    cmd[0]   =   MAX30100_SPO2_CONFIGURATION;
    aux      =   _i2c.write ( _MAX30100_Addr, &cmd[0], 1, true );
    aux      =   _i2c.read  ( _MAX30100_Addr, &cmd[1], 1 );

    /* Parse data   */
    myLEDWidth->Resolution   =  (MAX30100::MAX30100_spo2_configuration_led_pw_t)( cmd[1] & SPO2_CONFIGURATION_LED_PW_MASK );




    if ( aux == I2C_SUCCESS )
        return   MAX30100_SUCCESS;
    else
        return   MAX30100_FAILURE;
}



/**
 * @brief       MAX30100_SetRed_LED_CurrentControl ( MAX30100_led_configuration_red_pa_t )
 *
 * @details     It sets the current level of the Red LED.
 *
 * @param[in]    myRedLED:          Current level of the Red LED.
 *
 * @param[out]   N/A.
 *
 *
 * @return       Status of MAX30100_SetRed_LED_CurrentControl.
 *
 *
 * @author      Manuel Caballero
 * @date        13/July/2018
 * @version     13/July/2018   The ORIGIN
 * @pre         N/A.
 * @warning     N/A.
 */
MAX30100::MAX30100_status_t  MAX30100::MAX30100_SetRed_LED_CurrentControl ( MAX30100_led_configuration_red_pa_t myRedLED )
{
    char     cmd[]    =  { 0, 0 };
    uint32_t aux;


    /* Read LED CONFIGURATION register    */
    cmd[0]   =   MAX30100_LED_CONFIGURATION;
    aux      =   _i2c.write ( _MAX30100_Addr, &cmd[0], 1, true );
    aux      =   _i2c.read  ( _MAX30100_Addr, &cmd[1], 1 );

    /* Parse data   */
    cmd[1]  &=  ~LED_CONFIGURATION_RED_PA_MASK;
    cmd[1]  |=   myRedLED;

    /* Update the register   */
    aux      =   _i2c.write ( _MAX30100_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ), false );



    if ( aux == I2C_SUCCESS )
        return   MAX30100_SUCCESS;
    else
        return   MAX30100_FAILURE;
}



/**
 * @brief       MAX30100_SetIR_LED_CurrentControl ( MAX30100_led_configuration_red_pa_t )
 *
 * @details     It sets the current level of the IR LED.
 *
 * @param[in]    myRedLED:          Current level of the IR LED.
 *
 * @param[out]   N/A.
 *
 *
 * @return       Status of MAX30100_SetIR_LED_CurrentControl.
 *
 *
 * @author      Manuel Caballero
 * @date        13/July/2018
 * @version     13/July/2018   The ORIGIN
 * @pre         N/A.
 * @warning     N/A.
 */
MAX30100::MAX30100_status_t  MAX30100::MAX30100_SetIR_LED_CurrentControl ( MAX30100_led_configuration_ir_pa_t myIRLED )
{
    char     cmd[]    =  { 0, 0 };
    uint32_t aux;


    /* Read LED CONFIGURATION register    */
    cmd[0]   =   MAX30100_LED_CONFIGURATION;
    aux      =   _i2c.write ( _MAX30100_Addr, &cmd[0], 1, true );
    aux      =   _i2c.read  ( _MAX30100_Addr, &cmd[1], 1 );

    /* Parse data   */
    cmd[1]  &=  ~LED_CONFIGURATION_IR_PA_MASK;
    cmd[1]  |=   myIRLED;

    /* Update the register   */
    aux      =   _i2c.write ( _MAX30100_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ), false );



    if ( aux == I2C_SUCCESS )
        return   MAX30100_SUCCESS;
    else
        return   MAX30100_FAILURE;
}



/**
 * @brief       MAX30100_GetRawTemperature ( MAX30100_vector_data_t* )
 *
 * @details     It gets the raw temperature data ( temperature integer and temperature fraction ).
 *
 * @param[in]    N/A.
 *
 * @param[out]   myRawTemperature:  Temperature integer and temperature fraction
 *
 *
 * @return       Status of MAX30100_GetRawTemperature.
 *
 *
 * @author      Manuel Caballero
 * @date        13/July/2018
 * @version     13/July/2018   The ORIGIN
 * @pre         N/A.
 * @warning     N/A.
 */
MAX30100::MAX30100_status_t  MAX30100::MAX30100_GetRawTemperature ( MAX30100_vector_data_t* myRawTemperature )
{
    char     cmd[]    =  { 0, 0 };
    uint32_t aux;


    /* Read TEMP_INTEGER and TEMP_FRACTION register ( auto-increment )    */
    cmd[0]   =   MAX30100_TEMP_INTEGER;
    aux      =   _i2c.write ( _MAX30100_Addr, &cmd[0], 1, true );
    aux      =   _i2c.read  ( _MAX30100_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ) );


    /* Parse data   */
    myRawTemperature->Temp_Integer   =   cmd[0];
    myRawTemperature->Temp_Fraction  =   cmd[1];



    if ( aux == I2C_SUCCESS )
        return   MAX30100_SUCCESS;
    else
        return   MAX30100_FAILURE;
}



/**
 * @brief       MAX30100_GetTemperature ( MAX30100_vector_data_t* )
 *
 * @details     It gets the temperature value.
 *
 * @param[in]    N/A.
 *
 * @param[out]   myTemperature:     Temperature
 *
 *
 * @return       Status of MAX30100_GetTemperature.
 *
 *
 * @author      Manuel Caballero
 * @date        13/July/2018
 * @version     13/July/2018   The ORIGIN
 * @pre         This function updates both Temp_Integer and Temp_Fraction values.
 * @warning     N/A.
 */
MAX30100::MAX30100_status_t  MAX30100::MAX30100_GetTemperature ( MAX30100_vector_data_t* myTemperature )
{
    MAX30100::MAX30100_status_t   myMAX30100Status;


    /* Get the raw temperature    */
    myMAX30100Status     =   MAX30100_GetRawTemperature ( myTemperature );

    /* Process the temperature    */
    if ( ( myTemperature->Temp_Integer & 0x80 ) == 0x80 ) {
        /* Negative temperature     */
        myTemperature->Temp_Integer   =  ~myTemperature->Temp_Integer;
        myTemperature->Temp_Integer  +=   1;

        myTemperature->Temperature   =   ( -1.0 ) * ( (float)( myTemperature->Temp_Integer + (float)( myTemperature->Temp_Fraction * 0.0625 ) ) );
    } else {
        /* Positive temperature     */
        myTemperature->Temperature   =   (float)( myTemperature->Temp_Integer + (float)( myTemperature->Temp_Fraction * 0.0625 ) );
    }





    if ( myMAX30100Status == MAX30100_SUCCESS )
        return   MAX30100_SUCCESS;
    else
        return   MAX30100_FAILURE;
}



/**
 * @brief       MAX30100_GetRevisionID ( MAX30100_vector_data_t* )
 *
 * @details     It gets the revision ID.
 *
 * @param[in]    N/A.
 *
 * @param[out]   myRevisionID:      Revision ID
 *
 *
 * @return       Status of MAX30100_GetRevisionID.
 *
 *
 * @author      Manuel Caballero
 * @date        13/July/2018
 * @version     13/July/2018   The ORIGIN
 * @pre         N/A.
 * @warning     N/A.
 */
MAX30100::MAX30100_status_t  MAX30100::MAX30100_GetRevisionID ( MAX30100_vector_data_t* myRevisionID )
{
    char     cmd    =  0;
    uint32_t aux;


    /* Read REVISION ID register    */
    cmd      =   MAX30100_REVISION_ID;
    aux      =   _i2c.write ( _MAX30100_Addr, &cmd, 1, true );
    aux      =   _i2c.read  ( _MAX30100_Addr, &cmd, 1 );

    /* Parse data   */
    myRevisionID->RevisionID   =   cmd;



    if ( aux == I2C_SUCCESS )
        return   MAX30100_SUCCESS;
    else
        return   MAX30100_FAILURE;
}



/**
 * @brief       MAX30100_GetPartID ( MAX30100_vector_data_t* )
 *
 * @details     It gets the part ID.
 *
 * @param[in]    N/A.
 *
 * @param[out]   myPartID:          Part ID
 *
 *
 * @return       Status of MAX30100_GetPartID.
 *
 *
 * @author      Manuel Caballero
 * @date        13/July/2018
 * @version     13/July/2018   The ORIGIN
 * @pre         N/A.
 * @warning     N/A.
 */
MAX30100::MAX30100_status_t  MAX30100::MAX30100_GetPartID ( MAX30100_vector_data_t* myPartID )
{
    char     cmd    =  0;
    uint32_t aux;


    /* Read PART ID register    */
    cmd      =   MAX30100_PART_ID;
    aux      =   _i2c.write ( _MAX30100_Addr, &cmd, 1, true );
    aux      =   _i2c.read  ( _MAX30100_Addr, &cmd, 1 );

    /* Parse data   */
    myPartID->PartID   =   cmd;



    if ( aux == I2C_SUCCESS )
        return   MAX30100_SUCCESS;
    else
        return   MAX30100_FAILURE;
}



/**
 * @brief       MAX30100_PollingTemperatureConversion ( MAX30100_vector_data_t* )
 *
 * @details     It gets the TEMP_EN value in Mode Configuration register.
 *
 * @param[in]    N/A.
 *
 * @param[out]   myTempFlag:        Temperature flag
 *
 *
 * @return       Status of MAX30100_PollingTemperatureConversion.
 *
 *
 * @author      Manuel Caballero
 * @date        13/July/2018
 * @version     13/July/2018   The ORIGIN
 * @pre         N/A.
 * @warning     N/A.
 */
MAX30100::MAX30100_status_t  MAX30100::MAX30100_PollingTemperatureConversion ( MAX30100_vector_data_t* myTempFlag )
{
    char     cmd    =  0;
    uint32_t aux;


    /* Read MODE CONFIGURATION register    */
    cmd      =   MAX30100_MODE_CONFIGURATION;
    aux      =   _i2c.write ( _MAX30100_Addr, &cmd, 1, true );
    aux      =   _i2c.read  ( _MAX30100_Addr, &cmd, 1 );

    /* Parse data   */
    myTempFlag->TemperatureFlag   =   (MAX30100::MAX30100_mode_configuration_temp_en_t)( cmd & MODE_CONFIGURATION_TEMP_EN_MASK );



    if ( aux == I2C_SUCCESS )
        return   MAX30100_SUCCESS;
    else
        return   MAX30100_FAILURE;
}



/**
 * @brief       MAX30100_PollingSoftwareReset ( MAX30100_vector_data_t* )
 *
 * @details     It checks if the software reset was completed by polling mode.
 *
 * @param[in]    N/A.
 *
 * @param[out]   myResetFlag:       Reset flag
 *
 *
 * @return       Status of MAX30100_PollingSoftwareReset.
 *
 *
 * @author      Manuel Caballero
 * @date        13/July/2018
 * @version     13/July/2018   The ORIGIN
 * @pre         N/A.
 * @warning     N/A.
 */
MAX30100::MAX30100_status_t  MAX30100::MAX30100_PollingSoftwareReset ( MAX30100_vector_data_t* myResetFlag )
{
    char     cmd    =  0;
    uint32_t aux;


    /* Read MODE CONFIGURATION register    */
    cmd      =   MAX30100_MODE_CONFIGURATION;
    aux      =   _i2c.write ( _MAX30100_Addr, &cmd, 1, true );
    aux      =   _i2c.read  ( _MAX30100_Addr, &cmd, 1 );

    /* Parse data   */
    myResetFlag->ResetFlag   =   (MAX30100_mode_configuration_reset_t)( cmd & MODE_CONFIGURATION_RESET_MASK );



    if ( aux == I2C_SUCCESS )
        return   MAX30100_SUCCESS;
    else
        return   MAX30100_FAILURE;
}



/**
 * @brief       MAX30100_ReadFIFO ( MAX30100_vector_data_t* , uint32_t )
 *
 * @details     It checks if the software reset was completed by polling mode.
 *
 * @param[in]    myNumSamplesToRead:    Number of samples to read.
 *
 * @param[out]   myDATA:            Data from the FIFO
 *
 *
 * @return       Status of MAX30100_ReadFIFO.
 *
 *
 * @author      Manuel Caballero
 * @date        13/July/2018
 * @version     13/July/2018   The ORIGIN
 * @pre         N/A.
 * @warning     N/A.
 */
MAX30100::MAX30100_status_t  MAX30100::MAX30100_ReadFIFO ( MAX30100_vector_data_t* myDATA, uint32_t myNumSamplesToRead )
{
    char            cmd[3]                  =  { 0 } ;
    uint32_t        num_available_samples   =   0;
    uint32_t        i                       =   0;
    uint32_t        myShift                 =   0;
    uint32_t        aux;
    
    MAX30100::MAX30100_status_t   myMAX30100Status;



    /* Check the sample size     */
    if ( ( myNumSamplesToRead > 0 ) && ( myNumSamplesToRead < 17 ) ) {
        /* FIRST TRANSACTION: Get the FIFO_WR_PTR, OVF_COUNTER and FIFO_RD_PTR    */
        cmd[0]   =   MAX30100_FIFO_WRITE_POINTER;
        aux      =   _i2c.write ( _MAX30100_Addr, &cmd[0], 1, true );
        aux      =   _i2c.read  ( _MAX30100_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ) );

        /* Parse data   */
        myDATA->FIFO_wr_ptr   =   ( cmd[0] & FIFO_FIFO_WRITE_POINTER_MASK );
        myDATA->OVF_counter   =   ( cmd[1] & FIFO_OVER_FLOW_COUNTER_MASK );
        myDATA->FIFO_rd_ptr   =   ( cmd[2] & FIFO_FIFO_READ_POINTER_MASK );


        /* If the FIFO is full, just start reading data  */
        if ( myDATA->OVF_counter == 0xF ) {
            /* Get data from FIFO    */
            cmd[0]   =   MAX30100_FIFO_DATA_REGISTER;
            aux      =   _i2c.write ( _MAX30100_Addr, &cmd[0], 1, true );
            aux      =   _i2c.read  ( _MAX30100_Addr, (char*)&myDATA->FIFO_buff[0], ( myNumSamplesToRead << 2U ) );

            /* Parse the data    */
            for ( i = 0; i < myNumSamplesToRead; i++ ) {
                myDATA->FIFO_IR_samples[i]     =   myDATA->FIFO_buff[ ( i << 2 ) ];
                myDATA->FIFO_IR_samples[i]   <<=   8U;
                myDATA->FIFO_IR_samples[i]    |=   myDATA->FIFO_buff[ ( i << 2 ) + 1 ];

                myDATA->FIFO_RED_samples[i]    =   myDATA->FIFO_buff[ ( i << 2 ) + 2 ];
                myDATA->FIFO_RED_samples[i]  <<=   8U;
                myDATA->FIFO_RED_samples[i]   |=   myDATA->FIFO_buff[ ( ( i << 2 ) + 2 ) + 1 ];
            }
        } else {
            /* Evaluate the number of samples to be read from the FIFO    */
            num_available_samples    =   (uint32_t)( myDATA->FIFO_wr_ptr - myDATA->FIFO_rd_ptr );


            /* SECOND TRANSACTION: Read 'myNumSamplesToRead' samples from the FIFO    */
            if ( myNumSamplesToRead <= num_available_samples ) {
                /* Get data from FIFO    */
                cmd[0]   =   MAX30100_FIFO_DATA_REGISTER;
                aux      =   _i2c.write ( _MAX30100_Addr, &cmd[0], 1, true );
                aux      =   _i2c.read  ( _MAX30100_Addr, (char*)&myDATA->FIFO_buff[0], ( myNumSamplesToRead << 2U ) );

                /* Parse the data    */
                for ( i = 0; i < myNumSamplesToRead; i++ ) {
                    myDATA->FIFO_IR_samples[i]     =   myDATA->FIFO_buff[ ( i << 2 ) ];
                    myDATA->FIFO_IR_samples[i]   <<=   8U;
                    myDATA->FIFO_IR_samples[i]    |=   myDATA->FIFO_buff[ ( i << 2 ) + 1 ];

                    myDATA->FIFO_RED_samples[i]    =   myDATA->FIFO_buff[ ( i << 2 ) + 2 ];
                    myDATA->FIFO_RED_samples[i]  <<=   8U;
                    myDATA->FIFO_RED_samples[i]   |=   myDATA->FIFO_buff[ ( ( i << 2 ) + 2 ) + 1 ];
                }
            } else {
                /* THIRD TRANSACTION: Write to FIFO_RD_PTR register. If the second transaction was successful, FIFO_RD_PTR points to the next sample in the FIFO,
                                      and this third transaction is not necessary. Otherwise, the processor updates the FIFO_RD_PTR appropriately, so that the samples are reread
                */

                // [TODO] NOT IMPLEMENTED

                return   MAX30100_FAILURE;
            }
        }
    } else {
        return   MAX30100_FAILURE;
    }



    /* Parse the data according to the ADC resolution    */
    /* Get the pulse width/resolution    */
    myMAX30100Status = MAX30100_Get_LED_PulseWidthControl ( myDATA );
    switch ( myDATA->Resolution ) {
        default:
        case SPO2_CONFIGURATION_LED_PW_200US_13BITS:
            myShift  =   3U;
            break;

        case SPO2_CONFIGURATION_LED_PW_400US_14BITS:
            myShift  =   2U;
            break;

        case SPO2_CONFIGURATION_LED_PW_800US_15BITS:
            myShift  =   1U;
            break;

        case SPO2_CONFIGURATION_LED_PW_1600US_16BITS:
            myShift  =   0U;
            break;

    }

    /* Update the data    */
    for ( i = 0; i < myNumSamplesToRead; i++ ) {
        myDATA->FIFO_IR_samples[i]  >>=   myShift;
        myDATA->FIFO_RED_samples[i] >>=   myShift;
    }


    /* Update FIFO pointers: Get the FIFO_WR_PTR, OVF_COUNTER and FIFO_RD_PTR    */
    cmd[0]   =   MAX30100_FIFO_WRITE_POINTER;
    aux      =   _i2c.write ( _MAX30100_Addr, &cmd[0], 1, true );
    aux      =   _i2c.read  ( _MAX30100_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ) );

    /* Parse data   */
    myDATA->FIFO_wr_ptr   =   ( cmd[0] & FIFO_FIFO_WRITE_POINTER_MASK );
    myDATA->OVF_counter   =   ( cmd[1] & FIFO_OVER_FLOW_COUNTER_MASK );
    myDATA->FIFO_rd_ptr   =   ( cmd[2] & FIFO_FIFO_READ_POINTER_MASK );




    if ( ( aux == I2C_SUCCESS ) && ( myMAX30100Status == MAX30100_SUCCESS ) ) {
        return   MAX30100_SUCCESS;
    } else {
        return   MAX30100_FAILURE;
    }
}



/**
 * @brief       MAX30100_ClearFIFO ( MAX30100_vector_data_t* )
 *
 * @details     It clears the FIFO_WR_PTR, OVF_COUNTER, and FIFO_RD_PTR
 *              registers to all zeros (0x00) to ensure the FIFO is empty and in a known state.
 *
 * @param[in]    N/A.
 *
 * @param[out]   myDATA:            Data from the FIFO
 *
 *
 * @return       Status of MAX30100_ClearFIFO.
 *
 *
 * @author      Manuel Caballero
 * @date        13/July/2018
 * @version     13/July/2018   The ORIGIN
 * @pre         N/A.
 * @warning     N/A.
 */
MAX30100::MAX30100_status_t  MAX30100::MAX30100_ClearFIFO ( MAX30100_vector_data_t* myDATA )
{
    char     cmd[]    =  { 0, 0, 0, 0 } ;
    uint32_t aux;


    /* Update the FIFO_WR_PTR, FIFO_WR_PTR and OVF_COUNTER registers    */
    cmd[0]   =   MAX30100_FIFO_WRITE_POINTER;
    aux      =   _i2c.write ( _MAX30100_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ), false );


    /* Get the FIFO_WR_PTR, OVF_COUNTER and FIFO_RD_PTR    */
    cmd[0]   =   MAX30100_FIFO_WRITE_POINTER;
    aux      =   _i2c.write ( _MAX30100_Addr, &cmd[0], 1, true );
    aux      =   _i2c.read  ( _MAX30100_Addr, &cmd[0], 3 );


    /* Update data   */
    myDATA->FIFO_wr_ptr   =   ( cmd[0] & FIFO_FIFO_WRITE_POINTER_MASK );
    myDATA->OVF_counter   =   ( cmd[1] & FIFO_OVER_FLOW_COUNTER_MASK );
    myDATA->FIFO_rd_ptr   =   ( cmd[2] & FIFO_FIFO_READ_POINTER_MASK );




    if ( aux == I2C_SUCCESS )
        return   MAX30100_SUCCESS;
    else
        return   MAX30100_FAILURE;
}