2018-05-28 11:17:01 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
* 3. Neither the name of the copyright holder nor the names of its
|
|
|
|
* contributors may be used to endorse or promote products derived
|
|
|
|
* from this software without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
|
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
|
|
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
|
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
|
|
|
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
|
|
* \addtogroup sensortag-cc26xx-opt-sensor
|
|
|
|
* @{
|
|
|
|
*
|
|
|
|
* \file
|
|
|
|
* Driver for the Sensortag Opt3001 light sensor
|
|
|
|
*/
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
#include "contiki.h"
|
|
|
|
#include "lib/sensors.h"
|
|
|
|
#include "sys/ctimer.h"
|
2018-05-31 15:17:07 +00:00
|
|
|
#include "opt-3001-sensor.h"
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
#include <Board.h>
|
|
|
|
#include <ti/drivers/I2C.h>
|
|
|
|
/*---------------------------------------------------------------------------*/
|
2018-05-28 11:17:01 +00:00
|
|
|
#include <stdint.h>
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
#define DEBUG 0
|
|
|
|
#if DEBUG
|
|
|
|
#define PRINTF(...) printf(__VA_ARGS__)
|
|
|
|
#else
|
|
|
|
#define PRINTF(...)
|
|
|
|
#endif
|
|
|
|
/*---------------------------------------------------------------------------*/
|
2018-05-31 15:17:07 +00:00
|
|
|
#ifndef Board_OPT3001_ADDR
|
|
|
|
# error "Board file doesn't define I2C address Board_OPT3001_ADDR"
|
|
|
|
#endif
|
2018-05-28 11:17:01 +00:00
|
|
|
/* Slave address */
|
2018-05-31 15:17:07 +00:00
|
|
|
#define OPT_3001_I2C_ADDRESS Board_OPT3001_ADDR
|
2018-05-28 11:17:01 +00:00
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/* Register addresses */
|
|
|
|
#define REG_RESULT 0x00
|
|
|
|
#define REG_CONFIGURATION 0x01
|
|
|
|
#define REG_LOW_LIMIT 0x02
|
|
|
|
#define REG_HIGH_LIMIT 0x03
|
|
|
|
|
|
|
|
#define REG_MANUFACTURER_ID 0x7E
|
|
|
|
#define REG_DEVICE_ID 0x7F
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/*
|
|
|
|
* Configuration Register Bits and Masks.
|
|
|
|
* We use uint16_t to read from / write to registers, meaning that the
|
|
|
|
* register's MSB is the variable's LSB.
|
|
|
|
*/
|
2018-05-31 15:17:07 +00:00
|
|
|
#define CFG_RN 0x00F0 /* [15..12] Range Number */
|
|
|
|
#define CFG_CT 0x0008 /* [11] Conversion Time */
|
|
|
|
#define CFG_M 0x0006 /* [10..9] Mode of Conversion */
|
|
|
|
#define CFG_OVF 0x0001 /* [8] Overflow */
|
|
|
|
#define CFG_CRF 0x8000 /* [7] Conversion Ready Field */
|
|
|
|
#define CFG_FH 0x4000 /* [6] Flag High */
|
|
|
|
#define CFG_FL 0x2000 /* [5] Flag Low */
|
|
|
|
#define CFG_L 0x1000 /* [4] Latch */
|
|
|
|
#define CFG_POL 0x0800 /* [3] Polarity */
|
|
|
|
#define CFG_ME 0x0400 /* [2] Mask Exponent */
|
|
|
|
#define CFG_FC 0x0300 /* [1..0] Fault Count */
|
2018-05-28 11:17:01 +00:00
|
|
|
|
|
|
|
/* Possible Values for CT */
|
2018-05-31 15:17:07 +00:00
|
|
|
#define CFG_CT_100 0x0000
|
|
|
|
#define CFG_CT_800 CFG_CT
|
2018-05-28 11:17:01 +00:00
|
|
|
|
|
|
|
/* Possible Values for M */
|
2018-05-31 15:17:07 +00:00
|
|
|
#define CFG_M_CONTI 0x0004
|
|
|
|
#define CFG_M_SINGLE 0x0002
|
|
|
|
#define CFG_M_SHUTDOWN 0x0000
|
2018-05-28 11:17:01 +00:00
|
|
|
|
|
|
|
/* Reset Value for the register 0xC810. All zeros except: */
|
2018-05-31 15:17:07 +00:00
|
|
|
#define CFG_RN_RESET 0x00C0
|
|
|
|
#define CFG_CT_RESET CFG_CT_800
|
|
|
|
#define CFG_L_RESET 0x1000
|
|
|
|
#define CFG_DEFAULTS (CFG_RN_RESET | CFG_CT_100 | CFG_L_RESET)
|
2018-05-28 11:17:01 +00:00
|
|
|
|
|
|
|
/* Enable / Disable */
|
2018-05-31 15:17:07 +00:00
|
|
|
#define CFG_ENABLE_CONTINUOUS (CFG_M_CONTI | CFG_DEFAULTS)
|
|
|
|
#define CFG_ENABLE_SINGLE_SHOT (CFG_M_SINGLE | CFG_DEFAULTS)
|
|
|
|
#define CFG_DISABLE CFG_DEFAULTS
|
2018-05-28 11:17:01 +00:00
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/* Register length */
|
|
|
|
#define REGISTER_LENGTH 2
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/* Sensor data size */
|
|
|
|
#define DATA_LENGTH 2
|
|
|
|
/*---------------------------------------------------------------------------*/
|
2018-05-31 15:17:07 +00:00
|
|
|
/* Byte swap of 16-bit register value */
|
|
|
|
#define HI_UINT16(a) (((a) >> 8) & 0xFF)
|
|
|
|
#define LO_UINT16(a) ((a) & 0xFF)
|
|
|
|
|
|
|
|
#define SWAP16(v) ((LO_UINT16(v) << 8) | HI_UINT16(v))
|
|
|
|
|
|
|
|
#define LSB16(v) (LO_UINT16(v)), (HI_UINT16(v))
|
|
|
|
#define MSB16(v) (HI_UINT16(v)), (LO_UINT16(v))
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
typedef struct {
|
|
|
|
volatile OPT_3001_STATUS status;
|
|
|
|
} OPT_3001_Object;
|
2018-05-28 11:17:01 +00:00
|
|
|
|
2018-05-31 15:17:07 +00:00
|
|
|
static OPT_3001_Object opt_3001;
|
2018-05-28 11:17:01 +00:00
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/* Wait SENSOR_STARTUP_DELAY for the sensor to be ready - 125ms */
|
|
|
|
#define SENSOR_STARTUP_DELAY (CLOCK_SECOND >> 3)
|
|
|
|
|
|
|
|
static struct ctimer startup_timer;
|
|
|
|
/*---------------------------------------------------------------------------*/
|
2018-05-31 15:17:07 +00:00
|
|
|
static I2C_Handle i2cHandle;
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
static bool
|
|
|
|
i2c_write_read(void *writeBuf, size_t writeCount, void *readBuf, size_t readCount)
|
2018-05-28 11:17:01 +00:00
|
|
|
{
|
2018-05-31 15:17:07 +00:00
|
|
|
I2C_Transaction i2cTransaction = {
|
|
|
|
.writeBuf = writeBuf,
|
|
|
|
.writeCount = writeCount,
|
|
|
|
.readBuf = readBuf,
|
|
|
|
.readCount = readCount,
|
|
|
|
.slaveAddress = OPT_3001_I2C_ADDRESS,
|
|
|
|
};
|
|
|
|
|
|
|
|
return I2C_transfer(i2cHandle, &i2cTransaction);
|
2018-05-28 11:17:01 +00:00
|
|
|
}
|
2018-05-31 15:17:07 +00:00
|
|
|
|
|
|
|
#define i2c_write(writeBuf, writeCount) i2c_write_read(writeBuf, writeCount, NULL, 0)
|
|
|
|
#define i2c_read(readBuf, readCount) i2c_write_read(NULL, 0, readBuf, readCount)
|
2018-05-28 11:17:01 +00:00
|
|
|
/*---------------------------------------------------------------------------*/
|
2018-05-31 15:17:07 +00:00
|
|
|
static bool
|
|
|
|
sensor_init(void)
|
2018-05-28 11:17:01 +00:00
|
|
|
{
|
2018-05-31 15:17:07 +00:00
|
|
|
if (i2cHandle) {
|
|
|
|
return true;
|
|
|
|
}
|
2018-05-28 11:17:01 +00:00
|
|
|
|
2018-05-31 15:17:07 +00:00
|
|
|
I2C_Params i2cParams;
|
|
|
|
I2C_Params_init(&i2cParams);
|
|
|
|
i2cParams.transferMode = I2C_MODE_BLOCKING;
|
|
|
|
i2cParams.bitRate = I2C_400kHz;
|
2018-05-28 11:17:01 +00:00
|
|
|
|
2018-05-31 15:17:07 +00:00
|
|
|
i2cHandle = I2C_open(Board_I2C0, &i2cParams);
|
|
|
|
if (i2cHandle == NULL) {
|
|
|
|
return false;
|
2018-05-28 11:17:01 +00:00
|
|
|
}
|
2018-05-31 15:17:07 +00:00
|
|
|
|
|
|
|
opt_3001.status = OPT_3001_STATUS_DISABLED;
|
|
|
|
|
|
|
|
return true;
|
2018-05-28 11:17:01 +00:00
|
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
|
|
* \brief Turn the sensor on/off
|
|
|
|
* \param enable TRUE: on, FALSE: off
|
|
|
|
*/
|
2018-05-31 15:17:07 +00:00
|
|
|
static bool
|
|
|
|
sensor_enable(bool enable)
|
2018-05-28 11:17:01 +00:00
|
|
|
{
|
2018-05-31 15:17:07 +00:00
|
|
|
uint16_t data = (enable)
|
|
|
|
? CFG_ENABLE_SINGLE_SHOT
|
|
|
|
: CFG_DISABLE;
|
2018-05-28 11:17:01 +00:00
|
|
|
|
2018-05-31 15:17:07 +00:00
|
|
|
uint8_t cfg_data[] = { REG_CONFIGURATION, LSB16(data) };
|
|
|
|
return i2c_write(cfg_data, sizeof(cfg_data));
|
2018-05-28 11:17:01 +00:00
|
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
2018-05-31 15:17:07 +00:00
|
|
|
static void
|
|
|
|
notify_ready_cb(void *not_used)
|
2018-05-28 11:17:01 +00:00
|
|
|
{
|
2018-05-31 15:17:07 +00:00
|
|
|
/*
|
|
|
|
* Depending on the CONFIGURATION.CONVERSION_TIME bits, a conversion will
|
|
|
|
* take either 100 or 800 ms. Here we inspect the CONVERSION_READY bit and
|
|
|
|
* if the reading is ready we notify, otherwise we just reschedule ourselves
|
|
|
|
*/
|
2018-05-28 11:17:01 +00:00
|
|
|
|
2018-05-31 15:17:07 +00:00
|
|
|
uint8_t cfg_data[] = { REG_CONFIGURATION };
|
|
|
|
uint16_t cfg_value = 0;
|
2018-05-28 11:17:01 +00:00
|
|
|
|
2018-05-31 15:17:07 +00:00
|
|
|
bool spi_ok = i2c_write_read(cfg_data, sizeof(cfg_data), &cfg_value, sizeof(cfg_value));
|
|
|
|
if (!spi_ok) {
|
|
|
|
opt_3001.status = OPT_3001_STATUS_I2C_ERROR;
|
|
|
|
return;
|
2018-05-28 11:17:01 +00:00
|
|
|
}
|
|
|
|
|
2018-05-31 15:17:07 +00:00
|
|
|
if (cfg_value & CFG_CRF) {
|
|
|
|
opt_3001.status = OPT_3001_STATUS_DATA_READY;
|
|
|
|
sensors_changed(&opt_3001_sensor);
|
2018-05-28 11:17:01 +00:00
|
|
|
} else {
|
2018-05-31 15:17:07 +00:00
|
|
|
ctimer_set(&startup_timer, SENSOR_STARTUP_DELAY, notify_ready_cb, NULL);
|
2018-05-28 11:17:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
|
|
* \brief Returns a reading from the sensor
|
|
|
|
* \param type Ignored
|
|
|
|
* \return Illuminance in centilux
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
value(int type)
|
|
|
|
{
|
2018-05-31 15:17:07 +00:00
|
|
|
if (opt_3001.status != OPT_3001_STATUS_DATA_READY) {
|
|
|
|
return MPU_9250_READING_ERROR;
|
|
|
|
}
|
2018-05-28 11:17:01 +00:00
|
|
|
|
2018-05-31 15:17:07 +00:00
|
|
|
uint8_t cfg_data[] = { REG_CONFIGURATION };
|
|
|
|
uint16_t cfg_value = 0;
|
2018-05-28 11:17:01 +00:00
|
|
|
|
2018-05-31 15:17:07 +00:00
|
|
|
bool spi_ok = i2c_write_read(cfg_data, sizeof(cfg_data), &cfg_value, sizeof(cfg_value));
|
|
|
|
if (!spi_ok) {
|
|
|
|
opt_3001.status = OPT_3001_STATUS_I2C_ERROR;
|
|
|
|
return MPU_9250_READING_ERROR;
|
2018-05-28 11:17:01 +00:00
|
|
|
}
|
|
|
|
|
2018-05-31 15:17:07 +00:00
|
|
|
uint8_t result_data[] = { REG_RESULT };
|
|
|
|
uint16_t result_value = 0;
|
2018-05-28 11:17:01 +00:00
|
|
|
|
2018-05-31 15:17:07 +00:00
|
|
|
spi_ok = i2c_write_read(result_data, sizeof(result_data), &result_value, sizeof(result_value));
|
|
|
|
if (!spi_ok) {
|
|
|
|
opt_3001.status = OPT_3001_STATUS_I2C_ERROR;
|
|
|
|
return MPU_9250_READING_ERROR;
|
|
|
|
}
|
2018-05-28 11:17:01 +00:00
|
|
|
|
2018-05-31 15:17:07 +00:00
|
|
|
result_value = SWAP16(result_value);
|
|
|
|
|
|
|
|
uint32_t e = (result_value & 0x0FFF) >> 0;
|
|
|
|
uint32_t m = (result_value & 0xF000) >> 12;
|
|
|
|
uint32_t converted = m * 100 * (1 << e);
|
|
|
|
|
|
|
|
PRINTF("OPT: %04X r=%d (centilux)\n", result_value,
|
|
|
|
(int)(converted));
|
|
|
|
|
|
|
|
return (int)converted;
|
2018-05-28 11:17:01 +00:00
|
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
|
|
* \brief Configuration function for the OPT3001 sensor.
|
|
|
|
*
|
|
|
|
* \param type Activate, enable or disable the sensor. See below
|
|
|
|
* \param enable
|
|
|
|
*
|
|
|
|
* When type == SENSORS_HW_INIT we turn on the hardware
|
|
|
|
* When type == SENSORS_ACTIVE and enable==1 we enable the sensor
|
|
|
|
* When type == SENSORS_ACTIVE and enable==0 we disable the sensor
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
configure(int type, int enable)
|
|
|
|
{
|
|
|
|
int rv = 0;
|
|
|
|
switch(type) {
|
|
|
|
case SENSORS_HW_INIT:
|
2018-05-31 15:17:07 +00:00
|
|
|
if (sensor_init()) {
|
|
|
|
opt_3001.status = OPT_3001_STATUS_STANDBY;
|
|
|
|
} else {
|
|
|
|
opt_3001.status = OPT_3001_STATUS_DISABLED;
|
|
|
|
rv = MPU_9250_READING_ERROR;
|
|
|
|
}
|
2018-05-28 11:17:01 +00:00
|
|
|
break;
|
2018-05-31 15:17:07 +00:00
|
|
|
|
2018-05-28 11:17:01 +00:00
|
|
|
case SENSORS_ACTIVE:
|
|
|
|
if(enable) {
|
2018-05-31 15:17:07 +00:00
|
|
|
sensor_enable(true);
|
|
|
|
ctimer_set(&startup_timer, SENSOR_STARTUP_DELAY, notify_ready_cb, NULL);
|
|
|
|
|
|
|
|
opt_3001.status = OPT_3001_STATUS_BOOTING;
|
2018-05-28 11:17:01 +00:00
|
|
|
} else {
|
|
|
|
ctimer_stop(&startup_timer);
|
2018-05-31 15:17:07 +00:00
|
|
|
sensor_enable(false);
|
2018-05-28 11:17:01 +00:00
|
|
|
}
|
|
|
|
break;
|
2018-05-31 15:17:07 +00:00
|
|
|
|
2018-05-28 11:17:01 +00:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2018-05-31 15:17:07 +00:00
|
|
|
|
2018-05-28 11:17:01 +00:00
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
|
|
* \brief Returns the status of the sensor
|
|
|
|
* \param type ignored
|
|
|
|
* \return The state of the sensor SENSOR_STATE_xyz
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
status(int type)
|
|
|
|
{
|
2018-05-31 15:17:07 +00:00
|
|
|
(void)type;
|
|
|
|
|
|
|
|
return opt_3001.status;
|
2018-05-28 11:17:01 +00:00
|
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
SENSORS_SENSOR(opt_3001_sensor, "OPT3001", value, configure, status);
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/** @} */
|