556 lines
15 KiB
C
556 lines
15 KiB
C
/**
|
|
* @file sensor.h
|
|
*
|
|
* @brief Public APIs for the sensor driver.
|
|
*/
|
|
|
|
/*
|
|
* Copyright (c) 2016 Intel Corporation
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
#ifndef __SENSOR_H__
|
|
#define __SENSOR_H__
|
|
|
|
/**
|
|
* @brief Sensor Interface
|
|
* @defgroup sensor_interface Sensor Interface
|
|
* @ingroup io_interfaces
|
|
* @{
|
|
*/
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
#include <stdint.h>
|
|
#include <device.h>
|
|
#include <errno.h>
|
|
|
|
/** @brief Sensor value types. */
|
|
enum sensor_value_type {
|
|
/** val1 contains an integer value, val2 is unused. */
|
|
SENSOR_VALUE_TYPE_INT,
|
|
/**
|
|
* val1 contains an integer value, val2 is the fractional value.
|
|
* To obtain the final value, use the formula: val1 + val2 *
|
|
* 10^(-6).
|
|
*/
|
|
SENSOR_VALUE_TYPE_INT_PLUS_MICRO,
|
|
/**
|
|
* @brief val1 contains a Q16.16 representation, val2 is
|
|
* unused.
|
|
*/
|
|
SENSOR_VALUE_TYPE_Q16_16,
|
|
/** @brief dval contains a floating point value. */
|
|
SENSOR_VALUE_TYPE_DOUBLE,
|
|
};
|
|
|
|
/**
|
|
* @brief Representation of a sensor readout value.
|
|
*
|
|
* The meaning of the fields is dictated by the type field.
|
|
*/
|
|
struct sensor_value {
|
|
enum sensor_value_type type;
|
|
union {
|
|
struct {
|
|
int32_t val1;
|
|
int32_t val2;
|
|
};
|
|
double dval;
|
|
};
|
|
};
|
|
|
|
/**
|
|
* @brief Sensor channels.
|
|
*/
|
|
enum sensor_channel {
|
|
/** Acceleration on the X axis, in m/s^2. */
|
|
SENSOR_CHAN_ACCEL_X,
|
|
/** Acceleration on the Y axis, in m/s^2. */
|
|
SENSOR_CHAN_ACCEL_Y,
|
|
/** Acceleration on the Z axis, in m/s^2. */
|
|
SENSOR_CHAN_ACCEL_Z,
|
|
/** Acceleration on any axis. */
|
|
SENSOR_CHAN_ACCEL_ANY,
|
|
/** Angular velocity around the X axis, in radians/s. */
|
|
SENSOR_CHAN_GYRO_X,
|
|
/** Angular velocity around the Y axis, in radians/s. */
|
|
SENSOR_CHAN_GYRO_Y,
|
|
/** Angular velocity around the Z axis, in radians/s. */
|
|
SENSOR_CHAN_GYRO_Z,
|
|
/** Angular velocity on any axis. */
|
|
SENSOR_CHAN_GYRO_ANY,
|
|
/** Magnetic field on the X axis, in Gauss. */
|
|
SENSOR_CHAN_MAGN_X,
|
|
/** Magnetic field on the Y axis, in Gauss. */
|
|
SENSOR_CHAN_MAGN_Y,
|
|
/** Magnetic field on the Z axis, in Gauss. */
|
|
SENSOR_CHAN_MAGN_Z,
|
|
/** Magnetic field on any axis. */
|
|
SENSOR_CHAN_MAGN_ANY,
|
|
/** Temperature in degrees Celsius. */
|
|
SENSOR_CHAN_TEMP,
|
|
/** Pressure in kilopascal. */
|
|
SENSOR_CHAN_PRESS,
|
|
/**
|
|
* Proximity. Adimensional. A value of 1 indicates that an
|
|
* object is close.
|
|
*/
|
|
SENSOR_CHAN_PROX,
|
|
/** Humidity, in milli percent. */
|
|
SENSOR_CHAN_HUMIDITY,
|
|
/** Illuminance in visible spectrum, in lux. */
|
|
SENSOR_CHAN_LIGHT,
|
|
/** Illuminance in infra-red spectrum, in lux. */
|
|
SENSOR_CHAN_IR,
|
|
/** Altitude, in meters */
|
|
SENSOR_CHAN_ALTITUDE,
|
|
/** All channels. */
|
|
SENSOR_CHAN_ALL,
|
|
};
|
|
|
|
/**
|
|
* @brief Sensor trigger types.
|
|
*/
|
|
enum sensor_trigger_type {
|
|
/**
|
|
* Timer-based trigger, useful when the sensor does not have an
|
|
* interrupt line.
|
|
*/
|
|
SENSOR_TRIG_TIMER,
|
|
/** Trigger fires whenever new data is ready. */
|
|
SENSOR_TRIG_DATA_READY,
|
|
/**
|
|
* Trigger fires when the selected channel varies significantly.
|
|
* This includes any-motion detection when the channel is
|
|
* acceleration or gyro. If detection is based on slope between
|
|
* successive channel readings, the slope threshold is configured
|
|
* via the @ref SENSOR_ATTR_SLOPE_TH and @ref SENSOR_ATTR_SLOPE_DUR
|
|
* attributes.
|
|
*/
|
|
SENSOR_TRIG_DELTA,
|
|
/** Trigger fires when a near/far event is detected. */
|
|
SENSOR_TRIG_NEAR_FAR,
|
|
/**
|
|
* Trigger fires when channel reading transitions configured
|
|
* thresholds. The thresholds are configured via the @ref
|
|
* SENSOR_ATTR_LOWER_THRESH and @ref SENSOR_ATTR_UPPER_THRESH
|
|
* attributes.
|
|
*/
|
|
SENSOR_TRIG_THRESHOLD,
|
|
};
|
|
|
|
/**
|
|
* @brief Sensor trigger spec.
|
|
*/
|
|
struct sensor_trigger {
|
|
/** Trigger type. */
|
|
enum sensor_trigger_type type;
|
|
/** Channel the trigger is set on. */
|
|
enum sensor_channel chan;
|
|
};
|
|
|
|
/**
|
|
* @brief Sensor attribute types.
|
|
*/
|
|
enum sensor_attribute {
|
|
/**
|
|
* Sensor sampling frequency, i.e. how many times a second the
|
|
* sensor takes a measurement.
|
|
*/
|
|
SENSOR_ATTR_SAMPLING_FREQUENCY,
|
|
/** Lower threshold for trigger. */
|
|
SENSOR_ATTR_LOWER_THRESH,
|
|
/** Upper threshold for trigger. */
|
|
SENSOR_ATTR_UPPER_THRESH,
|
|
/** Threshold for any-motion (slope) trigger. */
|
|
SENSOR_ATTR_SLOPE_TH,
|
|
/**
|
|
* Duration for which the slope values needs to be
|
|
* outside the threshold for the trigger to fire.
|
|
*/
|
|
SENSOR_ATTR_SLOPE_DUR,
|
|
/** Oversampling factor */
|
|
SENSOR_ATTR_OVERSAMPLING,
|
|
/** Sensor range, in SI units. */
|
|
SENSOR_ATTR_FULL_SCALE,
|
|
/**
|
|
* The sensor value returned will be altered by the amount indicated by
|
|
* offset: final_value = sensor_value + offset.
|
|
*/
|
|
SENSOR_ATTR_OFFSET,
|
|
/**
|
|
* Calibration target. This will be used by the internal chip's
|
|
* algorithms to calibrate itself on a certain axis, or all of them.
|
|
*/
|
|
SENSOR_ATTR_CALIB_TARGET,
|
|
};
|
|
|
|
/**
|
|
* @typedef sensor_trigger_handler_t
|
|
* @brief Callback API upon firing of a trigger
|
|
*
|
|
* @param "struct device *dev" Pointer to the sensor device
|
|
* @param "struct sensor_trigger *trigger" The trigger
|
|
*/
|
|
typedef void (*sensor_trigger_handler_t)(struct device *dev,
|
|
struct sensor_trigger *trigger);
|
|
|
|
/**
|
|
* @typedef sensor_attr_set_t
|
|
* @brief Callback API upon setting a sensor's attributes
|
|
*
|
|
* See sensor_attr_set() for argument description
|
|
*/
|
|
typedef int (*sensor_attr_set_t)(struct device *dev,
|
|
enum sensor_channel chan,
|
|
enum sensor_attribute attr,
|
|
const struct sensor_value *val);
|
|
/**
|
|
* @typedef sensor_trigger_set_t
|
|
* @brief Callback API for setting a sensor's trigger and handler
|
|
*
|
|
* See sensor_trigger_set() for argument description
|
|
*/
|
|
typedef int (*sensor_trigger_set_t)(struct device *dev,
|
|
const struct sensor_trigger *trig,
|
|
sensor_trigger_handler_t handler);
|
|
/**
|
|
* @typedef sensor_sample_fetch_t
|
|
* @brief Callback API for fetching data from a sensor
|
|
*
|
|
* See sensor_sample_fetch() for argument descriptor
|
|
*/
|
|
typedef int (*sensor_sample_fetch_t)(struct device *dev,
|
|
enum sensor_channel chan);
|
|
/**
|
|
* @typedef sensor_channel_get_t
|
|
* @brief Callback API for getting a reading from a sensor
|
|
*
|
|
* See sensor_channel_get() for argument descriptor
|
|
*/
|
|
typedef int (*sensor_channel_get_t)(struct device *dev,
|
|
enum sensor_channel chan,
|
|
struct sensor_value *val);
|
|
|
|
struct sensor_driver_api {
|
|
sensor_attr_set_t attr_set;
|
|
sensor_trigger_set_t trigger_set;
|
|
sensor_sample_fetch_t sample_fetch;
|
|
sensor_channel_get_t channel_get;
|
|
};
|
|
|
|
/**
|
|
* @brief Set an attribute for a sensor
|
|
*
|
|
* @param dev Pointer to the sensor device
|
|
* @param chan The channel the attribute belongs to, if any. Some
|
|
* attributes may only be set for all channels of a device, depending on
|
|
* device capabilities.
|
|
* @param attr The attribute to set
|
|
* @param val The value to set the attribute to
|
|
*
|
|
* @return 0 if successful, negative errno code if failure.
|
|
*/
|
|
static inline int sensor_attr_set(struct device *dev,
|
|
enum sensor_channel chan,
|
|
enum sensor_attribute attr,
|
|
const struct sensor_value *val)
|
|
{
|
|
struct sensor_driver_api *api;
|
|
|
|
api = (struct sensor_driver_api *)dev->driver_api;
|
|
if (!api->attr_set) {
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
return api->attr_set(dev, chan, attr, val);
|
|
}
|
|
|
|
/**
|
|
* @brief Activate a sensor's trigger and set the trigger handler
|
|
*
|
|
* The handler will be called from a fiber, so I2C or SPI operations are
|
|
* safe. However, the fiber's stack is limited and defined by the
|
|
* driver. It is currently up to the caller to ensure that the handler
|
|
* does not overflow the stack.
|
|
*
|
|
* @param dev Pointer to the sensor device
|
|
* @param trig The trigger to activate
|
|
* @param handler The function that should be called when the trigger
|
|
* fires
|
|
*
|
|
* @return 0 if successful, negative errno code if failure.
|
|
*/
|
|
static inline int sensor_trigger_set(struct device *dev,
|
|
struct sensor_trigger *trig,
|
|
sensor_trigger_handler_t handler)
|
|
{
|
|
struct sensor_driver_api *api;
|
|
|
|
api = (struct sensor_driver_api *)dev->driver_api;
|
|
if (!api->trigger_set) {
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
return api->trigger_set(dev, trig, handler);
|
|
}
|
|
|
|
/**
|
|
* @brief Fetch a sample from the sensor and store it in an internal
|
|
* driver buffer
|
|
*
|
|
* Read all of a sensor's active channels and, if necessary, perform any
|
|
* additional operations necessary to make the values useful. The user
|
|
* may then get individual channel values by calling @ref
|
|
* sensor_channel_get.
|
|
*
|
|
* Since the function communicates with the sensor device, it is unsafe
|
|
* to call it in an ISR if the device is connected via I2C or SPI.
|
|
*
|
|
* @param dev Pointer to the sensor device
|
|
*
|
|
* @return 0 if successful, negative errno code if failure.
|
|
*/
|
|
static inline int sensor_sample_fetch(struct device *dev)
|
|
{
|
|
struct sensor_driver_api *api;
|
|
|
|
api = (struct sensor_driver_api *)dev->driver_api;
|
|
|
|
return api->sample_fetch(dev, SENSOR_CHAN_ALL);
|
|
}
|
|
|
|
/**
|
|
* @brief Fetch a sample from the sensor and store it in an internal
|
|
* driver buffer
|
|
*
|
|
* Read and compute compensation for one type of sensor data (magnetometer,
|
|
* accelerometer, etc). The user may then get individual channel values by
|
|
* calling @ref sensor_channel_get.
|
|
*
|
|
* This is mostly implemented by multi function devices enabling reading at
|
|
* different sampling rates.
|
|
*
|
|
* Since the function communicates with the sensor device, it is unsafe
|
|
* to call it in an ISR if the device is connected via I2C or SPI.
|
|
*
|
|
* @param dev Pointer to the sensor device
|
|
* @param type The channel that needs updated
|
|
*
|
|
* @return 0 if successful, negative errno code if failure.
|
|
*/
|
|
static inline int sensor_sample_fetch_chan(struct device *dev,
|
|
enum sensor_channel type)
|
|
{
|
|
struct sensor_driver_api *api;
|
|
|
|
api = (struct sensor_driver_api *)dev->driver_api;
|
|
|
|
return api->sample_fetch(dev, type);
|
|
}
|
|
|
|
/**
|
|
* @brief Get a reading from a sensor device
|
|
*
|
|
* Return a useful value for a particular channel, from the driver's
|
|
* internal data. Before calling this function, a sample must be
|
|
* obtained by calling @ref sensor_sample_fetch or
|
|
* @ref sensor_sample_fetch_chan. It is guaranteed that two subsequent
|
|
* calls of this function for the same channels will yield the same
|
|
* value, if @ref sensor_sample_fetch or @ref sensor_sample_fetch_chan
|
|
* has not been called in the meantime.
|
|
*
|
|
* For vectorial data samples you can request all axes in just one call
|
|
* by passing the specific channel with _ANY suffix. The sample will be
|
|
* returned at val[0], val[1] and val[2] (X, Y and Z in that order).
|
|
*
|
|
* @param dev Pointer to the sensor device
|
|
* @param chan The channel to read
|
|
* @param val Where to store the value
|
|
*
|
|
* @return 0 if successful, negative errno code if failure.
|
|
*/
|
|
static inline int sensor_channel_get(struct device *dev,
|
|
enum sensor_channel chan,
|
|
struct sensor_value *val)
|
|
{
|
|
struct sensor_driver_api *api;
|
|
|
|
api = (struct sensor_driver_api *)dev->driver_api;
|
|
|
|
return api->channel_get(dev, chan, val);
|
|
}
|
|
|
|
/**
|
|
* @brief The value of gravitational constant in micro m/s^2.
|
|
*/
|
|
#define SENSOR_G 9806650LL
|
|
|
|
/**
|
|
* @brief The value of constant PI in micros.
|
|
*/
|
|
#define SENSOR_PI 3141592LL
|
|
|
|
/**
|
|
* @brief Helper function to convert acceleration from m/s^2 to Gs
|
|
*
|
|
* @param ms2 A pointer to a sensor_value struct holding the acceleration,
|
|
* in m/s^2.
|
|
*
|
|
* @return The converted value, in Gs.
|
|
*/
|
|
static inline int32_t sensor_ms2_to_g(const struct sensor_value *ms2)
|
|
{
|
|
int64_t micro_ms2 = ms2->val1 * 1000000LL + ms2->val2;
|
|
|
|
if (micro_ms2 > 0) {
|
|
return (micro_ms2 + SENSOR_G / 2) / SENSOR_G;
|
|
} else {
|
|
return (micro_ms2 - SENSOR_G / 2) / SENSOR_G;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Helper function to convert acceleration from Gs to m/s^2
|
|
*
|
|
* @param g The G value to be converted.
|
|
* @param ms2 A pointer to a sensor_value struct, where the result is stored.
|
|
*/
|
|
static inline void sensor_g_to_ms2(int32_t g, struct sensor_value *ms2)
|
|
{
|
|
ms2->type = SENSOR_VALUE_TYPE_INT_PLUS_MICRO;
|
|
ms2->val1 = ((int64_t)g * SENSOR_G) / 1000000LL;
|
|
ms2->val2 = ((int64_t)g * SENSOR_G) % 1000000LL;
|
|
}
|
|
|
|
/**
|
|
* @brief Helper function for converting radians to degrees.
|
|
*
|
|
* @param rad A pointer to a sensor_value struct, holding the value in radians.
|
|
*
|
|
* @return The converted value, in degrees.
|
|
*/
|
|
static inline int32_t sensor_rad_to_degrees(const struct sensor_value *rad)
|
|
{
|
|
int64_t micro_rad_s = rad->val1 * 1000000LL + rad->val2;
|
|
|
|
if (micro_rad_s > 0) {
|
|
return (micro_rad_s * 180LL + SENSOR_PI / 2) / SENSOR_PI;
|
|
} else {
|
|
return (micro_rad_s * 180LL - SENSOR_PI / 2) / SENSOR_PI;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Helper function for converting degrees to radians.
|
|
*
|
|
* @param d The value (in degrees) to be converted.
|
|
* @param rad A pointer to a sensor_value struct, where the result is stored.
|
|
*/
|
|
static inline void sensor_degrees_to_rad(int32_t d, struct sensor_value *rad)
|
|
{
|
|
rad->type = SENSOR_VALUE_TYPE_INT_PLUS_MICRO;
|
|
rad->val1 = ((int64_t)d * SENSOR_PI / 180LL) / 1000000LL;
|
|
rad->val2 = ((int64_t)d * SENSOR_PI / 180LL) % 1000000LL;
|
|
}
|
|
|
|
/**
|
|
* @brief configuration parameters for sensor triggers.
|
|
*/
|
|
enum sensor_trigger_mode {
|
|
/** Do not use triggering. */
|
|
SENSOR_TRIG_MODE_NONE,
|
|
/**
|
|
* Driver should start a workqueue specifically for this
|
|
* device. See @ref sensor_trig_or_wq_config for instruction on
|
|
* how to specify the parameters of the workqueue.
|
|
*/
|
|
SENSOR_TRIG_MODE_OWN_WQ,
|
|
/** Use the system workqueue. */
|
|
SENSOR_TRIG_MODE_GLOBAL_WQ,
|
|
};
|
|
|
|
/**
|
|
* @brief configuration parameters for sensor triggers.
|
|
*/
|
|
struct sensor_trigger_config {
|
|
/**
|
|
* This is always set to NULL when using a @ref
|
|
* sensor_trigger_config. See the comment in @ref
|
|
* sensor_trig_or_wq_config.
|
|
*/
|
|
void *always_null;
|
|
enum sensor_trigger_mode mode;
|
|
};
|
|
|
|
/**
|
|
* @brief Structure used for sensor trigger configuration.
|
|
*
|
|
* If fiber_config.stack is non-NULL, the driver should start its
|
|
* own fiber based on @ref fiber_config. Otherwise, use
|
|
* sensor_interface::sensor_trigger_mode to decide if and how to use
|
|
* triggering.
|
|
*/
|
|
union sensor_trig_or_wq_config {
|
|
struct fiber_config fiber_config;
|
|
struct sensor_trigger_config trig_config;
|
|
};
|
|
|
|
#define SENSOR_DECLARE_TRIG_CONFIG \
|
|
union sensor_trig_or_wq_config trig_or_wq_config
|
|
|
|
#define SENSOR_TRIG_WQ_OWN(_stack, _prio) \
|
|
.trig_or_wq_config = { \
|
|
.fiber_config = { \
|
|
.stack = (_stack), \
|
|
.stack_size = sizeof(_stack), \
|
|
.prio = (_prio), \
|
|
} \
|
|
}
|
|
|
|
#define SENSOR_TRIG_WQ_GLOBAL \
|
|
.trig_or_wq_config = { \
|
|
.trig_config = { \
|
|
.always_null = NULL, \
|
|
.mode = SENSOR_TRIG_MODE_GLOBAL_WQ, \
|
|
} \
|
|
}
|
|
|
|
#define SENSOR_TRIG_NONE \
|
|
.trig_or_wq_config = { \
|
|
.trig_config = { \
|
|
.always_null = NULL, \
|
|
.mode = SENSOR_TRIG_MODE_NONE, \
|
|
} \
|
|
}
|
|
|
|
#define SENSOR_GET_TRIG_MODE(_conf) \
|
|
(!(_conf)->trig_or_wq_config.fiber_config.stack \
|
|
? SENSOR_TRIG_MODE_OWN_WQ : \
|
|
(_conf)->trig_or_wq_config.trig_config.mode)
|
|
#define SENSOR_GET_WQ_CONFIG(_conf) \
|
|
((_conf)->trig_or_wq_config.fiber_config)
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
#endif /* __SENSOR_H__ */
|