297 lines
8.7 KiB
C
297 lines
8.7 KiB
C
/*
|
|
* Copyright (C) 2016 The Android Open Source Project
|
|
*
|
|
* Licensed 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 <stdlib.h>
|
|
#include <string.h>
|
|
#include <timer.h>
|
|
#include <heap.h>
|
|
#include <plat/rtc.h>
|
|
#include <plat/syscfg.h>
|
|
#include <hostIntf.h>
|
|
#include <nanohubPacket.h>
|
|
|
|
#include <seos.h>
|
|
|
|
#include <nanohub_math.h>
|
|
#include <sensors.h>
|
|
#include <limits.h>
|
|
|
|
#define TILT_APP_VERSION 1
|
|
|
|
#define EVT_SENSOR_ANY_MOTION sensorGetMyEventType(SENS_TYPE_ANY_MOTION)
|
|
#define EVT_SENSOR_NO_MOTION sensorGetMyEventType(SENS_TYPE_NO_MOTION)
|
|
#define EVT_SENSOR_ACCEL sensorGetMyEventType(SENS_TYPE_ACCEL)
|
|
|
|
#define ACCEL_MIN_RATE SENSOR_HZ(50)
|
|
#define ACCEL_MAX_LATENCY 250000000ull // 250 ms
|
|
|
|
#define BATCH_TIME 2000000000ull // 2.0 seconds
|
|
#define ANGLE_THRESH (0.819 * 9.81 * 9.81) // ~cos(35) * (1G in m/s^2)^2
|
|
|
|
struct TiltAlgoState {
|
|
uint64_t this_batch_init_ts;
|
|
uint32_t this_batch_num_samples;
|
|
float this_batch_sample_sum[3];
|
|
float this_batch_g[3];
|
|
float last_ref_g_vector[3];
|
|
bool last_ref_g_vector_valid;
|
|
bool anamoly_this_batch;
|
|
bool tilt_detected;
|
|
};
|
|
|
|
static struct TiltDetectionTask {
|
|
struct TiltAlgoState algoState;
|
|
uint32_t taskId;
|
|
uint32_t handle;
|
|
uint32_t anyMotionHandle;
|
|
uint32_t noMotionHandle;
|
|
uint32_t accelHandle;
|
|
enum {
|
|
STATE_DISABLED,
|
|
STATE_AWAITING_ANY_MOTION,
|
|
STATE_AWAITING_TILT,
|
|
} taskState;
|
|
} mTask;
|
|
|
|
// *****************************************************************************
|
|
|
|
static void algoInit()
|
|
{
|
|
// nothing here
|
|
}
|
|
|
|
static bool algoUpdate(struct TripleAxisDataEvent *ev)
|
|
{
|
|
float dotProduct = 0.0f;
|
|
uint64_t dt;
|
|
bool latch_g_vector = false;
|
|
bool tilt_detected = false;
|
|
struct TiltAlgoState *state = &mTask.algoState;
|
|
uint64_t sample_ts = ev->referenceTime;
|
|
uint32_t numSamples = ev->samples[0].firstSample.numSamples;
|
|
uint32_t i;
|
|
struct TripleAxisDataPoint *sample;
|
|
float invN;
|
|
|
|
for (i = 0; i < numSamples; i++) {
|
|
sample = &ev->samples[i];
|
|
if (i > 0)
|
|
sample_ts += sample->deltaTime;
|
|
|
|
if (state->this_batch_init_ts == 0) {
|
|
state->this_batch_init_ts = sample_ts;
|
|
}
|
|
|
|
state->this_batch_sample_sum[0] += sample->x;
|
|
state->this_batch_sample_sum[1] += sample->y;
|
|
state->this_batch_sample_sum[2] += sample->z;
|
|
|
|
state->this_batch_num_samples++;
|
|
|
|
dt = (sample_ts - state->this_batch_init_ts);
|
|
|
|
if (dt > BATCH_TIME) {
|
|
invN = 1.0f / state->this_batch_num_samples;
|
|
state->this_batch_g[0] = state->this_batch_sample_sum[0] * invN;
|
|
state->this_batch_g[1] = state->this_batch_sample_sum[1] * invN;
|
|
state->this_batch_g[2] = state->this_batch_sample_sum[2] * invN;
|
|
|
|
if (state->last_ref_g_vector_valid) {
|
|
dotProduct = state->this_batch_g[0] * state->last_ref_g_vector[0] +
|
|
state->this_batch_g[1] * state->last_ref_g_vector[1] +
|
|
state->this_batch_g[2] * state->last_ref_g_vector[2];
|
|
|
|
if (dotProduct < ANGLE_THRESH) {
|
|
tilt_detected = true;
|
|
latch_g_vector = true;
|
|
}
|
|
} else { // reference g vector not valid, first time computing
|
|
latch_g_vector = true;
|
|
state->last_ref_g_vector_valid = true;
|
|
}
|
|
|
|
// latch the first batch or when dotProduct < ANGLE_THRESH
|
|
if (latch_g_vector) {
|
|
state->last_ref_g_vector[0] = state->this_batch_g[0];
|
|
state->last_ref_g_vector[1] = state->this_batch_g[1];
|
|
state->last_ref_g_vector[2] = state->this_batch_g[2];
|
|
}
|
|
|
|
// Seed the next batch
|
|
state->this_batch_init_ts = 0;
|
|
state->this_batch_num_samples = 0;
|
|
state->this_batch_sample_sum[0] = 0;
|
|
state->this_batch_sample_sum[1] = 0;
|
|
state->this_batch_sample_sum[2] = 0;
|
|
}
|
|
}
|
|
|
|
return tilt_detected;
|
|
}
|
|
|
|
static void configAnyMotion(bool on) {
|
|
if (on) {
|
|
sensorRequest(mTask.taskId, mTask.anyMotionHandle, SENSOR_RATE_ONCHANGE, 0);
|
|
osEventSubscribe(mTask.taskId, EVT_SENSOR_ANY_MOTION);
|
|
} else {
|
|
sensorRelease(mTask.taskId, mTask.anyMotionHandle);
|
|
osEventUnsubscribe(mTask.taskId, EVT_SENSOR_ANY_MOTION);
|
|
}
|
|
}
|
|
|
|
static void configNoMotion(bool on) {
|
|
if (on) {
|
|
sensorRequest(mTask.taskId, mTask.noMotionHandle, SENSOR_RATE_ONCHANGE, 0);
|
|
osEventSubscribe(mTask.taskId, EVT_SENSOR_NO_MOTION);
|
|
} else {
|
|
sensorRelease(mTask.taskId, mTask.noMotionHandle);
|
|
osEventUnsubscribe(mTask.taskId, EVT_SENSOR_NO_MOTION);
|
|
}
|
|
}
|
|
|
|
static void configAccel(bool on) {
|
|
if (on) {
|
|
sensorRequest(mTask.taskId, mTask.accelHandle, ACCEL_MIN_RATE,
|
|
ACCEL_MAX_LATENCY);
|
|
osEventSubscribe(mTask.taskId, EVT_SENSOR_ACCEL);
|
|
} else {
|
|
sensorRelease(mTask.taskId, mTask.accelHandle);
|
|
osEventUnsubscribe(mTask.taskId, EVT_SENSOR_ACCEL);
|
|
}
|
|
|
|
}
|
|
|
|
// *****************************************************************************
|
|
|
|
static const struct SensorInfo mSi =
|
|
{
|
|
.sensorName = "Tilt Detection",
|
|
.sensorType = SENS_TYPE_TILT,
|
|
.numAxis = NUM_AXIS_EMBEDDED,
|
|
.interrupt = NANOHUB_INT_WAKEUP,
|
|
.minSamples = 20
|
|
};
|
|
|
|
static bool tiltDetectionPower(bool on, void *cookie)
|
|
{
|
|
if (on) {
|
|
configAnyMotion(true);
|
|
mTask.taskState = STATE_AWAITING_ANY_MOTION;
|
|
} else {
|
|
configAnyMotion(false);
|
|
configNoMotion(false);
|
|
configAccel(false);
|
|
mTask.taskState = STATE_DISABLED;
|
|
}
|
|
|
|
sensorSignalInternalEvt(mTask.handle, SENSOR_INTERNAL_EVT_POWER_STATE_CHG,
|
|
on, 0);
|
|
return true;
|
|
}
|
|
|
|
static bool tiltDetectionSetRate(uint32_t rate, uint64_t latency, void *cookie)
|
|
{
|
|
sensorSignalInternalEvt(mTask.handle, SENSOR_INTERNAL_EVT_RATE_CHG, rate,
|
|
latency);
|
|
return true;
|
|
}
|
|
|
|
static bool tiltDetectionFirmwareUpload(void *cookie)
|
|
{
|
|
sensorSignalInternalEvt(mTask.handle, SENSOR_INTERNAL_EVT_FW_STATE_CHG,
|
|
1, 0);
|
|
return true;
|
|
}
|
|
|
|
static bool tiltDetectionFlush(void *cookie)
|
|
{
|
|
return osEnqueueEvt(sensorGetMyEventType(SENS_TYPE_TILT),
|
|
SENSOR_DATA_EVENT_FLUSH, NULL);
|
|
}
|
|
|
|
static void tiltDetectionHandleEvent(uint32_t evtType, const void* evtData)
|
|
{
|
|
if (evtData == SENSOR_DATA_EVENT_FLUSH)
|
|
return;
|
|
|
|
switch (evtType) {
|
|
case EVT_APP_START:
|
|
osEventUnsubscribe(mTask.taskId, EVT_APP_START);
|
|
sensorFind(SENS_TYPE_ANY_MOTION, 0, &mTask.anyMotionHandle);
|
|
sensorFind(SENS_TYPE_NO_MOTION, 0, &mTask.noMotionHandle);
|
|
sensorFind(SENS_TYPE_ACCEL, 0, &mTask.accelHandle);
|
|
break;
|
|
|
|
case EVT_SENSOR_ANY_MOTION:
|
|
if (mTask.taskState == STATE_AWAITING_ANY_MOTION) {
|
|
configAnyMotion(false);
|
|
configNoMotion(true);
|
|
configAccel(true);
|
|
|
|
mTask.taskState = STATE_AWAITING_TILT;
|
|
}
|
|
break;
|
|
|
|
case EVT_SENSOR_NO_MOTION:
|
|
if (mTask.taskState == STATE_AWAITING_TILT) {
|
|
configNoMotion(false);
|
|
configAccel(false);
|
|
configAnyMotion(true);
|
|
|
|
mTask.taskState = STATE_AWAITING_ANY_MOTION;
|
|
}
|
|
break;
|
|
|
|
case EVT_SENSOR_ACCEL:
|
|
if (mTask.taskState == STATE_AWAITING_TILT) {
|
|
if (algoUpdate((struct TripleAxisDataEvent *)evtData)) {
|
|
union EmbeddedDataPoint sample;
|
|
sample.idata = 1;
|
|
osEnqueueEvt(sensorGetMyEventType(SENS_TYPE_TILT), sample.vptr, NULL);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
static const struct SensorOps mSops =
|
|
{
|
|
.sensorPower = tiltDetectionPower,
|
|
.sensorFirmwareUpload = tiltDetectionFirmwareUpload,
|
|
.sensorSetRate = tiltDetectionSetRate,
|
|
.sensorFlush = tiltDetectionFlush,
|
|
};
|
|
|
|
static bool tiltDetectionStart(uint32_t taskId)
|
|
{
|
|
mTask.taskId = taskId;
|
|
mTask.handle = sensorRegister(&mSi, &mSops, NULL, true);
|
|
algoInit();
|
|
osEventSubscribe(taskId, EVT_APP_START);
|
|
return true;
|
|
}
|
|
|
|
static void tiltDetectionEnd()
|
|
{
|
|
}
|
|
|
|
INTERNAL_APP_INIT(
|
|
APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 8),
|
|
TILT_APP_VERSION,
|
|
tiltDetectionStart,
|
|
tiltDetectionEnd,
|
|
tiltDetectionHandleEvent);
|