Forked so that I can make it take I2C as a parameter; on a bus with other I2C things.

Fork of Si1133 by Silicon Labs

Si1133.cpp

Committer:
stevew817
Date:
2017-11-12
Revision:
2:1e2dd643afa8
Parent:
1:410f61a3900b

File content as of revision 2:1e2dd643afa8:

/***************************************************************************//**
 * @file Si1133.cpp
 *******************************************************************************
 * @section License
 * <b>(C) Copyright 2017 Silicon Labs, http://www.silabs.com</b>
 *******************************************************************************
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ******************************************************************************/

#include "Si1133.h"

#define SI1133_I2C_ADDRESS (0xAA) /** Hardcoded address for Si1133 sensor */

/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */

#define X_ORDER_MASK            0x0070
#define Y_ORDER_MASK            0x0007
#define SIGN_MASK               0x0080
#define GET_X_ORDER(m)          ( ((m) & X_ORDER_MASK) >> 4)
#define GET_Y_ORDER(m)          ( ((m) & Y_ORDER_MASK) )
#define GET_SIGN(m)             ( ((m) & SIGN_MASK) >> 7)

#define UV_INPUT_FRACTION       15
#define UV_OUTPUT_FRACTION      12
#define UV_NUMCOEFF             2

#define ADC_THRESHOLD           16000
#define INPUT_FRACTION_HIGH     7
#define INPUT_FRACTION_LOW      15
#define LUX_OUTPUT_FRACTION     12
#define NUMCOEFF_LOW            9
#define NUMCOEFF_HIGH           4

/** @endcond */

/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
/***************************************************************************//**
 * @brief
 *    Coefficients for lux calculation
 ******************************************************************************/
const Si1133::LuxCoeff_t Si1133::lk = {
    {   {     0, 209 },           /**< coeff_high[0]   */
        {  1665, 93  },           /**< coeff_high[1]   */
        {  2064, 65  },           /**< coeff_high[2]   */
        { -2671, 234 } },         /**< coeff_high[3]   */
    {   {     0, 0   },           /**< coeff_low[0]    */
        {  1921, 29053 },         /**< coeff_low[1]    */
        { -1022, 36363 },         /**< coeff_low[2]    */
        {  2320, 20789 },         /**< coeff_low[3]    */
        {  -367, 57909 },         /**< coeff_low[4]    */
        { -1774, 38240 },         /**< coeff_low[5]    */
        {  -608, 46775 },         /**< coeff_low[6]    */
        { -1503, 51831 },         /**< coeff_low[7]    */
        { -1886, 58928 } }        /**< coeff_low[8]    */
};

/***************************************************************************//**
 * @brief
 *    Coefficients for UV index calculation
 ******************************************************************************/
const Si1133::Coeff_t Si1133::uk[2] = {
    { 1281, 30902 },            /**< coeff[0]        */
    { -638, 46301 }             /**< coeff[1]        */
};

/**************************************************************************//**
* @name Error Codes
* @{
******************************************************************************/
#define SI1133_OK                            0x0000   /**< No errors                  */
#define SI1133_ERROR_I2C_TRANSACTION_FAILED  0x0001   /**< I2C transaction failed     */
#define SI1133_ERROR_SLEEP_FAILED            0x0002   /**< Entering sleep mode failed */
/**@}*/

/** @endcond */

Si1133::Si1133(PinName sda, PinName scl, int hz) : m_I2C(sda, scl)
{
    //Set the I2C bus frequency
    m_I2C.frequency(hz);
}

Si1133::~Si1133(void)
{
    deinit();
}

bool Si1133::open()
{
    //Probe for the Si1133 using a Zero Length Transfer
    if (m_I2C.write(SI1133_I2C_ADDRESS, NULL, 0)) {
        //Return success
        return false;
    }

    // initialize sensor
    if (SI1133_OK == init()) {
        return true;
    }
    return false;
}

/** Measure the current light level (in lux) on the Si1133
 *
 * @returns The current temperature measurement in Lux.
 */
float Si1133::get_light_level()
{
    float lux, uvi;
    measure_lux_uv(&lux, &uvi);
    return lux;
}

/** Measure the current UV Index on the Si1133
 *
 * @returns The current UV index.
 */
float Si1133::get_uv_index()
{
    float lux, uvi;
    measure_lux_uv(&lux, &uvi);
    return uvi;
}

