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
DummyDynamicAccelDaemon(DynamicSensorManager & manager)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
createSensor(const std::string & deviceKey)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
DummySensor(const std::string & name)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
~DummySensor()100 DummyDynamicAccelDaemon::DummySensor::~DummySensor() {
101 requestExitAndWait();
102 // unlock mRunLock so thread can be unblocked
103 mRunLock.unlock();
104 }
105
getSensor() const106 const sensor_t* DummyDynamicAccelDaemon::DummySensor::getSensor() const {
107 return &mSensor;
108 }
109
getUuid(uint8_t * uuid) const110 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
enable(bool enable)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
batch(int64_t,int64_t)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
waitUntilNextSample()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
threadLoop()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