Contiki-NG
opt-3001-sensor.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the copyright holder nor the names of its
14  * contributors may be used to endorse or promote products derived
15  * from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28  * OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 /*---------------------------------------------------------------------------*/
31 /**
32  * \addtogroup sensortag-cc26xx-opt-sensor
33  * @{
34  *
35  * \file
36  * Driver for the Sensortag Opt3001 light sensor
37  */
38 /*---------------------------------------------------------------------------*/
39 #include "contiki.h"
40 #include "lib/sensors.h"
41 #include "opt-3001-sensor.h"
42 #include "sys/ctimer.h"
43 #include "ti-lib.h"
44 #include "board-i2c.h"
45 #include "sensor-common.h"
46 
47 #include <stdint.h>
48 #include <stdbool.h>
49 #include <string.h>
50 #include <stdio.h>
51 #include <math.h>
52 /*---------------------------------------------------------------------------*/
53 #define DEBUG 0
54 #if DEBUG
55 #define PRINTF(...) printf(__VA_ARGS__)
56 #else
57 #define PRINTF(...)
58 #endif
59 /*---------------------------------------------------------------------------*/
60 /* Slave address */
61 #define OPT3001_I2C_ADDRESS 0x45
62 /*---------------------------------------------------------------------------*/
63 /* Register addresses */
64 #define REG_RESULT 0x00
65 #define REG_CONFIGURATION 0x01
66 #define REG_LOW_LIMIT 0x02
67 #define REG_HIGH_LIMIT 0x03
68 
69 #define REG_MANUFACTURER_ID 0x7E
70 #define REG_DEVICE_ID 0x7F
71 /*---------------------------------------------------------------------------*/
72 /*
73  * Configuration Register Bits and Masks.
74  * We use uint16_t to read from / write to registers, meaning that the
75  * register's MSB is the variable's LSB.
76  */
77 #define CONFIG_RN 0x00F0 /* [15..12] Range Number */
78 #define CONFIG_CT 0x0008 /* [11] Conversion Time */
79 #define CONFIG_M 0x0006 /* [10..9] Mode of Conversion */
80 #define CONFIG_OVF 0x0001 /* [8] Overflow */
81 #define CONFIG_CRF 0x8000 /* [7] Conversion Ready Field */
82 #define CONFIG_FH 0x4000 /* [6] Flag High */
83 #define CONFIG_FL 0x2000 /* [5] Flag Low */
84 #define CONFIG_L 0x1000 /* [4] Latch */
85 #define CONFIG_POL 0x0800 /* [3] Polarity */
86 #define CONFIG_ME 0x0400 /* [2] Mask Exponent */
87 #define CONFIG_FC 0x0300 /* [1..0] Fault Count */
88 
89 /* Possible Values for CT */
90 #define CONFIG_CT_100 0x0000
91 #define CONFIG_CT_800 CONFIG_CT
92 
93 /* Possible Values for M */
94 #define CONFIG_M_CONTI 0x0004
95 #define CONFIG_M_SINGLE 0x0002
96 #define CONFIG_M_SHUTDOWN 0x0000
97 
98 /* Reset Value for the register 0xC810. All zeros except: */
99 #define CONFIG_RN_RESET 0x00C0
100 #define CONFIG_CT_RESET CONFIG_CT_800
101 #define CONFIG_L_RESET 0x1000
102 #define CONFIG_DEFAULTS (CONFIG_RN_RESET | CONFIG_CT_100 | CONFIG_L_RESET)
103 
104 /* Enable / Disable */
105 #define CONFIG_ENABLE_CONTINUOUS (CONFIG_M_CONTI | CONFIG_DEFAULTS)
106 #define CONFIG_ENABLE_SINGLE_SHOT (CONFIG_M_SINGLE | CONFIG_DEFAULTS)
107 #define CONFIG_DISABLE CONFIG_DEFAULTS
108 /*---------------------------------------------------------------------------*/
109 /* Register length */
110 #define REGISTER_LENGTH 2
111 /*---------------------------------------------------------------------------*/
112 /* Sensor data size */
113 #define DATA_LENGTH 2
114 /*---------------------------------------------------------------------------*/
115 /*
116  * SENSOR_STATE_SLEEPING and SENSOR_STATE_ACTIVE are mutually exclusive.
117  * SENSOR_STATE_DATA_READY can be ORd with both of the above. For example the
118  * sensor may be sleeping but with a conversion ready to read out.
119  */
120 #define SENSOR_STATE_SLEEPING 0
121 #define SENSOR_STATE_ACTIVE 1
122 #define SENSOR_STATE_DATA_READY 2
123 
124 static int state = SENSOR_STATE_SLEEPING;
125 /*---------------------------------------------------------------------------*/
126 /* Wait SENSOR_STARTUP_DELAY for the sensor to be ready - 125ms */
127 #define SENSOR_STARTUP_DELAY (CLOCK_SECOND >> 3)
128 
129 static struct ctimer startup_timer;
130 /*---------------------------------------------------------------------------*/
131 /**
132  * \brief Select the sensor on the I2C bus
133  */
134 static void
136 {
137  /* Select slave and set clock rate */
138  board_i2c_select(BOARD_I2C_INTERFACE_0, OPT3001_I2C_ADDRESS);
139 }
140 /*---------------------------------------------------------------------------*/
141 static void
142 notify_ready(void *not_used)
143 {
144  /*
145  * Depending on the CONFIGURATION.CONVERSION_TIME bits, a conversion will
146  * take either 100 or 800 ms. Here we inspect the CONVERSION_READY bit and
147  * if the reading is ready we notify, otherwise we just reschedule ourselves
148  */
149  uint16_t val;
150 
151  select_on_bus();
152 
153  sensor_common_read_reg(REG_CONFIGURATION, (uint8_t *)&val, REGISTER_LENGTH);
154 
155  if(val & CONFIG_CRF) {
156  sensors_changed(&opt_3001_sensor);
157  state = SENSOR_STATE_DATA_READY;
158  } else {
159  ctimer_set(&startup_timer, SENSOR_STARTUP_DELAY, notify_ready, NULL);
160  }
161 }
162 /*---------------------------------------------------------------------------*/
163 /**
164  * \brief Turn the sensor on/off
165  * \param enable TRUE: on, FALSE: off
166  */
167 static void
168 enable_sensor(bool enable)
169 {
170  uint16_t val;
171  uint16_t had_data_ready = state & SENSOR_STATE_DATA_READY;
172 
173  select_on_bus();
174 
175  if(enable) {
176  val = CONFIG_ENABLE_SINGLE_SHOT;
177 
178  /* Writing CONFIG_ENABLE_SINGLE_SHOT to M bits will clear CRF bits */
179  state = SENSOR_STATE_ACTIVE;
180  } else {
181  val = CONFIG_DISABLE;
182 
183  /* Writing CONFIG_DISABLE to M bits will not clear CRF bits */
184  state = SENSOR_STATE_SLEEPING | had_data_ready;
185  }
186 
187  sensor_common_write_reg(REG_CONFIGURATION, (uint8_t *)&val, REGISTER_LENGTH);
188 }
189 /*---------------------------------------------------------------------------*/
190 /**
191  * \brief Read the result register
192  * \param raw_data Pointer to a buffer to store the reading
193  * \return TRUE if valid data
194  */
195 static bool
196 read_data(uint16_t *raw_data)
197 {
198  bool success;
199  uint16_t val;
200 
201  if((state & SENSOR_STATE_DATA_READY) != SENSOR_STATE_DATA_READY) {
202  return false;
203  }
204 
205  select_on_bus();
206 
207  success = sensor_common_read_reg(REG_CONFIGURATION, (uint8_t *)&val,
208  REGISTER_LENGTH);
209 
210  if(success) {
211  success = sensor_common_read_reg(REG_RESULT, (uint8_t *)&val, DATA_LENGTH);
212  }
213 
214  if(success) {
215  /* Swap bytes */
216  *raw_data = (val << 8) | (val >> 8 & 0xFF);
217  } else {
218  sensor_common_set_error_data((uint8_t *)raw_data, DATA_LENGTH);
219  }
220 
221  return success;
222 }
223 /*---------------------------------------------------------------------------*/
224 /**
225  * \brief Convert raw data to a value in lux
226  * \param raw_data data Pointer to a buffer with a raw sensor reading
227  * \return Converted value (lux)
228  */
229 static float
230 convert(uint16_t raw_data)
231 {
232  uint16_t e, m;
233 
234  m = raw_data & 0x0FFF;
235  e = (raw_data & 0xF000) >> 12;
236 
237  return m * (0.01 * exp2(e));
238 }
239 /*---------------------------------------------------------------------------*/
240 /**
241  * \brief Returns a reading from the sensor
242  * \param type Ignored
243  * \return Illuminance in centilux
244  */
245 static int
246 value(int type)
247 {
248  int rv;
249  uint16_t raw_val;
250  float converted_val;
251 
252  rv = read_data(&raw_val);
253 
254  if(rv == false) {
255  return CC26XX_SENSOR_READING_ERROR;
256  }
257 
258  converted_val = convert(raw_val);
259  PRINTF("OPT: %04X r=%d (centilux)\n", raw_val,
260  (int)(converted_val * 100));
261 
262  rv = (int)(converted_val * 100);
263 
264  return rv;
265 }
266 /*---------------------------------------------------------------------------*/
267 /**
268  * \brief Configuration function for the OPT3001 sensor.
269  *
270  * \param type Activate, enable or disable the sensor. See below
271  * \param enable
272  *
273  * When type == SENSORS_HW_INIT we turn on the hardware
274  * When type == SENSORS_ACTIVE and enable==1 we enable the sensor
275  * When type == SENSORS_ACTIVE and enable==0 we disable the sensor
276  */
277 static int
278 configure(int type, int enable)
279 {
280  int rv = 0;
281 
282  switch(type) {
283  case SENSORS_HW_INIT:
284  /*
285  * Device reset won't reset the sensor, so we put it to sleep here
286  * explicitly
287  */
288  enable_sensor(0);
289  rv = 0;
290  break;
291  case SENSORS_ACTIVE:
292  if(enable) {
293  enable_sensor(1);
294  ctimer_set(&startup_timer, SENSOR_STARTUP_DELAY, notify_ready, NULL);
295  rv = 1;
296  } else {
297  ctimer_stop(&startup_timer);
298  enable_sensor(0);
299  rv = 0;
300  }
301  break;
302  default:
303  break;
304  }
305  return rv;
306 }
307 /*---------------------------------------------------------------------------*/
308 /**
309  * \brief Returns the status of the sensor
310  * \param type ignored
311  * \return The state of the sensor SENSOR_STATE_xyz
312  */
313 static int
314 status(int type)
315 {
316  switch(type) {
317  case SENSORS_ACTIVE:
318  case SENSORS_READY:
319  default:
320  break;
321  }
322  return state;
323 }
324 /*---------------------------------------------------------------------------*/
325 SENSORS_SENSOR(opt_3001_sensor, "OPT3001", value, configure, status);
326 /*---------------------------------------------------------------------------*/
327 /** @} */
void ctimer_stop(struct ctimer *c)
Stop a pending callback timer.
Definition: ctimer.c:149
static float convert(uint16_t raw_data)
Convert raw data to a value in lux.
Header file with macros which rename TI CC26xxware functions.
Header file for the Sensortag I2C Driver.
static void enable_sensor(bool enable)
Turn the sensor on/off.
void sensor_common_set_error_data(uint8_t *buf, uint8_t len)
Fill a result buffer with dummy error data.
Definition: sensor-common.c:71
bool sensor_common_read_reg(uint8_t addr, uint8_t *buf, uint8_t len)
Reads a sensor&#39;s register over I2C.
Definition: sensor-common.c:48
Header file for the Sensortag Opt3001 light sensor.
Header file for the callback timer
Header file for the Sensortag Common sensor utilities.
static bool read_data(uint16_t *raw_data)
Read the result register.
void ctimer_set(struct ctimer *c, clock_time_t t, void(*f)(void *), void *ptr)
Set a callback timer.
Definition: ctimer.c:99
static int value(int type)
Returns a reading from the sensor.
static int status(int type)
Returns the status of the sensor.
void board_i2c_select(uint8_t new_interface, uint8_t address)
Select an I2C slave.
Definition: board-i2c.c:310
bool sensor_common_write_reg(uint8_t addr, uint8_t *buf, uint8_t len)
Write to a sensor&#39;s register over I2C.
Definition: sensor-common.c:54
static void select_on_bus(void)
Select the sensor on the I2C bus.
static void notify_ready(void *unused)
Callback when sensor is ready to read data from.
static int configure(int type, int enable)
Configuration function for the OPT3001 sensor.