1 /*
2 * Author: Nandkishor Sonar <Nandkishor.Sonar@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
TSL2561(int bus,uint8_t devAddr,uint8_t gain,uint8_t integrationTime)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
~TSL2561()82 TSL2561::~TSL2561()
83 {
84 // POWER DOWN
85 m_i2ControlCtx.writeReg(REGISTER_Control, CONTROL_POWEROFF);
86 }
87
88 int
getLux()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
i2cWriteReg(uint8_t reg,uint8_t value)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
i2cReadReg(uint8_t reg,uint8_t & data)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