Driver for the Silicon Labs Si1133 Visible Light/UV sensor

Dependents:   TBSense2_Sensor_Demo mbed-BLE-coragem-teste Pulga_BLE_GPS pulga-mbed-lorawan-gps ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers Si1133.cpp Source File

Si1133.cpp

Go to the documentation of this file.
00001 /***************************************************************************//**
00002  * @file Si1133.cpp
00003  *******************************************************************************
00004  * @section License
00005  * <b>(C) Copyright 2017 Silicon Labs, http://www.silabs.com</b>
00006  *******************************************************************************
00007  *
00008  * SPDX-License-Identifier: Apache-2.0
00009  *
00010  * Licensed under the Apache License, Version 2.0 (the "License"); you may
00011  * not use this file except in compliance with the License.
00012  * You may obtain a copy of the License at
00013  *
00014  * http://www.apache.org/licenses/LICENSE-2.0
00015  *
00016  * Unless required by applicable law or agreed to in writing, software
00017  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
00018  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00019  * See the License for the specific language governing permissions and
00020  * limitations under the License.
00021  *
00022  ******************************************************************************/
00023 
00024 #include "Si1133.h "
00025 
00026 #define SI1133_I2C_ADDRESS (0xAA) /** Hardcoded address for Si1133 sensor */
00027 
00028 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
00029 
00030 #define X_ORDER_MASK            0x0070
00031 #define Y_ORDER_MASK            0x0007
00032 #define SIGN_MASK               0x0080
00033 #define GET_X_ORDER(m)          ( ((m) & X_ORDER_MASK) >> 4)
00034 #define GET_Y_ORDER(m)          ( ((m) & Y_ORDER_MASK) )
00035 #define GET_SIGN(m)             ( ((m) & SIGN_MASK) >> 7)
00036 
00037 #define UV_INPUT_FRACTION       15
00038 #define UV_OUTPUT_FRACTION      12
00039 #define UV_NUMCOEFF             2
00040 
00041 #define ADC_THRESHOLD           16000
00042 #define INPUT_FRACTION_HIGH     7
00043 #define INPUT_FRACTION_LOW      15
00044 #define LUX_OUTPUT_FRACTION     12
00045 #define NUMCOEFF_LOW            9
00046 #define NUMCOEFF_HIGH           4
00047 
00048 /** @endcond */
00049 
00050 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
00051 /***************************************************************************//**
00052  * @brief
00053  *    Coefficients for lux calculation
00054  ******************************************************************************/
00055 const Si1133::LuxCoeff_t Si1133::lk = {
00056     {   {     0, 209 },           /**< coeff_high[0]   */
00057         {  1665, 93  },           /**< coeff_high[1]   */
00058         {  2064, 65  },           /**< coeff_high[2]   */
00059         { -2671, 234 } },         /**< coeff_high[3]   */
00060     {   {     0, 0   },           /**< coeff_low[0]    */
00061         {  1921, 29053 },         /**< coeff_low[1]    */
00062         { -1022, 36363 },         /**< coeff_low[2]    */
00063         {  2320, 20789 },         /**< coeff_low[3]    */
00064         {  -367, 57909 },         /**< coeff_low[4]    */
00065         { -1774, 38240 },         /**< coeff_low[5]    */
00066         {  -608, 46775 },         /**< coeff_low[6]    */
00067         { -1503, 51831 },         /**< coeff_low[7]    */
00068         { -1886, 58928 } }        /**< coeff_low[8]    */
00069 };
00070 
00071 /***************************************************************************//**
00072  * @brief
00073  *    Coefficients for UV index calculation
00074  ******************************************************************************/
00075 const Si1133::Coeff_t Si1133::uk[2] = {
00076     { 1281, 30902 },            /**< coeff[0]        */
00077     { -638, 46301 }             /**< coeff[1]        */
00078 };
00079 
00080 /**************************************************************************//**
00081 * @name Error Codes
00082 * @{
00083 ******************************************************************************/
00084 #define SI1133_OK                            0x0000   /**< No errors                  */
00085 #define SI1133_ERROR_I2C_TRANSACTION_FAILED  0x0001   /**< I2C transaction failed     */
00086 #define SI1133_ERROR_SLEEP_FAILED            0x0002   /**< Entering sleep mode failed */
00087 /**@}*/
00088 
00089 /** @endcond */
00090 
00091 Si1133::Si1133(PinName sda, PinName scl, int hz) : m_I2C(sda, scl)
00092 {
00093     //Set the I2C bus frequency
00094     m_I2C.frequency(hz);
00095 }
00096 
00097 Si1133::~Si1133(void)
00098 {
00099     deinit();
00100 }
00101 
00102 bool Si1133::open()
00103 {
00104     //Probe for the Si1133 using a Zero Length Transfer
00105     if (m_I2C.write(SI1133_I2C_ADDRESS, NULL, 0)) {
00106         //Return success
00107         return false;
00108     }
00109 
00110     // initialize sensor
00111     if (SI1133_OK == init()) {
00112         return true;
00113     }
00114     return false;
00115 }
00116 
00117 /** Measure the current light level (in lux) on the Si1133
00118  *
00119  * @returns The current temperature measurement in Lux.
00120  */
00121 float Si1133::get_light_level()
00122 {
00123     float lux, uvi;
00124     measure_lux_uv(&lux, &uvi);
00125     return lux;
00126 }
00127 
00128 /** Measure the current UV Index on the Si1133
00129  *
00130  * @returns The current UV index.
00131  */
00132 float Si1133::get_uv_index()
00133 {
00134     float lux, uvi;
00135     measure_lux_uv(&lux, &uvi);
00136     return uvi;
00137 }
00138 
00139 bool Si1133::get_light_and_uv(float *light_level, float *uv_index)
00140 {
00141     if(measure_lux_uv(light_level, uv_index)) {
00142         return false;
00143     }
00144     return true;
00145 }
00146 
00147 /***************************************************************************//**
00148  * @brief
00149  *    Reads register from the Si1133 sensor
00150  *
00151  * @param[in] reg
00152  *    The register address to read from in the sensor.
00153  *
00154  * @param[out] data
00155  *    The data read from the sensor
00156  *
00157  * @return
00158  *    Returns zero on OK, non-zero otherwise
00159  ******************************************************************************/
00160 uint32_t Si1133::read_register(enum Si1133::Register reg, uint8_t *data)
00161 {
00162     char buf[1];
00163     buf[0] = (char) reg;
00164 
00165     if (m_I2C.write(SI1133_I2C_ADDRESS, buf, 1, true)) {
00166         //Return failure
00167         return SI1133_ERROR_I2C_TRANSACTION_FAILED;
00168     }
00169 
00170     if (m_I2C.read(SI1133_I2C_ADDRESS, buf, 1)) {
00171         //Return failure
00172         return SI1133_ERROR_I2C_TRANSACTION_FAILED;
00173     }
00174 
00175     *data = buf[0];
00176 
00177     return SI1133_OK;
00178 }
00179 
00180 /***************************************************************************//**
00181  * @brief
00182  *    Writes register in the Si1133 sensor
00183  *
00184  * @param[in] reg
00185  *    The register address to write to in the sensor
00186  *
00187  * @param[in] data
00188  *    The data to write to the sensor
00189  *
00190  * @return
00191  *    Returns zero on OK, non-zero otherwise
00192  ******************************************************************************/
00193 uint32_t Si1133::write_register(enum Si1133::Register reg, uint8_t data)
00194 {
00195     char buf[2];
00196     buf[0] = (char) reg;
00197     buf[1] = (char) data;
00198 
00199     if (m_I2C.write(SI1133_I2C_ADDRESS, buf, 2)) {
00200         //Return failure
00201         return SI1133_ERROR_I2C_TRANSACTION_FAILED;
00202     }
00203 
00204     return SI1133_OK;
00205 }
00206 
00207 /***************************************************************************//**
00208  * @brief
00209  *    Writes a block of data to the Si1133 sensor.
00210  *
00211  * @param[in] reg
00212  *    The first register to begin writing to
00213  *
00214  * @param[in] length
00215  *    The number of bytes to write to the sensor
00216  *
00217  * @param[in] data
00218  *    The data to write to the sensor
00219  *
00220  * @return
00221  *    Returns zero on OK, non-zero otherwise
00222  ******************************************************************************/
00223 uint32_t Si1133::write_register_block(enum Si1133::Register reg, uint8_t length, uint8_t *data)
00224 {
00225     char buf[3];
00226     buf[0] = (char)reg;
00227 
00228     if (length > 2) {
00229         return SI1133_ERROR_I2C_TRANSACTION_FAILED;
00230     }
00231 
00232     memcpy(&buf[1], data, length);
00233 
00234     if (m_I2C.write(SI1133_I2C_ADDRESS, buf, length + 1)) {
00235         //Return failure
00236         return SI1133_ERROR_I2C_TRANSACTION_FAILED;
00237     }
00238 
00239     return SI1133_OK;
00240 }
00241 
00242 /***************************************************************************//**
00243  * @brief
00244  *    Reads a block of data from the Si1133 sensor.
00245  *
00246  * @param[in] reg
00247  *    The first register to begin reading from
00248  *
00249  * @param[in] length
00250  *    The number of bytes to write to the sensor
00251  *
00252  * @param[out] data
00253  *    The data read from the sensor
00254  *
00255  * @return
00256  *    Returns zero on OK, non-zero otherwise
00257  ******************************************************************************/
00258 uint32_t Si1133::read_register_block(enum Si1133::Register reg, uint8_t length, uint8_t *data)
00259 {
00260     char reg_c = (char)reg;
00261     if (m_I2C.write(SI1133_I2C_ADDRESS, &reg_c, 1, true)) {
00262         //Return failure
00263         return SI1133_ERROR_I2C_TRANSACTION_FAILED;
00264     }
00265 
00266     if (m_I2C.read(SI1133_I2C_ADDRESS, (char*) data, length)) {
00267         //Return failure
00268         return SI1133_ERROR_I2C_TRANSACTION_FAILED;
00269     }
00270 
00271     return SI1133_OK;
00272 }
00273 
00274 /***************************************************************************//**
00275  * @brief
00276  *    Reads the interrupt status register of the device
00277  *
00278  * @param[out] irqStatus
00279  *    The contentof the IRQ status register
00280  *
00281  * @return
00282  *    Returns zero on OK, non-zero otherwise
00283  ******************************************************************************/
00284 uint32_t Si1133::get_irq_status(uint8_t *irq_status)
00285 {
00286     return read_register(REG_IRQ_STATUS, irq_status);
00287 }
00288 
00289 /***************************************************************************//**
00290  * @brief
00291  *    Waits until the Si1133 is sleeping before proceeding
00292  *
00293  * @return
00294  *    Returns zero on OK, non-zero otherwise
00295  ******************************************************************************/
00296 uint32_t Si1133::wait_until_sleep(void)
00297 {
00298   uint32_t ret;
00299   uint8_t response;
00300   size_t count = 0;
00301 
00302   /* This loops until the Si1133 is known to be in its sleep state  */
00303   /* or if an i2c error occurs                                      */
00304   while ( count < 5 ) {
00305     ret = read_register(REG_RESPONSE0, &response);
00306     if ( (response & (uint8_t)RSP0_CHIPSTAT_MASK) == (uint8_t)RSP0_SLEEP ) {
00307       return SI1133_OK;
00308     }
00309 
00310     if ( ret != SI1133_OK ) {
00311       return SI1133_ERROR_SLEEP_FAILED;
00312     }
00313 
00314     count++;
00315   }
00316 
00317   return SI1133_ERROR_SLEEP_FAILED;
00318 }
00319 
00320 /***************************************************************************//**
00321  * @brief
00322  *    Resets the Si1133
00323  *
00324  * @return
00325  *    Returns zero on OK, non-zero otherwise
00326  ******************************************************************************/
00327 uint32_t Si1133::reset(void)
00328 {
00329     uint32_t retval;
00330 
00331     /* Do not access the Si1133 earlier than 25 ms from power-up */
00332     wait_ms(30);
00333 
00334     /* Perform the Reset Command */
00335     retval = write_register(REG_COMMAND, (uint8_t)CMD_RESET);
00336 
00337     /* Delay for 10 ms. This delay is needed to allow the Si1133   */
00338     /* to perform internal reset sequence.                         */
00339     wait_ms(10);
00340 
00341     return retval;
00342 }
00343 
00344 /***************************************************************************//**
00345  * @brief
00346  *    Helper function to send a command to the Si1133
00347  *
00348  * @param[in] command
00349  *    The command to send to the sensor
00350  *
00351  * @return
00352  *    Returns zero on OK, non-zero otherwise
00353  ******************************************************************************/
00354 uint32_t Si1133::send_cmd(enum Si1133::Command command)
00355 {
00356     uint8_t response;
00357     uint8_t response_stored;
00358     uint8_t count = 0;
00359     uint32_t ret;
00360 
00361     /* Get the response register contents */
00362     ret = read_register(REG_RESPONSE0, &response_stored);
00363     if ( ret != SI1133_OK ) {
00364         return ret;
00365     }
00366 
00367     response_stored = response_stored & (uint8_t)RSP0_COUNTER_MASK;
00368 
00369     /* Double-check the response register is consistent */
00370     while ( count < 5 ) {
00371         ret = wait_until_sleep();
00372         if ( ret != SI1133_OK ) {
00373             return ret;
00374         }
00375         /* Skip if the command is RESET COMMAND COUNTER */
00376         if ( command == (uint8_t)CMD_RESET_CMD_CTR ) {
00377             break;
00378         }
00379 
00380         ret = read_register(REG_RESPONSE0, &response);
00381 
00382         if ( (response & (uint8_t)RSP0_COUNTER_MASK) == response_stored ) {
00383             break;
00384         } else {
00385             if ( ret != SI1133_OK ) {
00386                 return ret;
00387             } else {
00388                 response_stored = response & (uint8_t)RSP0_COUNTER_MASK;
00389             }
00390         }
00391 
00392         count++;
00393     }
00394 
00395     /* Send the command */
00396     ret = write_register(REG_COMMAND, command);
00397     if ( ret != SI1133_OK ) {
00398         return ret;
00399     }
00400 
00401     count = 0;
00402     /* Expect a change in the response register */
00403     while ( count < 5 ) {
00404         /* Skip if the command is RESET COMMAND COUNTER */
00405         if ( command == (uint8_t)CMD_RESET_CMD_CTR ) {
00406             break;
00407         }
00408 
00409         ret = read_register(REG_RESPONSE0, &response);
00410         if ( (response & (uint8_t)RSP0_COUNTER_MASK) != response_stored ) {
00411             break;
00412         } else {
00413             if ( ret != SI1133_OK ) {
00414                 return ret;
00415             }
00416         }
00417 
00418         count++;
00419     }
00420 
00421     return SI1133_OK;
00422 }
00423 
00424 /***************************************************************************//**
00425  * @brief
00426  *    Sends a RESET COMMAND COUNTER command to the Si1133
00427  *
00428  * @return
00429  *    Returns zero on OK, non-zero otherwise
00430  ******************************************************************************/
00431 uint32_t Si1133::reset_cmd_counter(void)
00432 {
00433   return send_cmd(CMD_RESET_CMD_CTR);
00434 }
00435 
00436 /***************************************************************************//**
00437  * @brief
00438  *    Sends a FORCE command to the Si1133
00439  *
00440  * @return
00441  *    Returns zero on OK, non-zero otherwise
00442  ******************************************************************************/
00443 uint32_t Si1133::force_measurement(void)
00444 {
00445   return send_cmd(CMD_FORCE_CH);
00446 }
00447 
00448 /***************************************************************************//**
00449  * @brief
00450  *    Sends a START command to the Si1133
00451  *
00452  * @return
00453  *    Returns zero on OK, non-zero otherwise
00454  ******************************************************************************/
00455 uint32_t Si1133::start_measurement(void)
00456 {
00457   return send_cmd(CMD_START);
00458 }
00459 
00460 /***************************************************************************//**
00461  * @brief
00462  *    Sends a PAUSE command to the Si1133
00463  *
00464  * @return
00465  *    Returns zero on OK, non-zero otherwise
00466  ******************************************************************************/
00467 uint32_t Si1133::pause_measurement(void)
00468 {
00469   return send_cmd(CMD_PAUSE_CH);
00470 }
00471 
00472 /***************************************************************************//**
00473  * @brief
00474  *    Writes a byte to an Si1133 Parameter
00475  *
00476  * @param[in] address
00477  *    The parameter address
00478  *
00479  * @param[in] value
00480  *    The byte value to be written to the Si1133 parameter
00481  *
00482  * @return
00483  *    Returns zero on OK, non-zero otherwise
00484  *
00485  * @note
00486  *    This function ensures that the Si1133 is idle and ready to
00487  *    receive a command before writing the parameter. Furthermore,
00488  *    command completion is checked. If setting parameter is not done
00489  *    properly, no measurements will occur. This is the most common
00490  *    error. It is highly recommended that host code make use of this
00491  *    function.
00492  ******************************************************************************/
00493 uint32_t Si1133::set_parameter (enum Si1133::Parameter address, uint8_t value)
00494 {
00495     uint32_t retval;
00496     uint8_t buffer[2];
00497     uint8_t response_stored;
00498     uint8_t response;
00499     size_t count;
00500 
00501     retval = wait_until_sleep();
00502     if ( retval != SI1133_OK ) {
00503         return retval;
00504     }
00505 
00506     read_register(REG_RESPONSE0, &response_stored);
00507     response_stored &= (uint8_t)RSP0_COUNTER_MASK;
00508 
00509     buffer[0] = value;
00510     buffer[1] = 0x80 + ((uint8_t)address & 0x3F);
00511 
00512     retval = write_register_block(REG_HOSTIN0, 2, (uint8_t*) buffer);
00513     if ( retval != SI1133_OK ) {
00514         return retval;
00515     }
00516 
00517     /* Wait for command to finish */
00518     count = 0;
00519     /* Expect a change in the response register */
00520     while ( count < 5 ) {
00521         retval = read_register(REG_RESPONSE0, &response);
00522         if ( (response & (uint8_t)RSP0_COUNTER_MASK) != response_stored ) {
00523             break;
00524         } else {
00525             if ( retval != SI1133_OK ) {
00526                 return retval;
00527             }
00528         }
00529 
00530         count++;
00531     }
00532 
00533     if (count >= 5) {
00534         return SI1133_ERROR_I2C_TRANSACTION_FAILED;
00535     }
00536 
00537     return SI1133_OK;
00538 }
00539 
00540 /***************************************************************************//**
00541  * @brief
00542  *    Reads a parameter from the Si1133
00543  *
00544  * @param[in] address
00545  *    The address of the parameter.
00546  *
00547  * @return
00548  *    Returns zero on OK, non-zero otherwise
00549  ******************************************************************************/
00550 uint32_t Si1133::read_parameter (enum Si1133::Parameter address)
00551 {
00552     uint8_t retval;
00553     uint8_t cmd;
00554 
00555     cmd = 0x40 + ((uint8_t)address & 0x3F);
00556 
00557     retval = send_cmd((enum Si1133::Command)cmd);
00558     if ( retval != SI1133_OK ) {
00559         return retval;
00560     }
00561 
00562     read_register(REG_RESPONSE1, &retval);
00563 
00564     return retval;
00565 }
00566 
00567 /**************************************************************************//**
00568  * @brief
00569  *    Initializes the Si1133 chip
00570  *
00571  * @return
00572  *    Returns zero on OK, non-zero otherwise
00573  *****************************************************************************/
00574 uint32_t Si1133::init (void)
00575 {
00576     uint32_t retval;
00577 
00578     /* Allow some time for the part to power up */
00579     wait_ms(5);
00580 
00581     retval = reset();
00582 
00583     wait_ms(10);
00584 
00585     retval += set_parameter(PARAM_CH_LIST, 0x0f);
00586     retval += set_parameter(PARAM_ADCCONFIG0, 0x78);
00587     retval += set_parameter(PARAM_ADCSENS0, 0x71);
00588     retval += set_parameter(PARAM_ADCPOST0, 0x40);
00589     retval += set_parameter(PARAM_ADCCONFIG1, 0x4d);
00590     retval += set_parameter(PARAM_ADCSENS1, 0xe1);
00591     retval += set_parameter(PARAM_ADCPOST1, 0x40);
00592     retval += set_parameter(PARAM_ADCCONFIG2, 0x41);
00593     retval += set_parameter(PARAM_ADCSENS2, 0xe1);
00594     retval += set_parameter(PARAM_ADCPOST2, 0x50);
00595     retval += set_parameter(PARAM_ADCCONFIG3, 0x4d);
00596     retval += set_parameter(PARAM_ADCSENS3, 0x87);
00597     retval += set_parameter(PARAM_ADCPOST3, 0x40);
00598 
00599     retval += write_register(REG_IRQ_ENABLE, 0x0f);
00600 
00601     return retval;
00602 }
00603 
00604 /***************************************************************************//**
00605  * @brief
00606  *    Stops the measurements on all channel and waits until the chip
00607  *    goes to sleep state.
00608  *
00609  * @return
00610  *    Returns zero on OK, non-zero otherwise
00611  ******************************************************************************/
00612 uint32_t Si1133::deinit (void)
00613 {
00614     uint32_t retval;
00615 
00616     retval = set_parameter(PARAM_CH_LIST, 0x3f);
00617     retval += pause_measurement();
00618     retval += wait_until_sleep();
00619 
00620     return retval;
00621 }
00622 
00623 /***************************************************************************//**
00624  * @brief
00625  *    Read samples from the Si1133 chip
00626  *
00627  * @param[out] samples
00628  *    Retrieves interrupt status and measurement data for channel 0..3 and
00629  *    converts the data to int32_t format
00630  *
00631  * @return
00632  *    Returns zero on OK, non-zero otherwise
00633  ******************************************************************************/
00634 uint32_t Si1133::measure (Si1133::Samples_t *samples)
00635 {
00636     uint8_t buffer[13];
00637     uint32_t retval;
00638 
00639     retval = read_register_block(REG_IRQ_STATUS, 13, buffer);
00640 
00641     samples->irq_status = buffer[0];
00642 
00643     samples->ch0 = buffer[1] << 16;
00644     samples->ch0 |= buffer[2] << 8;
00645     samples->ch0 |= buffer[3];
00646     if ( samples->ch0 & 0x800000 ) {
00647         samples->ch0 |= 0xFF000000;
00648     }
00649 
00650     samples->ch1 = buffer[4] << 16;
00651     samples->ch1 |= buffer[5] << 8;
00652     samples->ch1 |= buffer[6];
00653     if ( samples->ch1 & 0x800000 ) {
00654         samples->ch1 |= 0xFF000000;
00655     }
00656 
00657     samples->ch2 = buffer[7] << 16;
00658     samples->ch2 |= buffer[8] << 8;
00659     samples->ch2 |= buffer[9];
00660     if ( samples->ch2 & 0x800000 ) {
00661         samples->ch2 |= 0xFF000000;
00662     }
00663 
00664     samples->ch3 = buffer[10] << 16;
00665     samples->ch3 |= buffer[11] << 8;
00666     samples->ch3 |= buffer[12];
00667     if ( samples->ch3 & 0x800000 ) {
00668         samples->ch3 |= 0xFF000000;
00669     }
00670 
00671     return retval;
00672 }
00673 
00674 int32_t Si1133::calculate_polynomial_helper (int32_t input, int8_t fraction, uint16_t mag, int8_t shift)
00675 {
00676     int32_t value;
00677 
00678     if ( shift < 0 ) {
00679         value = ( (input << fraction) / mag) >> -shift;
00680     } else {
00681         value = ( (input << fraction) / mag) << shift;
00682     }
00683 
00684     return value;
00685 }
00686 
00687 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)
00688 {
00689     uint8_t info, x_order, y_order, counter;
00690     int8_t sign, shift;
00691     uint16_t mag;
00692     int32_t output = 0, x1, x2, y1, y2;
00693 
00694     for ( counter = 0; counter < num_coeff; counter++ ) {
00695         info = kp->info;
00696         x_order = GET_X_ORDER(info);
00697         y_order = GET_Y_ORDER(info);
00698 
00699         shift = ( (uint16_t) kp->info & 0xff00) >> 8;
00700         shift ^= 0x00ff;
00701         shift += 1;
00702         shift = -shift;
00703 
00704         mag = kp->mag;
00705 
00706         if ( GET_SIGN(info) ) {
00707             sign = -1;
00708         } else {
00709             sign = 1;
00710         }
00711 
00712         if ( (x_order == 0) && (y_order == 0) ) {
00713             output += sign * mag << output_fraction;
00714         } else {
00715             if ( x_order > 0 ) {
00716                 x1 = calculate_polynomial_helper(x, input_fraction, mag, shift);
00717                 if ( x_order > 1 ) {
00718                     x2 = calculate_polynomial_helper(x, input_fraction, mag, shift);
00719                 } else {
00720                     x2 = 1;
00721                 }
00722             } else {
00723                 x1 = 1;
00724                 x2 = 1;
00725             }
00726 
00727             if ( y_order > 0 ) {
00728                 y1 = calculate_polynomial_helper(y, input_fraction, mag, shift);
00729                 if ( y_order > 1 ) {
00730                     y2 = calculate_polynomial_helper(y, input_fraction, mag, shift);
00731                 } else {
00732                     y2 = 1;
00733                 }
00734             } else {
00735                 y1 = 1;
00736                 y2 = 1;
00737             }
00738 
00739             output += sign * x1 * x2 * y1 * y2;
00740         }
00741 
00742         kp++;
00743     }
00744 
00745     if ( output < 0 ) {
00746         output = -output;
00747     }
00748 
00749     return output;
00750 }
00751 
00752 /***************************************************************************//**
00753  * @brief
00754  *    Compute UV index
00755  *
00756  * @param[in] uv
00757  *    UV sensor raw data
00758  *
00759  * @param[in] uk
00760  *    UV calculation coefficients
00761  *
00762  * @return
00763  *    UV index scaled by UV_OUPTUT_FRACTION
00764  ******************************************************************************/
00765 int32_t Si1133::get_uv (int32_t uv)
00766 {
00767     int32_t uvi;
00768 
00769     uvi = calculate_polynomial(0, uv, UV_INPUT_FRACTION, UV_OUTPUT_FRACTION, UV_NUMCOEFF, uk);
00770 
00771     return uvi;
00772 }
00773 
00774 /***************************************************************************//**
00775  * @brief
00776  *    Compute lux value
00777  *
00778  * @param[in] vis_high
00779  *    Visible light sensor raw data
00780  *
00781  * @param[in] vis_low
00782  *    Visible light sensor raw data
00783  *
00784  * @param[in] ir
00785  *    Infrared sensor raw data
00786  *
00787  * @param[in] lk
00788  *    Lux calculation coefficients
00789  *
00790  * @return
00791  *    Lux value scaled by LUX_OUPTUT_FRACTION
00792  ******************************************************************************/
00793 int32_t Si1133::get_lux (int32_t vis_high, int32_t vis_low, int32_t ir)
00794 {
00795     int32_t lux;
00796 
00797     if ( (vis_high > ADC_THRESHOLD) || (ir > ADC_THRESHOLD) ) {
00798         lux = calculate_polynomial(vis_high,
00799                                    ir,
00800                                    INPUT_FRACTION_HIGH,
00801                                    LUX_OUTPUT_FRACTION,
00802                                    NUMCOEFF_HIGH,
00803                                    &(lk.coeff_high[0]) );
00804     } else {
00805         lux = calculate_polynomial(vis_low,
00806                                    ir,
00807                                    INPUT_FRACTION_LOW,
00808                                    LUX_OUTPUT_FRACTION,
00809                                    NUMCOEFF_LOW,
00810                                    &(lk.coeff_low[0]) );
00811     }
00812 
00813     return lux;
00814 }
00815 
00816 /***************************************************************************//**
00817  * @brief
00818  *    Measure lux and UV index using the Si1133 sensor
00819  *
00820  * @param[out] lux
00821  *    The measured ambient light illuminace in lux
00822  *
00823  * @param[out] uvi
00824  *    UV index
00825  *
00826  * @return
00827  *    Returns zero on OK, non-zero otherwise
00828  ******************************************************************************/
00829 uint32_t Si1133::measure_lux_uv (float *lux, float *uvi)
00830 {
00831     Si1133::Samples_t samples;
00832     uint32_t retval;
00833     uint8_t response;
00834 
00835     /* Force measurement */
00836     retval = force_measurement();
00837 
00838     /* Go to sleep while the sensor does the conversion */
00839     wait_ms(200);
00840 
00841     /* Check if the measurement finished, if not then wait */
00842     retval += read_register(REG_IRQ_STATUS, &response);
00843     while ( response != 0x0F ) {
00844         wait_ms(5);
00845         retval += read_register(REG_IRQ_STATUS, &response);
00846     }
00847 
00848     /* Get the results */
00849     measure(&samples);
00850 
00851     /* Convert the readings to lux */
00852     *lux = (float) get_lux(samples.ch1, samples.ch3, samples.ch2);
00853     *lux = *lux / (1 << LUX_OUTPUT_FRACTION);
00854 
00855     /* Convert the readings to UV index */
00856     *uvi = (float) get_uv(samples.ch0);
00857     *uvi = *uvi / (1 << UV_OUTPUT_FRACTION);
00858 
00859     return retval;
00860 }
00861 
00862 /***************************************************************************//**
00863  * @brief
00864  *    Reads Hardware ID from the SI1133 sensor
00865  *
00866  * @param[out] hardwareID
00867  *    The Hardware ID of the chip (should be 0x33)
00868  *
00869  * @return
00870  *    Returns zero on OK, non-zero otherwise
00871  ******************************************************************************/
00872 uint32_t Si1133::get_hardware_id (uint8_t *hardware_id)
00873 {
00874     uint32_t retval;
00875 
00876     retval = read_register(REG_PART_ID, hardware_id);
00877 
00878     return retval;
00879 }
00880 
00881 /***************************************************************************//**
00882  * @brief
00883  *    Retrieve the sample values from the chip and convert them
00884  *    to lux and UV index values
00885  *
00886  * @param[out] lux
00887  *    The measured ambient light illuminace in lux
00888  *
00889  * @param[out] uvi
00890  *    UV index
00891  *
00892  * @return
00893  *    Returns zero on OK, non-zero otherwise
00894  ******************************************************************************/
00895 uint32_t Si1133::get_measurement (float *lux, float *uvi)
00896 {
00897     Si1133::Samples_t samples;
00898     uint32_t retval;
00899 
00900     /* Get the results */
00901     retval = measure(&samples);
00902 
00903     /* Convert the readings to lux */
00904     *lux = (float) get_lux(samples.ch1, samples.ch3, samples.ch2);
00905     *lux = *lux / (1 << LUX_OUTPUT_FRACTION);
00906 
00907     /* Convert the readings to UV index */
00908     *uvi = (float) get_uv(samples.ch0);
00909     *uvi = *uvi / (1 << UV_OUTPUT_FRACTION);
00910 
00911     return retval;
00912 }