| /** |
| * @file drivers/sensor.h |
| * |
| * @brief Public APIs for the sensor driver. |
| */ |
| |
| /* |
| * Copyright (c) 2016 Intel Corporation |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| #ifndef ZEPHYR_INCLUDE_DRIVERS_SENSOR_H_ |
| #define ZEPHYR_INCLUDE_DRIVERS_SENSOR_H_ |
| |
| /** |
| * @brief Sensor Interface |
| * @defgroup sensor_interface Sensor Interface |
| * @since 1.2 |
| * @version 1.0.0 |
| * @ingroup io_interfaces |
| * @{ |
| */ |
| |
| #include <errno.h> |
| #include <stdlib.h> |
| |
| #include <zephyr/device.h> |
| #include <zephyr/drivers/sensor_data_types.h> |
| #include <zephyr/dsp/types.h> |
| #include <zephyr/rtio/rtio.h> |
| #include <zephyr/sys/iterable_sections.h> |
| #include <zephyr/types.h> |
| |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| |
| /** |
| * @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). Negative |
| * values also adhere to the above formula, but may need special attention. |
| * Here are some examples of the value representation: |
| * |
| * 0.5: val1 = 0, val2 = 500000 |
| * -0.5: val1 = 0, val2 = -500000 |
| * -1.0: val1 = -1, val2 = 0 |
| * -1.5: val1 = -1, val2 = -500000 |
| */ |
| struct sensor_value { |
| /** Integer part of the value. */ |
| int32_t val1; |
| /** Fractional part of the value (in one-millionth parts). */ |
| 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, |
| /** 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, |
| /** 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, |
| /** Device die temperature in degrees Celsius. */ |
| SENSOR_CHAN_DIE_TEMP, |
| /** Ambient temperature in degrees Celsius. */ |
| SENSOR_CHAN_AMBIENT_TEMP, |
| /** Pressure in kilopascal. */ |
| SENSOR_CHAN_PRESS, |
| /** |
| * Proximity. Adimensional. A value of 1 indicates that an |
| * object is close. |
| */ |
| SENSOR_CHAN_PROX, |
| /** Humidity, in 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, |
| /** Illuminance in blue spectrum, in lux. */ |
| SENSOR_CHAN_BLUE, |
| /** Altitude, in meters */ |
| SENSOR_CHAN_ALTITUDE, |
| |
| /** 1.0 micro-meters Particulate Matter, in ug/m^3 */ |
| SENSOR_CHAN_PM_1_0, |
| /** 2.5 micro-meters Particulate Matter, in ug/m^3 */ |
| SENSOR_CHAN_PM_2_5, |
| /** 10 micro-meters Particulate Matter, in ug/m^3 */ |
| SENSOR_CHAN_PM_10, |
| /** Distance. From sensor to target, in meters */ |
| SENSOR_CHAN_DISTANCE, |
| |
| /** CO2 level, in parts per million (ppm) **/ |
| SENSOR_CHAN_CO2, |
| /** O2 level, in parts per million (ppm) **/ |
| SENSOR_CHAN_O2, |
| /** VOC level, in parts per billion (ppb) **/ |
| SENSOR_CHAN_VOC, |
| /** Gas sensor resistance in ohms. */ |
| SENSOR_CHAN_GAS_RES, |
| |
| /** Voltage, in volts **/ |
| SENSOR_CHAN_VOLTAGE, |
| |
| /** Current Shunt Voltage in milli-volts **/ |
| SENSOR_CHAN_VSHUNT, |
| |
| /** Current, in amps **/ |
| SENSOR_CHAN_CURRENT, |
| /** Power in watts **/ |
| SENSOR_CHAN_POWER, |
| |
| /** Resistance , in Ohm **/ |
| SENSOR_CHAN_RESISTANCE, |
| |
| /** Angular rotation, in degrees */ |
| SENSOR_CHAN_ROTATION, |
| |
| /** Position change on the X axis, in points. */ |
| SENSOR_CHAN_POS_DX, |
| /** Position change on the Y axis, in points. */ |
| SENSOR_CHAN_POS_DY, |
| /** Position change on the Z axis, in points. */ |
| SENSOR_CHAN_POS_DZ, |
| /** Position change on the X, Y and Z axis, in points. */ |
| SENSOR_CHAN_POS_DXYZ, |
| |
| /** Revolutions per minute, in RPM. */ |
| SENSOR_CHAN_RPM, |
| |
| /** Voltage, in volts **/ |
| SENSOR_CHAN_GAUGE_VOLTAGE, |
| /** Average current, in amps **/ |
| SENSOR_CHAN_GAUGE_AVG_CURRENT, |
| /** Standby current, in amps **/ |
| SENSOR_CHAN_GAUGE_STDBY_CURRENT, |
| /** Max load current, in amps **/ |
| SENSOR_CHAN_GAUGE_MAX_LOAD_CURRENT, |
| /** Gauge temperature **/ |
| SENSOR_CHAN_GAUGE_TEMP, |
| /** State of charge measurement in % **/ |
| SENSOR_CHAN_GAUGE_STATE_OF_CHARGE, |
| /** Full Charge Capacity in mAh **/ |
| SENSOR_CHAN_GAUGE_FULL_CHARGE_CAPACITY, |
| /** Remaining Charge Capacity in mAh **/ |
| SENSOR_CHAN_GAUGE_REMAINING_CHARGE_CAPACITY, |
| /** Nominal Available Capacity in mAh **/ |
| SENSOR_CHAN_GAUGE_NOM_AVAIL_CAPACITY, |
| /** Full Available Capacity in mAh **/ |
| SENSOR_CHAN_GAUGE_FULL_AVAIL_CAPACITY, |
| /** Average power in mW **/ |
| SENSOR_CHAN_GAUGE_AVG_POWER, |
| /** State of health measurement in % **/ |
| SENSOR_CHAN_GAUGE_STATE_OF_HEALTH, |
| /** Time to empty in minutes **/ |
| SENSOR_CHAN_GAUGE_TIME_TO_EMPTY, |
| /** Time to full in minutes **/ |
| SENSOR_CHAN_GAUGE_TIME_TO_FULL, |
| /** Cycle count (total number of charge/discharge cycles) **/ |
| SENSOR_CHAN_GAUGE_CYCLE_COUNT, |
| /** Design voltage of cell in V (max voltage)*/ |
| SENSOR_CHAN_GAUGE_DESIGN_VOLTAGE, |
| /** Desired voltage of cell in V (nominal voltage) */ |
| SENSOR_CHAN_GAUGE_DESIRED_VOLTAGE, |
| /** Desired charging current in mA */ |
| SENSOR_CHAN_GAUGE_DESIRED_CHARGING_CURRENT, |
| |
| /** All channels. */ |
| SENSOR_CHAN_ALL, |
| |
| /** |
| * Number of all common sensor channels. |
| */ |
| SENSOR_CHAN_COMMON_COUNT, |
| |
| /** |
| * This and higher values are sensor specific. |
| * Refer to the sensor header file. |
| */ |
| SENSOR_CHAN_PRIV_START = SENSOR_CHAN_COMMON_COUNT, |
| |
| /** |
| * Maximum value describing a sensor channel type. |
| */ |
| SENSOR_CHAN_MAX = INT16_MAX, |
| }; |
| |
| /** |
| * @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, @ref SENSOR_ATTR_UPPER_THRESH, and |
| * @ref SENSOR_ATTR_HYSTERESIS 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, |
| |
| /** Trigger fires when a free fall is detected. */ |
| SENSOR_TRIG_FREEFALL, |
| |
| /** Trigger fires when motion is detected. */ |
| SENSOR_TRIG_MOTION, |
| |
| /** Trigger fires when no motion has been detected for a while. */ |
| SENSOR_TRIG_STATIONARY, |
| |
| /** Trigger fires when the FIFO watermark has been reached. */ |
| SENSOR_TRIG_FIFO_WATERMARK, |
| |
| /** Trigger fires when the FIFO becomes full. */ |
| SENSOR_TRIG_FIFO_FULL, |
| /** |
| * Number of all common sensor triggers. |
| */ |
| SENSOR_TRIG_COMMON_COUNT, |
| |
| /** |
| * This and higher values are sensor specific. |
| * Refer to the sensor header file. |
| */ |
| SENSOR_TRIG_PRIV_START = SENSOR_TRIG_COMMON_COUNT, |
| |
| /** |
| * Maximum value describing a sensor trigger type. |
| */ |
| SENSOR_TRIG_MAX = INT16_MAX, |
| }; |
| |
| /** |
| * @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, |
| /* Hysteresis for trigger thresholds. */ |
| SENSOR_ATTR_HYSTERESIS, |
| /** 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, |
| /** Configure the operating modes of a sensor. */ |
| SENSOR_ATTR_CONFIGURATION, |
| /** Set a calibration value needed by a sensor. */ |
| SENSOR_ATTR_CALIBRATION, |
| /** Enable/disable sensor features */ |
| SENSOR_ATTR_FEATURE_MASK, |
| /** Alert threshold or alert enable/disable */ |
| SENSOR_ATTR_ALERT, |
| /** Free-fall duration represented in milliseconds. |
| * If the sampling frequency is changed during runtime, |
| * this attribute should be set to adjust freefall duration |
| * to the new sampling frequency. |
| */ |
| SENSOR_ATTR_FF_DUR, |
| |
| /** Hardware batch duration in ticks */ |
| SENSOR_ATTR_BATCH_DURATION, |
| |
| /** |
| * Number of all common sensor attributes. |
| */ |
| SENSOR_ATTR_COMMON_COUNT, |
| |
| /** |
| * This and higher values are sensor specific. |
| * Refer to the sensor header file. |
| */ |
| SENSOR_ATTR_PRIV_START = SENSOR_ATTR_COMMON_COUNT, |
| |
| /** |
| * Maximum value describing a sensor attribute type. |
| */ |
| SENSOR_ATTR_MAX = INT16_MAX, |
| }; |
| |
| /** |
| * @typedef sensor_trigger_handler_t |
| * @brief Callback API upon firing of a trigger |
| * |
| * @param dev Pointer to the sensor device |
| * @param trigger The trigger |
| */ |
| typedef void (*sensor_trigger_handler_t)(const struct device *dev, |
| const 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)(const struct device *dev, |
| enum sensor_channel chan, |
| enum sensor_attribute attr, |
| const struct sensor_value *val); |
| |
| /** |
| * @typedef sensor_attr_get_t |
| * @brief Callback API upon getting a sensor's attributes |
| * |
| * See sensor_attr_get() for argument description |
| */ |
| typedef int (*sensor_attr_get_t)(const struct device *dev, |
| enum sensor_channel chan, |
| enum sensor_attribute attr, |
| 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)(const 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)(const 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)(const struct device *dev, |
| enum sensor_channel chan, |
| struct sensor_value *val); |
| |
| /** |
| * @brief Sensor Channel Specification |
| * |
| * A sensor channel specification is a unique identifier per sensor device describing |
| * a measurement channel. |
| * |
| * @note Typically passed by value as the size of a sensor_chan_spec is a single word. |
| */ |
| struct sensor_chan_spec { |
| uint16_t chan_type; /**< A sensor channel type */ |
| uint16_t chan_idx; /**< A sensor channel index */ |
| }; |
| |
| /** @cond INTERNAL_HIDDEN */ |
| /* Ensure sensor_chan_spec is sensibly sized to pass by value */ |
| BUILD_ASSERT(sizeof(struct sensor_chan_spec) <= sizeof(uintptr_t), |
| "sensor_chan_spec size should be equal or less than the size of a machine word"); |
| /** @endcond */ |
| |
| /** |
| * @brief Check if channel specs are equivalent |
| * |
| * @param chan_spec0 First chan spec |
| * @param chan_spec1 Second chan spec |
| * @retval true If equivalent |
| * @retval false If not equivalent |
| */ |
| static inline bool sensor_chan_spec_eq(struct sensor_chan_spec chan_spec0, |
| struct sensor_chan_spec chan_spec1) |
| { |
| return chan_spec0.chan_type == chan_spec1.chan_type && |
| chan_spec0.chan_idx == chan_spec1.chan_idx; |
| } |
| |
| /** |
| * @brief Decodes a single raw data buffer |
| * |
| * Data buffers are provided on the @ref rtio context that's supplied to |
| * @ref sensor_read. |
| */ |
| struct sensor_decoder_api { |
| /** |
| * @brief Get the number of frames in the current buffer. |
| * |
| * @param[in] buffer The buffer provided on the @ref rtio context. |
| * @param[in] channel The channel to get the count for |
| * @param[out] frame_count The number of frames on the buffer (at least 1) |
| * @return 0 on success |
| * @return -ENOTSUP if the channel/channel_idx aren't found |
| */ |
| int (*get_frame_count)(const uint8_t *buffer, struct sensor_chan_spec channel, |
| uint16_t *frame_count); |
| |
| /** |
| * @brief Get the size required to decode a given channel |
| * |
| * When decoding a single frame, use @p base_size. For every additional frame, add another |
| * @p frame_size. As an example, to decode 3 frames use: 'base_size + 2 * frame_size'. |
| * |
| * @param[in] channel The channel to query |
| * @param[out] base_size The size of decoding the first frame |
| * @param[out] frame_size The additional size of every additional frame |
| * @return 0 on success |
| * @return -ENOTSUP if the channel is not supported |
| */ |
| int (*get_size_info)(struct sensor_chan_spec channel, size_t *base_size, |
| size_t *frame_size); |
| |
| /** |
| * @brief Decode up to @p max_count samples from the buffer |
| * |
| * Decode samples of channel @ref sensor_channel across multiple frames. If there exist |
| * multiple instances of the same channel, @p channel_index is used to differentiate them. |
| * As an example, assume a sensor provides 2 distance measurements: |
| * |
| * @code{.c} |
| * // Decode the first channel instance of 'distance' |
| * decoder->decode(buffer, SENSOR_CHAN_DISTANCE, 0, &fit, 5, out); |
| * ... |
| * |
| * // Decode the second channel instance of 'distance' |
| * decoder->decode(buffer, SENSOR_CHAN_DISTANCE, 1, &fit, 5, out); |
| * @endcode |
| * |
| * @param[in] buffer The buffer provided on the @ref rtio context |
| * @param[in] channel The channel to decode |
| * @param[in,out] fit The current frame iterator |
| * @param[in] max_count The maximum number of channels to decode. |
| * @param[out] data_out The decoded data |
| * @return 0 no more samples to decode |
| * @return >0 the number of decoded frames |
| * @return <0 on error |
| */ |
| int (*decode)(const uint8_t *buffer, struct sensor_chan_spec channel, uint32_t *fit, |
| uint16_t max_count, void *data_out); |
| |
| /** |
| * @brief Check if the given trigger type is present |
| * |
| * @param[in] buffer The buffer provided on the @ref rtio context |
| * @param[in] trigger The trigger type in question |
| * @return Whether the trigger is present in the buffer |
| */ |
| bool (*has_trigger)(const uint8_t *buffer, enum sensor_trigger_type trigger); |
| }; |
| |
| /** |
| * @brief Used for iterating over the data frames via the sensor_decoder_api. |
| * |
| * Example usage: |
| * |
| * @code(.c) |
| * struct sensor_decode_context ctx = SENSOR_DECODE_CONTEXT_INIT( |
| * decoder, buffer, SENSOR_CHAN_ACCEL_XYZ, 0); |
| * |
| * while (true) { |
| * struct sensor_three_axis_data accel_out_data; |
| * |
| * num_decoded_channels = sensor_decode(ctx, &accel_out_data, 1); |
| * |
| * if (num_decoded_channels <= 0) { |
| * printk("Done decoding buffer\n"); |
| * break; |
| * } |
| * |
| * printk("Decoded (%" PRId32 ", %" PRId32 ", %" PRId32 ")\n", accel_out_data.readings[0].x, |
| * accel_out_data.readings[0].y, accel_out_data.readings[0].z); |
| * } |
| * @endcode |
| */ |
| struct sensor_decode_context { |
| const struct sensor_decoder_api *decoder; |
| const uint8_t *buffer; |
| struct sensor_chan_spec channel; |
| uint32_t fit; |
| }; |
| |
| /** |
| * @brief Initialize a sensor_decode_context |
| */ |
| #define SENSOR_DECODE_CONTEXT_INIT(decoder_, buffer_, channel_type_, channel_index_) \ |
| { \ |
| .decoder = (decoder_), \ |
| .buffer = (buffer_), \ |
| .channel = {.chan_type = (channel_type_), .chan_idx = (channel_index_)}, \ |
| .fit = 0, \ |
| } |
| |
| /** |
| * @brief Decode N frames using a sensor_decode_context |
| * |
| * @param[in,out] ctx The context to use for decoding |
| * @param[out] out The output buffer |
| * @param[in] max_count Maximum number of frames to decode |
| * @return The decode result from sensor_decoder_api's decode function |
| */ |
| static inline int sensor_decode(struct sensor_decode_context *ctx, void *out, uint16_t max_count) |
| { |
| return ctx->decoder->decode(ctx->buffer, ctx->channel, &ctx->fit, max_count, out); |
| } |
| |
| int sensor_natively_supported_channel_size_info(struct sensor_chan_spec channel, size_t *base_size, |
| size_t *frame_size); |
| |
| /** |
| * @typedef sensor_get_decoder_t |
| * @brief Get the decoder associate with the given device |
| * |
| * @see sensor_get_decoder for more details |
| */ |
| typedef int (*sensor_get_decoder_t)(const struct device *dev, |
| const struct sensor_decoder_api **api); |
| |
| /** |
| * @brief Options for what to do with the associated data when a trigger is consumed |
| */ |
| enum sensor_stream_data_opt { |
| /** @brief Include whatever data is associated with the trigger */ |
| SENSOR_STREAM_DATA_INCLUDE = 0, |
| /** @brief Do nothing with the associated trigger data, it may be consumed later */ |
| SENSOR_STREAM_DATA_NOP = 1, |
| /** @brief Flush/clear whatever data is associated with the trigger */ |
| SENSOR_STREAM_DATA_DROP = 2, |
| }; |
| |
| struct sensor_stream_trigger { |
| enum sensor_trigger_type trigger; |
| enum sensor_stream_data_opt opt; |
| }; |
| |
| #define SENSOR_STREAM_TRIGGER_PREP(_trigger, _opt) \ |
| { \ |
| .trigger = (_trigger), .opt = (_opt), \ |
| } |
| |
| /* |
| * Internal data structure used to store information about the IODevice for async reading and |
| * streaming sensor data. |
| */ |
| struct sensor_read_config { |
| const struct device *sensor; |
| const bool is_streaming; |
| union { |
| struct sensor_chan_spec *const channels; |
| struct sensor_stream_trigger *const triggers; |
| }; |
| size_t count; |
| const size_t max; |
| }; |
| |
| /** |
| * @brief Define a reading instance of a sensor |
| * |
| * Use this macro to generate a @ref rtio_iodev for reading specific channels. Example: |
| * |
| * @code(.c) |
| * SENSOR_DT_READ_IODEV(icm42688_accelgyro, DT_NODELABEL(icm42688), |
| * { SENSOR_CHAN_ACCEL_XYZ, 0 }, |
| * { SENSOR_CHAN_GYRO_XYZ, 0 }); |
| * |
| * int main(void) { |
| * sensor_read_async_mempool(&icm42688_accelgyro, &rtio); |
| * } |
| * @endcode |
| */ |
| #define SENSOR_DT_READ_IODEV(name, dt_node, ...) \ |
| static struct sensor_chan_spec _CONCAT(__channel_array_, name)[] = {__VA_ARGS__}; \ |
| static struct sensor_read_config _CONCAT(__sensor_read_config_, name) = { \ |
| .sensor = DEVICE_DT_GET(dt_node), \ |
| .is_streaming = false, \ |
| .channels = _CONCAT(__channel_array_, name), \ |
| .count = ARRAY_SIZE(_CONCAT(__channel_array_, name)), \ |
| .max = ARRAY_SIZE(_CONCAT(__channel_array_, name)), \ |
| }; \ |
| RTIO_IODEV_DEFINE(name, &__sensor_iodev_api, _CONCAT(&__sensor_read_config_, name)) |
| |
| /** |
| * @brief Define a stream instance of a sensor |
| * |
| * Use this macro to generate a @ref rtio_iodev for starting a stream that's triggered by specific |
| * interrupts. Example: |
| * |
| * @code(.c) |
| * SENSOR_DT_STREAM_IODEV(imu_stream, DT_ALIAS(imu), |
| * {SENSOR_TRIG_FIFO_WATERMARK, SENSOR_STREAM_DATA_INCLUDE}, |
| * {SENSOR_TRIG_FIFO_FULL, SENSOR_STREAM_DATA_NOP}); |
| * |
| * int main(void) { |
| * struct rtio_sqe *handle; |
| * sensor_stream(&imu_stream, &rtio, NULL, &handle); |
| * k_msleep(1000); |
| * rtio_sqe_cancel(handle); |
| * } |
| * @endcode |
| */ |
| #define SENSOR_DT_STREAM_IODEV(name, dt_node, ...) \ |
| static struct sensor_stream_trigger _CONCAT(__trigger_array_, name)[] = {__VA_ARGS__}; \ |
| static struct sensor_read_config _CONCAT(__sensor_read_config_, name) = { \ |
| .sensor = DEVICE_DT_GET(dt_node), \ |
| .is_streaming = true, \ |
| .triggers = _CONCAT(__trigger_array_, name), \ |
| .count = ARRAY_SIZE(_CONCAT(__trigger_array_, name)), \ |
| .max = ARRAY_SIZE(_CONCAT(__trigger_array_, name)), \ |
| }; \ |
| RTIO_IODEV_DEFINE(name, &__sensor_iodev_api, &_CONCAT(__sensor_read_config_, name)) |
| |
| /* Used to submit an RTIO sqe to the sensor's iodev */ |
| typedef void (*sensor_submit_t)(const struct device *sensor, struct rtio_iodev_sqe *sqe); |
| |
| /* The default decoder API */ |
| extern const struct sensor_decoder_api __sensor_default_decoder; |
| |
| /* The default sensor iodev API */ |
| extern const struct rtio_iodev_api __sensor_iodev_api; |
| |
| __subsystem struct sensor_driver_api { |
| sensor_attr_set_t attr_set; |
| sensor_attr_get_t attr_get; |
| sensor_trigger_set_t trigger_set; |
| sensor_sample_fetch_t sample_fetch; |
| sensor_channel_get_t channel_get; |
| sensor_get_decoder_t get_decoder; |
| sensor_submit_t submit; |
| }; |
| |
| /** |
| * @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. |
| */ |
| __syscall int sensor_attr_set(const struct device *dev, |
| enum sensor_channel chan, |
| enum sensor_attribute attr, |
| const struct sensor_value *val); |
| |
| static inline int z_impl_sensor_attr_set(const struct device *dev, |
| enum sensor_channel chan, |
| enum sensor_attribute attr, |
| const struct sensor_value *val) |
| { |
| const struct sensor_driver_api *api = |
| (const struct sensor_driver_api *)dev->api; |
| |
| if (api->attr_set == NULL) { |
| return -ENOSYS; |
| } |
| |
| return api->attr_set(dev, chan, attr, val); |
| } |
| |
| /** |
| * @brief Get 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 get |
| * @param val Pointer to where to store the attribute |
| * |
| * @return 0 if successful, negative errno code if failure. |
| */ |
| __syscall int sensor_attr_get(const struct device *dev, |
| enum sensor_channel chan, |
| enum sensor_attribute attr, |
| struct sensor_value *val); |
| |
| static inline int z_impl_sensor_attr_get(const struct device *dev, |
| enum sensor_channel chan, |
| enum sensor_attribute attr, |
| struct sensor_value *val) |
| { |
| const struct sensor_driver_api *api = |
| (const struct sensor_driver_api *)dev->api; |
| |
| if (api->attr_get == NULL) { |
| return -ENOSYS; |
| } |
| |
| return api->attr_get(dev, chan, attr, val); |
| } |
| |
| /** |
| * @brief Activate a sensor's trigger and set the trigger handler |
| * |
| * The handler will be called from a thread, so I2C or SPI operations are |
| * safe. However, the thread'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. |
| * |
| * The user-allocated trigger will be stored by the driver as a pointer, rather |
| * than a copy, and passed back to the handler. This enables the handler to use |
| * CONTAINER_OF to retrieve a context pointer when the trigger is embedded in a |
| * larger struct and requires that the trigger is not allocated on the stack. |
| * |
| * @funcprops \supervisor |
| * |
| * @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(const struct device *dev, |
| const struct sensor_trigger *trig, |
| sensor_trigger_handler_t handler) |
| { |
| const struct sensor_driver_api *api = |
| (const struct sensor_driver_api *)dev->api; |
| |
| if (api->trigger_set == NULL) { |
| return -ENOSYS; |
| } |
| |
| 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. |
| * |
| * The function blocks until the fetch operation is complete. |
| * |
| * 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. |
| */ |
| __syscall int sensor_sample_fetch(const struct device *dev); |
| |
| static inline int z_impl_sensor_sample_fetch(const struct device *dev) |
| { |
| const struct sensor_driver_api *api = |
| (const struct sensor_driver_api *)dev->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. |
| * |
| * The function blocks until the fetch operation is complete. |
| * |
| * 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. |
| */ |
| __syscall int sensor_sample_fetch_chan(const struct device *dev, |
| enum sensor_channel type); |
| |
| static inline int z_impl_sensor_sample_fetch_chan(const struct device *dev, |
| enum sensor_channel type) |
| { |
| const struct sensor_driver_api *api = |
| (const struct sensor_driver_api *)dev->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. |
| */ |
| __syscall int sensor_channel_get(const struct device *dev, |
| enum sensor_channel chan, |
| struct sensor_value *val); |
| |
| static inline int z_impl_sensor_channel_get(const struct device *dev, |
| enum sensor_channel chan, |
| struct sensor_value *val) |
| { |
| const struct sensor_driver_api *api = |
| (const struct sensor_driver_api *)dev->api; |
| |
| return api->channel_get(dev, chan, val); |
| } |
| |
| #if defined(CONFIG_SENSOR_ASYNC_API) || defined(__DOXYGEN__) |
| |
| /* |
| * Generic data structure used for encoding the sample timestamp and number of channels sampled. |
| */ |
| struct __attribute__((__packed__)) sensor_data_generic_header { |
| /* The timestamp at which the data was collected from the sensor */ |
| uint64_t timestamp_ns; |
| |
| /* |
| * The number of channels present in the frame. This will be the true number of elements in |
| * channel_info and in the q31 values that follow the header. |
| */ |
| uint32_t num_channels; |
| |
| /* Shift value for all samples in the frame */ |
| int8_t shift; |
| |
| /* This padding is needed to make sure that the 'channels' field is aligned */ |
| int8_t _padding[sizeof(struct sensor_chan_spec) - 1]; |
| |
| /* Channels present in the frame */ |
| struct sensor_chan_spec channels[0]; |
| }; |
| |
| /** |
| * @brief checks if a given channel is a 3-axis channel |
| * |
| * @param[in] chan The channel to check |
| * @retval true if @p chan is any of @ref SENSOR_CHAN_ACCEL_XYZ, @ref SENSOR_CHAN_GYRO_XYZ, or |
| * @ref SENSOR_CHAN_MAGN_XYZ, or @ref SENSOR_CHAN_POS_DXYZ |
| * @retval false otherwise |
| */ |
| #define SENSOR_CHANNEL_3_AXIS(chan) \ |
| ((chan) == SENSOR_CHAN_ACCEL_XYZ || (chan) == SENSOR_CHAN_GYRO_XYZ || \ |
| (chan) == SENSOR_CHAN_MAGN_XYZ || (chan) == SENSOR_CHAN_POS_DXYZ) |
| |
| /** |
| * @brief Get the sensor's decoder API |
| * |
| * @param[in] dev The sensor device |
| * @param[in] decoder Pointer to the decoder which will be set upon success |
| * @return 0 on success |
| * @return < 0 on error |
| */ |
| __syscall int sensor_get_decoder(const struct device *dev, |
| const struct sensor_decoder_api **decoder); |
| |
| static inline int z_impl_sensor_get_decoder(const struct device *dev, |
| const struct sensor_decoder_api **decoder) |
| { |
| const struct sensor_driver_api *api = (const struct sensor_driver_api *)dev->api; |
| |
| __ASSERT_NO_MSG(api != NULL); |
| |
| if (api->get_decoder == NULL) { |
| *decoder = &__sensor_default_decoder; |
| return 0; |
| } |
| |
| return api->get_decoder(dev, decoder); |
| } |
| |
| /** |
| * @brief Reconfigure a reading iodev |
| * |
| * Allows a reconfiguration of the iodev associated with reading a sample from a sensor. |
| * |
| * <b>Important</b>: If the iodev is currently servicing a read operation, the data will likely be |
| * invalid. Please be sure the flush or wait for all pending operations to complete before using the |
| * data after a configuration change. |
| * |
| * It is also important that the `data` field of the iodev is a @ref sensor_read_config. |
| * |
| * @param[in] iodev The iodev to reconfigure |
| * @param[in] sensor The sensor to read from |
| * @param[in] channels One or more channels to read |
| * @param[in] num_channels The number of channels in @p channels |
| * @return 0 on success |
| * @return < 0 on error |
| */ |
| __syscall int sensor_reconfigure_read_iodev(struct rtio_iodev *iodev, const struct device *sensor, |
| const struct sensor_chan_spec *channels, |
| size_t num_channels); |
| |
| static inline int z_impl_sensor_reconfigure_read_iodev(struct rtio_iodev *iodev, |
| const struct device *sensor, |
| const struct sensor_chan_spec *channels, |
| size_t num_channels) |
| { |
| struct sensor_read_config *cfg = (struct sensor_read_config *)iodev->data; |
| |
| if (cfg->max < num_channels || cfg->is_streaming) { |
| return -ENOMEM; |
| } |
| |
| cfg->sensor = sensor; |
| memcpy(cfg->channels, channels, num_channels * sizeof(struct sensor_chan_spec)); |
| cfg->count = num_channels; |
| return 0; |
| } |
| |
| static inline int sensor_stream(struct rtio_iodev *iodev, struct rtio *ctx, void *userdata, |
| struct rtio_sqe **handle) |
| { |
| if (IS_ENABLED(CONFIG_USERSPACE)) { |
| struct rtio_sqe sqe; |
| |
| rtio_sqe_prep_read_multishot(&sqe, iodev, RTIO_PRIO_NORM, userdata); |
| rtio_sqe_copy_in_get_handles(ctx, &sqe, handle, 1); |
| } else { |
| struct rtio_sqe *sqe = rtio_sqe_acquire(ctx); |
| |
| if (sqe == NULL) { |
| return -ENOMEM; |
| } |
| if (handle != NULL) { |
| *handle = sqe; |
| } |
| rtio_sqe_prep_read_multishot(sqe, iodev, RTIO_PRIO_NORM, userdata); |
| } |
| rtio_submit(ctx, 0); |
| return 0; |
| } |
| |
| /** |
| * @brief Blocking one shot read of samples from a sensor into a buffer |
| * |
| * Using @p cfg, read data from the device by using the provided RTIO context |
| * @p ctx. This call will generate a @ref rtio_sqe that will be given the provided buffer. The call |
| * will wait for the read to complete before returning to the caller. |
| * |
| * @param[in] iodev The iodev created by @ref SENSOR_DT_READ_IODEV |
| * @param[in] ctx The RTIO context to service the read |
| * @param[in] buf Pointer to memory to read sample data into |
| * @param[in] buf_len Size in bytes of the given memory that are valid to read into |
| * @return 0 on success |
| * @return < 0 on error |
| */ |
| static inline int sensor_read(struct rtio_iodev *iodev, struct rtio *ctx, uint8_t *buf, |
| size_t buf_len) |
| { |
| if (IS_ENABLED(CONFIG_USERSPACE)) { |
| struct rtio_sqe sqe; |
| |
| rtio_sqe_prep_read(&sqe, iodev, RTIO_PRIO_NORM, buf, buf_len, buf); |
| rtio_sqe_copy_in(ctx, &sqe, 1); |
| } else { |
| struct rtio_sqe *sqe = rtio_sqe_acquire(ctx); |
| |
| if (sqe == NULL) { |
| return -ENOMEM; |
| } |
| rtio_sqe_prep_read(sqe, iodev, RTIO_PRIO_NORM, buf, buf_len, buf); |
| } |
| rtio_submit(ctx, 1); |
| |
| struct rtio_cqe *cqe = rtio_cqe_consume(ctx); |
| int res = cqe->result; |
| |
| __ASSERT(cqe->userdata != buf, |
| "consumed non-matching completion for sensor read into buffer %p\n", buf); |
| |
| rtio_cqe_release(ctx, cqe); |
| |
| return res; |
| } |
| |
| /** |
| * @brief One shot non-blocking read with pool allocated buffer |
| * |
| * Using @p cfg, read one snapshot of data from the device by using the provided RTIO context |
| * @p ctx. This call will generate a @ref rtio_sqe that will leverage the RTIO's internal |
| * mempool when the time comes to service the read. |
| * |
| * @param[in] iodev The iodev created by @ref SENSOR_DT_READ_IODEV |
| * @param[in] ctx The RTIO context to service the read |
| * @param[in] userdata Optional userdata that will be available when the read is complete |
| * @return 0 on success |
| * @return < 0 on error |
| */ |
| static inline int sensor_read_async_mempool(struct rtio_iodev *iodev, struct rtio *ctx, |
| void *userdata) |
| { |
| if (IS_ENABLED(CONFIG_USERSPACE)) { |
| struct rtio_sqe sqe; |
| |
| rtio_sqe_prep_read_with_pool(&sqe, iodev, RTIO_PRIO_NORM, userdata); |
| rtio_sqe_copy_in(ctx, &sqe, 1); |
| } else { |
| struct rtio_sqe *sqe = rtio_sqe_acquire(ctx); |
| |
| if (sqe == NULL) { |
| return -ENOMEM; |
| } |
| rtio_sqe_prep_read_with_pool(sqe, iodev, RTIO_PRIO_NORM, userdata); |
| } |
| rtio_submit(ctx, 0); |
| return 0; |
| } |
| |
| /** |
| * @typedef sensor_processing_callback_t |
| * @brief Callback function used with the helper processing function. |
| * |
| * @see sensor_processing_with_callback |
| * |
| * @param[in] result The result code of the read (0 being success) |
| * @param[in] buf The data buffer holding the sensor data |
| * @param[in] buf_len The length (in bytes) of the @p buf |
| * @param[in] userdata The optional userdata passed to sensor_read_async_mempool() |
| */ |
| typedef void (*sensor_processing_callback_t)(int result, uint8_t *buf, uint32_t buf_len, |
| void *userdata); |
| |
| /** |
| * @brief Helper function for common processing of sensor data. |
| * |
| * This function can be called in a blocking manner after sensor_read() or in a standalone |
| * thread dedicated to processing. It will wait for a cqe from the RTIO context, once received, it |
| * will decode the userdata and call the @p cb. Once the @p cb returns, the buffer will be released |
| * back into @p ctx's mempool if available. |
| * |
| * @param[in] ctx The RTIO context to wait on |
| * @param[in] cb Callback to call when data is ready for processing |
| */ |
| void sensor_processing_with_callback(struct rtio *ctx, sensor_processing_callback_t cb); |
| |
| #endif /* defined(CONFIG_SENSOR_ASYNC_API) || defined(__DOXYGEN__) */ |
| |
| /** |
| * @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 to convert acceleration from m/s^2 to micro Gs |
| * |
| * @param ms2 A pointer to a sensor_value struct holding the acceleration, |
| * in m/s^2. |
| * |
| * @return The converted value, in micro Gs. |
| */ |
| static inline int32_t sensor_ms2_to_ug(const struct sensor_value *ms2) |
| { |
| int64_t micro_ms2 = (ms2->val1 * INT64_C(1000000)) + ms2->val2; |
| |
| return (micro_ms2 * 1000000LL) / SENSOR_G; |
| } |
| |
| /** |
| * @brief Helper function to convert acceleration from micro Gs to m/s^2 |
| * |
| * @param ug The micro G value to be converted. |
| * @param ms2 A pointer to a sensor_value struct, where the result is stored. |
| */ |
| static inline void sensor_ug_to_ms2(int32_t ug, struct sensor_value *ms2) |
| { |
| ms2->val1 = ((int64_t)ug * SENSOR_G / 1000000LL) / 1000000LL; |
| ms2->val2 = ((int64_t)ug * SENSOR_G / 1000000LL) % 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 radians to 10 micro degrees. |
| * |
| * When the unit is 1 micro degree, the range that the int32_t can represent is |
| * +/-2147.483 degrees. In order to increase this range, here we use 10 micro |
| * degrees as the unit. |
| * |
| * @param rad A pointer to a sensor_value struct, holding the value in radians. |
| * |
| * @return The converted value, in 10 micro degrees. |
| */ |
| static inline int32_t sensor_rad_to_10udegrees(const struct sensor_value *rad) |
| { |
| int64_t micro_rad_s = rad->val1 * 1000000LL + rad->val2; |
| |
| return (micro_rad_s * 180LL * 100000LL) / SENSOR_PI; |
| } |
| |
| /** |
| * @brief Helper function for converting 10 micro degrees to radians. |
| * |
| * @param d The value (in 10 micro degrees) to be converted. |
| * @param rad A pointer to a sensor_value struct, where the result is stored. |
| */ |
| static inline void sensor_10udegrees_to_rad(int32_t d, struct sensor_value *rad) |
| { |
| rad->val1 = ((int64_t)d * SENSOR_PI / 180LL / 100000LL) / 1000000LL; |
| rad->val2 = ((int64_t)d * SENSOR_PI / 180LL / 100000LL) % 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(const struct sensor_value *val) |
| { |
| return (double)val->val1 + (double)val->val2 / 1000000; |
| } |
| |
| /** |
| * @brief Helper function for converting struct sensor_value to float. |
| * |
| * @param val A pointer to a sensor_value struct. |
| * @return The converted value. |
| */ |
| static inline float sensor_value_to_float(const struct sensor_value *val) |
| { |
| return (float)val->val1 + (float)val->val2 / 1000000; |
| } |
| |
| /** |
| * @brief Helper function for converting double to struct sensor_value. |
| * |
| * @param val A pointer to a sensor_value struct. |
| * @param inp The converted value. |
| * @return 0 if successful, negative errno code if failure. |
| */ |
| static inline int sensor_value_from_double(struct sensor_value *val, double inp) |
| { |
| if (inp < INT32_MIN || inp > INT32_MAX) { |
| return -ERANGE; |
| } |
| |
| double val2 = (inp - (int32_t)inp) * 1000000.0; |
| |
| if (val2 < INT32_MIN || val2 > INT32_MAX) { |
| return -ERANGE; |
| } |
| |
| val->val1 = (int32_t)inp; |
| val->val2 = (int32_t)val2; |
| |
| return 0; |
| } |
| |
| /** |
| * @brief Helper function for converting float to struct sensor_value. |
| * |
| * @param val A pointer to a sensor_value struct. |
| * @param inp The converted value. |
| * @return 0 if successful, negative errno code if failure. |
| */ |
| static inline int sensor_value_from_float(struct sensor_value *val, float inp) |
| { |
| float val2 = (inp - (int32_t)inp) * 1000000.0f; |
| |
| if (val2 < INT32_MIN || val2 > (float)(INT32_MAX - 1)) { |
| return -ERANGE; |
| } |
| |
| val->val1 = (int32_t)inp; |
| val->val2 = (int32_t)val2; |
| |
| return 0; |
| } |
| |
| #ifdef CONFIG_SENSOR_INFO |
| |
| struct sensor_info { |
| const struct device *dev; |
| const char *vendor; |
| const char *model; |
| const char *friendly_name; |
| }; |
| |
| #define SENSOR_INFO_INITIALIZER(_dev, _vendor, _model, _friendly_name) \ |
| { \ |
| .dev = _dev, \ |
| .vendor = _vendor, \ |
| .model = _model, \ |
| .friendly_name = _friendly_name, \ |
| } |
| |
| #define SENSOR_INFO_DEFINE(name, ...) \ |
| static const STRUCT_SECTION_ITERABLE(sensor_info, name) = \ |
| SENSOR_INFO_INITIALIZER(__VA_ARGS__) |
| |
| #define SENSOR_INFO_DT_NAME(node_id) \ |
| _CONCAT(__sensor_info, DEVICE_DT_NAME_GET(node_id)) |
| |
| #define SENSOR_INFO_DT_DEFINE(node_id) \ |
| SENSOR_INFO_DEFINE(SENSOR_INFO_DT_NAME(node_id), \ |
| DEVICE_DT_GET(node_id), \ |
| DT_NODE_VENDOR_OR(node_id, NULL), \ |
| DT_NODE_MODEL_OR(node_id, NULL), \ |
| DT_PROP_OR(node_id, friendly_name, NULL)) \ |
| |
| #else |
| |
| #define SENSOR_INFO_DEFINE(name, ...) |
| #define SENSOR_INFO_DT_DEFINE(node_id) |
| |
| #endif /* CONFIG_SENSOR_INFO */ |
| |
| /** |
| * @brief Like DEVICE_DT_DEFINE() with sensor specifics. |
| * |
| * @details Defines a device which implements the sensor API. May define an |
| * element in the sensor info iterable section used to enumerate all sensor |
| * devices. |
| * |
| * @param node_id The devicetree node identifier. |
| * |
| * @param init_fn Name of the init function of the driver. |
| * |
| * @param pm_device PM device resources reference (NULL if device does not use |
| * PM). |
| * |
| * @param data_ptr Pointer to the device's private data. |
| * |
| * @param cfg_ptr The address to the structure containing the configuration |
| * information for this instance of the driver. |
| * |
| * @param level The initialization level. See SYS_INIT() for details. |
| * |
| * @param prio Priority within the selected initialization level. See |
| * SYS_INIT() for details. |
| * |
| * @param api_ptr Provides an initial pointer to the API function struct used |
| * by the driver. Can be NULL. |
| */ |
| #define SENSOR_DEVICE_DT_DEFINE(node_id, init_fn, pm_device, \ |
| data_ptr, cfg_ptr, level, prio, \ |
| api_ptr, ...) \ |
| DEVICE_DT_DEFINE(node_id, init_fn, pm_device, \ |
| data_ptr, cfg_ptr, level, prio, \ |
| api_ptr, __VA_ARGS__); \ |
| \ |
| SENSOR_INFO_DT_DEFINE(node_id); |
| |
| /** |
| * @brief Like SENSOR_DEVICE_DT_DEFINE() for an instance of a DT_DRV_COMPAT |
| * compatible |
| * |
| * @param inst instance number. This is replaced by |
| * <tt>DT_DRV_COMPAT(inst)</tt> in the call to SENSOR_DEVICE_DT_DEFINE(). |
| * |
| * @param ... other parameters as expected by SENSOR_DEVICE_DT_DEFINE(). |
| */ |
| #define SENSOR_DEVICE_DT_INST_DEFINE(inst, ...) \ |
| SENSOR_DEVICE_DT_DEFINE(DT_DRV_INST(inst), __VA_ARGS__) |
| |
| /** |
| * @brief Helper function for converting struct sensor_value to integer milli units. |
| * |
| * @param val A pointer to a sensor_value struct. |
| * @return The converted value. |
| */ |
| static inline int64_t sensor_value_to_milli(const struct sensor_value *val) |
| { |
| return ((int64_t)val->val1 * 1000) + val->val2 / 1000; |
| } |
| |
| /** |
| * @brief Helper function for converting struct sensor_value to integer micro units. |
| * |
| * @param val A pointer to a sensor_value struct. |
| * @return The converted value. |
| */ |
| static inline int64_t sensor_value_to_micro(const struct sensor_value *val) |
| { |
| return ((int64_t)val->val1 * 1000000) + val->val2; |
| } |
| |
| /** |
| * @brief Helper function for converting integer milli units to struct sensor_value. |
| * |
| * @param val A pointer to a sensor_value struct. |
| * @param milli The converted value. |
| * @return 0 if successful, negative errno code if failure. |
| */ |
| static inline int sensor_value_from_milli(struct sensor_value *val, int64_t milli) |
| { |
| if (milli < ((int64_t)INT32_MIN - 1) * 1000LL || |
| milli > ((int64_t)INT32_MAX + 1) * 1000LL) { |
| return -ERANGE; |
| } |
| |
| val->val1 = (int32_t)(milli / 1000); |
| val->val2 = (int32_t)(milli % 1000) * 1000; |
| |
| return 0; |
| } |
| |
| /** |
| * @brief Helper function for converting integer micro units to struct sensor_value. |
| * |
| * @param val A pointer to a sensor_value struct. |
| * @param micro The converted value. |
| * @return 0 if successful, negative errno code if failure. |
| */ |
| static inline int sensor_value_from_micro(struct sensor_value *val, int64_t micro) |
| { |
| if (micro < ((int64_t)INT32_MIN - 1) * 1000000LL || |
| micro > ((int64_t)INT32_MAX + 1) * 1000000LL) { |
| return -ERANGE; |
| } |
| |
| val->val1 = (int32_t)(micro / 1000000LL); |
| val->val2 = (int32_t)(micro % 1000000LL); |
| |
| return 0; |
| } |
| |
| /** |
| * @} |
| */ |
| |
| /** |
| * @brief Get the decoder name for the current driver |
| * |
| * This function depends on `DT_DRV_COMPAT` being defined. |
| */ |
| #define SENSOR_DECODER_NAME() UTIL_CAT(DT_DRV_COMPAT, __decoder_api) |
| |
| /** |
| * @brief Statically get the decoder for a given node |
| * |
| * @code{.c} |
| * static const sensor_decoder_api *decoder = SENSOR_DECODER_DT_GET(DT_ALIAS(accel)); |
| * @endcode |
| */ |
| #define SENSOR_DECODER_DT_GET(node_id) \ |
| &UTIL_CAT(DT_STRING_TOKEN_BY_IDX(node_id, compatible, 0), __decoder_api) |
| |
| /** |
| * @brief Define a decoder API |
| * |
| * This macro should be created once per compatible string of a sensor and will create a statically |
| * referenceable decoder API. |
| * |
| * @code{.c} |
| * SENSOR_DECODER_API_DT_DEFINE() = { |
| * .get_frame_count = my_driver_get_frame_count, |
| * .get_timestamp = my_driver_get_timestamp, |
| * .get_shift = my_driver_get_shift, |
| * .decode = my_driver_decode, |
| * }; |
| * @endcode |
| */ |
| #define SENSOR_DECODER_API_DT_DEFINE() \ |
| COND_CODE_1(DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT), (), (static)) \ |
| const STRUCT_SECTION_ITERABLE(sensor_decoder_api, SENSOR_DECODER_NAME()) |
| |
| #define Z_MAYBE_SENSOR_DECODER_DECLARE_INTERNAL_IDX(node_id, prop, idx) \ |
| extern const struct sensor_decoder_api UTIL_CAT( \ |
| DT_STRING_TOKEN_BY_IDX(node_id, prop, idx), __decoder_api); |
| |
| #define Z_MAYBE_SENSOR_DECODER_DECLARE_INTERNAL(node_id) \ |
| COND_CODE_1(DT_NODE_HAS_PROP(node_id, compatible), \ |
| (DT_FOREACH_PROP_ELEM(node_id, compatible, \ |
| Z_MAYBE_SENSOR_DECODER_DECLARE_INTERNAL_IDX)), \ |
| ()) |
| |
| DT_FOREACH_STATUS_OKAY_NODE(Z_MAYBE_SENSOR_DECODER_DECLARE_INTERNAL) |
| |
| #ifdef __cplusplus |
| } |
| #endif |
| |
| #include <zephyr/syscalls/sensor.h> |
| |
| #endif /* ZEPHYR_INCLUDE_DRIVERS_SENSOR_H_ */ |