bool Si1133::get_light_and_uv(float *light_level, float *uv_index)
{
    if(measure_lux_uv(light_level, uv_index)) {
        return false;
    }
    return true;
}

/***************************************************************************//**
 * @brief
 *    Reads register from the Si1133 sensor
 *
 * @param[in] reg
 *    The register address to read from in the sensor.
 *
 * @param[out] data
 *    The data read from the sensor
 *
 * @return
 *    Returns zero on OK, non-zero otherwise
 ******************************************************************************/
uint32_t Si1133::read_register(enum Si1133::Register reg, uint8_t *data)
{
    char buf[1];
    buf[0] = (char) reg;

    if (m_I2C.write(SI1133_I2C_ADDRESS, buf, 1, true)) {
        //Return failure
        return SI1133_ERROR_I2C_TRANSACTION_FAILED;
    }

    if (m_I2C.read(SI1133_I2C_ADDRESS, buf, 1)) {
        //Return failure
        return SI1133_ERROR_I2C_TRANSACTION_FAILED;
    }

    *data = buf[0];

    return SI1133_OK;
}

/***************************************************************************//**
 * @brief
 *    Writes register in the Si1133 sensor
 *
 * @param[in] reg
 *    The register address to write to in the sensor
 *
 * @param[in] data
 *    The data to write to the sensor
 *
 * @return
 *    Returns zero on OK, non-zero otherwise
 ******************************************************************************/
uint32_t Si1133::write_register(enum Si1133::Register reg, uint8_t data)
{
    char buf[2];
    buf[0] = (char) reg;
    buf[1] = (char) data;

    if (m_I2C.write(SI1133_I2C_ADDRESS, buf, 2)) {
        //Return failure
        return SI1133_ERROR_I2C_TRANSACTION_FAILED;
    }

    return SI1133_OK;
}

/***************************************************************************//**
 * @brief
 *    Writes a block of data to the Si1133 sensor.
 *
 * @param[in] reg
 *    The first register to begin writing to
 *
 * @param[in] length
 *    The number of bytes to write to the sensor
 *
 * @param[in] data
 *    The data to write to the sensor
 *
 * @return
 *    Returns zero on OK, non-zero otherwise
 ******************************************************************************/
uint32_t Si1133::write_register_block(enum Si1133::Register reg, uint8_t length, uint8_t *data)
{
    char buf[length+1];
    buf[0] = (char)reg;
    memcpy(&buf[1], data, length);
    
    if (m_I2C.write(SI1133_I2C_ADDRESS, buf, length + 1)) {
        //Return failure
        return SI1133_ERROR_I2C_TRANSACTION_FAILED;
    }

    return SI1133_OK;
}

/***************************************************************************//**
 * @brief
 *    Reads a block of data from the Si1133 sensor.
 *
 * @param[in] reg
 *    The first register to begin reading from
 *
 * @param[in] length
 *    The number of bytes to write to the sensor
 *
 * @param[out] data
 *    The data read from the sensor
 *
 * @return
 *    Returns zero on OK, non-zero otherwise
 ******************************************************************************/
uint32_t Si1133::read_register_block(enum Si1133::Register reg, uint8_t length, uint8_t *data)
{
    char reg_c = (char)reg;
    if (m_I2C.write(SI1133_I2C_ADDRESS, &reg_c, 1, true)) {
        //Return failure
        return SI1133_ERROR_I2C_TRANSACTION_FAILED;
    }

    if (m_I2C.read(SI1133_I2C_ADDRESS, (char*) data, length)) {
        //Return failure
        return SI1133_ERROR_I2C_TRANSACTION_FAILED;
    }

    return SI1133_OK;
}

/***************************************************************************//**
 * @brief
 *    Reads the interrupt status register of the device
 *
 * @param[out] irqStatus
 *    The contentof the IRQ status register
 *
 * @return
 *    Returns zero on OK, non-zero otherwise
 ******************************************************************************/
uint32_t Si1133::get_irq_status(uint8_t *irq_status)
{
    return read_register(REG_IRQ_STATUS, irq_status);
}

/***************************************************************************//**
 * @brief
 *    Waits until the Si1133 is sleeping before proceeding
 *
 * @return
 *    Returns zero on OK, non-zero otherwise
 ******************************************************************************/
