| /* |
| * Copyright (C) 2017 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 <eventnums.h> |
| #include <seos.h> |
| #include <timer.h> |
| #include <toolchain.h> |
| #include <crt_priv.h> |
| #include <string.h> |
| |
| #include <chre.h> |
| #include <sensors.h> |
| #include <syscallDo.h> |
| #include <hostIntf.h> |
| |
| #define SENSOR_TYPE(x) ((x) & 0xFF) |
| |
| /* |
| * Common CHRE App support code |
| */ |
| |
| static bool chreappStart(uint32_t tid) |
| { |
| __crt_init(); |
| return nanoappStart(); |
| } |
| |
| static void chreappEnd(void) |
| { |
| nanoappEnd(); |
| __crt_exit(); |
| } |
| |
| static void initDataHeader(struct chreSensorDataHeader *header, uint64_t timestamp, uint32_t sensorHandle) { |
| header->baseTimestamp = timestamp; |
| header->sensorHandle = sensorHandle; |
| header->readingCount = 1; |
| header->reserved[0] = header->reserved[1] = 0; |
| } |
| |
| static void processTripleAxisData(const struct TripleAxisDataEvent *src, uint32_t sensorHandle, uint8_t sensorType) |
| { |
| int i; |
| struct chreSensorThreeAxisData three; |
| |
| initDataHeader(&three.header, src->referenceTime, sensorHandle); |
| three.readings[0].timestampDelta = 0; |
| |
| for (i=0; i<src->samples[0].firstSample.numSamples; i++) { |
| if (i > 0) |
| three.header.baseTimestamp += src->samples[i].deltaTime; |
| three.readings[0].x = src->samples[i].x; |
| three.readings[0].y = src->samples[i].y; |
| three.readings[0].z = src->samples[i].z; |
| |
| nanoappHandleEvent(CHRE_INSTANCE_ID, CHRE_EVENT_SENSOR_DATA_EVENT_BASE | sensorType, &three); |
| } |
| } |
| |
| static void processSingleAxisData(const struct SingleAxisDataEvent *src, uint32_t sensorHandle, uint8_t sensorType) |
| { |
| int i; |
| |
| switch (sensorType) { |
| case CHRE_SENSOR_TYPE_INSTANT_MOTION_DETECT: |
| case CHRE_SENSOR_TYPE_STATIONARY_DETECT: { |
| struct chreSensorOccurrenceData occ; |
| |
| initDataHeader(&occ.header, src->referenceTime, sensorHandle); |
| occ.readings[0].timestampDelta = 0; |
| |
| for (i=0; i<src->samples[0].firstSample.numSamples; i++) { |
| if (i > 0) |
| occ.header.baseTimestamp += src->samples[i].deltaTime; |
| |
| nanoappHandleEvent(CHRE_INSTANCE_ID, CHRE_EVENT_SENSOR_DATA_EVENT_BASE | sensorType, &occ); |
| } |
| break; |
| } |
| case CHRE_SENSOR_TYPE_LIGHT: |
| case CHRE_SENSOR_TYPE_PRESSURE: { |
| struct chreSensorFloatData flt; |
| |
| initDataHeader(&flt.header, src->referenceTime, sensorHandle); |
| flt.readings[0].timestampDelta = 0; |
| |
| for (i=0; i<src->samples[0].firstSample.numSamples; i++) { |
| if (i > 0) |
| flt.header.baseTimestamp += src->samples[i].deltaTime; |
| flt.readings[0].value = src->samples[i].fdata; |
| |
| nanoappHandleEvent(CHRE_INSTANCE_ID, CHRE_EVENT_SENSOR_DATA_EVENT_BASE | sensorType, &flt); |
| } |
| break; |
| } |
| case CHRE_SENSOR_TYPE_PROXIMITY: { |
| struct chreSensorByteData byte; |
| |
| initDataHeader(&byte.header, src->referenceTime, sensorHandle); |
| byte.readings[0].timestampDelta = 0; |
| |
| for (i=0; i<src->samples[0].firstSample.numSamples; i++) { |
| if (i > 0) |
| byte.header.baseTimestamp += src->samples[i].deltaTime; |
| byte.readings[0].isNear = src->samples[i].fdata == 0.0f; |
| byte.readings[0].invalid = false; |
| byte.readings[0].padding0 = 0; |
| |
| nanoappHandleEvent(CHRE_INSTANCE_ID, CHRE_EVENT_SENSOR_DATA_EVENT_BASE | sensorType, &byte); |
| } |
| break; |
| } |
| } |
| } |
| |
| static void processEmbeddedData(const void *src, uint32_t sensorHandle, uint8_t sensorType) |
| { |
| union EmbeddedDataPoint data = (union EmbeddedDataPoint)((void *)src); |
| |
| switch (sensorType) { |
| case CHRE_SENSOR_TYPE_INSTANT_MOTION_DETECT: |
| case CHRE_SENSOR_TYPE_STATIONARY_DETECT: { |
| struct chreSensorOccurrenceData occ; |
| |
| initDataHeader(&occ.header, eOsSensorGetTime(), sensorHandle); |
| occ.readings[0].timestampDelta = 0; |
| |
| nanoappHandleEvent(CHRE_INSTANCE_ID, CHRE_EVENT_SENSOR_DATA_EVENT_BASE | sensorType, &occ); |
| break; |
| } |
| case CHRE_SENSOR_TYPE_LIGHT: |
| case CHRE_SENSOR_TYPE_PRESSURE: { |
| struct chreSensorFloatData flt; |
| |
| initDataHeader(&flt.header, eOsSensorGetTime(), sensorHandle); |
| flt.readings[0].timestampDelta = 0; |
| flt.readings[0].value = data.fdata; |
| |
| nanoappHandleEvent(CHRE_INSTANCE_ID, CHRE_EVENT_SENSOR_DATA_EVENT_BASE | sensorType, &flt); |
| break; |
| } |
| case CHRE_SENSOR_TYPE_PROXIMITY: { |
| struct chreSensorByteData byte; |
| |
| initDataHeader(&byte.header, eOsSensorGetTime(), sensorHandle); |
| byte.readings[0].timestampDelta = 0; |
| byte.readings[0].isNear = data.fdata == 0.0f; |
| byte.readings[0].invalid = false; |
| byte.readings[0].padding0 = 0; |
| |
| nanoappHandleEvent(CHRE_INSTANCE_ID, CHRE_EVENT_SENSOR_DATA_EVENT_BASE | sensorType, &byte); |
| break; |
| } |
| } |
| } |
| |
| static void chreappProcessSensorData(uint16_t evt, const void *eventData) |
| { |
| const struct SensorInfo *si; |
| uint32_t sensorHandle; |
| |
| if (eventData == SENSOR_DATA_EVENT_FLUSH) |
| return; |
| |
| si = eOsSensorFind(SENSOR_TYPE(evt), 0, &sensorHandle); |
| if (si && eOsSensorGetReqRate(sensorHandle)) { |
| switch (si->numAxis) { |
| case NUM_AXIS_EMBEDDED: |
| processEmbeddedData(eventData, sensorHandle, SENSOR_TYPE(evt)); |
| break; |
| case NUM_AXIS_ONE: |
| processSingleAxisData(eventData, sensorHandle, SENSOR_TYPE(evt)); |
| break; |
| case NUM_AXIS_THREE: |
| processTripleAxisData(eventData, sensorHandle, SENSOR_TYPE(evt)); |
| break; |
| } |
| |
| if (SENSOR_TYPE(evt) == CHRE_SENSOR_TYPE_INSTANT_MOTION_DETECT |
| || SENSOR_TYPE(evt) == CHRE_SENSOR_TYPE_STATIONARY_DETECT) { |
| // one-shot, disable after receiving sample |
| chreSensorConfigure(sensorHandle, CHRE_SENSOR_CONFIGURE_MODE_DONE, CHRE_SENSOR_INTERVAL_DEFAULT, CHRE_SENSOR_LATENCY_DEFAULT); |
| } |
| } |
| } |
| |
| static void chreappProcessConfigEvt(uint16_t evt, const void *eventData) |
| { |
| const struct SensorRateChangeEvent *msg = eventData; |
| struct chreSensorSamplingStatusEvent change; |
| |
| change.sensorHandle = msg->sensorHandle; |
| if (!msg->newRate) { |
| change.status.enabled = 0; |
| change.status.interval = 0; |
| change.status.latency = 0; |
| } else { |
| change.status.enabled = true; |
| if (msg->newRate == SENSOR_RATE_ONDEMAND |
| || msg->newRate == SENSOR_RATE_ONCHANGE |
| || msg->newRate == SENSOR_RATE_ONESHOT) |
| change.status.interval = CHRE_SENSOR_INTERVAL_DEFAULT; |
| else |
| change.status.interval = (UINT32_C(1024000000) / msg->newRate) * UINT64_C(1000); |
| |
| if (msg->newLatency == SENSOR_LATENCY_NODATA) |
| change.status.latency = CHRE_SENSOR_INTERVAL_DEFAULT; |
| else |
| change.status.latency = msg->newLatency; |
| } |
| |
| nanoappHandleEvent(CHRE_INSTANCE_ID, CHRE_EVENT_SENSOR_SAMPLING_CHANGE, &change); |
| } |
| |
| static void chreappHandle(uint32_t eventTypeAndTid, const void *eventData) |
| { |
| uint16_t evt = eventTypeAndTid; |
| uint16_t srcTid = eventTypeAndTid >> 16; |
| const void *data = eventData; |
| |
| union EventLocalData { |
| struct chreMessageFromHostData msg; |
| } u; |
| |
| switch(evt) { |
| case EVT_APP_TIMER: |
| evt = CHRE_EVENT_TIMER; |
| data = ((struct TimerEvent *)eventData)->data; |
| break; |
| case EVT_APP_FROM_HOST: |
| srcTid = CHRE_INSTANCE_ID; |
| evt = CHRE_EVENT_MESSAGE_FROM_HOST; |
| data = &u.msg; |
| u.msg.message = (uint8_t*)eventData + 1; |
| u.msg.reservedMessageType = 0; |
| u.msg.messageSize = *(uint8_t*)eventData; |
| break; |
| case EVT_APP_FROM_HOST_CHRE: |
| { |
| const struct NanohubMsgChreHdrV10 *hdr = eventData; |
| srcTid = CHRE_INSTANCE_ID; |
| evt = CHRE_EVENT_MESSAGE_FROM_HOST; |
| data = &u.msg; |
| u.msg.message = hdr + 1; |
| u.msg.reservedMessageType = hdr->appEvent; |
| u.msg.messageSize = hdr->size; |
| break; |
| } |
| case EVT_APP_SENSOR_SELF_TEST: |
| case EVT_APP_SENSOR_MARSHALL: |
| case EVT_APP_SENSOR_SEND_ONE_DIR_EVT: |
| case EVT_APP_SENSOR_CFG_DATA: |
| case EVT_APP_SENSOR_CALIBRATE: |
| case EVT_APP_SENSOR_TRIGGER: |
| case EVT_APP_SENSOR_FLUSH: |
| case EVT_APP_SENSOR_SET_RATE: |
| case EVT_APP_SENSOR_FW_UPLD: |
| case EVT_APP_SENSOR_POWER: |
| // sensor events; pass through |
| break; |
| default: |
| // ignore any other system events; OS may send them to any app |
| if (evt < EVT_NO_FIRST_USER_EVENT) |
| return; |
| else if (evt > EVT_NO_FIRST_SENSOR_EVENT && evt < EVT_NO_SENSOR_CONFIG_EVENT) { |
| return chreappProcessSensorData(evt, data); |
| } else if (evt > EVT_NO_SENSOR_CONFIG_EVENT && evt < EVT_APP_START) { |
| return chreappProcessConfigEvt(evt, data); |
| } |
| } |
| nanoappHandleEvent(srcTid, evt, data); |
| } |
| |
| // Collect entry points |
| const struct AppFuncs SET_EXTERNAL_APP_ATTRIBUTES(used, section (".app_init"),visibility("default")) _mAppFuncs = { |
| .init = chreappStart, |
| .end = chreappEnd, |
| .handle = chreappHandle, |
| }; |
| |
| // declare version for compatibility with current runtime |
| const uint32_t SET_EXTERNAL_APP_VERSION(used, section (".app_version"), visibility("default")) _mAppVer = 0; |