Home | History | Annotate | Download | only in tsl2561
      1 /*
      2  * Author: Nandkishor Sonar <Nandkishor.Sonar (at) intel.com>
      3  * Copyright (c) 2014 Intel Corporation.
      4  *
      5  * LIGHT-TO-DIGITAL CONVERTER [TAOS-TSL2561]
      6  *   Inspiration and lux calculation formulas from data sheet
      7  *   URL: http://www.adafruit.com/datasheets/TSL2561.pdf
      8  *
      9  * Permission is hereby granted, free of charge, to any person obtaining
     10  * a copy of this software and associated documentation files (the
     11  * "Software"), to deal in the Software without restriction, including
     12  * without limitation the rights to use, copy, modify, merge, publish,
     13  * distribute, sublicense, and/or sell copies of the Software, and to
     14  * permit persons to whom the Software is furnished to do so, subject to
     15  * the following conditions:
     16  *
     17  * The above copyright notice and this permission notice shall be
     18  * included in all copies or substantial portions of the Software.
     19  *
     20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     21  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     22  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     23  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
     24  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
     25  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
     26  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     27  */
     28 
     29 
     30 #include <string>
     31 #include <stdexcept>
     32 #include <unistd.h>
     33 #include "tsl2561.h"
     34 
     35 using namespace upm;
     36 
     37 
     38 TSL2561::TSL2561(int bus, uint8_t devAddr, uint8_t gain, uint8_t integrationTime)
     39                                                 : m_i2ControlCtx(bus)
     40 {
     41     m_controlAddr = devAddr;
     42     m_bus = bus;
     43     m_gain = gain ;
     44     m_integrationTime = integrationTime;
     45 
     46     m_name = "TSL2561- Digital Light Sensor";
     47 
     48     mraa::Result error = m_i2ControlCtx.address(m_controlAddr);
     49     if (error != mraa::SUCCESS) {
     50         throw std::invalid_argument(std::string(__FUNCTION__) +
     51                                     ": mraa_i2c_address() failed");
     52         return;
     53     }
     54 
     55     // POWER UP.
     56     error = m_i2ControlCtx.writeReg(REGISTER_Control, CONTROL_POWERON);
     57     if (error != mraa::SUCCESS) {
     58         throw std::runtime_error(std::string(__FUNCTION__) +
     59                                ": Unable to power up TSL2561");
     60         return;
     61     }
     62     // Power on Settling time
     63     usleep(1000);
     64 
     65     // Gain & Integration time .
     66     error = m_i2ControlCtx.writeReg(REGISTER_Timing, m_gain | m_integrationTime);
     67     if (error != mraa::SUCCESS) {
     68         throw std::runtime_error(std::string(__FUNCTION__) +
     69                                  ": Unable to set gain/time");
     70         return;
     71     }
     72 
     73     // Set interrupt threshold to default.
     74     error = m_i2ControlCtx.writeReg(REGISTER_Interrupt, 0x00);
     75     if (error != mraa::SUCCESS) {
     76         throw std::runtime_error(std::string(__FUNCTION__) +
     77                                  ": Unable to set interrupt threshold");
     78         return;
     79     }
     80 }
     81 
     82 TSL2561::~TSL2561()
     83 {
     84     // POWER DOWN
     85     m_i2ControlCtx.writeReg(REGISTER_Control, CONTROL_POWEROFF);
     86 }
     87 
     88 int
     89 TSL2561::getLux()
     90 {
     91     mraa::Result error = mraa::SUCCESS;
     92     int lux;
     93     uint16_t rawLuxCh0;
     94     uint16_t rawLuxCh1;
     95     uint8_t ch0_low, ch0_high, ch1_low, ch1_high;
     96 
     97     error = i2cReadReg(REGISTER_Channal0L, ch0_low);
     98     if (error != mraa::SUCCESS) {
     99         fprintf(stderr, "Error: Unable to read channel0L in getRawLux()\n");
    100         return error;
    101     }
    102 
    103     error = i2cReadReg(REGISTER_Channal0H, ch0_high);
    104     if (error != mraa::SUCCESS) {
    105         fprintf(stderr, "Error: Unable to read channel0H in getRawLux()\n");
    106         return error;
    107     }
    108 
    109     rawLuxCh0 = ch0_high*256+ch0_low;
    110 
    111     error= i2cReadReg(REGISTER_Channal1L, ch1_low);
    112     if (error != mraa::SUCCESS) {
    113         fprintf(stderr, "Error: Unable to read channel1L in getRawLux()\n");
    114         return error;
    115     }
    116 
    117     error = i2cReadReg(REGISTER_Channal1H, ch1_high);
    118     if (error != mraa::SUCCESS) {
    119         fprintf(stderr, "Error: Unable to read channel1H in getRawLux()\n");
    120         return error;
    121     }
    122 
    123     rawLuxCh1 = ch1_high*256+ch1_low;
    124 
    125     uint64_t scale = 0;
    126 
    127     switch (m_integrationTime)
    128     {
    129       case 0: // 13.7 msec
    130          scale = LUX_CHSCALE_TINT0;
    131       break;
    132       case 1: // 101 msec
    133          scale = LUX_CHSCALE_TINT1;
    134       break;
    135       default: // assume no scaling
    136          scale = (1 << LUX_CHSCALE);
    137       break;
    138     }
    139 
    140     // scale if gain is NOT 16X
    141     if (!m_gain) scale = scale << 4;
    142 
    143     uint64_t channel1 = 0;
    144     uint64_t channel0 = 0;
    145     // scale the channel values
    146     channel0 = (rawLuxCh0 * scale) >> LUX_CHSCALE;
    147     channel1 = (rawLuxCh1 * scale) >> LUX_CHSCALE;
    148 
    149     // find the ratio of the channel values (Channel1/Channel0)
    150     // protect against divide by zero
    151     unsigned long ratio1 = 0;
    152     if (channel0 != 0) ratio1 = (channel1 << (LUX_RATIOSCALE+1)) / channel0;
    153 
    154     // round the ratio value
    155     unsigned long ratio = (ratio1 + 1) >> 1;
    156 
    157     unsigned int b, m;
    158 
    159     // CS package
    160     // Check if ratio <= eachBreak ?
    161     if ((ratio >= 0) && (ratio <= LUX_K1C))
    162        {b=LUX_B1C; m=LUX_M1C;}
    163     else if (ratio <= LUX_K2C)
    164        {b=LUX_B2C; m=LUX_M2C;}
    165     else if (ratio <= LUX_K3C)
    166        {b=LUX_B3C; m=LUX_M3C;}
    167     else if (ratio <= LUX_K4C)
    168        {b=LUX_B4C; m=LUX_M4C;}
    169     else if (ratio <= LUX_K5C)
    170        {b=LUX_B5C; m=LUX_M5C;}
    171     else if (ratio <= LUX_K6C)
    172        {b=LUX_B6C; m=LUX_M6C;}
    173     else if (ratio <= LUX_K7C)
    174        {b=LUX_B7C; m=LUX_M7C;}
    175     else if (ratio > LUX_K8C)
    176        {b=LUX_B8C; m=LUX_M8C;}
    177 
    178     uint64_t tempLux = 0;
    179     tempLux = ((channel0 * b) - (channel1 * m));
    180     // do not allow negative lux value
    181     if (tempLux < 0) tempLux = 0;
    182 
    183     // round lsb (2^(LUX_SCALE-1))
    184     tempLux += (1 << (LUX_SCALE-1));
    185 
    186     // strip off fractional portion
    187     lux = tempLux >> LUX_SCALE;
    188 
    189     return lux;
    190 }
    191 
    192 
    193 mraa::Result
    194 TSL2561::i2cWriteReg (uint8_t reg, uint8_t value)
    195 {
    196     mraa::Result error = mraa::SUCCESS;
    197 
    198     // Start transmission to device
    199     error = m_i2ControlCtx.address (m_controlAddr);
    200     if (error != mraa::SUCCESS) {
    201         fprintf(stderr, "Error: on i2c bus address setup in i2cWriteReg()\n");
    202         return error;
    203     }
    204     // Write register to I2C
    205     error = m_i2ControlCtx.writeByte (reg);
    206     if (error != mraa::SUCCESS) {
    207         fprintf(stderr, "Error: on i2c bus write reg in i2cWriteReg()\n");
    208         return error;
    209     }
    210 
    211     // Write value to I2C
    212     error = m_i2ControlCtx.writeByte (value);
    213     if (error != mraa::SUCCESS) {
    214         fprintf(stderr, "Error: on i2c bus write value in i2cWriteReg()\n");
    215         return error;
    216     }
    217 
    218     usleep(100000);
    219 
    220     return error;
    221 }
    222 
    223 mraa::Result
    224 TSL2561::i2cReadReg(uint8_t reg, uint8_t &data)
    225 {
    226     mraa::Result error = mraa::SUCCESS;
    227 
    228     // Start transmission to device
    229     error = m_i2ControlCtx.address(m_controlAddr);
    230     if (error != mraa::SUCCESS) {
    231         fprintf(stderr, "Error: on i2c bus address setup in i2cReadReg()\n");
    232         return error;
    233     }
    234 
    235     // Send address of register to be read.
    236     error = m_i2ControlCtx.writeByte(reg);
    237     if (error != mraa::SUCCESS) {
    238         fprintf(stderr, "Error: on i2c bus write in i2cReadReg()\n");
    239         return error;
    240     }
    241 
    242     // Read byte.
    243     data = m_i2ControlCtx.readByte();
    244 
    245     usleep(10000);
    246 
    247     return error;
    248 }
    249