uint32_t Si1133::wait_until_sleep(void)
{
  uint32_t ret;
  uint8_t response;
  size_t count = 0;

  /* This loops until the Si1133 is known to be in its sleep state  */
  /* or if an i2c error occurs                                      */
  while ( count < 5 ) {
    ret = read_register(REG_RESPONSE0, &response);
    if ( (response & (uint8_t)RSP0_CHIPSTAT_MASK) == (uint8_t)RSP0_SLEEP ) {
      return SI1133_OK;
    }

    if ( ret != SI1133_OK ) {
      return SI1133_ERROR_SLEEP_FAILED;
    }

    count++;
  }

  return SI1133_ERROR_SLEEP_FAILED;
}

/***************************************************************************//**
 * @brief
 *    Resets the Si1133
 *
 * @return
 *    Returns zero on OK, non-zero otherwise
 ******************************************************************************/
uint32_t Si1133::reset(void)
{
    uint32_t retval;

    /* Do not access the Si1133 earlier than 25 ms from power-up */
    wait_ms(30);

    /* Perform the Reset Command */
    retval = write_register(REG_COMMAND, (uint8_t)CMD_RESET);

    /* Delay for 10 ms. This delay is needed to allow the Si1133   */
    /* to perform internal reset sequence.                         */
    wait_ms(10);

    return retval;
}

/***************************************************************************//**
 * @brief
 *    Helper function to send a command to the Si1133
 *
 * @param[in] command
 *    The command to send to the sensor
 *
 * @return
 *    Returns zero on OK, non-zero otherwise
 ******************************************************************************/
uint32_t Si1133::send_cmd(enum Si1133::Command command)
{
    uint8_t response;
    uint8_t response_stored;
    uint8_t count = 0;
    uint32_t ret;

    /* Get the response register contents */
    ret = read_register(REG_RESPONSE0, &response_stored);
    if ( ret != SI1133_OK ) {
        return ret;
    }

    response_stored = response_stored & (uint8_t)RSP0_COUNTER_MASK;

    /* Double-check the response register is consistent */
    while ( count < 5 ) {
        ret = wait_until_sleep();
        if ( ret != SI1133_OK ) {
            return ret;
        }
        /* Skip if the command is RESET COMMAND COUNTER */
        if ( command == (uint8_t)CMD_RESET_CMD_CTR ) {
            break;
        }

        ret = read_register(REG_RESPONSE0, &response);

        if ( (response & (uint8_t)RSP0_COUNTER_MASK) == response_stored ) {
            break;
        } else {
            if ( ret != SI1133_OK ) {
                return ret;
            } else {
                response_stored = response & (uint8_t)RSP0_COUNTER_MASK;
            }
        }

        count++;
    }

    /* Send the command */
    ret = write_register(REG_COMMAND, command);
    if ( ret != SI1133_OK ) {
        return ret;
    }

    count = 0;
    /* Expect a change in the response register */
    while ( count < 5 ) {
        /* Skip if the command is RESET COMMAND COUNTER */
        if ( command == (uint8_t)CMD_RESET_CMD_CTR ) {
            break;
        }

        ret = read_register(REG_RESPONSE0, &response);
        if ( (response & (uint8_t)RSP0_COUNTER_MASK) != response_stored ) {
            break;
        } else {
            if ( ret != SI1133_OK ) {
                return ret;
            }
        }

        count++;
    }

    return SI1133_OK;
}

/***************************************************************************//**
 * @brief
 *    Sends a RESET COMMAND COUNTER command to the Si1133
 *
 * @return
 *    Returns zero on OK, non-zero otherwise
 ******************************************************************************/
uint32_t Si1133::reset_cmd_counter(void)
{
  return send_cmd(CMD_RESET_CMD_CTR);
}

/***************************************************************************//**
 * @brief
 *    Sends a FORCE command to the Si1133
 *
 * @return
 *    Returns zero on OK, non-zero otherwise
 ******************************************************************************/
uint32_t Si1133::force_measurement(void)
{
  return send_cmd(CMD_FORCE_CH);
}

/***************************************************************************//**
 * @brief
 *    Sends a START command to the Si1133
 *
 * @return
 *    Returns zero on OK, non-zero otherwise
 ******************************************************************************/
uint32_t Si1133::start_measurement(void)
{
  return send_cmd(CMD_START);
}

