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

Revision:
0:667132a19341
Child:
1:410f61a3900b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Si1133.cpp	Sun Nov 12 15:58:26 2017 +0100
@@ -0,0 +1,899 @@
+/***************************************************************************//**
+ * @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;
+    measureLuxUvi(&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;
+    measureLuxUvi(&lux, &uvi);
+    return uvi;
+}
+
+/***************************************************************************//**
+ * @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::measurementGet (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::getUv (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::getLux (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::measureLuxUvi (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 */
+    measurementGet(&samples);
+
+    /* Convert the readings to lux */
+    *lux = (float) getLux(samples.ch1, samples.ch3, samples.ch2);
+    *lux = *lux / (1 << LUX_OUTPUT_FRACTION);
+
+    /* Convert the readings to UV index */
+    *uvi = (float) getUv(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::getHardwareID (uint8_t *hardwareID)
+{
+    uint32_t retval;
+
+    retval = read_register(REG_PART_ID, hardwareID);
+
+    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::getMeasurement (float *lux, float *uvi)
+{
+    Si1133::Samples_t samples;
+    uint32_t retval;
+
+    /* Get the results */
+    retval = measurementGet(&samples);
+
+    /* Convert the readings to lux */
+    *lux = (float) getLux(samples.ch1, samples.ch3, samples.ch2);
+    *lux = *lux / (1 << LUX_OUTPUT_FRACTION);
+
+    /* Convert the readings to UV index */
+    *uvi = (float) getUv(samples.ch0);
+    *uvi = *uvi / (1 << UV_OUTPUT_FRACTION);
+
+    return retval;
+}