/* * 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 "BaseSensorObject.h" #include "ConnectionDetector.h" #include "DummyDynamicAccelDaemon.h" #include "DynamicSensorManager.h" #include <cutils/properties.h> #include <utils/Log.h> #include <utils/SystemClock.h> #include <utils/misc.h> #include <sys/socket.h> #include <netinet/in.h> #include <algorithm> //std::max #define SYSPROP_PREFIX "dynamic_sensor.dummy" #define FILE_NAME_BASE "dummy_accel_file" #define FILE_NAME_REGEX ("^" FILE_NAME_BASE "[0-9]$") namespace android { namespace SensorHalExt { DummyDynamicAccelDaemon::DummyDynamicAccelDaemon(DynamicSensorManager& manager) : BaseDynamicSensorDaemon(manager) { char property[PROPERTY_VALUE_MAX+1]; property_get(SYSPROP_PREFIX ".file", property, ""); if (strcmp(property, "") != 0) { mFileDetector = new FileConnectionDetector( this, std::string(property), std::string(FILE_NAME_REGEX)); } property_get(SYSPROP_PREFIX ".socket", property, ""); if (strcmp(property, "") != 0) { mSocketDetector = new SocketConnectionDetector(this, atoi(property)); } } BaseSensorVector DummyDynamicAccelDaemon::createSensor(const std::string &deviceKey) { BaseSensorVector ret; if (deviceKey.compare(0, 1, "/") == 0) { // file detector result, deviceKey is file absolute path const size_t len = ::strlen(FILE_NAME_BASE) + 1; // +1 for number if (deviceKey.length() < len) { ALOGE("illegal file device key %s", deviceKey.c_str()); } else { size_t start = deviceKey.length() - len; ret.emplace_back(new DummySensor(deviceKey.substr(start))); } } else if (deviceKey.compare(0, ::strlen("socket:"), "socket:") == 0) { ret.emplace_back(new DummySensor(deviceKey)); } else { // unknown deviceKey ALOGE("unknown deviceKey: %s", deviceKey.c_str()); } return ret; } DummyDynamicAccelDaemon::DummySensor::DummySensor(const std::string &name) : Thread(false /*canCallJava*/), mRunState(false) { mSensorName = "Dummy Accel - " + name; // fake sensor information for dummy sensor mSensor = (struct sensor_t) { mSensorName.c_str(), "DemoSense, Inc.", 1, // version -1, // handle, dummy number here SENSOR_TYPE_ACCELEROMETER, 9.8 * 8.0f, // maxRange 9.8 * 8.0f / 32768.0f, // resolution 0.5f, // power (int32_t)(1.0E6f / 50), // minDelay 0, // fifoReservedEventCount 0, // fifoMaxEventCount SENSOR_STRING_TYPE_ACCELEROMETER, "", // requiredPermission (long)(1.0E6f / 50), // maxDelay SENSOR_FLAG_CONTINUOUS_MODE, { NULL, NULL } }; mRunLock.lock(); run("DummySensor"); } DummyDynamicAccelDaemon::DummySensor::~DummySensor() { requestExitAndWait(); // unlock mRunLock so thread can be unblocked mRunLock.unlock(); } const sensor_t* DummyDynamicAccelDaemon::DummySensor::getSensor() const { return &mSensor; } void DummyDynamicAccelDaemon::DummySensor::getUuid(uint8_t* uuid) const { // at maximum, there will be always one instance, so we can hardcode size_t hash = std::hash<std::string>()(mSensorName); memset(uuid, 'x', 16); memcpy(uuid, &hash, sizeof(hash)); } int DummyDynamicAccelDaemon::DummySensor::enable(bool enable) { std::lock_guard<std::mutex> lk(mLock); if (mRunState != enable) { if (enable) { mRunLock.unlock(); } else { mRunLock.lock(); } mRunState = enable; } return 0; } int DummyDynamicAccelDaemon::DummySensor::batch(int64_t /*samplePeriod*/, int64_t /*batchPeriod*/) { // Dummy sensor does not support changing rate and batching. But return successful anyway. return 0; } void DummyDynamicAccelDaemon::DummySensor::waitUntilNextSample() { // block when disabled (mRunLock locked) mRunLock.lock(); mRunLock.unlock(); if (!Thread::exitPending()) { // sleep 20 ms (50Hz) usleep(20000); } } bool DummyDynamicAccelDaemon::DummySensor::threadLoop() { // designated intialization will leave the unspecified fields zeroed sensors_event_t event = { .version = sizeof(event), .sensor = -1, .type = SENSOR_TYPE_ACCELEROMETER, }; int64_t startTimeNs = elapsedRealtimeNano(); ALOGI("Dynamic Dummy Accel started for sensor %s", mSensorName.c_str()); while (!Thread::exitPending()) { waitUntilNextSample(); if (Thread::exitPending()) { break; } int64_t nowTimeNs = elapsedRealtimeNano(); float t = (nowTimeNs - startTimeNs) / 1e9f; event.data[0] = 2 * ::sin(3 * M_PI * t); event.data[1] = 3 * ::cos(3 * M_PI * t); event.data[2] = 1.5 * ::sin(6 * M_PI * t); event.timestamp = nowTimeNs; generateEvent(event); } ALOGI("Dynamic Dummy Accel thread ended for sensor %s", mSensorName.c_str()); return false; } } // namespace SensorHalExt } // namespace android