/***************************************************************************//**
 * @brief
 *    Sends a PAUSE command to the Si1133
 *
 * @return
 *    Returns zero on OK, non-zero otherwise
 ******************************************************************************/
uint32_t Si1133::pause_measurement(void)
{
  return send_cmd(CMD_PAUSE_CH);
}

/***************************************************************************//**
 * @brief
 *    Writes a byte to an Si1133 Parameter
 *
 * @param[in] address
 *    The parameter address
 *
 * @param[in] value
 *    The byte value to be written to the Si1133 parameter
 *
 * @return
 *    Returns zero on OK, non-zero otherwise
 *
 * @note
 *    This function ensures that the Si1133 is idle and ready to
 *    receive a command before writing the parameter. Furthermore,
 *    command completion is checked. If setting parameter is not done
 *    properly, no measurements will occur. This is the most common
 *    error. It is highly recommended that host code make use of this
 *    function.
 ******************************************************************************/
uint32_t Si1133::set_parameter (enum Si1133::Parameter address, uint8_t value)
{
    uint32_t retval;
    uint8_t buffer[2];
    uint8_t response_stored;
    uint8_t response;
    size_t count;

    retval = wait_until_sleep();
    if ( retval != SI1133_OK ) {
        return retval;
    }

    read_register(REG_RESPONSE0, &response_stored);
    response_stored &= (uint8_t)RSP0_COUNTER_MASK;

    buffer[0] = value;
    buffer[1] = 0x80 + ((uint8_t)address & 0x3F);

    retval = write_register_block(REG_HOSTIN0, 2, (uint8_t*) buffer);
    if ( retval != SI1133_OK ) {
        return retval;
    }

    /* Wait for command to finish */
    count = 0;
    /* Expect a change in the response register */
    while ( count < 5 ) {
        retval = read_register(REG_RESPONSE0, &response);
        if ( (response & (uint8_t)RSP0_COUNTER_MASK) != response_stored ) {
            break;
        } else {
            if ( retval != SI1133_OK ) {
                return retval;
            }
        }

        count++;
    }

    if (count >= 5) {
        return SI1133_ERROR_I2C_TRANSACTION_FAILED;
    }
    
    return SI1133_OK;
}

/***************************************************************************//**
 * @brief
 *    Reads a parameter from the Si1133
 *
 * @param[in] address
 *    The address of the parameter.
 *
 * @return
 *    Returns zero on OK, non-zero otherwise
 ******************************************************************************/
uint32_t Si1133::read_parameter (enum Si1133::Parameter address)
{
    uint8_t retval;
    uint8_t cmd;

    cmd = 0x40 + ((uint8_t)address & 0x3F);

    retval = send_cmd((enum Si1133::Command)cmd);
    if ( retval != SI1133_OK ) {
        return retval;
    }

    read_register(REG_RESPONSE1, &retval);

    return retval;
}

/**************************************************************************//**
 * @brief
 *    Initializes the Si1133 chip
 *
 * @return
 *    Returns zero on OK, non-zero otherwise
 *****************************************************************************/
uint32_t Si1133::init (void)
{
    uint32_t retval;

    /* Allow some time for the part to power up */
    wait_ms(5);

    retval = reset();

    wait_ms(10);

    retval += set_parameter(PARAM_CH_LIST, 0x0f);
    retval += set_parameter(PARAM_ADCCONFIG0, 0x78);
    retval += set_parameter(PARAM_ADCSENS0, 0x71);
    retval += set_parameter(PARAM_ADCPOST0, 0x40);
    retval += set_parameter(PARAM_ADCCONFIG1, 0x4d);
    retval += set_parameter(PARAM_ADCSENS1, 0xe1);
    retval += set_parameter(PARAM_ADCPOST1, 0x40);
    retval += set_parameter(PARAM_ADCCONFIG2, 0x41);
    retval += set_parameter(PARAM_ADCSENS2, 0xe1);
    retval += set_parameter(PARAM_ADCPOST2, 0x50);
    retval += set_parameter(PARAM_ADCCONFIG3, 0x4d);
    retval += set_parameter(PARAM_ADCSENS3, 0x87);
    retval += set_parameter(PARAM_ADCPOST3, 0x40);

    retval += write_register(REG_IRQ_ENABLE, 0x0f);

    return retval;
}

/***************************************************************************//**
 * @brief
 *    Stops the measurements on all channel and waits until the chip
 *    goes to sleep state.
 *
 * @return
 *    Returns zero on OK, non-zero otherwise
 ******************************************************************************/
