Home | History | Annotate | Download | only in sensor_world
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <chre.h>
     18 #include <cinttypes>
     19 
     20 #include "chre/util/macros.h"
     21 #include "chre/util/nanoapp/log.h"
     22 #include "chre/util/nanoapp/sensor.h"
     23 #include "chre/util/time.h"
     24 
     25 #define LOG_TAG "[SensorWorld]"
     26 
     27 #ifdef CHRE_NANOAPP_INTERNAL
     28 namespace chre {
     29 namespace {
     30 #endif  // CHRE_NANOAPP_INTERNAL
     31 
     32 using chre::Milliseconds;
     33 using chre::Seconds;
     34 using chre::getSensorNameForEventType;
     35 using chre::kOneMillisecondInNanoseconds;
     36 
     37 namespace {
     38 
     39 //! Enable BreakIt test mode.
     40 // In BreakIt test mode, a timer will be set periodically to randomly
     41 // enable/disable each sensor.
     42 constexpr bool kBreakIt = false;
     43 constexpr Milliseconds kBreakItPeriod = Milliseconds(2000);
     44 
     45 //! Whether to enable sensor event logging or not.
     46 constexpr bool kEnableSensorEventLogging = true;
     47 
     48 //! Enable/disable all sensors by default.
     49 // This allows disabling all sensens by default and enabling only targeted
     50 // sensors for testing by locally overriding 'enable' field in SensorState.
     51 // Note that enabling BreakIt test disables all sensors at init by default.
     52 constexpr bool kEnableDefault = !kBreakIt;
     53 
     54 struct SensorState {
     55   const uint8_t type;
     56   uint32_t handle;
     57   bool isInitialized;
     58   bool enable;
     59   uint64_t interval;  // nsec
     60   uint64_t latency;  // nsec
     61   chreSensorInfo info;
     62 };
     63 
     64 SensorState sensors[] = {
     65   { .type = CHRE_SENSOR_TYPE_ACCELEROMETER,
     66     .handle = 0,
     67     .isInitialized = false,
     68     .enable = kEnableDefault,
     69     .interval = Milliseconds(80).toRawNanoseconds(),
     70     .latency = Seconds(4).toRawNanoseconds(),
     71     .info = {},
     72   },
     73   { .type = CHRE_SENSOR_TYPE_INSTANT_MOTION_DETECT,
     74     .handle = 0,
     75     .isInitialized = false,
     76     .enable = false,  // InstantMotion is triggered by Prox
     77     .interval = CHRE_SENSOR_INTERVAL_DEFAULT,
     78     .latency = CHRE_SENSOR_LATENCY_DEFAULT,
     79     .info = {},
     80   },
     81   { .type = CHRE_SENSOR_TYPE_STATIONARY_DETECT,
     82     .handle = 0,
     83     .isInitialized = false,
     84     .enable = false,  // StationaryDetect is triggered by Prox
     85     .interval = CHRE_SENSOR_INTERVAL_DEFAULT,
     86     .latency = CHRE_SENSOR_LATENCY_DEFAULT,
     87     .info = {},
     88   },
     89   { .type = CHRE_SENSOR_TYPE_GYROSCOPE,
     90     .handle = 0,
     91     .isInitialized = false,
     92     .enable = kEnableDefault,
     93     .interval = Milliseconds(80).toRawNanoseconds(),
     94     .latency = Seconds(4).toRawNanoseconds(),
     95     .info = {},
     96   },
     97   { .type = CHRE_SENSOR_TYPE_GEOMAGNETIC_FIELD,
     98     .handle = 0,
     99     .isInitialized = false,
    100     .enable = kEnableDefault,
    101     .interval = Milliseconds(80).toRawNanoseconds(),
    102     .latency = Seconds(4).toRawNanoseconds(),
    103     .info = {},
    104   },
    105   { .type = CHRE_SENSOR_TYPE_PRESSURE,
    106     .handle = 0,
    107     .isInitialized = false,
    108     .enable = kEnableDefault,
    109     .interval = Milliseconds(200).toRawNanoseconds(),
    110     .latency = Seconds(4).toRawNanoseconds(),
    111     .info = {},
    112   },
    113   { .type = CHRE_SENSOR_TYPE_LIGHT,
    114     .handle = 0,
    115     .isInitialized = false,
    116     .enable = kEnableDefault,
    117     .interval = Milliseconds(200).toRawNanoseconds(),
    118     .latency = 0,
    119     .info = {},
    120   },
    121   { .type = CHRE_SENSOR_TYPE_PROXIMITY,
    122     .handle = 0,
    123     .isInitialized = false,
    124     .enable = kEnableDefault,
    125     .interval = Milliseconds(200).toRawNanoseconds(),
    126     .latency = 0,
    127     .info = {},
    128   },
    129   { .type = CHRE_SENSOR_TYPE_ACCELEROMETER_TEMPERATURE,
    130     .handle = 0,
    131     .isInitialized = false,
    132     .enable = kEnableDefault,
    133     .interval = Seconds(2).toRawNanoseconds(),
    134     .latency = 0,
    135     .info = {},
    136   },
    137   { .type = CHRE_SENSOR_TYPE_GYROSCOPE_TEMPERATURE,
    138     .handle = 0,
    139     .isInitialized = false,
    140     .enable = kEnableDefault,
    141     .interval = Seconds(2).toRawNanoseconds(),
    142     .latency = 0,
    143     .info = {},
    144   },
    145   { .type = CHRE_SENSOR_TYPE_GEOMAGNETIC_FIELD_TEMPERATURE,
    146     .handle = 0,
    147     .isInitialized = false,
    148     .enable = kEnableDefault,
    149     .interval = Seconds(2).toRawNanoseconds(),
    150     .latency = 0,
    151     .info = {},
    152   },
    153   { .type = CHRE_SENSOR_TYPE_UNCALIBRATED_ACCELEROMETER,
    154     .handle = 0,
    155     .isInitialized = false,
    156     .enable = kEnableDefault,
    157     .interval = Milliseconds(80).toRawNanoseconds(),
    158     .latency = Seconds(4).toRawNanoseconds(),
    159     .info = {},
    160   },
    161   { .type = CHRE_SENSOR_TYPE_UNCALIBRATED_GYROSCOPE,
    162     .handle = 0,
    163     .isInitialized = false,
    164     .enable = kEnableDefault,
    165     .interval = Milliseconds(80).toRawNanoseconds(),
    166     .latency = Seconds(4).toRawNanoseconds(),
    167     .info = {},
    168   },
    169   { .type = CHRE_SENSOR_TYPE_UNCALIBRATED_GEOMAGNETIC_FIELD,
    170     .handle = 0,
    171     .isInitialized = false,
    172     .enable = kEnableDefault,
    173     .interval = Milliseconds(80).toRawNanoseconds(),
    174     .latency = Seconds(4).toRawNanoseconds(),
    175     .info = {},
    176   },
    177 };
    178 
    179 uint32_t gBreakItTimerHandle;
    180 
    181 // Conditional logging macro
    182 #define CLOGI(fmt, ...) do {               \
    183     if (kEnableSensorEventLogging) {       \
    184       LOGI(fmt, ##__VA_ARGS__);            \
    185     }                                      \
    186   } while (0);
    187 
    188 // Helpers for testing InstantMotion and StationaryDetect
    189 enum class MotionMode {
    190   Instant,
    191   Stationary,
    192 };
    193 
    194 // Storage to help access InstantMotion and StationaryDetect sensor handle and
    195 // info
    196 size_t motionSensorIndices[2];
    197 MotionMode motionMode = MotionMode::Instant;
    198 
    199 size_t getMotionSensorIndex() {
    200   motionMode = (motionMode == MotionMode::Instant) ?
    201       MotionMode::Stationary : MotionMode::Instant;
    202   return motionSensorIndices[static_cast<size_t>(motionMode)];
    203 }
    204 
    205 //! Used to loop through all sensors to query sensor sampling status.
    206 size_t statusIndex = 0;
    207 
    208 // Obtains 16-bit psuedo-random numbers.
    209 uint16_t getNextLfsrState() {
    210   // 15-bit LFSR with feedback polynomial x^15 + x^14 + 1 gives us a
    211   // pseudo-random sequence over all 32767 possible values
    212   static uint16_t lfsr = 0x1337;
    213   uint16_t nextBit = ((lfsr << 14) ^ (lfsr << 13)) & 0x4000;
    214   lfsr = nextBit | (lfsr >> 1);
    215 
    216   return lfsr;
    217 }
    218 
    219 void handleTimerEvent(const void *eventData) {
    220   for (size_t i = 0; i < ARRAY_SIZE(sensors); i++) {
    221     SensorState& sensor = sensors[i];
    222 
    223     bool enable = getNextLfsrState() & 0x1;
    224     if (sensor.isInitialized && sensor.enable != enable) {
    225       sensor.enable = enable;
    226 
    227       bool status;
    228       if (!enable) {
    229         status = chreSensorConfigureModeOnly(
    230             sensor.handle, CHRE_SENSOR_CONFIGURE_MODE_DONE);
    231       } else {
    232         enum chreSensorConfigureMode mode = sensor.info.isOneShot
    233             ? CHRE_SENSOR_CONFIGURE_MODE_ONE_SHOT
    234             : CHRE_SENSOR_CONFIGURE_MODE_CONTINUOUS;
    235         status = chreSensorConfigure(
    236             sensor.handle, mode, sensor.interval, sensor.latency);
    237       }
    238 
    239       LOGI("Configure [enable %d, status %d]: %s",
    240            enable, status, getSensorTypeName(sensor.type));
    241     }
    242   }
    243 
    244   gBreakItTimerHandle = chreTimerSet(kBreakItPeriod.toRawNanoseconds(),
    245         nullptr /* data */, true /* oneShot */);
    246 }
    247 
    248 } // namespace
    249 
    250 bool nanoappStart() {
    251   LOGI("App started on platform ID %" PRIx64, chreGetPlatformId());
    252 
    253   for (size_t i = 0; i < ARRAY_SIZE(sensors); i++) {
    254     SensorState& sensor = sensors[i];
    255     sensor.isInitialized = chreSensorFindDefault(sensor.type, &sensor.handle);
    256     LOGI("Sensor %zu initialized: %s with handle %" PRIu32,
    257          i, sensor.isInitialized ? "true" : "false", sensor.handle);
    258 
    259     if (sensor.type == CHRE_SENSOR_TYPE_INSTANT_MOTION_DETECT) {
    260       motionSensorIndices[static_cast<size_t>(MotionMode::Instant)] = i;
    261     } else if (sensor.type == CHRE_SENSOR_TYPE_STATIONARY_DETECT) {
    262       motionSensorIndices[static_cast<size_t>(MotionMode::Stationary)] = i;
    263     }
    264 
    265     if (sensor.isInitialized) {
    266       // Get sensor info
    267       chreSensorInfo& info = sensor.info;
    268       bool infoStatus = chreGetSensorInfo(sensor.handle, &info);
    269       if (infoStatus) {
    270         LOGI("SensorInfo: %s, Type=%" PRIu8 " OnChange=%d"
    271              " OneShot=%d minInterval=%" PRIu64 "nsec",
    272              info.sensorName, info.sensorType, info.isOnChange,
    273              info.isOneShot, info.minInterval);
    274       } else {
    275         LOGE("chreGetSensorInfo failed");
    276       }
    277 
    278       // Subscribe to sensors
    279       if (sensor.enable) {
    280         float odrHz = 1e9f / sensor.interval;
    281         float latencySec = sensor.latency / 1e9f;
    282         bool status = chreSensorConfigure(sensor.handle,
    283             CHRE_SENSOR_CONFIGURE_MODE_CONTINUOUS, sensor.interval,
    284             sensor.latency);
    285         LOGI("Requested data: odr %f Hz, latency %f sec, %s",
    286              odrHz, latencySec, status ? "success" : "failure");
    287       }
    288     }
    289   }
    290 
    291   // Set timer for BreakIt test.
    292   if (kBreakIt) {
    293     gBreakItTimerHandle = chreTimerSet(kBreakItPeriod.toRawNanoseconds(),
    294         nullptr /* data */, true /* oneShot */);
    295   }
    296 
    297   return true;
    298 }
    299 
    300 void nanoappHandleEvent(uint32_t senderInstanceId,
    301                         uint16_t eventType,
    302                         const void *eventData) {
    303   uint64_t chreTime = chreGetTime();
    304   uint64_t sampleTime;
    305   switch (eventType) {
    306     case CHRE_EVENT_SENSOR_ACCELEROMETER_DATA:
    307     case CHRE_EVENT_SENSOR_UNCALIBRATED_ACCELEROMETER_DATA:
    308     case CHRE_EVENT_SENSOR_GYROSCOPE_DATA:
    309     case CHRE_EVENT_SENSOR_UNCALIBRATED_GYROSCOPE_DATA:
    310     case CHRE_EVENT_SENSOR_GEOMAGNETIC_FIELD_DATA:
    311     case CHRE_EVENT_SENSOR_UNCALIBRATED_GEOMAGNETIC_FIELD_DATA: {
    312       const auto *ev = static_cast<const chreSensorThreeAxisData *>(eventData);
    313       const auto header = ev->header;
    314       const auto *data = ev->readings;
    315       sampleTime = header.baseTimestamp;
    316 
    317       float x = 0, y = 0, z = 0;
    318       for (size_t i = 0; i < header.readingCount; i++) {
    319         x += data[i].v[0];
    320         y += data[i].v[1];
    321         z += data[i].v[2];
    322         sampleTime += data[i].timestampDelta;
    323       }
    324       x /= header.readingCount;
    325       y /= header.readingCount;
    326       z /= header.readingCount;
    327 
    328       CLOGI("%s, %d samples: %f %f %f, t=%" PRIu64 " ms",
    329             getSensorNameForEventType(eventType), header.readingCount, x, y, z,
    330             header.baseTimestamp / kOneMillisecondInNanoseconds);
    331 
    332       if (eventType == CHRE_EVENT_SENSOR_UNCALIBRATED_GYROSCOPE_DATA) {
    333         CLOGI("UncalGyro time: first %" PRIu64 " last %" PRIu64 " chre %" PRIu64
    334               " delta [%" PRId64 ", %" PRId64 "]ms",
    335               header.baseTimestamp, sampleTime, chreTime,
    336               static_cast<int64_t>(header.baseTimestamp - chreTime)
    337               / static_cast<int64_t>(kOneMillisecondInNanoseconds),
    338               static_cast<int64_t>(sampleTime - chreTime)
    339               / static_cast<int64_t>(kOneMillisecondInNanoseconds));
    340       }
    341       break;
    342     }
    343 
    344     case CHRE_EVENT_SENSOR_PRESSURE_DATA:
    345     case CHRE_EVENT_SENSOR_LIGHT_DATA:
    346     case CHRE_EVENT_SENSOR_ACCELEROMETER_TEMPERATURE_DATA:
    347     case CHRE_EVENT_SENSOR_GYROSCOPE_TEMPERATURE_DATA:
    348     case CHRE_EVENT_SENSOR_GEOMAGNETIC_FIELD_TEMPERATURE_DATA: {
    349       const auto *ev = static_cast<const chreSensorFloatData *>(eventData);
    350       const auto header = ev->header;
    351 
    352       float v = 0;
    353       for (size_t i = 0; i < header.readingCount; i++) {
    354         v += ev->readings[i].value;
    355       }
    356       v /= header.readingCount;
    357 
    358       CLOGI("%s, %d samples: %f, t=%" PRIu64 " ms",
    359             getSensorNameForEventType(eventType), header.readingCount, v,
    360             header.baseTimestamp / kOneMillisecondInNanoseconds);
    361       break;
    362     }
    363 
    364     case CHRE_EVENT_SENSOR_PROXIMITY_DATA: {
    365       const auto *ev = static_cast<const chreSensorByteData *>(eventData);
    366       const auto header = ev->header;
    367       const auto reading = ev->readings[0];
    368       sampleTime = header.baseTimestamp;
    369 
    370       CLOGI("%s, %d samples: isNear %d, invalid %d",
    371             getSensorNameForEventType(eventType), header.readingCount,
    372             reading.isNear, reading.invalid);
    373 
    374       CLOGI("Prox time: sample %" PRIu64 " chre %" PRIu64 " delta %" PRId64
    375             "ms", header.baseTimestamp, chreTime,
    376             static_cast<int64_t>(sampleTime - chreTime) / 1000000);
    377 
    378       // Enable InstantMotion and StationaryDetect alternatively on near->far.
    379       if (reading.isNear == 0 && !kBreakIt) {
    380         size_t motionSensorIndex = getMotionSensorIndex();
    381         bool status = chreSensorConfigure(sensors[motionSensorIndex].handle,
    382             CHRE_SENSOR_CONFIGURE_MODE_ONE_SHOT,
    383             CHRE_SENSOR_INTERVAL_DEFAULT,
    384             CHRE_SENSOR_LATENCY_DEFAULT);
    385         LOGI("Requested %s: %s", sensors[motionSensorIndex].info.sensorName,
    386               status ? "success" : "failure");
    387       }
    388 
    389       // Exercise chreGetSensorSamplingStatus on one sensor on near->far.
    390       if (sensors[statusIndex].isInitialized && reading.isNear == 0) {
    391         struct chreSensorSamplingStatus status;
    392         bool success = chreGetSensorSamplingStatus(sensors[statusIndex].handle,
    393                                                    &status);
    394         LOGI("%s success %d: enabled %d interval %" PRIu64 " latency %" PRIu64,
    395              sensors[statusIndex].info.sensorName, success, status.enabled,
    396              status.interval, status.latency);
    397       }
    398       statusIndex = (statusIndex + 1) % ARRAY_SIZE(sensors);
    399       break;
    400     }
    401 
    402     case CHRE_EVENT_SENSOR_INSTANT_MOTION_DETECT_DATA:
    403     case CHRE_EVENT_SENSOR_STATIONARY_DETECT_DATA: {
    404       const auto *ev = static_cast<const chreSensorOccurrenceData *>(eventData);
    405       const auto header = ev->header;
    406 
    407       CLOGI("%s, %d samples",
    408             getSensorNameForEventType(eventType), header.readingCount);
    409       break;
    410     }
    411 
    412     case CHRE_EVENT_SENSOR_SAMPLING_CHANGE: {
    413       const auto *ev = static_cast<const chreSensorSamplingStatusEvent *>(
    414           eventData);
    415 
    416       CLOGI("Sampling Change: handle %" PRIu32 ", status: interval %" PRIu64
    417             " latency %" PRIu64 " enabled %d",
    418             ev->sensorHandle, ev->status.interval, ev->status.latency,
    419             ev->status.enabled);
    420       break;
    421     }
    422 
    423 
    424     case CHRE_EVENT_TIMER:
    425       if (!kBreakIt) {
    426         LOGE("Timer event received with gBreakIt is disabled");
    427       } else {
    428         handleTimerEvent(eventData);
    429       }
    430       break;
    431 
    432     default:
    433       LOGW("Unhandled event %d", eventType);
    434       break;
    435   }
    436 }
    437 
    438 void nanoappEnd() {
    439   LOGI("Stopped");
    440 }
    441 
    442 #ifdef CHRE_NANOAPP_INTERNAL
    443 }  // anonymous namespace
    444 }  // namespace chre
    445 
    446 #include "chre/util/nanoapp/app_id.h"
    447 #include "chre/platform/static_nanoapp_init.h"
    448 
    449 CHRE_STATIC_NANOAPP_INIT(SensorWorld, chre::kSensorWorldAppId, 0);
    450 #endif  // CHRE_NANOAPP_INTERNAL
    451