blob: 7d84627c7df1ba77b991e41c043a7d4b945d9484 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
#include <string.h>
#include <errno.h>
#include <assert.h>
#include "os/mynewt.h"
#include "sensor/sensor.h"
#include "sensor_priv.h"
#include "sensor/accel.h"
#include "sensor/mag.h"
#include "sensor/light.h"
#include "sensor/quat.h"
#include "sensor/euler.h"
#include "sensor/color.h"
#include "sensor/temperature.h"
#include "sensor/pressure.h"
#include "sensor/humidity.h"
#include "sensor/gyro.h"
#include "console/console.h"
#if MYNEWT_VAL(SENSOR_POLL_TEST_LOG)
uint32_t test_log_idx;
uint32_t smgr_wakeup_idx;
struct test_log {
os_time_t delta;
uint16_t polls_left;
os_time_t now;
os_time_t os_now;
char name[2];
uint32_t poll_multiple;
}test_log[100];
os_time_t smgr_wakeup[500];
#endif
struct {
struct os_mutex mgr_lock;
struct os_callout mgr_wakeup_callout;
struct os_eventq *mgr_eventq;
SLIST_HEAD(, sensor) mgr_sensor_list;
} sensor_mgr;
struct sensor_read_ctx {
sensor_data_func_t user_func;
void *user_arg;
};
struct sensor_timestamp sensor_base_ts;
struct os_callout st_up_osco;
static void sensor_notify_ev_cb(struct os_event * ev);
static void sensor_read_ev_cb(struct os_event *ev);
static void sensor_interrupt_ev_cb(struct os_event *ev);
/** OS event - for doing a sensor read */
static struct os_event sensor_read_event = {
.ev_cb = sensor_read_ev_cb,
};
#define SENSOR_NOTIFY_EVT_MEMPOOL_SIZE \
OS_MEMPOOL_SIZE(MYNEWT_VAL(SENSOR_NOTIF_EVENTS_MAX), \
sizeof(struct sensor_notify_os_ev))
static struct os_mempool sensor_notify_evt_pool;
static os_membuf_t sensor_notify_evt_area[SENSOR_NOTIFY_EVT_MEMPOOL_SIZE];
/**
* Lock sensor manager to access the list of sensors
*/
int
sensor_mgr_lock(void)
{
int rc;
rc = os_mutex_pend(&sensor_mgr.mgr_lock, OS_TIMEOUT_NEVER);
if (rc == 0 || rc == OS_NOT_STARTED) {
return (0);
}
return (rc);
}
/**
* Unlock sensor manager once the list of sensors has been accessed
*/
void
sensor_mgr_unlock(void)
{
(void) os_mutex_release(&sensor_mgr.mgr_lock);
}
static void
sensor_mgr_remove(struct sensor *sensor)
{
SLIST_REMOVE(&sensor_mgr.mgr_sensor_list, sensor, sensor, s_next);
}
static void
sensor_mgr_insert(struct sensor *sensor)
{
struct sensor *cursor, *prev;
prev = cursor = NULL;
if (!sensor->s_poll_rate) {
SLIST_FOREACH(cursor, &sensor_mgr.mgr_sensor_list, s_next) {
prev = cursor;
}
goto insert;
}
prev = cursor = NULL;
SLIST_FOREACH(cursor, &sensor_mgr.mgr_sensor_list, s_next) {
if (!cursor->s_poll_rate) {
break;
}
if (OS_TIME_TICK_LT(sensor->s_next_run, cursor->s_next_run)) {
break;
}
prev = cursor;
}
insert:
if (prev == NULL) {
SLIST_INSERT_HEAD(&sensor_mgr.mgr_sensor_list, sensor, s_next);
} else {
SLIST_INSERT_AFTER(prev, sensor, s_next);
}
}
/**
* Remove a sensor type trait. This allows a calling application to clear
* sensortype trait for a given sensor object.
*
* @param The sensor object
* @param The sensor trait to remove from the sensor type trait list
*
* @return 0 on success, non-zero error code on failure.
*/
static int
sensor_remove_type_trait(struct sensor *sensor,
struct sensor_type_traits *stt)
{
int rc;
rc = sensor_lock(sensor);
if (rc != 0) {
goto err;
}
/* Remove this entry from the list */
SLIST_REMOVE(&sensor->s_type_traits_list, stt, sensor_type_traits,
stt_next);
sensor_unlock(sensor);
return (0);
err:
return (rc);
}
/**
* Insert sensor type trait sorting based on the poll rate multiple
*
* @param sensor to insert type traits in
* @param sensor type traits to insert
*
* @return 0 on success, non-zero on failure
*/
static int
sensor_insert_type_trait(struct sensor *sensor, struct sensor_type_traits *stt)
{
struct sensor_type_traits *cursor, *prev;
int rc;
if (!sensor) {
rc = SYS_EINVAL;
goto err;
}
stt->stt_sensor = sensor;
rc = sensor_lock(sensor);
if (rc != 0) {
goto err;
}
prev = cursor = NULL;
SLIST_FOREACH(cursor, &sensor->s_type_traits_list, stt_next) {
if (cursor->stt_poll_n == 0) {
break;
}
if (OS_TIME_TICK_LT(stt->stt_poll_n, cursor->stt_poll_n)) {
break;
}
prev = cursor;
}
if (prev == NULL) {
SLIST_INSERT_HEAD(&sensor->s_type_traits_list, stt, stt_next);
} else {
SLIST_INSERT_AFTER(prev, stt, stt_next);
}
sensor_unlock(sensor);
return 0;
err:
return rc;
}
/**
* Set the sensor poll rate multiple based on the device name, sensor type
*
* @param The devname
* @param The sensor type trait
*/
int
sensor_set_n_poll_rate(char *devname, struct sensor_type_traits *stt)
{
struct sensor *sensor;
struct sensor_type_traits *stt_tmp;
int rc;
if (!stt) {
rc = SYS_EINVAL;
goto err;
}
stt_tmp = NULL;
sensor = sensor_get_type_traits_byname(devname, &stt_tmp,
stt->stt_sensor_type);
if (!sensor) {
rc = SYS_EINVAL;
goto err;
}
if (!stt_tmp && stt) {
rc = sensor_insert_type_trait(sensor, stt);
rc |= sensor_lock(sensor);
if (rc) {
goto err;
}
stt_tmp = stt;
stt_tmp->stt_polls_left = stt->stt_poll_n;
sensor_unlock(sensor);
} else if (stt_tmp) {
rc = sensor_remove_type_trait(sensor, stt_tmp);
if (rc) {
goto err;
}
sensor_lock(sensor);
stt_tmp->stt_poll_n = stt->stt_poll_n;
stt_tmp->stt_polls_left = stt->stt_poll_n;
sensor_unlock(sensor);
rc = sensor_insert_type_trait(sensor, stt_tmp);
if (rc) {
goto err;
}
} else {
rc = SYS_EINVAL;
goto err;
}
return 0;
err:
return rc;
}
static void
sensor_update_poll_rate(struct sensor *sensor, uint32_t poll_rate)
{
sensor_lock(sensor);
sensor->s_poll_rate = poll_rate;
sensor_unlock(sensor);
}
static os_time_t
sensor_calc_nextrun_delta(struct sensor *sensor, os_time_t now)
{
os_time_t sensor_ticks;
int delta;
sensor_lock(sensor);
delta = (int32_t)(sensor->s_next_run - now);
if (delta < 0) {
/* This fires the callout right away */
sensor_ticks = 0;
} else {
sensor_ticks = delta;
}
sensor_unlock(sensor);
return sensor_ticks;
}
static struct sensor *
sensor_find_min_nextrun_sensor(os_time_t now, os_time_t *min_nextrun)
{
struct sensor *head;
head = NULL;
sensor_mgr_lock();
head = SLIST_FIRST(&sensor_mgr.mgr_sensor_list);
*min_nextrun = sensor_calc_nextrun_delta(head, now);
sensor_mgr_unlock();
return head;
}
static void
sensor_update_nextrun(struct sensor *sensor, os_time_t now)
{
os_time_t sensor_ticks;
os_time_ms_to_ticks(sensor->s_poll_rate, &sensor_ticks);
sensor_lock(sensor);
/* Remove the sensor from the sensor list for insert. */
sensor_mgr_remove(sensor);
/* Set next wakeup, and insert the sensor back into the
* list.
*/
sensor->s_next_run = sensor_ticks + now;
/* Re-insert the sensor manager, with the new wakeup time. */
sensor_mgr_insert(sensor);
sensor_unlock(sensor);
}
/**
* Set the sensor poll rate based on the device name
*
* @param The devname
* @param The poll rate in milli seconds
*/
int
sensor_set_poll_rate_ms(char *devname, uint32_t poll_rate)
{
struct sensor *sensor;
os_time_t next_wakeup;
os_time_t now;
int rc;
os_callout_stop(&sensor_mgr.mgr_wakeup_callout);
sensor = sensor_mgr_find_next_bydevname(devname, NULL);
if (!sensor) {
rc = SYS_EINVAL;
goto err;
}
sensor_lock(sensor);
now = os_time_get();
os_time_ms_to_ticks(poll_rate, &next_wakeup);
sensor_update_poll_rate(sensor, poll_rate);
sensor_update_nextrun(sensor, now);
sensor_unlock(sensor);
sensor = sensor_find_min_nextrun_sensor(now, &next_wakeup);
os_callout_reset(&sensor_mgr.mgr_wakeup_callout, next_wakeup);
return 0;
err:
return rc;
}
/**
* Register the sensor with the global sensor list. This makes the sensor
* searchable by other packages, who may want to look it up by type.
*
* @param The sensor to register
*
* @return 0 on success, non-zero error code on failure.
*/
int
sensor_mgr_register(struct sensor *sensor)
{
int rc;
rc = sensor_mgr_lock();
if (rc != 0) {
goto err;
}
rc = sensor_lock(sensor);
if (rc != 0) {
goto err;
}
sensor_mgr_insert(sensor);
sensor_unlock(sensor);
sensor_mgr_unlock();
return (0);
err:
return (rc);
}
/* Sensor poll one completes the poll, updates the sensor's "next
* run," and re-inserts it into the list
*/
static void
sensor_mgr_poll_bytype(struct sensor *sensor, sensor_type_t type,
struct sensor_type_traits *stt, os_time_t now)
{
if (!stt || !stt->stt_polls_left) {
/* Sensor read results. Every time a sensor is read, all of its
* listeners are called by default. Specify NULL as a callback,
* because we just want to run all the listeners.
*/
sensor_read(sensor, type, NULL, NULL, OS_TIMEOUT_NEVER);
sensor_lock(sensor);
if (stt) {
if (!stt->stt_polls_left && stt->stt_poll_n) {
stt->stt_polls_left = stt->stt_poll_n;
stt->stt_polls_left--;
}
#if MYNEWT_VAL(SENSOR_POLL_TEST_LOG)
test_log[test_log_idx].delta = (uint32_t)(now - stt->prev_now);
test_log[test_log_idx].polls_left = stt->stt_polls_left;
test_log[test_log_idx].now = now;
test_log[test_log_idx].os_now = os_time_get();
test_log[test_log_idx].name[0] = sensor->s_dev->od_name[0];
test_log[test_log_idx].name[1] = type == 1 ? 'a' : type == 32 ? 't' : type == 64 ? 'p' : 'x';
test_log[test_log_idx].poll_multiple = stt->stt_poll_n;
test_log_idx++;
test_log_idx %= 100;
stt->prev_now = now;
#endif
}
/* Unlock the sensor to allow other access */
sensor_unlock(sensor);
} else {
stt->stt_polls_left--;
}
}
static uint8_t
sensor_type_traits_empty(struct sensor *sensor)
{
return SLIST_EMPTY(&sensor->s_type_traits_list);
}
static void
sensor_poll_per_type_trait(struct sensor *sensor, os_time_t now,
os_time_t next_wakeup)
{
struct sensor_type_traits *stt;
/* Lock the sensor */
sensor_lock(sensor);
SLIST_FOREACH(stt, &sensor->s_type_traits_list, stt_next) {
/* poll multiple is one if no multiple is specified,
* as a result, the sensor would get polled at the
* poll rate if no multiple is specified
*
* If a multiple is specified, the sensor would get polled
* at the poll multiple
*/
sensor_mgr_poll_bytype(sensor, stt->stt_sensor_type, stt,
now);
}
/* Unlock the sensor to allow other access */
sensor_unlock(sensor);
}
/**
* Event that wakes up the sensor manager, this goes through the sensor
* list and polls any active sensors.
*
* @param OS event
*/
static void
sensor_mgr_wakeup_event(struct os_event *ev)
{
struct sensor *cursor;
os_time_t now;
os_time_t next_wakeup;
now = os_time_get();
#if MYNEWT_VAL(SENSOR_POLL_TEST_LOG)
smgr_wakeup[smgr_wakeup_idx++%500] = now;
#endif
sensor_mgr_lock();
cursor = NULL;
while (1) {
cursor = sensor_find_min_nextrun_sensor(now, &next_wakeup);
sensor_lock(cursor);
/* Sensors that are not periodic are inserted at the end of the sensor
* list.
*/
if (!cursor->s_poll_rate) {
sensor_unlock(cursor);
sensor_mgr_unlock();
return;
}
/* List is sorted by what runs first. If we reached the first element that
* doesn't run, break out.
*/
if (next_wakeup > 0) {
break;
}
if (sensor_type_traits_empty(cursor)) {
sensor_mgr_poll_bytype(cursor, cursor->s_mask, NULL, now);
} else {
sensor_poll_per_type_trait(cursor, now, next_wakeup);
}
sensor_update_nextrun(cursor, now);
sensor_unlock(cursor);
}
sensor_mgr_unlock();
os_callout_reset(&sensor_mgr.mgr_wakeup_callout, next_wakeup);
}
/**
* Event that wakes up timestamp update procedure, this updates the base
* os_timeval in the global structure along with the base cputime
* @param OS event
*/
static void
sensor_base_ts_update_event(struct os_event *ev)
{
os_time_t ticks;
int rc;
struct os_timeval ostv;
struct os_timezone ostz;
ticks = os_time_get();
rc = os_gettimeofday(&ostv, &ostz);
if (rc) {
/* There is nothing we can do here
* just reset the timer frequently if we
* fail to get time, till then we will keep using
* old timestamp values.
*/
ticks += OS_TICKS_PER_SEC * 600;
goto done;
}
/* CPU time gets wrapped in 4295 seconds since it is uint32_t,
* hence the hardcoded value of 3600 seconds, We want to make
* sure that the cputime never gets wrapped more than once.
* os_timeval usecs value gets wrapped in 2147 secs since it is int32_t.
* Hence, we take 2000 secs so that we update before it gets wrapped
* without cutting it too close.
*/
ticks += OS_TICKS_PER_SEC * 2000;
sensor_base_ts.st_ostv = ostv;
sensor_base_ts.st_ostz = ostz;
sensor_base_ts.st_cputime = os_cputime_get32();
done:
os_callout_reset(&st_up_osco, ticks);
}
/**
* Get the current eventq, the system is misconfigured if there is still
* no parent eventq.
*/
struct os_eventq *
sensor_mgr_evq_get(void)
{
return (sensor_mgr.mgr_eventq);
}
static void
sensor_mgr_evq_set(struct os_eventq *evq)
{
sensor_mgr.mgr_eventq = evq;
}
static void
sensor_mgr_init(void)
{
struct os_timeval ostv;
struct os_timezone ostz;
int rc;
#ifdef MYNEWT_VAL_SENSOR_MGR_EVQ
sensor_mgr_evq_set(MYNEWT_VAL(SENSOR_MGR_EVQ));
#else
sensor_mgr_evq_set(os_eventq_dflt_get());
#endif
rc = os_mempool_init(&sensor_notify_evt_pool,
MYNEWT_VAL(SENSOR_NOTIF_EVENTS_MAX),
sizeof(struct sensor_notify_os_ev), sensor_notify_evt_area,
"sensor_notif_evts");
assert(rc == OS_OK);
/**
* Initialize sensor polling callout and set it to fire on boot.
*/
os_callout_init(&sensor_mgr.mgr_wakeup_callout, sensor_mgr_evq_get(),
sensor_mgr_wakeup_event, NULL);
/* Initialize sensor cputime update callout and set it to fire after an
* hour, CPU time gets wrapped in 4295 seconds,
* hence the hardcoded value of 3600 seconds, We make sure that the
* cputime never gets wrapped more than once.
*/
os_gettimeofday(&ostv, &ostz);
sensor_base_ts.st_ostv = ostv;
sensor_base_ts.st_ostz = ostz;
sensor_base_ts.st_cputime = os_cputime_get32();
os_callout_init(&st_up_osco, sensor_mgr_evq_get(),
sensor_base_ts_update_event, NULL);
os_callout_reset(&st_up_osco, OS_TICKS_PER_SEC);
os_mutex_init(&sensor_mgr.mgr_lock);
}
/**
* The sensor manager contains a list of sensors, this function returns
* the next sensor in that list, for which compare_func() returns successful
* (one). If prev_cursor is provided, the function starts at that point
* in the sensor list.
*
* @warn This function MUST be locked by sensor_mgr_lock/unlock() if the goal is
* to iterate through sensors (as opposed to just finding one.) As the
* "prev_cursor" may be resorted in the sensor list, in between calls.
*
* @param The comparison function to use against sensors in the list.
* @param The argument to provide to that comparison function
* @param The previous sensor in the sensor manager list, in case of
* iteration. If desire is to find first matching sensor, provide a
* NULL value.
*
* @return A pointer to the first sensor found from prev_cursor, or
* NULL, if none found.
*
*/
struct sensor *
sensor_mgr_find_next(sensor_mgr_compare_func_t compare_func, void *arg,
struct sensor *prev_cursor)
{
struct sensor *cursor;
int rc;
cursor = NULL;
/* Couldn't acquire lock of sensor list, exit */
rc = sensor_mgr_lock();
if (rc != 0) {
goto done;
}
cursor = prev_cursor;
if (cursor == NULL) {
cursor = SLIST_FIRST(&sensor_mgr.mgr_sensor_list);
} else {
cursor = SLIST_NEXT(prev_cursor, s_next);
}
while (cursor != NULL) {
if (compare_func(cursor, arg)) {
break;
}
cursor = SLIST_NEXT(cursor, s_next);
}
sensor_mgr_unlock();
done:
return (cursor);
}
/**
* Check if sensor type matches
*
* @param The sensor object
* @param The type to check
*
* @return 1 if matches, 0 if it doesn't match.
*/
int
sensor_mgr_match_bytype(struct sensor *sensor, void *arg)
{
sensor_type_t *type;
type = (sensor_type_t *) arg;
/* s_types is a bitmask that contains the supported sensor types for this
* sensor, and type is the bitmask we're searching for. We also look at
* the mask as the driver might be configured to work in a mode where only
* some of the sensors are supported but not all. Compare the three,
* and if there is a match, return 1. If it is not supported, return 0.
*/
return (*type & sensor->s_types & sensor->s_mask) ? 1 : 0;
}
/**
* Find the "next" sensor available for a given sensor type.
*
* If the sensor parameter, is present find the next entry from that
* parameter. Otherwise, find the first matching sensor.
*
* @param The type of sensor to search for
* @param The cursor to search from, or NULL to start from the beginning.
*
* @return A pointer to the sensor object matching that sensor type, or NULL if
* none found.
*/
struct sensor *
sensor_mgr_find_next_bytype(sensor_type_t type, struct sensor *prev_cursor)
{
return (sensor_mgr_find_next(sensor_mgr_match_bytype, (void *) &type,
prev_cursor));
}
static int
sensor_mgr_match_bydevname(struct sensor *sensor, void *arg)
{
char *devname;
devname = (char *) arg;
if (!strcmp(sensor->s_dev->od_name, devname)) {
return (1);
}
return (0);
}
/**
* Search the sensor thresh list for specific type of sensor
*
* @param The sensor type to search for
* @param Ptr to a sensor
*
* @return NULL when no sensor type is found, ptr to sensor_type_traits structure
* when found
*/
struct sensor_type_traits *
sensor_get_type_traits_bytype(sensor_type_t type, struct sensor *sensor)
{
struct sensor_type_traits *stt;
stt = NULL;
sensor_lock(sensor);
SLIST_FOREACH(stt, &sensor->s_type_traits_list, stt_next) {
if (stt->stt_sensor_type == type) {
break;
}
}
sensor_unlock(sensor);
return stt;
}
/**
* Search the sensor list and find the next sensor that corresponds
* to a given device name.
*
* @param The device name to search for
* @param The previous sensor found with this device name
*
* @return 0 on success, non-zero error code on failure
*/
struct sensor *
sensor_mgr_find_next_bydevname(char *devname, struct sensor *prev_cursor)
{
return (sensor_mgr_find_next(sensor_mgr_match_bydevname, devname,
prev_cursor));
}
/**
* Initialize the sensor package, called through SYSINIT. Note, this function
* will assert if called directly, and _NOT_ through the sysinit package.
*/
void
sensor_pkg_init(void)
{
sensor_mgr_init();
#if MYNEWT_VAL(SENSOR_CLI)
sensor_shell_register();
#endif
}
/**
* Lock access to the sensor_itf specified by si. Blocks until lock acquired.
*
* @param The sensor_itf to lock
* @param The timeout
*
* @return 0 on success, non-zero on failure.
*/
int
sensor_itf_lock(struct sensor_itf *si, uint32_t timeout)
{
int rc;
os_time_t ticks;
if (!si->si_lock) {
return 0;
}
rc = os_time_ms_to_ticks(timeout, &ticks);
if (rc) {
return rc;
}
rc = os_mutex_pend(si->si_lock, ticks);
if (rc == 0 || rc == OS_NOT_STARTED) {
return (0);
}
return (rc);
}
/**
* Unlock access to the sensor_itf specified by si.
*
* @param The sensor_itf to unlock access to
*
* @return 0 on success, non-zero on failure.
*/
void
sensor_itf_unlock(struct sensor_itf *si)
{
if (!si->si_lock) {
return;
}
os_mutex_release(si->si_lock);
}
/**
* Lock access to the sensor specified by sensor. Blocks until lock acquired.
*
* @param The sensor to lock
*
* @return 0 on success, non-zero on failure.
*/
int
sensor_lock(struct sensor *sensor)
{
int rc;
rc = os_mutex_pend(&sensor->s_lock, OS_TIMEOUT_NEVER);
if (rc == 0 || rc == OS_NOT_STARTED) {
return (0);
}
return (rc);
}
/**
* Unlock access to the sensor specified by sensor.
*
* @param The sensor to unlock access to.
*/
void
sensor_unlock(struct sensor *sensor)
{
os_mutex_release(&sensor->s_lock);
}
/**
* Initialize a sensor
*
* @param The sensor to initialize
* @param The device to associate with this sensor.
*
* @return 0 on success, non-zero error code on failure.
*/
int
sensor_init(struct sensor *sensor, struct os_dev *dev)
{
int rc;
memset(sensor, 0, sizeof(*sensor));
rc = os_mutex_init(&sensor->s_lock);
if (rc != 0) {
goto err;
}
sensor->s_dev = dev;
return (0);
err:
return (rc);
}
/**
* Register a sensor listener. This allows a calling application to receive
* callbacks for data from a given sensor object.
*
* For more information on the type of callbacks available, see the documentation
* for the sensor listener structure.
*
* @param The sensor to register a listener on
* @param The listener to register onto the sensor
*
* @return 0 on success, non-zero error code on failure.
*/
int
sensor_register_listener(struct sensor *sensor,
struct sensor_listener *listener)
{
int rc;
rc = sensor_lock(sensor);
if (rc != 0) {
goto err;
}
SLIST_INSERT_HEAD(&sensor->s_listener_list, listener, sl_next);
sensor_unlock(sensor);
return (0);
err:
return (rc);
}
/**
* Un-register a sensor listener. This allows a calling application to unset
* callbacks for a given sensor object.
*
* @param The sensor object
* @param The listener to remove from the sensor listener list
*
* @return 0 on success, non-zero error code on failure.
*/
int
sensor_unregister_listener(struct sensor *sensor,
struct sensor_listener *listener)
{
int rc;
struct sensor_listener *tmp;
rc = sensor_lock(sensor);
if (rc != 0) {
goto err;
}
SLIST_FOREACH(tmp, &sensor->s_listener_list, sl_next) {
if (listener == tmp) {
/* Remove this entry from the list */
SLIST_REMOVE(&sensor->s_listener_list, listener, sensor_listener,
sl_next);
break;
}
}
sensor_unlock(sensor);
return (0);
err:
return (rc);
}
int
sensor_register_err_func(struct sensor *sensor, sensor_error_func_t err_fn,
void *arg)
{
int rc;
rc = sensor_lock(sensor);
if (rc != 0) {
goto err;
}
sensor->s_err_fn = err_fn;
sensor->s_err_arg = arg;
sensor_unlock(sensor);
return (0);
err:
return (rc);
}
static int
sensor_set_notification(struct sensor *sensor, struct sensor_notifier *notifier)
{
int rc;
if (sensor->s_funcs->sd_set_notification) {
rc = sensor->s_funcs->sd_set_notification(sensor,
notifier->sn_sensor_event_type);
} else {
rc = SYS_ENODEV;
}
return rc;
}
/**
* Register a sensor notifier. This allows a calling application to receive
* callbacks any time a requested event is observed.
*
* @param The sensor to register the notifier on
* @param The notifier to register
*
* @return 0 on success, non-zero error code on failure.
*/
int
sensor_register_notifier(struct sensor *sensor,
struct sensor_notifier *notifier)
{
int rc;
struct sensor_notifier *tmp;
rc = sensor_lock(sensor);
if (rc != 0) {
goto err;
}
/* Check if notifier is not already on the list */
SLIST_FOREACH(tmp, &sensor->s_notifier_list, sn_next) {
if (notifier == tmp) {
rc = SYS_EINVAL;
goto err;
}
}
SLIST_INSERT_HEAD(&sensor->s_notifier_list, notifier, sn_next);
rc = sensor_set_notification(sensor, notifier);
if (rc != 0) {
goto remove;
}
sensor_unlock(sensor);
return (0);
remove:
SLIST_REMOVE(&sensor->s_notifier_list, notifier, sensor_notifier,
sn_next);
err:
sensor_unlock(sensor);
return (rc);
}
/**
* Un-register a sensor notifier. This allows a calling application to stop
* receiving callbacks for events on the sensor object.
*
* @param The sensor object to un-register the notifier on
* @param The notifier to remove from the notification list
*
* @return 0 on success, non-zero error code on failure.
*/
int
sensor_unregister_notifier(struct sensor *sensor,
struct sensor_notifier *notifier)
{
int rc = 0;
struct sensor_notifier *tmp;
rc = sensor_lock(sensor);
if (rc != 0) {
goto done;
}
SLIST_FOREACH(tmp, &sensor->s_notifier_list, sn_next) {
if (notifier == tmp) {
SLIST_REMOVE(&sensor->s_notifier_list, notifier, sensor_notifier,
sn_next);
break;
}
}
sensor_unlock(sensor);
if (sensor->s_funcs->sd_unset_notification) {
rc = sensor->s_funcs->sd_unset_notification(sensor,
notifier->sn_sensor_event_type);
}
done:
return (rc);
}
static int
sensor_read_data_func(struct sensor *sensor, void *arg, void *data,
sensor_type_t type)
{
struct sensor_listener *listener;
struct sensor_read_ctx *ctx;
ctx = (struct sensor_read_ctx *) arg;
if ((uint8_t)(uintptr_t)(ctx->user_arg) != SENSOR_IGN_LISTENER) {
/* Notify all listeners first */
SLIST_FOREACH(listener, &sensor->s_listener_list, sl_next) {
if (listener->sl_sensor_type & type) {
listener->sl_func(sensor, listener->sl_arg, data, type);
}
}
}
/* Call data function */
if (ctx->user_func != NULL) {
return (ctx->user_func(sensor, ctx->user_arg, data, type));
}
return (0);
}
/**
* Puts a interrupt event on the sensor manager evq
*
* @param interrupt event context
*/
void
sensor_mgr_put_interrupt_evt(struct sensor *sensor)
{
sensor->s_interrupt_evt.ev_arg = sensor;
sensor->s_interrupt_evt.ev_cb = sensor_interrupt_ev_cb;
os_eventq_put(sensor_mgr_evq_get(), &sensor->s_interrupt_evt);
}
/**
* Puts a notification event on the sensor manager evq
*
* @param ctx notification event context
* @param evtype The notification event type
*/
void
sensor_mgr_put_notify_evt(struct sensor_notify_ev_ctx *ctx,
sensor_event_type_t evtype)
{
struct sensor_notify_os_ev *snoe = os_memblock_get(&sensor_notify_evt_pool);
if (!snoe) {
/* no free events */
return;
}
*snoe = (struct sensor_notify_os_ev) {
.snoe_evt = {
.ev_arg = snoe,
.ev_cb = sensor_notify_ev_cb,
},
.snoe_evtype = evtype,
.snoe_sensor = ctx->snec_sensor,
};
os_eventq_put(sensor_mgr_evq_get(), &(snoe->snoe_evt));
}
/**
* Puts read event on the sensor manager evq
*
* @param arg Event argument
*/
void
sensor_mgr_put_read_evt(void *arg)
{
sensor_read_event.ev_arg = arg;
os_eventq_put(sensor_mgr_evq_get(), &sensor_read_event);
}
static void
sensor_interrupt_ev_cb(struct os_event *ev)
{
struct sensor *sensor;
sensor = ev->ev_arg;
if (sensor && sensor->s_funcs->sd_handle_interrupt) {
sensor->s_funcs->sd_handle_interrupt(sensor);
}
}
static void
sensor_notify_ev_cb(struct os_event * ev)
{
struct sensor_notify_os_ev *snoe;
const struct sensor_notifier *notifier;
snoe = ev->ev_arg;
SLIST_FOREACH(notifier, &snoe->snoe_sensor->s_notifier_list, sn_next) {
if (notifier->sn_sensor_event_type & snoe->snoe_evtype) {
notifier->sn_func(snoe->snoe_sensor,
notifier->sn_arg,
snoe->snoe_evtype);
break;
}
}
/* Put notify os event back into the pool */
os_memblock_put(&sensor_notify_evt_pool, snoe);
}
static void
sensor_read_ev_cb(struct os_event *ev)
{
int rc;
struct sensor_type_traits *stt;
stt = ev->ev_arg;
rc = sensor_read(stt->stt_sensor, stt->stt_sensor_type, NULL, NULL,
OS_TIMEOUT_NEVER);
assert(rc == 0);
}
static void
sensor_up_timestamp(struct sensor *sensor)
{
uint32_t curr_ts_ticks;
uint32_t ts;
curr_ts_ticks = os_cputime_get32();
ts = os_cputime_ticks_to_usecs(curr_ts_ticks -
sensor_base_ts.st_cputime);
/* Updating cputime */
sensor_base_ts.st_cputime = sensor->s_sts.st_cputime = curr_ts_ticks;
/* Updating seconds */
sensor_base_ts.st_ostv.tv_sec = sensor_base_ts.st_ostv.tv_sec + (ts +
sensor_base_ts.st_ostv.tv_usec)/1000000;
sensor->s_sts.st_ostv.tv_sec = sensor_base_ts.st_ostv.tv_sec;
/* Updating Micro seconds */
sensor_base_ts.st_ostv.tv_usec =
(sensor_base_ts.st_ostv.tv_usec + ts)%1000000;
sensor->s_sts.st_ostv.tv_usec = sensor_base_ts.st_ostv.tv_usec;
}
/**
* Get the type traits for a sensor
*
* @param name of the sensor
* @param Ptr to sensor types trait struct
* @param type of sensor
*
* @return NULL on failure, sensor struct on success
*/
struct sensor *
sensor_get_type_traits_byname(char *devname, struct sensor_type_traits **stt,
sensor_type_t type)
{
struct sensor *sensor;
sensor = sensor_mgr_find_next_bydevname(devname, NULL);
if (!sensor) {
goto err;
}
*stt = sensor_get_type_traits_bytype(type, sensor);
err:
return sensor;
}
static uint8_t
sensor_window_cmp_quat(struct sensor_quat_data *d_sqd,
struct sensor_quat_data *h_sqd,
struct sensor_quat_data *l_sqd)
{
uint8_t trigger;
trigger = 0;
trigger =
(SENSOR_DATA_CMP_LT(d_sqd, h_sqd, sqd_x) &&
SENSOR_DATA_CMP_GT(d_sqd, l_sqd, sqd_x));
trigger |=
(SENSOR_DATA_CMP_LT(d_sqd, h_sqd, sqd_y) &&
SENSOR_DATA_CMP_GT(d_sqd, l_sqd, sqd_y));
trigger |=
(SENSOR_DATA_CMP_LT(d_sqd, h_sqd, sqd_z) &&
SENSOR_DATA_CMP_GT(d_sqd, l_sqd, sqd_z));
return trigger;
}
static uint8_t
sensor_window_cmp_accel(struct sensor_accel_data *d_sad,
struct sensor_accel_data *h_sad,
struct sensor_accel_data *l_sad)
{
uint8_t trigger;
trigger = 0;
trigger =
(SENSOR_DATA_CMP_LT(d_sad, h_sad, sad_x) &&
SENSOR_DATA_CMP_GT(d_sad, l_sad, sad_x));
trigger |=
(SENSOR_DATA_CMP_LT(d_sad, h_sad, sad_y) &&
SENSOR_DATA_CMP_GT(d_sad, l_sad, sad_y));
trigger |=
(SENSOR_DATA_CMP_LT(d_sad, h_sad, sad_z) &&
SENSOR_DATA_CMP_GT(d_sad, l_sad, sad_z));
return trigger;
}
static uint8_t
sensor_window_cmp_euler(struct sensor_euler_data *d_sed,
struct sensor_euler_data *h_sed,
struct sensor_euler_data *l_sed)
{
uint8_t trigger;
trigger = 0;
trigger =
(SENSOR_DATA_CMP_LT(d_sed, h_sed, sed_h) &&
SENSOR_DATA_CMP_GT(d_sed, l_sed, sed_h));
trigger |=
(SENSOR_DATA_CMP_LT(d_sed, h_sed, sed_r) &&
SENSOR_DATA_CMP_GT(d_sed, l_sed, sed_r));
trigger |=
(SENSOR_DATA_CMP_LT(d_sed, h_sed, sed_p) &&
SENSOR_DATA_CMP_GT(d_sed, l_sed, sed_p));
return trigger;
}
static uint8_t
sensor_window_cmp_gyro(struct sensor_gyro_data *d_sgd,
struct sensor_gyro_data *h_sgd,
struct sensor_gyro_data *l_sgd)
{
uint8_t trigger;
trigger = 0;
trigger =
(SENSOR_DATA_CMP_LT(d_sgd, h_sgd, sgd_x) &&
SENSOR_DATA_CMP_GT(d_sgd, l_sgd, sgd_x));
trigger |=
(SENSOR_DATA_CMP_LT(d_sgd, h_sgd, sgd_y) &&
SENSOR_DATA_CMP_GT(d_sgd, l_sgd, sgd_y));
trigger |=
(SENSOR_DATA_CMP_LT(d_sgd, h_sgd, sgd_z) &&
SENSOR_DATA_CMP_GT(d_sgd, l_sgd, sgd_z));
return trigger;
}
static uint8_t
sensor_window_cmp_mag(struct sensor_mag_data *d_smd,
struct sensor_mag_data *h_smd,
struct sensor_mag_data *l_smd)
{
uint8_t trigger;
trigger = 0;
trigger =
(SENSOR_DATA_CMP_LT(d_smd, h_smd, smd_x) &&
SENSOR_DATA_CMP_GT(d_smd, l_smd, smd_x));
trigger |=
(SENSOR_DATA_CMP_LT(d_smd, h_smd, smd_y) &&
SENSOR_DATA_CMP_GT(d_smd, l_smd, smd_y));
trigger |=
(SENSOR_DATA_CMP_LT(d_smd, h_smd, smd_z) &&
SENSOR_DATA_CMP_GT(d_smd, l_smd, smd_z));
return trigger;
}
static uint8_t
sensor_window_cmp_temp(struct sensor_temp_data *d_std,
struct sensor_temp_data *h_std,
struct sensor_temp_data *l_std)
{
uint8_t trigger;
trigger = 0;
trigger |=
(SENSOR_DATA_CMP_LT(d_std, h_std, std_temp) &&
SENSOR_DATA_CMP_GT(d_std, l_std, std_temp));
return trigger;
}
static uint8_t
sensor_window_cmp_light(struct sensor_light_data *d_sld,
struct sensor_light_data *h_sld,
struct sensor_light_data *l_sld)
{
uint8_t trigger;
trigger = 0;
trigger =
(SENSOR_DATA_CMP_LT(d_sld, h_sld, sld_full) &&
SENSOR_DATA_CMP_GT(d_sld, l_sld, sld_full));
trigger |=
(SENSOR_DATA_CMP_LT(d_sld, h_sld, sld_ir) &&
SENSOR_DATA_CMP_GT(d_sld, l_sld, sld_ir));
trigger |=
(SENSOR_DATA_CMP_LT(d_sld, h_sld, sld_lux) &&
SENSOR_DATA_CMP_GT(d_sld, l_sld, sld_lux));
return trigger;
}
static uint8_t
sensor_window_cmp_color(struct sensor_color_data *d_scd,
struct sensor_color_data *h_scd,
struct sensor_color_data *l_scd)
{
uint8_t trigger;
trigger = 0;
trigger =
(SENSOR_DATA_CMP_LT(d_scd, h_scd, scd_r) &&
SENSOR_DATA_CMP_GT(d_scd, l_scd, scd_r));
trigger |=
(SENSOR_DATA_CMP_LT(d_scd, h_scd, scd_g) &&
SENSOR_DATA_CMP_GT(d_scd, l_scd, scd_g));
trigger |=
(SENSOR_DATA_CMP_LT(d_scd, h_scd, scd_b) &&
SENSOR_DATA_CMP_GT(d_scd, l_scd, scd_b));
trigger |=
(SENSOR_DATA_CMP_LT(d_scd, h_scd, scd_c) &&
SENSOR_DATA_CMP_GT(d_scd, l_scd, scd_c));
trigger |=
(SENSOR_DATA_CMP_LT(d_scd, h_scd, scd_lux) &&
SENSOR_DATA_CMP_GT(d_scd, l_scd, scd_lux));
trigger |=
(SENSOR_DATA_CMP_LT(d_scd, h_scd, scd_colortemp) &&
SENSOR_DATA_CMP_GT(d_scd, l_scd, scd_colortemp));
trigger |=
(SENSOR_DATA_CMP_LT(d_scd, h_scd, scd_ir) &&
SENSOR_DATA_CMP_GT(d_scd, l_scd, scd_ir));
return trigger;
}
static uint8_t
sensor_window_cmp_press(struct sensor_press_data *d_spd,
struct sensor_press_data *h_spd,
struct sensor_press_data *l_spd)
{
uint8_t trigger;
trigger = 0;
trigger =
(SENSOR_DATA_CMP_LT(d_spd, h_spd, spd_press) &&
SENSOR_DATA_CMP_GT(d_spd, l_spd, spd_press));
return trigger;
}
static uint8_t
sensor_window_cmp_humid(struct sensor_humid_data *d_shd,
struct sensor_humid_data *h_shd,
struct sensor_humid_data *l_shd)
{
uint8_t trigger;
trigger = 0;
trigger =
(SENSOR_DATA_CMP_LT(d_shd, h_shd, shd_humid) &&
SENSOR_DATA_CMP_GT(d_shd, l_shd, shd_humid));
return trigger;
}
static int
sensor_window_cmp(sensor_type_t type, sensor_data_t *low, sensor_data_t *high,
void *data)
{
uint8_t trigger;
sensor_data_t dptr;
trigger = 0;
switch(type) {
case SENSOR_TYPE_ROTATION_VECTOR:
dptr.sqd = data;
trigger = sensor_window_cmp_quat(dptr.sqd, high->sqd, low->sqd);
break;
case SENSOR_TYPE_ACCELEROMETER:
dptr.sad = data;
trigger = sensor_window_cmp_accel(dptr.sad, high->sad, low->sad);
break;
case SENSOR_TYPE_LINEAR_ACCEL:
dptr.slad = data;
trigger = sensor_window_cmp_accel(dptr.slad, high->slad, low->slad);
break;
case SENSOR_TYPE_EULER:
dptr.sed = data;
trigger = sensor_window_cmp_euler(dptr.sed, high->sed, low->sed);
break;
case SENSOR_TYPE_GYROSCOPE:
dptr.sgd = data;
trigger = sensor_window_cmp_gyro(dptr.sgd, high->sgd, low->sgd);
break;
case SENSOR_TYPE_GRAVITY:
dptr.sgrd = data;
trigger = sensor_window_cmp_accel(dptr.sgrd, high->sgrd, low->sgrd);
break;
case SENSOR_TYPE_MAGNETIC_FIELD:
dptr.smd = data;
trigger = sensor_window_cmp_mag(dptr.smd, high->smd, low->smd);
break;
case SENSOR_TYPE_TEMPERATURE:
dptr.std = data;
trigger = sensor_window_cmp_temp(dptr.std, high->std, low->std);
break;
case SENSOR_TYPE_AMBIENT_TEMPERATURE:
dptr.satd = data;
trigger = sensor_window_cmp_temp(dptr.satd, high->satd, low->satd);
break;
case SENSOR_TYPE_LIGHT:
dptr.sld = data;
trigger = sensor_window_cmp_light(dptr.sld, high->sld, low->sld);
break;
case SENSOR_TYPE_COLOR:
dptr.scd = data;
trigger = sensor_window_cmp_color(dptr.scd, high->scd, low->scd);
break;
case SENSOR_TYPE_PRESSURE:
dptr.spd = data;
trigger = sensor_window_cmp_press(dptr.spd, high->spd, low->spd);
break;
case SENSOR_TYPE_RELATIVE_HUMIDITY:
dptr.srhd = data;
trigger = sensor_window_cmp_humid(dptr.srhd, high->srhd, low->srhd);
break;
case SENSOR_TYPE_PROXIMITY:
/* Falls Through */
case SENSOR_TYPE_WEIGHT:
/* Falls Through */
case SENSOR_TYPE_ALTITUDE:
/* Falls Through */
case SENSOR_TYPE_NONE:
/* Falls Through */
default:
break;
}
return trigger;
}
static uint8_t
sensor_watermark_cmp_quat(struct sensor_quat_data *d_sqd,
struct sensor_quat_data *h_sqd,
struct sensor_quat_data *l_sqd)
{
uint8_t trigger;
trigger = 0;
trigger =
(SENSOR_DATA_CMP_LT(d_sqd, l_sqd, sqd_x) ||
SENSOR_DATA_CMP_GT(d_sqd, h_sqd, sqd_x));
trigger |=
(SENSOR_DATA_CMP_LT(d_sqd, l_sqd, sqd_y) ||
SENSOR_DATA_CMP_GT(d_sqd, h_sqd, sqd_y));
trigger |=
(SENSOR_DATA_CMP_LT(d_sqd, l_sqd, sqd_z) ||
SENSOR_DATA_CMP_GT(d_sqd, h_sqd, sqd_z));
return trigger;
}
static uint8_t
sensor_watermark_cmp_accel(struct sensor_accel_data *d_sad,
struct sensor_accel_data *h_sad,
struct sensor_accel_data *l_sad)
{
uint8_t trigger;
trigger = 0;
trigger =
(SENSOR_DATA_CMP_LT(d_sad, l_sad, sad_x) ||
SENSOR_DATA_CMP_GT(d_sad, h_sad, sad_x));
trigger |=
(SENSOR_DATA_CMP_LT(d_sad, l_sad, sad_y) ||
SENSOR_DATA_CMP_GT(d_sad, h_sad, sad_y));
trigger |=
(SENSOR_DATA_CMP_LT(d_sad, l_sad, sad_z) ||
SENSOR_DATA_CMP_GT(d_sad, h_sad, sad_z));
return trigger;
}
static uint8_t
sensor_watermark_cmp_euler(struct sensor_euler_data *d_sed,
struct sensor_euler_data *h_sed,
struct sensor_euler_data *l_sed)
{
uint8_t trigger;
trigger = 0;
trigger =
(SENSOR_DATA_CMP_LT(d_sed, l_sed, sed_h) ||
SENSOR_DATA_CMP_GT(d_sed, h_sed, sed_h));
trigger |=
(SENSOR_DATA_CMP_LT(d_sed, l_sed, sed_r) ||
SENSOR_DATA_CMP_GT(d_sed, h_sed, sed_r));
trigger |=
(SENSOR_DATA_CMP_LT(d_sed, l_sed, sed_p) ||
SENSOR_DATA_CMP_GT(d_sed, h_sed, sed_p));
return trigger;
}
static uint8_t
sensor_watermark_cmp_gyro(struct sensor_gyro_data *d_sgd,
struct sensor_gyro_data *h_sgd,
struct sensor_gyro_data *l_sgd)
{
uint8_t trigger;
trigger = 0;
trigger =
(SENSOR_DATA_CMP_LT(d_sgd, l_sgd, sgd_x) ||
SENSOR_DATA_CMP_GT(d_sgd, h_sgd, sgd_x));
trigger |=
(SENSOR_DATA_CMP_LT(d_sgd, l_sgd, sgd_y) ||
SENSOR_DATA_CMP_GT(d_sgd, h_sgd, sgd_y));
trigger |=
(SENSOR_DATA_CMP_LT(d_sgd, l_sgd, sgd_z) ||
SENSOR_DATA_CMP_GT(d_sgd, h_sgd, sgd_z));
return trigger;
}
static uint8_t
sensor_watermark_cmp_mag(struct sensor_mag_data *d_smd,
struct sensor_mag_data *h_smd,
struct sensor_mag_data *l_smd)
{
uint8_t trigger;
trigger = 0;
trigger =
(SENSOR_DATA_CMP_LT(d_smd, l_smd, smd_x) ||
SENSOR_DATA_CMP_GT(d_smd, h_smd, smd_x));
trigger |=
(SENSOR_DATA_CMP_LT(d_smd, l_smd, smd_y) ||
SENSOR_DATA_CMP_GT(d_smd, h_smd, smd_y));
trigger |=
(SENSOR_DATA_CMP_LT(d_smd, l_smd, smd_z) ||
SENSOR_DATA_CMP_GT(d_smd, h_smd, smd_z));
return trigger;
}
static uint8_t
sensor_watermark_cmp_temp(struct sensor_temp_data *d_std,
struct sensor_temp_data *h_std,
struct sensor_temp_data *l_std)
{
uint8_t trigger;
trigger = 0;
trigger =
(SENSOR_DATA_CMP_LT(d_std, l_std, std_temp) ||
SENSOR_DATA_CMP_GT(d_std, h_std, std_temp));
return trigger;
}
static uint8_t
sensor_watermark_cmp_light(struct sensor_light_data *d_sld,
struct sensor_light_data *h_sld,
struct sensor_light_data *l_sld)
{
uint8_t trigger;
trigger = 0;
trigger =
(SENSOR_DATA_CMP_LT(d_sld, l_sld, sld_full) ||
SENSOR_DATA_CMP_GT(d_sld, h_sld, sld_full));
trigger |=
(SENSOR_DATA_CMP_LT(d_sld, l_sld, sld_ir) ||
SENSOR_DATA_CMP_GT(d_sld, h_sld, sld_ir));
trigger |=
(SENSOR_DATA_CMP_LT(d_sld, l_sld, sld_lux) ||
SENSOR_DATA_CMP_GT(d_sld, h_sld, sld_lux));
return trigger;
}
static uint8_t
sensor_watermark_cmp_color(struct sensor_color_data *d_scd,
struct sensor_color_data *h_scd,
struct sensor_color_data *l_scd)
{
uint8_t trigger;
trigger = 0;
trigger =
(SENSOR_DATA_CMP_LT(d_scd, l_scd, scd_r) ||
SENSOR_DATA_CMP_GT(d_scd, h_scd, scd_r));
trigger |=
(SENSOR_DATA_CMP_LT(d_scd, l_scd, scd_g) ||
SENSOR_DATA_CMP_GT(d_scd, h_scd, scd_g));
trigger |=
(SENSOR_DATA_CMP_LT(d_scd, l_scd, scd_b) ||
SENSOR_DATA_CMP_GT(d_scd, h_scd, scd_b));
trigger |=
(SENSOR_DATA_CMP_LT(d_scd, l_scd, scd_c) ||
SENSOR_DATA_CMP_GT(d_scd, h_scd, scd_c));
trigger |=
(SENSOR_DATA_CMP_LT(d_scd, l_scd, scd_lux) ||
SENSOR_DATA_CMP_GT(d_scd, h_scd, scd_lux));
trigger |=
(SENSOR_DATA_CMP_LT(d_scd, l_scd, scd_colortemp) ||
SENSOR_DATA_CMP_GT(d_scd, h_scd, scd_colortemp));
trigger |=
(SENSOR_DATA_CMP_LT(d_scd, l_scd, scd_ir) ||
SENSOR_DATA_CMP_GT(d_scd, h_scd, scd_ir));
return trigger;
}
static uint8_t
sensor_watermark_cmp_press(struct sensor_press_data *d_spd,
struct sensor_press_data *h_spd,
struct sensor_press_data *l_spd)
{
uint8_t trigger;
trigger = 0;
trigger =
(SENSOR_DATA_CMP_LT(d_spd, l_spd, spd_press) ||
SENSOR_DATA_CMP_GT(d_spd, h_spd, spd_press));
return trigger;
}
static uint8_t
sensor_watermark_cmp_humid(struct sensor_humid_data *d_shd,
struct sensor_humid_data *h_shd,
struct sensor_humid_data *l_shd)
{
uint8_t trigger;
trigger = 0;
trigger =
(SENSOR_DATA_CMP_LT(d_shd, l_shd, shd_humid) ||
SENSOR_DATA_CMP_GT(d_shd, h_shd, shd_humid));
return trigger;
}
static int
sensor_watermark_cmp(sensor_type_t type, sensor_data_t *low, sensor_data_t *high,
void *data)
{
uint8_t trigger;
sensor_data_t dptr;
trigger = 0;
switch(type) {
case SENSOR_TYPE_ROTATION_VECTOR:
dptr.sqd = data;
trigger = sensor_watermark_cmp_quat(dptr.sqd, high->sqd,
low->sqd);
break;
case SENSOR_TYPE_ACCELEROMETER:
dptr.sad = data;
trigger = sensor_watermark_cmp_accel(dptr.sad, high->sad,
low->sad);
break;
case SENSOR_TYPE_LINEAR_ACCEL:
dptr.slad = data;
trigger = sensor_watermark_cmp_accel(dptr.slad, high->slad,
low->slad);
break;
case SENSOR_TYPE_EULER:
dptr.sed = data;
trigger = sensor_watermark_cmp_euler(dptr.sed, high->sed,
low->sed);
break;
case SENSOR_TYPE_GYROSCOPE:
dptr.sgd = data;
trigger = sensor_watermark_cmp_gyro(dptr.sgd, high->sgd,
low->sgd);
break;
case SENSOR_TYPE_GRAVITY:
dptr.sgrd = data;
trigger = sensor_watermark_cmp_accel(dptr.sgrd, high->sgrd,
low->sgrd);
break;
case SENSOR_TYPE_MAGNETIC_FIELD:
dptr.smd = data;
trigger = sensor_watermark_cmp_mag(dptr.smd, high->smd,
low->smd);
break;
case SENSOR_TYPE_TEMPERATURE:
dptr.std = data;
trigger = sensor_watermark_cmp_temp(dptr.std, high->std,
low->std);
break;
case SENSOR_TYPE_AMBIENT_TEMPERATURE:
dptr.satd = data;
trigger = sensor_watermark_cmp_temp(dptr.satd, high->satd,
low->satd);
break;
case SENSOR_TYPE_LIGHT:
dptr.sld = data;
trigger = sensor_watermark_cmp_light(dptr.sld, high->sld,
low->sld);
break;
case SENSOR_TYPE_COLOR:
dptr.scd = data;
trigger = sensor_watermark_cmp_color(dptr.scd, high->scd,
low->scd);
break;
case SENSOR_TYPE_PRESSURE:
dptr.spd = data;
trigger = sensor_watermark_cmp_press(dptr.spd, high->spd,
low->spd);
break;
case SENSOR_TYPE_RELATIVE_HUMIDITY:
dptr.srhd = data;
trigger = sensor_watermark_cmp_humid(dptr.srhd, high->srhd,
low->srhd);
break;
case SENSOR_TYPE_PROXIMITY:
/* Falls Through */
case SENSOR_TYPE_WEIGHT:
/* Falls Through */
case SENSOR_TYPE_ALTITUDE:
/* Falls Through */
case SENSOR_TYPE_NONE:
/* Falls Through */
default:
break;
}
return trigger;
}
static void
sensor_set_trigger_cmp_algo(struct sensor *sensor, struct sensor_type_traits *stt)
{
sensor_lock(sensor);
if (stt->stt_algo == SENSOR_THRESH_ALGO_WATERMARK) {
/* select watermark comparison algo */
stt->stt_trigger_cmp_algo = sensor_watermark_cmp;
} else if (stt->stt_algo == SENSOR_THRESH_ALGO_WINDOW) {
/* select window comparison algo */
stt->stt_trigger_cmp_algo = sensor_window_cmp;
} else if (stt->stt_algo == SENSOR_THRESH_ALGO_USERDEF) {
/* select user defined comparison algo if any */
stt->stt_trigger_cmp_algo = stt->stt_trigger_cmp_algo;
}
sensor_unlock(sensor);
}
/**
* Set the thresholds along with comparison algo for a sensor
*
* @param devname Name of the sensor
* @param stt Ptr to sensor threshold
*
* @return 0 on success, non-zero on failure
*/
int
sensor_set_thresh(char *devname, struct sensor_type_traits *stt)
{
struct sensor_type_traits *stt_tmp;
struct sensor *sensor;
int rc;
sensor = sensor_get_type_traits_byname(devname, &stt_tmp,
stt->stt_sensor_type);
if (!sensor) {
rc = SYS_EINVAL;
goto err;
}
if (!stt_tmp && stt) {
rc = sensor_insert_type_trait(sensor, stt);
stt_tmp = stt;
} else if (stt_tmp) {
rc = sensor_lock(sensor);
if (rc) {
goto err;
}
stt_tmp->stt_low_thresh = stt->stt_low_thresh;
stt_tmp->stt_high_thresh = stt->stt_high_thresh;
stt_tmp->stt_algo = stt->stt_algo;
stt_tmp->stt_sensor = sensor;
sensor_unlock(sensor);
} else {
rc = SYS_EINVAL;
goto err;
}
sensor_set_trigger_cmp_algo(sensor, stt_tmp);
rc = sensor_lock(sensor);
if (rc) {
goto err;
}
if (sensor->s_funcs->sd_set_trigger_thresh) {
rc = sensor->s_funcs->sd_set_trigger_thresh(sensor,
stt_tmp->stt_sensor_type,
stt_tmp);
if (rc) {
sensor_unlock(sensor);
goto err;
}
}
sensor_unlock(sensor);
return 0;
err:
return rc;
}
/**
* Clear the low threshold for a sensor
*
* @param name of the sensor
* @param sensor type
*
* @return 0 on success, non-zero on failure
*/
int
sensor_clear_low_thresh(char *devname, sensor_type_t type)
{
struct sensor *sensor;
struct sensor_type_traits *stt_tmp;
int rc;
sensor = sensor_get_type_traits_byname(devname, &stt_tmp, type);
if (!sensor || !stt_tmp) {
rc = SYS_EINVAL;
goto err;
}
rc = sensor_lock(sensor);
if (rc) {
goto err;
}
if (sensor->s_funcs->sd_clear_low_trigger_thresh) {
rc = sensor->s_funcs->sd_clear_low_trigger_thresh(sensor, type);
if (rc) {
sensor_unlock(sensor);
goto err;
}
}
sensor_unlock(sensor);
return 0;
err:
return rc;
}
/**
* Clear the high threshold for a sensor
*
* @param name of the sensor
* @param sensor type
*
* @return 0 on success, non-zero on failure
*/
int
sensor_clear_high_thresh(char *devname, sensor_type_t type)
{
struct sensor *sensor;
struct sensor_type_traits *stt_tmp;
int rc;
sensor = sensor_get_type_traits_byname(devname, &stt_tmp, type);
if (!sensor || !stt_tmp) {
rc = SYS_EINVAL;
goto err;
}
rc = sensor_lock(sensor);
if (rc) {
goto err;
}
if (sensor->s_funcs->sd_clear_high_trigger_thresh) {
rc = sensor->s_funcs->sd_clear_high_trigger_thresh(sensor, type);
if (rc) {
sensor_unlock(sensor);
goto err;
}
}
sensor_unlock(sensor);
return 0;
err:
return rc;
}
static int
sensor_generate_trig(struct sensor *sensor,
void *arg, void *data,
sensor_type_t type)
{
struct sensor_type_traits *stt;
sensor_data_t low_thresh;
sensor_data_t high_thresh;
uint8_t tx_trigger;
sensor_trigger_notify_func_t notify;
if (!arg) {
return SYS_EINVAL;
}
notify = arg;
stt = sensor_get_type_traits_bytype(type, sensor);
tx_trigger = 0;
memcpy(&low_thresh, &stt->stt_low_thresh, sizeof(low_thresh));
memcpy(&high_thresh, &stt->stt_high_thresh, sizeof(high_thresh));
if (stt->stt_trigger_cmp_algo) {
tx_trigger = stt->stt_trigger_cmp_algo(type, &low_thresh,
&high_thresh, data);
}
return tx_trigger ? notify(sensor, data, type): 0;
}
/**
* Sensor trigger initialization
*
* @param ptr to the sensor sturucture
* @param sensor type to enable trigger for
* @param the function to call if the trigger condition is satisfied
*/
void
sensor_trigger_init(struct sensor *sensor, sensor_type_t type,
sensor_trigger_notify_func_t notify)
{
int rc;
struct sensor_listener *sensor_trig_lner;
sensor_trig_lner = malloc(sizeof(struct sensor_listener));
assert(sensor_trig_lner != NULL);
sensor_trig_lner->sl_func = sensor_generate_trig;
sensor_trig_lner->sl_sensor_type = type;
sensor_trig_lner->sl_arg = (void *)notify;
rc = sensor_register_listener(sensor, sensor_trig_lner);
if (rc) {
return;
}
}
/**
* Read the data for sensor type "type," from the given sensor and
* return the result into the "value" parameter.
*
* @param The sensor to read data from
* @param The type of sensor data to read from the sensor
* @param The callback to call for data returned from that sensor
* @param The argument to pass to this callback.
* @param Timeout before aborting sensor read
*
* @return 0 on success, non-zero on failure.
*/
int
sensor_read(struct sensor *sensor, sensor_type_t type,
sensor_data_func_t data_func, void *arg, uint32_t timeout)
{
struct sensor_read_ctx src;
int rc;
rc = sensor_lock(sensor);
if (rc) {
goto err;
}
src.user_func = data_func;
src.user_arg = arg;
if (!sensor_mgr_match_bytype(sensor, (void *)&type)) {
rc = SYS_ENOENT;
goto err;
}
sensor_up_timestamp(sensor);
rc = sensor->s_funcs->sd_read(sensor, type, sensor_read_data_func, &src,
timeout);
if (rc) {
if (sensor->s_err_fn != NULL) {
sensor->s_err_fn(sensor, sensor->s_err_arg, rc);
}
goto err;
}
err:
sensor_unlock(sensor);
return (rc);
}