uint32_t Si1133::deinit (void)
{
    uint32_t retval;

    retval = set_parameter(PARAM_CH_LIST, 0x3f);
    retval += pause_measurement();
    retval += wait_until_sleep();

    return retval;
}

/***************************************************************************//**
 * @brief
 *    Read samples from the Si1133 chip
 *
 * @param[out] samples
 *    Retrieves interrupt status and measurement data for channel 0..3 and
 *    converts the data to int32_t format
 *
 * @return
 *    Returns zero on OK, non-zero otherwise
 ******************************************************************************/
uint32_t Si1133::measure (Si1133::Samples_t *samples)
{
    uint8_t buffer[13];
    uint32_t retval;

    retval = read_register_block(REG_IRQ_STATUS, 13, buffer);

    samples->irq_status = buffer[0];

    samples->ch0 = buffer[1] << 16;
    samples->ch0 |= buffer[2] << 8;
    samples->ch0 |= buffer[3];
    if ( samples->ch0 & 0x800000 ) {
        samples->ch0 |= 0xFF000000;
    }

    samples->ch1 = buffer[4] << 16;
    samples->ch1 |= buffer[5] << 8;
    samples->ch1 |= buffer[6];
    if ( samples->ch1 & 0x800000 ) {
        samples->ch1 |= 0xFF000000;
    }

    samples->ch2 = buffer[7] << 16;
    samples->ch2 |= buffer[8] << 8;
    samples->ch2 |= buffer[9];
    if ( samples->ch2 & 0x800000 ) {
        samples->ch2 |= 0xFF000000;
    }

    samples->ch3 = buffer[10] << 16;
    samples->ch3 |= buffer[11] << 8;
    samples->ch3 |= buffer[12];
    if ( samples->ch3 & 0x800000 ) {
        samples->ch3 |= 0xFF000000;
    }

    return retval;
}

int32_t Si1133::calculate_polynomial_helper (int32_t input, int8_t fraction, uint16_t mag, int8_t shift)
{
    int32_t value;

    if ( shift < 0 ) {
        value = ( (input << fraction) / mag) >> -shift;
    } else {
        value = ( (input << fraction) / mag) << shift;
    }

    return value;
}

int32_t Si1133::calculate_polynomial (int32_t x, int32_t y, uint8_t input_fraction, uint8_t output_fraction, uint8_t num_coeff, const Si1133::Coeff_t *kp)
{
    uint8_t info, x_order, y_order, counter;
    int8_t sign, shift;
    uint16_t mag;
    int32_t output = 0, x1, x2, y1, y2;

    for ( counter = 0; counter < num_coeff; counter++ ) {
        info = kp->info;
        x_order = GET_X_ORDER(info);
        y_order = GET_Y_ORDER(info);

        shift = ( (uint16_t) kp->info & 0xff00) >> 8;
        shift ^= 0x00ff;
        shift += 1;
        shift = -shift;

        mag = kp->mag;

        if ( GET_SIGN(info) ) {
            sign = -1;
        } else {
            sign = 1;
        }

        if ( (x_order == 0) && (y_order == 0) ) {
            output += sign * mag << output_fraction;
        } else {
            if ( x_order > 0 ) {
                x1 = calculate_polynomial_helper(x, input_fraction, mag, shift);
                if ( x_order > 1 ) {
                    x2 = calculate_polynomial_helper(x, input_fraction, mag, shift);
                } else {
                    x2 = 1;
                }
            } else {
                x1 = 1;
                x2 = 1;
            }

            if ( y_order > 0 ) {
                y1 = calculate_polynomial_helper(y, input_fraction, mag, shift);
                if ( y_order > 1 ) {
                    y2 = calculate_polynomial_helper(y, input_fraction, mag, shift);
                } else {
                    y2 = 1;
                }
            } else {
                y1 = 1;
                y2 = 1;
            }

            output += sign * x1 * x2 * y1 * y2;
        }

        kp++;
    }

    if ( output < 0 ) {
        output = -output;
    }

    return output;
}

/***************************************************************************//**
 * @brief
 *    Compute UV index
 *
 * @param[in] uv
 *    UV sensor raw data
 *
 * @param[in] uk
 *    UV calculation coefficients
 *
 * @return
 *    UV index scaled by UV_OUPTUT_FRACTION
 ******************************************************************************/
