Program test for Coragem
Dependencies: SX1272 SPI_MX25R
Diff: Si1133.cpp
- Revision:
- 4:05d5aa4d3f2d
diff -r cbe3f441353e -r 05d5aa4d3f2d Si1133.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Si1133.cpp Wed Nov 13 16:42:06 2019 +0000 @@ -0,0 +1,926 @@ +/***************************************************************************//** + * @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[3]; + buf[0] = (char)reg; + + if (length > 2) { + return SI1133_ERROR_I2C_TRANSACTION_FAILED; + } + + 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, ®_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); +} + +uint32_t Si1133::wake(void) +{ + uint8_t response; + read_register(REG_RESPONSE0, &response); + response = (response & 31) | 128; + write_register(REG_RESPONSE0, response); + read_register(REG_RESPONSE0, &response); + if (response & 224 == 128) + return 0; + else return 1; +} + + +/***************************************************************************//** + * @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; +} +