blob: c3f38d98387252d621d6630cf53cb1e64a75ebd7 [file] [log] [blame]
Mathias Agopian984826c2011-05-17 22:54:42 -07001/*
2 * Copyright (C) 2011 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 "SensorDevice.h"
18#include "SensorFusion.h"
19#include "SensorService.h"
20
Mike Ma24743862020-01-29 00:36:55 -080021#include <android/util/ProtoOutputStream.h>
22#include <frameworks/base/core/proto/android/service/sensor_service.proto.h>
23
Mathias Agopian984826c2011-05-17 22:54:42 -070024namespace android {
25// ---------------------------------------------------------------------------
26
27ANDROID_SINGLETON_STATIC_INSTANCE(SensorFusion)
28
29SensorFusion::SensorFusion()
30 : mSensorDevice(SensorDevice::getInstance()),
Peng Xuf66684a2015-07-23 11:41:53 -070031 mAttitude(mAttitudes[FUSION_9AXIS]),
32 mGyroTime(0), mAccTime(0)
Mathias Agopian984826c2011-05-17 22:54:42 -070033{
34 sensor_t const* list;
Mathias Agopian03193062013-05-10 19:32:39 -070035 Sensor uncalibratedGyro;
Mathias Agopian7b2b32f2011-07-14 16:39:46 -070036 ssize_t count = mSensorDevice.getSensorList(&list);
Peng Xuf66684a2015-07-23 11:41:53 -070037
38 mEnabled[FUSION_9AXIS] = false;
39 mEnabled[FUSION_NOMAG] = false;
40 mEnabled[FUSION_NOGYRO] = false;
41
Mathias Agopian7b2b32f2011-07-14 16:39:46 -070042 if (count > 0) {
43 for (size_t i=0 ; i<size_t(count) ; i++) {
Pontus Lidman24f862d2021-05-07 21:21:31 -070044 // Only use non-wakeup sensors
45 if ((list[i].flags & SENSOR_FLAG_WAKE_UP) == 0) {
46 if (list[i].type == SENSOR_TYPE_ACCELEROMETER) {
47 mAcc = Sensor(list + i);
48 }
49 if (list[i].type == SENSOR_TYPE_MAGNETIC_FIELD) {
50 mMag = Sensor(list + i);
51 }
52 if (list[i].type == SENSOR_TYPE_GYROSCOPE) {
53 mGyro = Sensor(list + i);
54 }
55 if (list[i].type == SENSOR_TYPE_GYROSCOPE_UNCALIBRATED) {
56 uncalibratedGyro = Sensor(list + i);
57 }
Mathias Agopian7b2b32f2011-07-14 16:39:46 -070058 }
Mathias Agopian984826c2011-05-17 22:54:42 -070059 }
Mathias Agopian03193062013-05-10 19:32:39 -070060
61 // Use the uncalibrated gyroscope for sensor fusion when available
62 if (uncalibratedGyro.getType() == SENSOR_TYPE_GYROSCOPE_UNCALIBRATED) {
63 mGyro = uncalibratedGyro;
64 }
65
66 // 200 Hz for gyro events is a good compromise between precision
67 // and power/cpu usage.
Mathias Agopian2e2a5602013-05-30 14:18:23 -070068 mEstimatedGyroRate = 200;
69 mTargetDelayNs = 1000000000LL/mEstimatedGyroRate;
Peng Xuf66684a2015-07-23 11:41:53 -070070
71 for (int i = 0; i<NUM_FUSION_MODE; ++i) {
72 mFusions[i].init(i);
73 }
Mathias Agopian984826c2011-05-17 22:54:42 -070074 }
Mathias Agopian984826c2011-05-17 22:54:42 -070075}
76
77void SensorFusion::process(const sensors_event_t& event) {
Peng Xuf66684a2015-07-23 11:41:53 -070078
Mathias Agopian03193062013-05-10 19:32:39 -070079 if (event.type == mGyro.getType()) {
Peng Xuf66684a2015-07-23 11:41:53 -070080 float dT;
81 if ( event.timestamp - mGyroTime> 0 &&
82 event.timestamp - mGyroTime< (int64_t)(5e7) ) { //0.05sec
83
84 dT = (event.timestamp - mGyroTime) / 1000000000.0f;
Mathias Agopian2e2a5602013-05-30 14:18:23 -070085 // here we estimate the gyro rate (useful for debugging)
Mathias Agopian984826c2011-05-17 22:54:42 -070086 const float freq = 1 / dT;
Mathias Agopian33015422011-05-27 18:18:13 -070087 if (freq >= 100 && freq<1000) { // filter values obviously wrong
88 const float alpha = 1 / (1 + dT); // 1s time-constant
Mathias Agopian2e2a5602013-05-30 14:18:23 -070089 mEstimatedGyroRate = freq + (mEstimatedGyroRate - freq)*alpha;
Mathias Agopian33015422011-05-27 18:18:13 -070090 }
Peng Xuf66684a2015-07-23 11:41:53 -070091
92 const vec3_t gyro(event.data);
93 for (int i = 0; i<NUM_FUSION_MODE; ++i) {
94 if (mEnabled[i]) {
95 // fusion in no gyro mode will ignore
96 mFusions[i].handleGyro(gyro, dT);
97 }
98 }
Mathias Agopian984826c2011-05-17 22:54:42 -070099 }
100 mGyroTime = event.timestamp;
Mathias Agopian984826c2011-05-17 22:54:42 -0700101 } else if (event.type == SENSOR_TYPE_MAGNETIC_FIELD) {
102 const vec3_t mag(event.data);
Peng Xuf66684a2015-07-23 11:41:53 -0700103 for (int i = 0; i<NUM_FUSION_MODE; ++i) {
104 if (mEnabled[i]) {
105 mFusions[i].handleMag(mag);// fusion in no mag mode will ignore
106 }
107 }
Mathias Agopian984826c2011-05-17 22:54:42 -0700108 } else if (event.type == SENSOR_TYPE_ACCELEROMETER) {
Peng Xuf66684a2015-07-23 11:41:53 -0700109 float dT;
110 if ( event.timestamp - mAccTime> 0 &&
111 event.timestamp - mAccTime< (int64_t)(1e8) ) { //0.1sec
112 dT = (event.timestamp - mAccTime) / 1000000000.0f;
113
114 const vec3_t acc(event.data);
115 for (int i = 0; i<NUM_FUSION_MODE; ++i) {
116 if (mEnabled[i]) {
117 mFusions[i].handleAcc(acc, dT);
118 mAttitudes[i] = mFusions[i].getAttitude();
119 }
120 }
121 }
122 mAccTime = event.timestamp;
Mathias Agopian984826c2011-05-17 22:54:42 -0700123 }
124}
125
126template <typename T> inline T min(T a, T b) { return a<b ? a : b; }
127template <typename T> inline T max(T a, T b) { return a>b ? a : b; }
128
Peng Xuf66684a2015-07-23 11:41:53 -0700129status_t SensorFusion::activate(int mode, void* ident, bool enabled) {
Mathias Agopian984826c2011-05-17 22:54:42 -0700130
Steve Blocka5512372011-12-20 16:23:08 +0000131 ALOGD_IF(DEBUG_CONNECTIONS,
Peng Xuf66684a2015-07-23 11:41:53 -0700132 "SensorFusion::activate(mode=%d, ident=%p, enabled=%d)",
133 mode, ident, enabled);
Mathias Agopian984826c2011-05-17 22:54:42 -0700134
Peng Xuf66684a2015-07-23 11:41:53 -0700135 const ssize_t idx = mClients[mode].indexOf(ident);
Mathias Agopian984826c2011-05-17 22:54:42 -0700136 if (enabled) {
137 if (idx < 0) {
Peng Xuf66684a2015-07-23 11:41:53 -0700138 mClients[mode].add(ident);
Mathias Agopian984826c2011-05-17 22:54:42 -0700139 }
140 } else {
141 if (idx >= 0) {
Peng Xuf66684a2015-07-23 11:41:53 -0700142 mClients[mode].removeItemsAt(idx);
143 }
144 }
145
146 const bool newState = mClients[mode].size() != 0;
147 if (newState != mEnabled[mode]) {
148 mEnabled[mode] = newState;
149 if (newState) {
150 mFusions[mode].init(mode);
Mathias Agopian984826c2011-05-17 22:54:42 -0700151 }
152 }
153
154 mSensorDevice.activate(ident, mAcc.getHandle(), enabled);
Peng Xuf66684a2015-07-23 11:41:53 -0700155 if (mode != FUSION_NOMAG) {
156 mSensorDevice.activate(ident, mMag.getHandle(), enabled);
157 }
158 if (mode != FUSION_NOGYRO) {
159 mSensorDevice.activate(ident, mGyro.getHandle(), enabled);
160 }
Mathias Agopian984826c2011-05-17 22:54:42 -0700161
Peng Xuf66684a2015-07-23 11:41:53 -0700162 return NO_ERROR;
163}
164
165status_t SensorFusion::setDelay(int mode, void* ident, int64_t ns) {
166 // Call batch with timeout zero instead of setDelay().
167 if (ns > (int64_t)5e7) {
168 ns = (int64_t)(5e7);
169 }
170 mSensorDevice.batch(ident, mAcc.getHandle(), 0, ns, 0);
171 if (mode != FUSION_NOMAG) {
Grigory Dzhavadyan4998c162016-10-31 17:02:32 -0700172 mSensorDevice.batch(ident, mMag.getHandle(), 0, ms2ns(10), 0);
Peng Xuf66684a2015-07-23 11:41:53 -0700173 }
174 if (mode != FUSION_NOGYRO) {
175 mSensorDevice.batch(ident, mGyro.getHandle(), 0, mTargetDelayNs, 0);
Mathias Agopian984826c2011-05-17 22:54:42 -0700176 }
177 return NO_ERROR;
178}
179
Mathias Agopian984826c2011-05-17 22:54:42 -0700180
Peng Xuf66684a2015-07-23 11:41:53 -0700181float SensorFusion::getPowerUsage(int mode) const {
Mathias Agopian33015422011-05-27 18:18:13 -0700182 float power = mAcc.getPowerUsage() +
Peng Xuf66684a2015-07-23 11:41:53 -0700183 ((mode != FUSION_NOMAG) ? mMag.getPowerUsage() : 0) +
184 ((mode != FUSION_NOGYRO) ? mGyro.getPowerUsage() : 0);
Mathias Agopian984826c2011-05-17 22:54:42 -0700185 return power;
186}
187
188int32_t SensorFusion::getMinDelay() const {
189 return mAcc.getMinDelay();
190}
191
Mike Ma24743862020-01-29 00:36:55 -0800192void SensorFusion::dump(String8& result) const {
Peng Xuf66684a2015-07-23 11:41:53 -0700193 const Fusion& fusion_9axis(mFusions[FUSION_9AXIS]);
Mark Salyzyn92dc3fc2014-03-12 13:12:44 -0700194 result.appendFormat("9-axis fusion %s (%zd clients), gyro-rate=%7.2fHz, "
Mathias Agopian33015422011-05-27 18:18:13 -0700195 "q=< %g, %g, %g, %g > (%g), "
196 "b=< %g, %g, %g >\n",
Peng Xuf66684a2015-07-23 11:41:53 -0700197 mEnabled[FUSION_9AXIS] ? "enabled" : "disabled",
198 mClients[FUSION_9AXIS].size(),
Mathias Agopian2e2a5602013-05-30 14:18:23 -0700199 mEstimatedGyroRate,
Peng Xuf66684a2015-07-23 11:41:53 -0700200 fusion_9axis.getAttitude().x,
201 fusion_9axis.getAttitude().y,
202 fusion_9axis.getAttitude().z,
203 fusion_9axis.getAttitude().w,
204 length(fusion_9axis.getAttitude()),
205 fusion_9axis.getBias().x,
206 fusion_9axis.getBias().y,
207 fusion_9axis.getBias().z);
208
209 const Fusion& fusion_nomag(mFusions[FUSION_NOMAG]);
210 result.appendFormat("game fusion(no mag) %s (%zd clients), "
211 "gyro-rate=%7.2fHz, "
212 "q=< %g, %g, %g, %g > (%g), "
213 "b=< %g, %g, %g >\n",
214 mEnabled[FUSION_NOMAG] ? "enabled" : "disabled",
215 mClients[FUSION_NOMAG].size(),
216 mEstimatedGyroRate,
217 fusion_nomag.getAttitude().x,
218 fusion_nomag.getAttitude().y,
219 fusion_nomag.getAttitude().z,
220 fusion_nomag.getAttitude().w,
221 length(fusion_nomag.getAttitude()),
222 fusion_nomag.getBias().x,
223 fusion_nomag.getBias().y,
224 fusion_nomag.getBias().z);
225
226 const Fusion& fusion_nogyro(mFusions[FUSION_NOGYRO]);
227 result.appendFormat("geomag fusion (no gyro) %s (%zd clients), "
228 "gyro-rate=%7.2fHz, "
229 "q=< %g, %g, %g, %g > (%g), "
230 "b=< %g, %g, %g >\n",
231 mEnabled[FUSION_NOGYRO] ? "enabled" : "disabled",
232 mClients[FUSION_NOGYRO].size(),
233 mEstimatedGyroRate,
234 fusion_nogyro.getAttitude().x,
235 fusion_nogyro.getAttitude().y,
236 fusion_nogyro.getAttitude().z,
237 fusion_nogyro.getAttitude().w,
238 length(fusion_nogyro.getAttitude()),
239 fusion_nogyro.getBias().x,
240 fusion_nogyro.getBias().y,
241 fusion_nogyro.getBias().z);
Mathias Agopian984826c2011-05-17 22:54:42 -0700242}
243
Mike Ma24743862020-01-29 00:36:55 -0800244void SensorFusion::dumpFusion(FUSION_MODE mode, util::ProtoOutputStream* proto) const {
245 using namespace service::SensorFusionProto::FusionProto;
246 const Fusion& fusion(mFusions[mode]);
247 proto->write(ENABLED, mEnabled[mode]);
248 proto->write(NUM_CLIENTS, (int)mClients[mode].size());
249 proto->write(ESTIMATED_GYRO_RATE, mEstimatedGyroRate);
250 proto->write(ATTITUDE_X, fusion.getAttitude().x);
251 proto->write(ATTITUDE_Y, fusion.getAttitude().y);
252 proto->write(ATTITUDE_Z, fusion.getAttitude().z);
253 proto->write(ATTITUDE_W, fusion.getAttitude().w);
254 proto->write(ATTITUDE_LENGTH, length(fusion.getAttitude()));
255 proto->write(BIAS_X, fusion.getBias().x);
256 proto->write(BIAS_Y, fusion.getBias().y);
257 proto->write(BIAS_Z, fusion.getBias().z);
258}
259
260/**
261 * Dump debugging information as android.service.SensorFusionProto protobuf message using
262 * ProtoOutputStream.
263 *
264 * See proto definition and some notes about ProtoOutputStream in
265 * frameworks/base/core/proto/android/service/sensor_service.proto
266 */
267void SensorFusion::dump(util::ProtoOutputStream* proto) const {
268 uint64_t token = proto->start(service::SensorFusionProto::FUSION_9AXIS);
269 dumpFusion(FUSION_9AXIS, proto);
270 proto->end(token);
271
272 token = proto->start(service::SensorFusionProto::FUSION_NOMAG);
273 dumpFusion(FUSION_NOMAG, proto);
274 proto->end(token);
275
276 token = proto->start(service::SensorFusionProto::FUSION_NOGYRO);
277 dumpFusion(FUSION_NOGYRO, proto);
278 proto->end(token);
279}
280
Mathias Agopian984826c2011-05-17 22:54:42 -0700281// ---------------------------------------------------------------------------
282}; // namespace android