int32_t Si1133::get_uv (int32_t uv)
{
    int32_t uvi;

    uvi = calculate_polynomial(0, uv, UV_INPUT_FRACTION, UV_OUTPUT_FRACTION, UV_NUMCOEFF, uk);

    return uvi;
}

/***************************************************************************//**
 * @brief
 *    Compute lux value
 *
 * @param[in] vis_high
 *    Visible light sensor raw data
 *
 * @param[in] vis_low
 *    Visible light sensor raw data
 *
 * @param[in] ir
 *    Infrared sensor raw data
 *
 * @param[in] lk
 *    Lux calculation coefficients
 *
 * @return
 *    Lux value scaled by LUX_OUPTUT_FRACTION
 ******************************************************************************/
int32_t Si1133::get_lux (int32_t vis_high, int32_t vis_low, int32_t ir)
{
    int32_t lux;

    if ( (vis_high > ADC_THRESHOLD) || (ir > ADC_THRESHOLD) ) {
        lux = calculate_polynomial(vis_high,
                                   ir,
                                   INPUT_FRACTION_HIGH,
                                   LUX_OUTPUT_FRACTION,
                                   NUMCOEFF_HIGH,
                                   &(lk.coeff_high[0]) );
    } else {
        lux = calculate_polynomial(vis_low,
                                   ir,
                                   INPUT_FRACTION_LOW,
                                   LUX_OUTPUT_FRACTION,
                                   NUMCOEFF_LOW,
                                   &(lk.coeff_low[0]) );
    }

    return lux;
}

/***************************************************************************//**
 * @brief
 *    Measure lux and UV index using the Si1133 sensor
 *
 * @param[out] lux
 *    The measured ambient light illuminace in lux
 *
 * @param[out] uvi
 *    UV index
 *
 * @return
 *    Returns zero on OK, non-zero otherwise
 ******************************************************************************/
uint32_t Si1133::measure_lux_uv (float *lux, float *uvi)
{
    Si1133::Samples_t samples;
    uint32_t retval;
    uint8_t response;

    /* Force measurement */
    retval = force_measurement();

    /* Go to sleep while the sensor does the conversion */
    wait_ms(200);

    /* Check if the measurement finished, if not then wait */
    retval += read_register(REG_IRQ_STATUS, &response);
    while ( response != 0x0F ) {
        wait_ms(5);
        retval += read_register(REG_IRQ_STATUS, &response);
    }

    /* Get the results */
    measure(&samples);

    /* Convert the readings to lux */
    *lux = (float) get_lux(samples.ch1, samples.ch3, samples.ch2);
    *lux = *lux / (1 << LUX_OUTPUT_FRACTION);

    /* Convert the readings to UV index */
    *uvi = (float) get_uv(samples.ch0);
    *uvi = *uvi / (1 << UV_OUTPUT_FRACTION);

    return retval;
}

/***************************************************************************//**
 * @brief
 *    Reads Hardware ID from the SI1133 sensor
 *
 * @param[out] hardwareID
 *    The Hardware ID of the chip (should be 0x33)
 *
 * @return
 *    Returns zero on OK, non-zero otherwise
 ******************************************************************************/
uint32_t Si1133::get_hardware_id (uint8_t *hardware_id)
{
    uint32_t retval;

    retval = read_register(REG_PART_ID, hardware_id);

    return retval;
}

/***************************************************************************//**
 * @brief
 *    Retrieve the sample values from the chip and convert them
 *    to lux and UV index values
 *
 * @param[out] lux
 *    The measured ambient light illuminace in lux
 *
 * @param[out] uvi
 *    UV index
 *
 * @return
 *    Returns zero on OK, non-zero otherwise
 ******************************************************************************/
uint32_t Si1133::get_measurement (float *lux, float *uvi)
{
    Si1133::Samples_t samples;
    uint32_t retval;

    /* Get the results */
    retval = measure(&samples);

    /* Convert the readings to lux */
    *lux = (float) get_lux(samples.ch1, samples.ch3, samples.ch2);
    *lux = *lux / (1 << LUX_OUTPUT_FRACTION);

    /* Convert the readings to UV index */
    *uvi = (float) get_uv(samples.ch0);
    *uvi = *uvi / (1 << UV_OUTPUT_FRACTION);

    return retval;
}