common: Refactor motion_sense_fifo
This change refactors the motion_sense_fifo to uniformly prefix all the functions to avoid collisions. It also adds several unit tests and fixes a few bugs with the fifo logic. BUG=b:137758297 BRANCH=kukui TEST=buildall TEST=run CTS on arcada, kohaku, and kukui TEST=boot kohaku (verify tablet mode works as expected) Change-Id: I6e8492ae5fa474d0aa870088ab56f76b220a73e3 Signed-off-by: Yuval Peress <peress@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/1835221 Reviewed-by: Jack Rosenthal <jrosenth@chromium.org>
This commit is contained in:
parent
9f15135068
commit
083ced83d7
|
@ -78,6 +78,9 @@ static void print_spoof_mode_status(int id);
|
|||
/* Flags to control whether to send an ODR change event for a sensor */
|
||||
static uint32_t odr_event_required;
|
||||
|
||||
/* Whether or not the FIFO interrupt should be enabled (set from the AP). */
|
||||
__maybe_unused static int fifo_int_enabled;
|
||||
|
||||
static inline int motion_sensor_in_forced_mode(
|
||||
const struct motion_sensor_t *sensor)
|
||||
{
|
||||
|
@ -680,7 +683,7 @@ static int motion_sense_process(struct motion_sensor_t *sensor,
|
|||
int flush_pending = atomic_read_clear(&sensor->flush_pending);
|
||||
|
||||
for (; flush_pending > 0; flush_pending--) {
|
||||
motion_sense_insert_async_event(
|
||||
motion_sense_fifo_insert_async_event(
|
||||
sensor, ASYNC_EVENT_FLUSH);
|
||||
}
|
||||
}
|
||||
|
@ -690,7 +693,7 @@ static int motion_sense_process(struct motion_sensor_t *sensor,
|
|||
motion_sense_set_data_rate(sensor);
|
||||
motion_sense_set_motion_intervals();
|
||||
if (IS_ENABLED(CONFIG_ACCEL_FIFO))
|
||||
motion_sense_insert_async_event(
|
||||
motion_sense_fifo_insert_async_event(
|
||||
sensor, ASYNC_EVENT_ODR);
|
||||
}
|
||||
return ret;
|
||||
|
@ -905,25 +908,18 @@ void motion_sense_task(void *u)
|
|||
* - we haven't done it for a while.
|
||||
*/
|
||||
if (IS_ENABLED(CONFIG_ACCEL_FIFO) &&
|
||||
(motion_sense_fifo_is_wake_up_needed() ||
|
||||
(motion_sense_fifo_wake_up_needed() ||
|
||||
event & (TASK_EVENT_MOTION_ODR_CHANGE |
|
||||
TASK_EVENT_MOTION_FLUSH_PENDING) ||
|
||||
motion_sense_fifo_over_thres() ||
|
||||
(ap_event_interval > 0 &&
|
||||
time_after(ts_begin_task.le.lo,
|
||||
ts_last_int.le.lo + ap_event_interval)))) {
|
||||
if ((event & TASK_EVENT_MOTION_FLUSH_PENDING) == 0) {
|
||||
motion_sense_fifo_stage_timestamp(
|
||||
motion_sense_fifo_add_timestamp(
|
||||
__hw_clock_source_read());
|
||||
motion_sense_fifo_commit_data();
|
||||
}
|
||||
ts_last_int = ts_begin_task;
|
||||
/*
|
||||
* Count the number of event the AP is allowed to
|
||||
* collect.
|
||||
*/
|
||||
mutex_lock(&g_sensor_mutex);
|
||||
fifo_queue_count = queue_count(&motion_sense_fifo);
|
||||
mutex_unlock(&g_sensor_mutex);
|
||||
#ifdef CONFIG_MKBP_EVENT
|
||||
/*
|
||||
* Send an event if we know we are in S0 and the kernel
|
||||
|
@ -933,9 +929,9 @@ void motion_sense_task(void *u)
|
|||
*/
|
||||
if ((fifo_int_enabled &&
|
||||
sensor_active == SENSOR_ACTIVE_S0) ||
|
||||
wake_up_needed) {
|
||||
motion_sense_fifo_wake_up_needed()) {
|
||||
mkbp_send_event(EC_MKBP_EVENT_SENSOR_FIFO);
|
||||
wake_up_needed = 0;
|
||||
motion_sense_fifo_reset_wake_up_needed();
|
||||
}
|
||||
#endif /* CONFIG_MKBP_EVENT */
|
||||
}
|
||||
|
@ -1270,12 +1266,11 @@ static enum ec_status host_cmd_motion_sense(struct host_cmd_handler_args *args)
|
|||
args->response_size = sizeof(out->fifo_info);
|
||||
break;
|
||||
}
|
||||
motion_sense_get_fifo_info(&out->fifo_info);
|
||||
motion_sense_fifo_get_info(&out->fifo_info, 1);
|
||||
for (i = 0; i < motion_sensor_count; i++) {
|
||||
out->fifo_info.lost[i] = motion_sensors[i].lost;
|
||||
motion_sensors[i].lost = 0;
|
||||
}
|
||||
motion_sense_fifo_lost = 0;
|
||||
args->response_size = sizeof(out->fifo_info) +
|
||||
sizeof(uint16_t) * motion_sensor_count;
|
||||
break;
|
||||
|
@ -1283,17 +1278,12 @@ static enum ec_status host_cmd_motion_sense(struct host_cmd_handler_args *args)
|
|||
case MOTIONSENSE_CMD_FIFO_READ:
|
||||
if (!IS_ENABLED(CONFIG_ACCEL_FIFO))
|
||||
return EC_RES_INVALID_PARAM;
|
||||
mutex_lock(&g_sensor_mutex);
|
||||
reported = MIN((args->response_max - sizeof(out->fifo_read)) /
|
||||
motion_sense_fifo.unit_bytes,
|
||||
MIN(queue_count(&motion_sense_fifo),
|
||||
in->fifo_read.max_data_vector));
|
||||
reported = queue_remove_units(&motion_sense_fifo,
|
||||
out->fifo_read.data, reported);
|
||||
mutex_unlock(&g_sensor_mutex);
|
||||
out->fifo_read.number_data = reported;
|
||||
args->response_size = sizeof(out->fifo_read) + reported *
|
||||
motion_sense_fifo.unit_bytes;
|
||||
out->fifo_read.number_data = motion_sense_fifo_read(
|
||||
args->response_max - sizeof(out->fifo_read),
|
||||
in->fifo_read.max_data_vector,
|
||||
out->fifo_read.data,
|
||||
&(args->response_size));
|
||||
args->response_size += sizeof(out->fifo_read);
|
||||
break;
|
||||
case MOTIONSENSE_CMD_FIFO_INT_ENABLE:
|
||||
if (!IS_ENABLED(CONFIG_ACCEL_FIFO))
|
||||
|
|
|
@ -7,30 +7,14 @@
|
|||
#include "hwtimer.h"
|
||||
#include "mkbp_event.h"
|
||||
#include "motion_sense_fifo.h"
|
||||
#include "queue.h"
|
||||
#include "tablet_mode.h"
|
||||
#include "task.h"
|
||||
#include "util.h"
|
||||
|
||||
#define CPRINTS(format, args...) cprints(CC_MOTION_SENSE, format, ## args)
|
||||
|
||||
static inline int is_timestamp(struct ec_response_motion_sensor_data *data)
|
||||
{
|
||||
return data->flags & MOTIONSENSE_SENSOR_FLAG_TIMESTAMP;
|
||||
}
|
||||
|
||||
/* Need to wake up the AP */
|
||||
int wake_up_needed;
|
||||
|
||||
/* Number of element the AP should collect */
|
||||
int fifo_queue_count;
|
||||
int fifo_int_enabled;
|
||||
|
||||
struct queue motion_sense_fifo = QUEUE_NULL(
|
||||
CONFIG_ACCEL_FIFO_SIZE, struct ec_response_motion_sensor_data);
|
||||
int motion_sense_fifo_lost;
|
||||
|
||||
/**
|
||||
* Staged metadata for the motion_sense_fifo.
|
||||
* Staged metadata for the fifo queue.
|
||||
* @read_ts: The timestamp at which the staged data was read. This value will
|
||||
* serve as the upper bound for spreading
|
||||
* @count: The total number of motion_sense_fifo entries that are currently
|
||||
|
@ -46,15 +30,61 @@ struct fifo_staged {
|
|||
uint8_t sample_count[SENSOR_COUNT];
|
||||
uint8_t requires_spreading;
|
||||
};
|
||||
|
||||
/**
|
||||
* Timestamp state metadata for maintaining spreading between commits.
|
||||
* @prev: The previous timestamp that was added to the FIFO
|
||||
* @next: The predicted next timestamp that will be added to the FIFO
|
||||
*/
|
||||
struct timestamp_state {
|
||||
uint32_t prev;
|
||||
uint32_t next;
|
||||
};
|
||||
|
||||
/** Queue to hold the data to be sent to the AP. */
|
||||
static struct queue fifo = QUEUE_NULL(CONFIG_ACCEL_FIFO_SIZE,
|
||||
struct ec_response_motion_sensor_data);
|
||||
/** Count of the number of entries lost due to a small queue. */
|
||||
static int fifo_lost;
|
||||
/** Metadata for the fifo, used for staging and spreading data. */
|
||||
static struct fifo_staged fifo_staged;
|
||||
|
||||
static inline struct ec_response_motion_sensor_data *
|
||||
get_motion_sense_fifo_head(void)
|
||||
/**
|
||||
* Cached expected timestamp per sensor. If a sensor's timestamp pre-dates this
|
||||
* timestamp it will be fast forwarded.
|
||||
*/
|
||||
static struct timestamp_state next_timestamp[SENSOR_COUNT];
|
||||
|
||||
/**
|
||||
* Bitmap telling which sensors have valid entries in the next_timestamp array.
|
||||
*/
|
||||
static uint32_t next_timestamp_initialized;
|
||||
|
||||
/** Need to wake up the AP. */
|
||||
static int wake_up_needed;
|
||||
|
||||
/**
|
||||
* Check whether or not a give sensor data entry is a timestamp or not.
|
||||
*
|
||||
* @param data The data entry to check.
|
||||
* @return 1 if the entry is a timestamp, 0 otherwise.
|
||||
*/
|
||||
static inline int is_timestamp(
|
||||
const struct ec_response_motion_sensor_data *data)
|
||||
{
|
||||
return ((struct ec_response_motion_sensor_data *)
|
||||
motion_sense_fifo.buffer) +
|
||||
(motion_sense_fifo.state->head &
|
||||
motion_sense_fifo.unit_bytes);
|
||||
return data->flags & MOTIONSENSE_SENSOR_FLAG_TIMESTAMP;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience function to get the head of the fifo. This function makes no
|
||||
* guarantee on whether or not the entry is valid.
|
||||
*
|
||||
* @return Pointer to the head of the fifo.
|
||||
*/
|
||||
static inline struct ec_response_motion_sensor_data *get_fifo_head(void)
|
||||
{
|
||||
return ((struct ec_response_motion_sensor_data *) fifo.buffer) +
|
||||
(fifo.state->head & fifo.buffer_units_mask);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -69,11 +99,10 @@ get_motion_sense_fifo_head(void)
|
|||
* WARNING: This function MUST be called from within a locked context of
|
||||
* g_sensor_mutex.
|
||||
*/
|
||||
static void motion_sense_fifo_pop(void)
|
||||
static void fifo_pop(void)
|
||||
{
|
||||
struct ec_response_motion_sensor_data *head =
|
||||
get_motion_sense_fifo_head();
|
||||
const size_t initial_count = queue_count(&motion_sense_fifo);
|
||||
struct ec_response_motion_sensor_data *head = get_fifo_head();
|
||||
const size_t initial_count = queue_count(&fifo);
|
||||
|
||||
/* Check that we have something to pop. */
|
||||
if (!initial_count && !fifo_staged.count)
|
||||
|
@ -85,13 +114,19 @@ static void motion_sense_fifo_pop(void)
|
|||
* staged data.
|
||||
*/
|
||||
if (!initial_count)
|
||||
queue_advance_tail(&motion_sense_fifo, 1);
|
||||
queue_advance_tail(&fifo, 1);
|
||||
|
||||
/*
|
||||
* If we're about to pop a wakeup flag, we should remember it as though
|
||||
* it was committed.
|
||||
*/
|
||||
if (head->flags & MOTIONSENSE_SENSOR_FLAG_WAKEUP)
|
||||
wake_up_needed = 1;
|
||||
/*
|
||||
* By not using queue_remove_unit we're avoiding an un-necessary memcpy.
|
||||
*/
|
||||
queue_advance_head(&motion_sense_fifo, 1);
|
||||
motion_sense_fifo_lost++;
|
||||
queue_advance_head(&fifo, 1);
|
||||
fifo_lost++;
|
||||
|
||||
/* Increment lost counter if we have valid data. */
|
||||
if (!is_timestamp(head))
|
||||
|
@ -127,10 +162,13 @@ static void motion_sense_fifo_pop(void)
|
|||
}
|
||||
}
|
||||
|
||||
static void motion_sense_fifo_ensure_space(void)
|
||||
/**
|
||||
* Make sure that the fifo has at least 1 empty spot to stage data into.
|
||||
*/
|
||||
static void fifo_ensure_space(void)
|
||||
{
|
||||
/* If we already have space just bail. */
|
||||
if (queue_space(&motion_sense_fifo) > fifo_staged.count)
|
||||
if (queue_space(&fifo) > fifo_staged.count)
|
||||
return;
|
||||
|
||||
/*
|
||||
|
@ -145,17 +183,21 @@ static void motion_sense_fifo_ensure_space(void)
|
|||
* would assign a bad timestamp to it.
|
||||
*/
|
||||
do {
|
||||
motion_sense_fifo_pop();
|
||||
fifo_pop();
|
||||
} while (IS_ENABLED(CONFIG_SENSOR_TIGHT_TIMESTAMPS) &&
|
||||
!is_timestamp(get_motion_sense_fifo_head()) &&
|
||||
queue_count(&motion_sense_fifo) + fifo_staged.count);
|
||||
!is_timestamp(get_fifo_head()) &&
|
||||
queue_count(&fifo) + fifo_staged.count);
|
||||
}
|
||||
|
||||
/*
|
||||
* Do not use this function directly if you just want to add sensor data, use
|
||||
* motion_sense_fifo_stage_data instead to get a proper timestamp too.
|
||||
/**
|
||||
* Stage a single data unit to the motion sense fifo. Note that for the AP to
|
||||
* see this data, it must be committed.
|
||||
*
|
||||
* @param data The data to stage.
|
||||
* @param sensor The sensor that generated the data
|
||||
* @param valid_data The number of readable data entries in the data.
|
||||
*/
|
||||
static void motion_sense_fifo_stage_unit(
|
||||
static void fifo_stage_unit(
|
||||
struct ec_response_motion_sensor_data *data,
|
||||
struct motion_sensor_t *sensor,
|
||||
int valid_data)
|
||||
|
@ -172,35 +214,27 @@ static void motion_sense_fifo_stage_unit(
|
|||
if (valid_data) {
|
||||
int removed;
|
||||
|
||||
if (sensor->oversampling_ratio == 0) {
|
||||
mutex_unlock(&g_sensor_mutex);
|
||||
return;
|
||||
}
|
||||
if (sensor->oversampling_ratio == 0)
|
||||
goto stage_unit_end;
|
||||
removed = sensor->oversampling++;
|
||||
sensor->oversampling %= sensor->oversampling_ratio;
|
||||
if (removed != 0) {
|
||||
mutex_unlock(&g_sensor_mutex);
|
||||
return;
|
||||
}
|
||||
if (removed)
|
||||
goto stage_unit_end;
|
||||
}
|
||||
|
||||
/* Make sure we have room for the data */
|
||||
motion_sense_fifo_ensure_space();
|
||||
mutex_unlock(&g_sensor_mutex);
|
||||
fifo_ensure_space();
|
||||
|
||||
if (data->flags & MOTIONSENSE_SENSOR_FLAG_WAKEUP)
|
||||
wake_up_needed = 1;
|
||||
if (IS_ENABLED(CONFIG_TABLET_MODE))
|
||||
data->flags |= (tablet_get_mode() ?
|
||||
MOTIONSENSE_SENSOR_FLAG_TABLET_MODE : 0);
|
||||
MOTIONSENSE_SENSOR_FLAG_TABLET_MODE : 0);
|
||||
|
||||
/*
|
||||
* Get the next writable block in the fifo. We don't need to lock this
|
||||
* because it will always be past the tail and thus the AP will never
|
||||
* read this until motion_sense_fifo_commit_data() is called.
|
||||
*/
|
||||
chunk = queue_get_write_chunk(
|
||||
&motion_sense_fifo, fifo_staged.count);
|
||||
chunk = queue_get_write_chunk(&fifo, fifo_staged.count);
|
||||
|
||||
if (!chunk.buffer) {
|
||||
/*
|
||||
|
@ -209,7 +243,7 @@ static void motion_sense_fifo_stage_unit(
|
|||
* address 0. Just don't add any data to the queue instead.
|
||||
*/
|
||||
CPRINTS("Failed to get write chunk for new fifo data!");
|
||||
return;
|
||||
goto stage_unit_end;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -220,7 +254,7 @@ static void motion_sense_fifo_stage_unit(
|
|||
* be written to the next available block and this one will remain
|
||||
* staged.
|
||||
*/
|
||||
memcpy(chunk.buffer, data, motion_sense_fifo.unit_bytes);
|
||||
memcpy(chunk.buffer, data, fifo.unit_bytes);
|
||||
fifo_staged.count++;
|
||||
|
||||
/*
|
||||
|
@ -233,64 +267,96 @@ static void motion_sense_fifo_stage_unit(
|
|||
!is_timestamp(data) &&
|
||||
++fifo_staged.sample_count[data->sensor_num] > 1)
|
||||
fifo_staged.requires_spreading = 1;
|
||||
|
||||
stage_unit_end:
|
||||
mutex_unlock(&g_sensor_mutex);
|
||||
}
|
||||
|
||||
void motion_sense_insert_async_event(struct motion_sensor_t *sensor,
|
||||
enum motion_sense_async_event evt)
|
||||
{
|
||||
struct ec_response_motion_sensor_data vector;
|
||||
|
||||
vector.flags = evt;
|
||||
vector.timestamp = __hw_clock_source_read();
|
||||
vector.sensor_num = sensor - motion_sensors;
|
||||
|
||||
motion_sense_fifo_stage_unit(&vector, sensor, 0);
|
||||
motion_sense_fifo_commit_data();
|
||||
}
|
||||
|
||||
void motion_sense_fifo_stage_timestamp(uint32_t timestamp)
|
||||
/**
|
||||
* Stage an entry representing a single timestamp.
|
||||
*
|
||||
* @param timestamp The timestamp to add to the fifo.
|
||||
*/
|
||||
static void fifo_stage_timestamp(uint32_t timestamp)
|
||||
{
|
||||
struct ec_response_motion_sensor_data vector;
|
||||
|
||||
vector.flags = MOTIONSENSE_SENSOR_FLAG_TIMESTAMP;
|
||||
vector.timestamp = timestamp;
|
||||
vector.sensor_num = 0;
|
||||
motion_sense_fifo_stage_unit(&vector, NULL, 0);
|
||||
fifo_stage_unit(&vector, NULL, 0);
|
||||
}
|
||||
|
||||
void motion_sense_fifo_stage_data(struct ec_response_motion_sensor_data *data,
|
||||
struct motion_sensor_t *sensor,
|
||||
int valid_data,
|
||||
uint32_t time)
|
||||
/**
|
||||
* Peek into the staged data at a given offset. This function performs no bound
|
||||
* checking and is purely for confinience.
|
||||
*
|
||||
* @param offset The offset into the staged data to peek into.
|
||||
* @return Pointer to the entry at the given offset.
|
||||
*/
|
||||
static inline struct ec_response_motion_sensor_data *
|
||||
peek_fifo_staged(size_t offset)
|
||||
{
|
||||
return (struct ec_response_motion_sensor_data *)
|
||||
queue_get_write_chunk(&fifo, offset).buffer;
|
||||
}
|
||||
|
||||
int motion_sense_fifo_wake_up_needed(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
mutex_lock(&g_sensor_mutex);
|
||||
res = wake_up_needed;
|
||||
mutex_unlock(&g_sensor_mutex);
|
||||
return res;
|
||||
}
|
||||
|
||||
void motion_sense_fifo_reset_wake_up_needed(void)
|
||||
{
|
||||
mutex_lock(&g_sensor_mutex);
|
||||
wake_up_needed = 0;
|
||||
mutex_unlock(&g_sensor_mutex);
|
||||
}
|
||||
|
||||
void motion_sense_fifo_insert_async_event(
|
||||
struct motion_sensor_t *sensor,
|
||||
enum motion_sense_async_event event)
|
||||
{
|
||||
struct ec_response_motion_sensor_data vector;
|
||||
|
||||
vector.flags = event;
|
||||
vector.timestamp = __hw_clock_source_read();
|
||||
vector.sensor_num = sensor - motion_sensors;
|
||||
|
||||
fifo_stage_unit(&vector, sensor, 0);
|
||||
motion_sense_fifo_commit_data();
|
||||
}
|
||||
|
||||
inline void motion_sense_fifo_add_timestamp(uint32_t timestamp)
|
||||
{
|
||||
fifo_stage_timestamp(timestamp);
|
||||
motion_sense_fifo_commit_data();
|
||||
}
|
||||
|
||||
void motion_sense_fifo_stage_data(
|
||||
struct ec_response_motion_sensor_data *data,
|
||||
struct motion_sensor_t *sensor,
|
||||
int valid_data,
|
||||
uint32_t time)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_SENSOR_TIGHT_TIMESTAMPS)) {
|
||||
/* First entry, save the time for spreading later. */
|
||||
if (!fifo_staged.count)
|
||||
fifo_staged.read_ts = __hw_clock_source_read();
|
||||
motion_sense_fifo_stage_timestamp(time);
|
||||
fifo_stage_timestamp(time);
|
||||
}
|
||||
motion_sense_fifo_stage_unit(data, sensor, valid_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Peek into the staged data at a given offset. This function performs no bound
|
||||
* checking and is purely for convenience.
|
||||
*/
|
||||
static inline struct ec_response_motion_sensor_data *
|
||||
motion_sense_peek_fifo_staged(size_t offset)
|
||||
{
|
||||
return (struct ec_response_motion_sensor_data *)
|
||||
queue_get_write_chunk(&motion_sense_fifo, offset).buffer;
|
||||
fifo_stage_unit(data, sensor, valid_data);
|
||||
}
|
||||
|
||||
void motion_sense_fifo_commit_data(void)
|
||||
{
|
||||
/*
|
||||
* Static data to use off stack. Note that next_timestamp should persist
|
||||
* and is only updated if the timestamp from the sensor is greater.
|
||||
*/
|
||||
/* Cached data periods, static to store off stack. */
|
||||
static uint32_t data_periods[SENSOR_COUNT];
|
||||
static uint32_t next_timestamp[SENSOR_COUNT];
|
||||
struct ec_response_motion_sensor_data *data;
|
||||
int i, window, sensor_num;
|
||||
|
||||
|
@ -298,15 +364,16 @@ void motion_sense_fifo_commit_data(void)
|
|||
if (!fifo_staged.count)
|
||||
return;
|
||||
|
||||
mutex_lock(&g_sensor_mutex);
|
||||
/*
|
||||
* If per-sensor event counts are never more than 1, no spreading is
|
||||
* needed. This will also catch cases where tight timestamps aren't
|
||||
* used.
|
||||
*/
|
||||
if (!fifo_staged.requires_spreading)
|
||||
goto flush_data_end;
|
||||
goto commit_data_end;
|
||||
|
||||
data = motion_sense_peek_fifo_staged(0);
|
||||
data = peek_fifo_staged(0);
|
||||
|
||||
/*
|
||||
* Spreading only makes sense if tight timestamps are used. In such case
|
||||
|
@ -316,7 +383,8 @@ void motion_sense_fifo_commit_data(void)
|
|||
*/
|
||||
if (!is_timestamp(data)) {
|
||||
CPRINTS("Spreading skipped, first entry is not a timestamp");
|
||||
goto flush_data_end;
|
||||
fifo_staged.requires_spreading = 0;
|
||||
goto commit_data_end;
|
||||
}
|
||||
|
||||
window = time_until(data->timestamp, fifo_staged.read_ts);
|
||||
|
@ -332,16 +400,18 @@ void motion_sense_fifo_commit_data(void)
|
|||
period = motion_sensors[i].collection_rate;
|
||||
/*
|
||||
* Clamp the sample period to the MIN of collection_rate and the
|
||||
* window length / sample counts.
|
||||
* window length / (sample count - 1).
|
||||
*/
|
||||
if (window)
|
||||
period = MIN(period,
|
||||
window / fifo_staged.sample_count[i]);
|
||||
if (window && fifo_staged.sample_count[i] > 1)
|
||||
period = MIN(
|
||||
period,
|
||||
window / (fifo_staged.sample_count[i] - 1));
|
||||
data_periods[i] = period;
|
||||
}
|
||||
|
||||
commit_data_end:
|
||||
/*
|
||||
* Spread the timestamps.
|
||||
* Conditionally spread the timestamps.
|
||||
*
|
||||
* If we got this far that means that the tight timestamps config is
|
||||
* enabled. This means that we can expect the staged entries to have 1
|
||||
|
@ -350,7 +420,9 @@ void motion_sense_fifo_commit_data(void)
|
|||
* the timestamp right before it to keep things correct.
|
||||
*/
|
||||
for (i = 0; i < fifo_staged.count; i++) {
|
||||
data = motion_sense_peek_fifo_staged(i);
|
||||
data = peek_fifo_staged(i);
|
||||
if (data->flags & MOTIONSENSE_SENSOR_FLAG_WAKEUP)
|
||||
wake_up_needed = 1;
|
||||
|
||||
/* Skip timestamp, we don't know the sensor number yet. */
|
||||
if (is_timestamp(data))
|
||||
|
@ -358,36 +430,52 @@ void motion_sense_fifo_commit_data(void)
|
|||
|
||||
/* Get the sensor number and point to the timestamp entry. */
|
||||
sensor_num = data->sensor_num;
|
||||
data = motion_sense_peek_fifo_staged(i - 1);
|
||||
data = peek_fifo_staged(i - 1);
|
||||
|
||||
/* If the timestamp is after our computed next, skip ahead. */
|
||||
if (time_after(data->timestamp, next_timestamp[sensor_num]))
|
||||
next_timestamp[sensor_num] = data->timestamp;
|
||||
/*
|
||||
* If this is the first time we're seeing a timestamp for this
|
||||
* sensor or the timestamp is after our computed next, skip
|
||||
* ahead.
|
||||
*/
|
||||
if (!(next_timestamp_initialized & BIT(sensor_num)) ||
|
||||
time_after(data->timestamp,
|
||||
next_timestamp[sensor_num].prev)) {
|
||||
next_timestamp[sensor_num].next = data->timestamp;
|
||||
next_timestamp_initialized |= BIT(sensor_num);
|
||||
}
|
||||
|
||||
/* Spread the timestamp and compute the expected next. */
|
||||
data->timestamp = next_timestamp[sensor_num];
|
||||
next_timestamp[sensor_num] += data_periods[sensor_num];
|
||||
data->timestamp = next_timestamp[sensor_num].next;
|
||||
next_timestamp[sensor_num].prev =
|
||||
next_timestamp[sensor_num].next;
|
||||
next_timestamp[sensor_num].next +=
|
||||
fifo_staged.requires_spreading
|
||||
? data_periods[sensor_num]
|
||||
: motion_sensors[sensor_num].collection_rate;
|
||||
}
|
||||
|
||||
flush_data_end:
|
||||
/* Advance the tail and clear the staged metadata. */
|
||||
mutex_lock(&g_sensor_mutex);
|
||||
queue_advance_tail(&motion_sense_fifo, fifo_staged.count);
|
||||
mutex_unlock(&g_sensor_mutex);
|
||||
queue_advance_tail(&fifo, fifo_staged.count);
|
||||
|
||||
/* Reset metadata for next staging cycle. */
|
||||
memset(&fifo_staged, 0, sizeof(fifo_staged));
|
||||
|
||||
mutex_unlock(&g_sensor_mutex);
|
||||
}
|
||||
|
||||
void motion_sense_get_fifo_info(
|
||||
struct ec_response_motion_sense_fifo_info *fifo_info)
|
||||
void motion_sense_fifo_get_info(
|
||||
struct ec_response_motion_sense_fifo_info *fifo_info,
|
||||
int reset)
|
||||
{
|
||||
fifo_info->size = motion_sense_fifo.buffer_units;
|
||||
mutex_lock(&g_sensor_mutex);
|
||||
fifo_info->count = fifo_queue_count;
|
||||
fifo_info->total_lost = motion_sense_fifo_lost;
|
||||
fifo_info->size = fifo.buffer_units;
|
||||
fifo_info->count = queue_count(&fifo);
|
||||
fifo_info->total_lost = fifo_lost;
|
||||
mutex_unlock(&g_sensor_mutex);
|
||||
fifo_info->timestamp = mkbp_last_event_time;
|
||||
|
||||
if (reset)
|
||||
fifo_lost = 0;
|
||||
}
|
||||
|
||||
static int motion_sense_get_next_event(uint8_t *out)
|
||||
|
@ -395,14 +483,41 @@ static int motion_sense_get_next_event(uint8_t *out)
|
|||
union ec_response_get_next_data *data =
|
||||
(union ec_response_get_next_data *)out;
|
||||
/* out is not padded. It has one byte for the event type */
|
||||
motion_sense_get_fifo_info(&data->sensor_fifo.info);
|
||||
motion_sense_fifo_get_info(&data->sensor_fifo.info, 0);
|
||||
return sizeof(data->sensor_fifo);
|
||||
}
|
||||
|
||||
DECLARE_EVENT_SOURCE(EC_MKBP_EVENT_SENSOR_FIFO, motion_sense_get_next_event);
|
||||
|
||||
inline int motion_sense_fifo_is_wake_up_needed(void)
|
||||
inline int motion_sense_fifo_over_thres(void)
|
||||
{
|
||||
return queue_space(&motion_sense_fifo) < CONFIG_ACCEL_FIFO_THRES ||
|
||||
wake_up_needed;
|
||||
int result;
|
||||
|
||||
mutex_lock(&g_sensor_mutex);
|
||||
result = queue_space(&fifo) < CONFIG_ACCEL_FIFO_THRES;
|
||||
mutex_unlock(&g_sensor_mutex);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int motion_sense_fifo_read(int capacity_bytes, int max_count, void *out,
|
||||
uint16_t *out_size)
|
||||
{
|
||||
int count;
|
||||
|
||||
mutex_lock(&g_sensor_mutex);
|
||||
count = MIN(capacity_bytes / fifo.unit_bytes,
|
||||
MIN(queue_count(&fifo), max_count));
|
||||
count = queue_remove_units(&fifo, out, count);
|
||||
mutex_unlock(&g_sensor_mutex);
|
||||
*out_size = count * fifo.unit_bytes;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
void motion_sense_fifo_reset(void)
|
||||
{
|
||||
next_timestamp_initialized = 0;
|
||||
memset(&fifo_staged, 0, sizeof(fifo_staged));
|
||||
queue_init(&fifo);
|
||||
}
|
||||
|
|
|
@ -7,14 +7,8 @@
|
|||
#define __CROS_EC_MOTION_SENSE_FIFO_H
|
||||
|
||||
#include "motion_sense.h"
|
||||
#include "task.h"
|
||||
|
||||
extern struct queue motion_sense_fifo;
|
||||
extern int wake_up_needed;
|
||||
extern int fifo_int_enabled;
|
||||
extern int fifo_queue_count;
|
||||
extern int motion_sense_fifo_lost;
|
||||
|
||||
/** Allowed async events. */
|
||||
enum motion_sense_async_event {
|
||||
ASYNC_EVENT_FLUSH = MOTIONSENSE_SENSOR_FLAG_FLUSH |
|
||||
MOTIONSENSE_SENSOR_FLAG_TIMESTAMP,
|
||||
|
@ -22,6 +16,35 @@ enum motion_sense_async_event {
|
|||
MOTIONSENSE_SENSOR_FLAG_TIMESTAMP,
|
||||
};
|
||||
|
||||
/**
|
||||
* Whether or not we need to wake up the AP.
|
||||
*
|
||||
* @return Non zero when a wake-up is needed.
|
||||
*/
|
||||
int motion_sense_fifo_wake_up_needed(void);
|
||||
|
||||
/**
|
||||
* Resets the flag for wake up needed.
|
||||
*/
|
||||
void motion_sense_fifo_reset_wake_up_needed(void);
|
||||
|
||||
/**
|
||||
* Insert an async event into the fifo.
|
||||
*
|
||||
* @param sensor The sensor that generated the async event.
|
||||
* @param event The event to insert.
|
||||
*/
|
||||
void motion_sense_fifo_insert_async_event(
|
||||
struct motion_sensor_t *sensor,
|
||||
enum motion_sense_async_event event);
|
||||
|
||||
/**
|
||||
* Insert a timestamp into the fifo.
|
||||
*
|
||||
* @param timestamp The timestamp to insert.
|
||||
*/
|
||||
void motion_sense_fifo_add_timestamp(uint32_t timestamp);
|
||||
|
||||
/**
|
||||
* Stage data to the fifo, including a timestamp. This data will not be
|
||||
* available to the AP until motion_sense_fifo_commit_data is called.
|
||||
|
@ -32,46 +55,51 @@ enum motion_sense_async_event {
|
|||
* @param time accurate time (ideally measured in an interrupt) the sample
|
||||
* was taken at
|
||||
*/
|
||||
void motion_sense_fifo_stage_data(struct ec_response_motion_sensor_data *data,
|
||||
struct motion_sensor_t *sensor,
|
||||
int valid_data,
|
||||
uint32_t time);
|
||||
void motion_sense_fifo_stage_data(
|
||||
struct ec_response_motion_sensor_data *data,
|
||||
struct motion_sensor_t *sensor,
|
||||
int valid_data,
|
||||
uint32_t time);
|
||||
|
||||
/**
|
||||
* Commits all staged data to the fifo. If multiple readings were placed using
|
||||
* the same timestamps, they will be spread out.
|
||||
* Commit all the currently staged data to the fifo. Doing so makes it readable
|
||||
* to the AP.
|
||||
*/
|
||||
void motion_sense_fifo_commit_data(void);
|
||||
|
||||
/**
|
||||
* Insert an async event into the fifo.
|
||||
*
|
||||
* @param sensor Pointer to the sensor generating the event.
|
||||
* @param evt The event to insert.
|
||||
*/
|
||||
void motion_sense_insert_async_event(struct motion_sensor_t *sensor,
|
||||
enum motion_sense_async_event evt);
|
||||
|
||||
/**
|
||||
* Stage a timestamp into the fifo.
|
||||
*
|
||||
* @param timestamp The timestamp to stage.
|
||||
*/
|
||||
void motion_sense_fifo_stage_timestamp(uint32_t timestamp);
|
||||
|
||||
/**
|
||||
* Get information about the fifo.
|
||||
*
|
||||
* @param fifo_info The struct to store the info.
|
||||
* @param fifo_info The struct to modify with the current information about the
|
||||
* fifo.
|
||||
* @param reset Whether or not to reset statistics after reading them.
|
||||
*/
|
||||
void motion_sense_get_fifo_info(
|
||||
struct ec_response_motion_sense_fifo_info *fifo_info);
|
||||
void motion_sense_fifo_get_info(
|
||||
struct ec_response_motion_sense_fifo_info *fifo_info,
|
||||
int reset);
|
||||
|
||||
/**
|
||||
* Checks if either the AP should be woken up due to the fifo.
|
||||
* Check whether or not the fifo has gone over its threshold.
|
||||
*
|
||||
* @return 1 if the AP should be woken up, 0 otherwise.
|
||||
* @return 1 if yes, 0 for no.
|
||||
*/
|
||||
int motion_sense_fifo_is_wake_up_needed(void);
|
||||
int motion_sense_fifo_over_thres(void);
|
||||
|
||||
#endif /* __CROS_EC_MOTION_SENSE_FIFO_H */
|
||||
/**
|
||||
* Read available committed entries from the fifo.
|
||||
*
|
||||
* @param capacity_bytes The number of bytes available to be written to `out`.
|
||||
* @param max_count The maximum number of entries to be placed in `out`.
|
||||
* @param out The target to copy the data into.
|
||||
* @param out_size The number of bytes written to `out`.
|
||||
* @return The number of entries written to `out`.
|
||||
*/
|
||||
int motion_sense_fifo_read(int capacity_bytes, int max_count, void *out,
|
||||
uint16_t *out_size);
|
||||
|
||||
/**
|
||||
* Reset the internal data structures of the motion sense fifo.
|
||||
*/
|
||||
__test_only void motion_sense_fifo_reset(void);
|
||||
|
||||
#endif /*__CROS_EC_MOTION_SENSE_FIFO_H */
|
||||
|
|
|
@ -58,6 +58,8 @@
|
|||
#define TEST_GE(a, b, fmt) TEST_OPERATOR(a, b, >=, fmt)
|
||||
#define TEST_BITS_SET(a, bits) TEST_OPERATOR(a & (int)bits, (int)bits, ==, "%u")
|
||||
#define TEST_BITS_CLEARED(a, bits) TEST_OPERATOR(a & (int)bits, 0, ==, "%u")
|
||||
#define TEST_NEAR(a, b, epsilon, fmt) \
|
||||
TEST_OPERATOR(ABS((a) - (b)), epsilon, <, fmt)
|
||||
|
||||
#define __ABS(n) ((n) > 0 ? (n) : -(n))
|
||||
|
||||
|
|
|
@ -46,6 +46,7 @@ test-list-host += math_util
|
|||
test-list-host += motion_angle
|
||||
test-list-host += motion_angle_tablet
|
||||
test-list-host += motion_lid
|
||||
test-list-host += motion_sense_fifo
|
||||
test-list-host += mutex
|
||||
test-list-host += nvmem
|
||||
test-list-host += pingpong
|
||||
|
@ -87,7 +88,6 @@ test-list-host += vboot
|
|||
test-list-host += x25519
|
||||
endif
|
||||
|
||||
|
||||
aes-y=aes.o
|
||||
base32-y=base32.o
|
||||
battery_get_params_smart-y=battery_get_params_smart.o
|
||||
|
@ -120,6 +120,7 @@ math_util-y=math_util.o
|
|||
motion_angle-y=motion_angle.o motion_angle_data_literals.o motion_common.o
|
||||
motion_angle_tablet-y=motion_angle_tablet.o motion_angle_data_literals_tablet.o motion_common.o
|
||||
motion_lid-y=motion_lid.o
|
||||
motion_sense_fifo-y=motion_sense_fifo.o
|
||||
mutex-y=mutex.o
|
||||
nvmem-y=nvmem.o nvmem_tpm2_mock.o
|
||||
pingpong-y=pingpong.o
|
||||
|
|
|
@ -0,0 +1,362 @@
|
|||
/* Copyright 2019 The Chromium OS Authors. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*
|
||||
* Test motion_sense_fifo.
|
||||
*/
|
||||
|
||||
#include "stdio.h"
|
||||
#include "motion_sense_fifo.h"
|
||||
#include "test_util.h"
|
||||
#include "util.h"
|
||||
#include "hwtimer.h"
|
||||
|
||||
struct motion_sensor_t motion_sensors[] = {
|
||||
[BASE] = {},
|
||||
[LID] = {},
|
||||
};
|
||||
|
||||
const unsigned int motion_sensor_count = ARRAY_SIZE(motion_sensors);
|
||||
|
||||
uint32_t mkbp_last_event_time;
|
||||
|
||||
static struct ec_response_motion_sensor_data data[CONFIG_ACCEL_FIFO_SIZE];
|
||||
static uint16_t data_bytes_read;
|
||||
|
||||
static int test_insert_async_event(void)
|
||||
{
|
||||
int read_count;
|
||||
|
||||
motion_sense_fifo_insert_async_event(motion_sensors, ASYNC_EVENT_FLUSH);
|
||||
motion_sense_fifo_insert_async_event(motion_sensors + 1,
|
||||
ASYNC_EVENT_ODR);
|
||||
|
||||
read_count = motion_sense_fifo_read(
|
||||
sizeof(data), CONFIG_ACCEL_FIFO_SIZE,
|
||||
data, &data_bytes_read);
|
||||
TEST_EQ(read_count, 2, "%d");
|
||||
TEST_EQ(data_bytes_read,
|
||||
(int) (2 * sizeof(struct ec_response_motion_sensor_data)),
|
||||
"%d");
|
||||
|
||||
TEST_BITS_SET(data[0].flags, ASYNC_EVENT_FLUSH);
|
||||
TEST_BITS_CLEARED(data[0].flags, MOTIONSENSE_SENSOR_FLAG_ODR);
|
||||
TEST_EQ(data[0].sensor_num, 0, "%d");
|
||||
|
||||
TEST_BITS_SET(data[1].flags, ASYNC_EVENT_ODR);
|
||||
TEST_BITS_CLEARED(data[1].flags, MOTIONSENSE_SENSOR_FLAG_FLUSH);
|
||||
TEST_EQ(data[1].sensor_num, 1, "%d");
|
||||
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
static int test_wake_up_needed(void)
|
||||
{
|
||||
data[0].flags = MOTIONSENSE_SENSOR_FLAG_WAKEUP;
|
||||
|
||||
motion_sense_fifo_stage_data(data, motion_sensors, 0, 100);
|
||||
TEST_EQ(motion_sense_fifo_wake_up_needed(), 0, "%d");
|
||||
|
||||
motion_sense_fifo_commit_data();
|
||||
TEST_EQ(motion_sense_fifo_wake_up_needed(), 1, "%d");
|
||||
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
static int test_wake_up_needed_overflow(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
data[0].flags = MOTIONSENSE_SENSOR_FLAG_WAKEUP;
|
||||
motion_sense_fifo_stage_data(data, motion_sensors, 0, 100);
|
||||
|
||||
data[0].flags = 0;
|
||||
/*
|
||||
* Using CONFIG_ACCEL_FIFO_SIZE / 2 since 2 entries are inserted per
|
||||
* 'data':
|
||||
* - a timestamp
|
||||
* - the data
|
||||
*/
|
||||
for (i = 0; i < (CONFIG_ACCEL_FIFO_SIZE / 2); i++)
|
||||
motion_sense_fifo_stage_data(data, motion_sensors, 0, 101 + i);
|
||||
|
||||
TEST_EQ(motion_sense_fifo_wake_up_needed(), 1, "%d");
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
static int test_adding_timestamp(void)
|
||||
{
|
||||
int read_count;
|
||||
|
||||
motion_sense_fifo_add_timestamp(100);
|
||||
read_count = motion_sense_fifo_read(
|
||||
sizeof(data), CONFIG_ACCEL_FIFO_SIZE,
|
||||
data, &data_bytes_read);
|
||||
|
||||
TEST_EQ(read_count, 1, "%d");
|
||||
TEST_BITS_SET(data[0].flags, MOTIONSENSE_SENSOR_FLAG_TIMESTAMP);
|
||||
TEST_EQ(data[0].timestamp, 100, "%u");
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
static int test_stage_data_sets_xyz(void)
|
||||
{
|
||||
motion_sensors->oversampling_ratio = 1;
|
||||
motion_sensors->oversampling = 0;
|
||||
data->data[0] = 1;
|
||||
data->data[1] = 2;
|
||||
data->data[2] = 3;
|
||||
motion_sense_fifo_stage_data(data, motion_sensors, 3, 100);
|
||||
|
||||
TEST_EQ(motion_sensors->xyz[0], 1, "%d");
|
||||
TEST_EQ(motion_sensors->xyz[1], 2, "%d");
|
||||
TEST_EQ(motion_sensors->xyz[2], 3, "%d");
|
||||
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
static int test_stage_data_removed_oversample(void)
|
||||
{
|
||||
int read_count;
|
||||
|
||||
motion_sensors->oversampling_ratio = 2;
|
||||
motion_sensors->oversampling = 0;
|
||||
data->data[0] = 1;
|
||||
data->data[1] = 2;
|
||||
data->data[2] = 3;
|
||||
motion_sense_fifo_stage_data(data, motion_sensors, 3, 100);
|
||||
|
||||
data->data[0] = 4;
|
||||
data->data[1] = 5;
|
||||
data->data[2] = 6;
|
||||
motion_sense_fifo_stage_data(data, motion_sensors, 3, 110);
|
||||
motion_sense_fifo_commit_data();
|
||||
|
||||
read_count = motion_sense_fifo_read(
|
||||
sizeof(data), CONFIG_ACCEL_FIFO_SIZE,
|
||||
data, &data_bytes_read);
|
||||
TEST_EQ(read_count, 3, "%d");
|
||||
TEST_BITS_SET(data[0].flags, MOTIONSENSE_SENSOR_FLAG_TIMESTAMP);
|
||||
TEST_EQ(data[0].timestamp, 100, "%u");
|
||||
TEST_BITS_CLEARED(data[1].flags, MOTIONSENSE_SENSOR_FLAG_TIMESTAMP);
|
||||
TEST_EQ(data[1].data[0], 1, "%d");
|
||||
TEST_EQ(data[1].data[1], 2, "%d");
|
||||
TEST_EQ(data[1].data[2], 3, "%d");
|
||||
TEST_BITS_SET(data[2].flags, MOTIONSENSE_SENSOR_FLAG_TIMESTAMP);
|
||||
TEST_EQ(data[2].timestamp, 110, "%u");
|
||||
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
static int test_stage_data_remove_all_oversampling(void)
|
||||
{
|
||||
int read_count;
|
||||
|
||||
motion_sensors->oversampling_ratio = 0;
|
||||
motion_sensors->oversampling = 0;
|
||||
data->data[0] = 1;
|
||||
data->data[1] = 2;
|
||||
data->data[2] = 3;
|
||||
motion_sense_fifo_stage_data(data, motion_sensors, 3, 100);
|
||||
|
||||
data->data[0] = 4;
|
||||
data->data[1] = 5;
|
||||
data->data[2] = 6;
|
||||
motion_sense_fifo_stage_data(data, motion_sensors, 3, 110);
|
||||
motion_sense_fifo_commit_data();
|
||||
|
||||
read_count = motion_sense_fifo_read(
|
||||
sizeof(data), CONFIG_ACCEL_FIFO_SIZE,
|
||||
data, &data_bytes_read);
|
||||
TEST_EQ(read_count, 2, "%d");
|
||||
TEST_BITS_SET(data[0].flags, MOTIONSENSE_SENSOR_FLAG_TIMESTAMP);
|
||||
TEST_EQ(data[0].timestamp, 100, "%u");
|
||||
TEST_BITS_SET(data[1].flags, MOTIONSENSE_SENSOR_FLAG_TIMESTAMP);
|
||||
TEST_EQ(data[1].timestamp, 110, "%u");
|
||||
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
static int test_stage_data_evicts_data_with_timestamp(void)
|
||||
{
|
||||
int i, read_count;
|
||||
|
||||
/* Fill the fifo */
|
||||
motion_sensors->oversampling_ratio = 1;
|
||||
for (i = 0; i < CONFIG_ACCEL_FIFO_SIZE / 2; i++)
|
||||
motion_sense_fifo_stage_data(data, motion_sensors,
|
||||
3, i * 100);
|
||||
|
||||
/* Add a single entry (should evict 2) */
|
||||
motion_sense_fifo_add_timestamp(CONFIG_ACCEL_FIFO_SIZE * 100);
|
||||
read_count = motion_sense_fifo_read(
|
||||
sizeof(data), CONFIG_ACCEL_FIFO_SIZE,
|
||||
data, &data_bytes_read);
|
||||
TEST_EQ(read_count, CONFIG_ACCEL_FIFO_SIZE - 1, "%d");
|
||||
TEST_BITS_SET(data->flags, MOTIONSENSE_SENSOR_FLAG_TIMESTAMP);
|
||||
TEST_EQ(data->timestamp, 100, "%u");
|
||||
TEST_BITS_SET(data[CONFIG_ACCEL_FIFO_SIZE - 2].flags,
|
||||
MOTIONSENSE_SENSOR_FLAG_TIMESTAMP);
|
||||
TEST_EQ(data[CONFIG_ACCEL_FIFO_SIZE - 2].timestamp,
|
||||
CONFIG_ACCEL_FIFO_SIZE * 100, "%u");
|
||||
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
static int test_add_data_no_spreading_when_different_sensors(void)
|
||||
{
|
||||
int read_count;
|
||||
uint32_t now = __hw_clock_source_read();
|
||||
|
||||
motion_sensors[0].oversampling_ratio = 1;
|
||||
motion_sensors[1].oversampling_ratio = 1;
|
||||
|
||||
motion_sense_fifo_stage_data(data, motion_sensors, 3, now);
|
||||
motion_sense_fifo_stage_data(data, motion_sensors + 1, 3, now);
|
||||
motion_sense_fifo_commit_data();
|
||||
|
||||
read_count = motion_sense_fifo_read(
|
||||
sizeof(data), CONFIG_ACCEL_FIFO_SIZE,
|
||||
data, &data_bytes_read);
|
||||
TEST_EQ(read_count, 4, "%d");
|
||||
TEST_BITS_SET(data[0].flags, MOTIONSENSE_SENSOR_FLAG_TIMESTAMP);
|
||||
TEST_EQ(data[0].timestamp, now, "%u");
|
||||
TEST_BITS_SET(data[2].flags, MOTIONSENSE_SENSOR_FLAG_TIMESTAMP);
|
||||
TEST_EQ(data[2].timestamp, now, "%u");
|
||||
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
static int test_add_data_no_spreading_different_timestamps(void)
|
||||
{
|
||||
int read_count;
|
||||
|
||||
motion_sensors[0].oversampling_ratio = 1;
|
||||
|
||||
motion_sense_fifo_stage_data(data, motion_sensors, 3, 100);
|
||||
motion_sense_fifo_stage_data(data, motion_sensors, 3, 120);
|
||||
motion_sense_fifo_commit_data();
|
||||
|
||||
read_count = motion_sense_fifo_read(
|
||||
sizeof(data), CONFIG_ACCEL_FIFO_SIZE,
|
||||
data, &data_bytes_read);
|
||||
TEST_EQ(read_count, 4, "%d");
|
||||
TEST_BITS_SET(data[0].flags, MOTIONSENSE_SENSOR_FLAG_TIMESTAMP);
|
||||
TEST_EQ(data[0].timestamp, 100, "%u");
|
||||
TEST_BITS_SET(data[2].flags, MOTIONSENSE_SENSOR_FLAG_TIMESTAMP);
|
||||
TEST_EQ(data[2].timestamp, 120, "%u");
|
||||
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
static int test_spread_data_in_window(void)
|
||||
{
|
||||
uint32_t now;
|
||||
int read_count;
|
||||
|
||||
motion_sensors[0].oversampling_ratio = 1;
|
||||
motion_sensors[0].collection_rate = 20000; /* ns */
|
||||
now = __hw_clock_source_read();
|
||||
|
||||
motion_sense_fifo_stage_data(data, motion_sensors, 3,
|
||||
now - 18000);
|
||||
motion_sense_fifo_stage_data(data, motion_sensors, 3,
|
||||
now - 18000);
|
||||
motion_sense_fifo_commit_data();
|
||||
read_count = motion_sense_fifo_read(
|
||||
sizeof(data), CONFIG_ACCEL_FIFO_SIZE,
|
||||
data, &data_bytes_read);
|
||||
TEST_EQ(read_count, 4, "%d");
|
||||
TEST_BITS_SET(data[0].flags, MOTIONSENSE_SENSOR_FLAG_TIMESTAMP);
|
||||
TEST_EQ(data[0].timestamp, now - 18000, "%u");
|
||||
TEST_BITS_SET(data[2].flags, MOTIONSENSE_SENSOR_FLAG_TIMESTAMP);
|
||||
/* TODO(b/142892004): mock __hw_clock_source_read so we can check for
|
||||
* exact TS.
|
||||
*/
|
||||
TEST_NEAR(data[2].timestamp, now, 2, "%u");
|
||||
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
static int test_spread_data_by_collection_rate(void)
|
||||
{
|
||||
const uint32_t now = __hw_clock_source_read();
|
||||
int read_count;
|
||||
|
||||
motion_sensors[0].oversampling_ratio = 1;
|
||||
motion_sensors[0].collection_rate = 20000; /* ns */
|
||||
motion_sense_fifo_stage_data(data, motion_sensors, 3,
|
||||
now - 20500);
|
||||
motion_sense_fifo_stage_data(data, motion_sensors, 3,
|
||||
now - 20500);
|
||||
motion_sense_fifo_commit_data();
|
||||
read_count = motion_sense_fifo_read(
|
||||
sizeof(data), CONFIG_ACCEL_FIFO_SIZE,
|
||||
data, &data_bytes_read);
|
||||
TEST_EQ(read_count, 4, "%d");
|
||||
TEST_BITS_SET(data[0].flags, MOTIONSENSE_SENSOR_FLAG_TIMESTAMP);
|
||||
TEST_EQ(data[0].timestamp, now - 20500, "%u");
|
||||
TEST_BITS_SET(data[2].flags, MOTIONSENSE_SENSOR_FLAG_TIMESTAMP);
|
||||
TEST_EQ(data[2].timestamp, now - 500, "%u");
|
||||
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
static int test_spread_double_commit_same_timestamp(void)
|
||||
{
|
||||
const uint32_t now = __hw_clock_source_read();
|
||||
int read_count;
|
||||
|
||||
motion_sensors[0].oversampling_ratio = 1;
|
||||
motion_sensors[0].collection_rate = 20000; /* ns */
|
||||
motion_sense_fifo_stage_data(data, motion_sensors, 3,
|
||||
now - 20500);
|
||||
motion_sense_fifo_commit_data();
|
||||
motion_sense_fifo_stage_data(data, motion_sensors, 3,
|
||||
now - 20500);
|
||||
motion_sense_fifo_commit_data();
|
||||
|
||||
read_count = motion_sense_fifo_read(
|
||||
sizeof(data), CONFIG_ACCEL_FIFO_SIZE,
|
||||
data, &data_bytes_read);
|
||||
TEST_EQ(read_count, 4, "%d");
|
||||
TEST_BITS_SET(data[0].flags, MOTIONSENSE_SENSOR_FLAG_TIMESTAMP);
|
||||
TEST_EQ(data[0].timestamp, now - 20500, "%u");
|
||||
TEST_BITS_SET(data[2].flags, MOTIONSENSE_SENSOR_FLAG_TIMESTAMP);
|
||||
TEST_GT(time_until(now - 20500, data[2].timestamp), 10000, "%u");
|
||||
TEST_LE(time_until(now - 20500, data[2].timestamp), 20000, "%u");
|
||||
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
void before_test(void)
|
||||
{
|
||||
motion_sense_fifo_commit_data();
|
||||
motion_sense_fifo_read(sizeof(data), CONFIG_ACCEL_FIFO_SIZE, &data,
|
||||
&data_bytes_read);
|
||||
motion_sense_fifo_reset_wake_up_needed();
|
||||
memset(data, 0, sizeof(data));
|
||||
motion_sense_fifo_reset();
|
||||
}
|
||||
|
||||
void run_test(void)
|
||||
{
|
||||
test_reset();
|
||||
|
||||
RUN_TEST(test_insert_async_event);
|
||||
RUN_TEST(test_wake_up_needed);
|
||||
RUN_TEST(test_wake_up_needed_overflow);
|
||||
RUN_TEST(test_adding_timestamp);
|
||||
RUN_TEST(test_stage_data_sets_xyz);
|
||||
RUN_TEST(test_stage_data_removed_oversample);
|
||||
RUN_TEST(test_stage_data_remove_all_oversampling);
|
||||
RUN_TEST(test_stage_data_evicts_data_with_timestamp);
|
||||
RUN_TEST(test_add_data_no_spreading_when_different_sensors);
|
||||
RUN_TEST(test_add_data_no_spreading_different_timestamps);
|
||||
RUN_TEST(test_spread_data_in_window);
|
||||
RUN_TEST(test_spread_data_by_collection_rate);
|
||||
RUN_TEST(test_spread_double_commit_same_timestamp);
|
||||
|
||||
test_print_result();
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
/* Copyright 2019 The Chromium OS Authors. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
/**
|
||||
* See CONFIG_TASK_LIST in config.h for details.
|
||||
*/
|
||||
#define CONFIG_TEST_TASK_LIST \
|
||||
TASK_TEST(MOTIONSENSE, motion_sense_task, NULL, TASK_STACK_SIZE)
|
|
@ -82,8 +82,14 @@
|
|||
#define CONFIG_SHA256
|
||||
#endif
|
||||
|
||||
#ifdef TEST_MOTION_SENSE_FIFO
|
||||
#define CONFIG_ACCEL_FIFO
|
||||
#define CONFIG_ACCEL_FIFO_SIZE 256
|
||||
#define CONFIG_ACCEL_FIFO_THRES 10
|
||||
#endif
|
||||
|
||||
#if defined(TEST_MOTION_LID) || defined(TEST_MOTION_ANGLE) || \
|
||||
defined(TEST_MOTION_ANGLE_TABLET)
|
||||
defined(TEST_MOTION_ANGLE_TABLET) || defined(TEST_MOTION_SENSE_FIFO)
|
||||
enum sensor_id {
|
||||
BASE,
|
||||
LID,
|
||||
|
|
Loading…
Reference in New Issue