zephyr/drivers/sensor/apds9960/apds9960_trigger.c
Michael Kaplan a818d06cf2 drivers: sensors: apds9960 fix trigger callback context
In the current implementation, the apds9960 trigger callback function
is called with the pointer of a driver-internal allocated trigger
structure. This structure is not initialized anywhere, so essentially
the trigger callback gets called with junk data.

Besides the missing initialization, it would be better instead to hold
a const pointer to a user allocated sensor_trigger object.
This way user code can establish a context with related user data (for
example a pointer to a C++ object) by storing its sensor_trigger object
within a structure alongside the user data, and then using
CONTAINER_OF() macro to get the pointer of the container struct (and
thus the user data).

Signed-off-by: Michael Kaplan <m.kaplan@evva.com>
2023-03-15 22:39:45 +00:00

101 lines
2.2 KiB
C

/*
* Copyright (c) 2018 Phytec Messtechnik GmbH
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/device.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/i2c.h>
#include <zephyr/sys/util.h>
#include <zephyr/kernel.h>
#include <zephyr/drivers/sensor.h>
#include "apds9960.h"
extern struct apds9960_data apds9960_driver;
#include <zephyr/logging/log.h>
LOG_MODULE_DECLARE(APDS9960, CONFIG_SENSOR_LOG_LEVEL);
void apds9960_work_cb(struct k_work *work)
{
struct apds9960_data *data = CONTAINER_OF(work,
struct apds9960_data,
work);
const struct device *dev = data->dev;
if (data->p_th_handler != NULL) {
data->p_th_handler(dev, data->p_th_trigger);
}
apds9960_setup_int(dev->config, true);
}
int apds9960_attr_set(const struct device *dev,
enum sensor_channel chan,
enum sensor_attribute attr,
const struct sensor_value *val)
{
const struct apds9960_config *config = dev->config;
if (chan == SENSOR_CHAN_PROX) {
if (attr == SENSOR_ATTR_UPPER_THRESH) {
if (i2c_reg_write_byte_dt(&config->i2c,
APDS9960_PIHT_REG,
(uint8_t)val->val1)) {
return -EIO;
}
return 0;
}
if (attr == SENSOR_ATTR_LOWER_THRESH) {
if (i2c_reg_write_byte_dt(&config->i2c,
APDS9960_PILT_REG,
(uint8_t)val->val1)) {
return -EIO;
}
return 0;
}
}
return -ENOTSUP;
}
int apds9960_trigger_set(const struct device *dev,
const struct sensor_trigger *trig,
sensor_trigger_handler_t handler)
{
const struct apds9960_config *config = dev->config;
struct apds9960_data *data = dev->data;
apds9960_setup_int(dev->config, false);
switch (trig->type) {
case SENSOR_TRIG_THRESHOLD:
if (trig->chan == SENSOR_CHAN_PROX) {
data->p_th_handler = handler;
data->p_th_trigger = trig;
if (i2c_reg_update_byte_dt(&config->i2c,
APDS9960_ENABLE_REG,
APDS9960_ENABLE_PIEN,
APDS9960_ENABLE_PIEN)) {
return -EIO;
}
} else {
return -ENOTSUP;
}
break;
default:
LOG_ERR("Unsupported sensor trigger");
return -ENOTSUP;
}
apds9960_setup_int(config, true);
if (gpio_pin_get_dt(&config->int_gpio) > 0) {
k_work_submit(&data->work);
}
return 0;
}