1 /*
2 * Copyright (C) Texas Instruments - http://www.ti.com/
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 /**
18 * @file SensorListener.cpp
19 *
20 * This file listens and propogates sensor events to CameraHal.
21 *
22 */
23
24 #define LOG_TAG "CameraHAL"
25
26 #include "SensorListener.h"
27 #include "CameraHal.h"
28
29 #include <stdint.h>
30 #include <math.h>
31 #include <sys/types.h>
32
33 namespace android {
34
35 /*** static declarations ***/
36 static const float RADIANS_2_DEG = (float) (180 / M_PI);
37 // measured values on device...might need tuning
38 static const int DEGREES_90_THRESH = 50;
39 static const int DEGREES_180_THRESH = 170;
40 static const int DEGREES_270_THRESH = 250;
41
sensor_events_listener(int fd,int events,void * data)42 static int sensor_events_listener(int fd, int events, void* data)
43 {
44 SensorListener* listener = (SensorListener*) data;
45 ssize_t num_sensors;
46 ASensorEvent sen_events[8];
47 while ((num_sensors = listener->mSensorEventQueue->read(sen_events, 8)) > 0) {
48 for (int i = 0; i < num_sensors; i++) {
49 if (sen_events[i].type == Sensor::TYPE_ACCELEROMETER) {
50 float x = sen_events[i].vector.azimuth;
51 float y = sen_events[i].vector.pitch;
52 float z = sen_events[i].vector.roll;
53 float radius = 0;
54 int tilt = 0, orient = 0;
55
56 CAMHAL_LOGVA("ACCELEROMETER EVENT");
57 CAMHAL_LOGVB(" azimuth = %f pitch = %f roll = %f",
58 sen_events[i].vector.azimuth,
59 sen_events[i].vector.pitch,
60 sen_events[i].vector.roll);
61 // see http://en.wikipedia.org/wiki/Spherical_coordinate_system#Cartesian_coordinates
62 // about conversion from cartesian to spherical for orientation calculations
63 radius = (float) sqrt(x * x + y * y + z * z);
64 tilt = (int) asinf(z / radius) * RADIANS_2_DEG;
65 orient = (int) atan2f(-x, y) * RADIANS_2_DEG;
66
67 if (orient < 0) {
68 orient += 360;
69 }
70
71 if (orient >= DEGREES_270_THRESH) {
72 orient = 270;
73 } else if (orient >= DEGREES_180_THRESH) {
74 orient = 180;
75 } else if (orient >= DEGREES_90_THRESH) {
76 orient = 90;
77 } else {
78 orient = 0;
79 }
80 listener->handleOrientation(orient, tilt);
81 CAMHAL_LOGVB(" tilt = %d orientation = %d", tilt, orient);
82 } else if (sen_events[i].type == Sensor::TYPE_GYROSCOPE) {
83 CAMHAL_LOGVA("GYROSCOPE EVENT");
84 }
85 }
86 }
87
88 if (num_sensors < 0 && num_sensors != -EAGAIN) {
89 CAMHAL_LOGEB("reading events failed: %s", strerror(-num_sensors));
90 }
91
92 return 1;
93 }
94
95 /****** public - member functions ******/
SensorListener()96 SensorListener::SensorListener() {
97 LOG_FUNCTION_NAME;
98
99 sensorsEnabled = 0;
100 mOrientationCb = NULL;
101 mSensorEventQueue = NULL;
102 mSensorLooperThread = NULL;
103
104 LOG_FUNCTION_NAME_EXIT;
105 }
106
~SensorListener()107 SensorListener::~SensorListener() {
108 LOG_FUNCTION_NAME;
109
110 CAMHAL_LOGDA("Kill looper thread");
111 if (mSensorLooperThread.get()) {
112 // 1. Request exit
113 // 2. Wake up looper which should be polling for an event
114 // 3. Wait for exit
115 mSensorLooperThread->requestExit();
116 mSensorLooperThread->wake();
117 mSensorLooperThread->join();
118 mSensorLooperThread.clear();
119 mSensorLooperThread = NULL;
120 }
121
122 CAMHAL_LOGDA("Kill looper");
123 if (mLooper.get()) {
124 mLooper->removeFd(mSensorEventQueue->getFd());
125 mLooper.clear();
126 mLooper = NULL;
127 }
128 CAMHAL_LOGDA("SensorListener destroyed");
129
130 LOG_FUNCTION_NAME_EXIT;
131 }
132
initialize()133 status_t SensorListener::initialize() {
134 status_t ret = NO_ERROR;
135 SensorManager& mgr(SensorManager::getInstance());
136
137 LOG_FUNCTION_NAME;
138
139 sp<Looper> mLooper;
140
141 mSensorEventQueue = mgr.createEventQueue();
142 if (mSensorEventQueue == NULL) {
143 CAMHAL_LOGEA("createEventQueue returned NULL");
144 ret = NO_INIT;
145 goto out;
146 }
147
148 mLooper = new Looper(false);
149 mLooper->addFd(mSensorEventQueue->getFd(), 0, ALOOPER_EVENT_INPUT, sensor_events_listener, this);
150
151 if (mSensorLooperThread.get() == NULL)
152 mSensorLooperThread = new SensorLooperThread(mLooper.get());
153
154 if (mSensorLooperThread.get() == NULL) {
155 CAMHAL_LOGEA("Couldn't create sensor looper thread");
156 ret = NO_MEMORY;
157 goto out;
158 }
159
160 ret = mSensorLooperThread->run("sensor looper thread", PRIORITY_URGENT_DISPLAY);
161 if (ret == INVALID_OPERATION){
162 CAMHAL_LOGDA("thread already running ?!?");
163 } else if (ret != NO_ERROR) {
164 CAMHAL_LOGEA("couldn't run thread");
165 goto out;
166 }
167
168 out:
169 LOG_FUNCTION_NAME_EXIT;
170 return ret;
171 }
172
setCallbacks(orientation_callback_t orientation_cb,void * cookie)173 void SensorListener::setCallbacks(orientation_callback_t orientation_cb, void *cookie) {
174 LOG_FUNCTION_NAME;
175
176 if (orientation_cb) {
177 mOrientationCb = orientation_cb;
178 }
179 mCbCookie = cookie;
180
181 LOG_FUNCTION_NAME_EXIT;
182 }
183
handleOrientation(uint32_t orientation,uint32_t tilt)184 void SensorListener::handleOrientation(uint32_t orientation, uint32_t tilt) {
185 LOG_FUNCTION_NAME;
186
187 Mutex::Autolock lock(&mLock);
188
189 if (mOrientationCb && (sensorsEnabled & SENSOR_ORIENTATION)) {
190 mOrientationCb(orientation, tilt, mCbCookie);
191 }
192
193 LOG_FUNCTION_NAME_EXIT;
194 }
195
enableSensor(sensor_type_t type)196 void SensorListener::enableSensor(sensor_type_t type) {
197 Sensor const* sensor;
198 SensorManager& mgr(SensorManager::getInstance());
199
200 LOG_FUNCTION_NAME;
201
202 Mutex::Autolock lock(&mLock);
203
204 if ((type & SENSOR_ORIENTATION) && !(sensorsEnabled & SENSOR_ORIENTATION)) {
205 sensor = mgr.getDefaultSensor(Sensor::TYPE_ACCELEROMETER);
206 CAMHAL_LOGDB("orientation = %p (%s)", sensor, sensor->getName().string());
207 mSensorEventQueue->enableSensor(sensor);
208 mSensorEventQueue->setEventRate(sensor, ms2ns(100));
209 sensorsEnabled |= SENSOR_ORIENTATION;
210 }
211
212 LOG_FUNCTION_NAME_EXIT;
213 }
214
disableSensor(sensor_type_t type)215 void SensorListener::disableSensor(sensor_type_t type) {
216 Sensor const* sensor;
217 SensorManager& mgr(SensorManager::getInstance());
218
219 LOG_FUNCTION_NAME;
220
221 Mutex::Autolock lock(&mLock);
222
223 if ((type & SENSOR_ORIENTATION) && (sensorsEnabled & SENSOR_ORIENTATION)) {
224 sensor = mgr.getDefaultSensor(Sensor::TYPE_ACCELEROMETER);
225 CAMHAL_LOGDB("orientation = %p (%s)", sensor, sensor->getName().string());
226 mSensorEventQueue->disableSensor(sensor);
227 sensorsEnabled &= ~SENSOR_ORIENTATION;
228 }
229
230 LOG_FUNCTION_NAME_EXIT;
231 }
232
233 } // namespace android
234