1 /* 2 * Copyright (C) 2017 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 "BaseSensorObject.h" 18 #include "ConnectionDetector.h" 19 #include "DummyDynamicAccelDaemon.h" 20 #include "DynamicSensorManager.h" 21 22 #include <cutils/properties.h> 23 #include <utils/Log.h> 24 #include <utils/SystemClock.h> 25 #include <utils/misc.h> 26 27 #include <sys/socket.h> 28 #include <netinet/in.h> 29 #include <algorithm> //std::max 30 31 #define SYSPROP_PREFIX "dynamic_sensor.dummy" 32 #define FILE_NAME_BASE "dummy_accel_file" 33 #define FILE_NAME_REGEX ("^" FILE_NAME_BASE "[0-9]$") 34 35 namespace android { 36 namespace SensorHalExt { 37 38 DummyDynamicAccelDaemon::DummyDynamicAccelDaemon(DynamicSensorManager& manager) 39 : BaseDynamicSensorDaemon(manager) { 40 char property[PROPERTY_VALUE_MAX+1]; 41 42 property_get(SYSPROP_PREFIX ".file", property, ""); 43 if (strcmp(property, "") != 0) { 44 mFileDetector = new FileConnectionDetector( 45 this, std::string(property), std::string(FILE_NAME_REGEX)); 46 } 47 48 property_get(SYSPROP_PREFIX ".socket", property, ""); 49 if (strcmp(property, "") != 0) { 50 mSocketDetector = new SocketConnectionDetector(this, atoi(property)); 51 } 52 } 53 54 BaseSensorVector DummyDynamicAccelDaemon::createSensor(const std::string &deviceKey) { 55 BaseSensorVector ret; 56 if (deviceKey.compare(0, 1, "/") == 0) { 57 // file detector result, deviceKey is file absolute path 58 const size_t len = ::strlen(FILE_NAME_BASE) + 1; // +1 for number 59 if (deviceKey.length() < len) { 60 ALOGE("illegal file device key %s", deviceKey.c_str()); 61 } else { 62 size_t start = deviceKey.length() - len; 63 ret.emplace_back(new DummySensor(deviceKey.substr(start))); 64 } 65 } else if (deviceKey.compare(0, ::strlen("socket:"), "socket:") == 0) { 66 ret.emplace_back(new DummySensor(deviceKey)); 67 } else { 68 // unknown deviceKey 69 ALOGE("unknown deviceKey: %s", deviceKey.c_str()); 70 } 71 return ret; 72 } 73 74 DummyDynamicAccelDaemon::DummySensor::DummySensor(const std::string &name) 75 : Thread(false /*canCallJava*/), mRunState(false) { 76 mSensorName = "Dummy Accel - " + name; 77 // fake sensor information for dummy sensor 78 mSensor = (struct sensor_t) { 79 mSensorName.c_str(), 80 "DemoSense, Inc.", 81 1, // version 82 -1, // handle, dummy number here 83 SENSOR_TYPE_ACCELEROMETER, 84 9.8 * 8.0f, // maxRange 85 9.8 * 8.0f / 32768.0f, // resolution 86 0.5f, // power 87 (int32_t)(1.0E6f / 50), // minDelay 88 0, // fifoReservedEventCount 89 0, // fifoMaxEventCount 90 SENSOR_STRING_TYPE_ACCELEROMETER, 91 "", // requiredPermission 92 (long)(1.0E6f / 50), // maxDelay 93 SENSOR_FLAG_CONTINUOUS_MODE, 94 { NULL, NULL } 95 }; 96 mRunLock.lock(); 97 run("DummySensor"); 98 } 99 100 DummyDynamicAccelDaemon::DummySensor::~DummySensor() { 101 requestExitAndWait(); 102 // unlock mRunLock so thread can be unblocked 103 mRunLock.unlock(); 104 } 105 106 const sensor_t* DummyDynamicAccelDaemon::DummySensor::getSensor() const { 107 return &mSensor; 108 } 109 110 void DummyDynamicAccelDaemon::DummySensor::getUuid(uint8_t* uuid) const { 111 // at maximum, there will be always one instance, so we can hardcode 112 size_t hash = std::hash<std::string>()(mSensorName); 113 memset(uuid, 'x', 16); 114 memcpy(uuid, &hash, sizeof(hash)); 115 } 116 117 int DummyDynamicAccelDaemon::DummySensor::enable(bool enable) { 118 std::lock_guard<std::mutex> lk(mLock); 119 if (mRunState != enable) { 120 if (enable) { 121 mRunLock.unlock(); 122 } else { 123 mRunLock.lock(); 124 } 125 mRunState = enable; 126 } 127 return 0; 128 } 129 130 int DummyDynamicAccelDaemon::DummySensor::batch(int64_t /*samplePeriod*/, int64_t /*batchPeriod*/) { 131 // Dummy sensor does not support changing rate and batching. But return successful anyway. 132 return 0; 133 } 134 135 void DummyDynamicAccelDaemon::DummySensor::waitUntilNextSample() { 136 // block when disabled (mRunLock locked) 137 mRunLock.lock(); 138 mRunLock.unlock(); 139 140 if (!Thread::exitPending()) { 141 // sleep 20 ms (50Hz) 142 usleep(20000); 143 } 144 } 145 146 bool DummyDynamicAccelDaemon::DummySensor::threadLoop() { 147 // designated intialization will leave the unspecified fields zeroed 148 sensors_event_t event = { 149 .version = sizeof(event), 150 .sensor = -1, 151 .type = SENSOR_TYPE_ACCELEROMETER, 152 }; 153 154 int64_t startTimeNs = elapsedRealtimeNano(); 155 156 ALOGI("Dynamic Dummy Accel started for sensor %s", mSensorName.c_str()); 157 while (!Thread::exitPending()) { 158 waitUntilNextSample(); 159 160 if (Thread::exitPending()) { 161 break; 162 } 163 int64_t nowTimeNs = elapsedRealtimeNano(); 164 float t = (nowTimeNs - startTimeNs) / 1e9f; 165 166 event.data[0] = 2 * ::sin(3 * M_PI * t); 167 event.data[1] = 3 * ::cos(3 * M_PI * t); 168 event.data[2] = 1.5 * ::sin(6 * M_PI * t); 169 event.timestamp = nowTimeNs; 170 generateEvent(event); 171 } 172 173 ALOGI("Dynamic Dummy Accel thread ended for sensor %s", mSensorName.c_str()); 174 return false; 175 } 176 177 } // namespace SensorHalExt 178 } // namespace android 179 180