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