/** * @file sensor.h * * @brief Public APIs for the sensor driver. */ /* * Copyright (c) 2016 Intel Corporation * * SPDX-License-Identifier: Apache-2.0 */ #ifndef __SENSOR_H__ #define __SENSOR_H__ /** * @brief Sensor Interface * @defgroup sensor_interface Sensor Interface * @ingroup io_interfaces * @{ */ #ifdef __cplusplus extern "C" { #endif #include #include #include /** * @brief Representation of a sensor readout value. * * The value is represented as having an integer and a fractional part, * and can be obtained using the formula val1 + val2 * 10^(-6). */ struct sensor_value { /** Integer part of the value. */ int32_t val1; /** Fractional part of the value. */ int32_t val2; }; /** * @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 the X, Y and Z axes. */ SENSOR_CHAN_ACCEL_XYZ, /** * This enum value will be deprecated. * Please use SENSOR_CHAN_ACCEL_XYZ instead. * * Acceleration on any axis. */ SENSOR_CHAN_ACCEL_ANY = SENSOR_CHAN_ACCEL_XYZ, /** 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 around the X, Y and Z axes. */ SENSOR_CHAN_GYRO_XYZ, /** * This enum value will be deprecated. * Please use SENSOR_CHAN_GYRO_XYZ instead. * * Angular velocity on any axis. */ SENSOR_CHAN_GYRO_ANY = SENSOR_CHAN_GYRO_XYZ, /** 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 the X, Y and Z axes. */ SENSOR_CHAN_MAGN_XYZ, /** * This enum value will be deprecated. * Please use SENSOR_CHAN_MAGN_XYZ instead. * * Magnetic field on any axis. */ SENSOR_CHAN_MAGN_ANY = SENSOR_CHAN_MAGN_XYZ, /** 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, /** Illuminance in red spectrum, in lux. */ SENSOR_CHAN_RED, /** Illuminance in green spectrum, in lux. */ SENSOR_CHAN_GREEN, /** 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, /** Trigger fires when a single tap is detected. */ SENSOR_TRIG_TAP, /** Trigger fires when a double tap is detected. */ SENSOR_TRIG_DOUBLE_TAP, }; /** * @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 description */ 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 description */ 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) { const struct sensor_driver_api *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) { const struct sensor_driver_api *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) { const struct sensor_driver_api *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) { const struct sensor_driver_api *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 _XYZ 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) { const struct sensor_driver_api *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->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->val1 = ((int64_t)d * SENSOR_PI / 180LL) / 1000000LL; rad->val2 = ((int64_t)d * SENSOR_PI / 180LL) % 1000000LL; } /** * @brief Helper function for converting struct sensor_value to double. * * @param val A pointer to a sensor_value struct. * @return The converted value. */ static inline double sensor_value_to_double(struct sensor_value *val) { return (double)val->val1 + (double)val->val2 / 1000000; } #ifdef __cplusplus } #endif /** * @} */ #endif /* __SENSOR_H__ */