1/*
2 * Copyright (C) 2012 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#define LOG_TAG "BubbleLevelImpl"
18//#define LOG_NDEBUG 0
19
20#include <utils/Log.h>
21#include "BubbleLevelImpl.h"
22
23namespace android {
24
25static int sensor_callback(int fd, int events, void* data);
26
27#define BL_SENSOR_POLL_INTERVAL_MS 20
28#define BL_SENSOR_POLL_TIMEOUT_MS (BL_SENSOR_POLL_INTERVAL_MS * 5)
29#define BL_SENSOR_POLL_COUNT 10
30
31
32BubbleLevelImpl::BubbleLevelImpl()
33    : Thread(false),
34      mState(BL_STATE_IDLE), mCmd(BL_CMD_NONE),
35      mPollIntervalSec(BL_POLL_INTERVAL_DEFAULT_SEC), mPollCount(0), mLevelCount(0),
36      mCallBack(NULL), mUserData(NULL),
37      mNumSensors(0), mAccelerometer(NULL)
38
39{
40    SensorManager& mgr(SensorManager::getInstance());
41    Sensor const* const* sensorList;
42
43    mNumSensors = mgr.getSensorList(&sensorList);
44
45    if (mNumSensors <= 0) {
46        ALOGE("CSTOR mNumSensors error %d", mNumSensors);
47        return;
48    }
49    mAccelerometer = mgr.getDefaultSensor(Sensor::TYPE_ACCELEROMETER);
50    if (mAccelerometer == NULL) {
51        ALOGE("CSTOR mAccelerometer error NULL");
52        return;
53    }
54
55    mSensorEventQueue = mgr.createEventQueue();
56    if (mSensorEventQueue == NULL) {
57        ALOGE("createEventQueue returned NULL");
58        return;
59    }
60
61    mLooper = new Looper(false);
62    mLooper->addFd(mSensorEventQueue->getFd(), 0, ALOOPER_EVENT_INPUT, sensor_callback, this);
63}
64
65BubbleLevelImpl::~BubbleLevelImpl()
66{
67    {
68        Mutex::Autolock _l(mStateLock);
69        mCmd = BL_CMD_EXIT;
70        mLooper->wake();
71        mCond.broadcast();
72    }
73    requestExitAndWait();
74}
75
76void BubbleLevelImpl::onFirstRef()
77{
78    run("Acc Loop", ANDROID_PRIORITY_URGENT_AUDIO);
79}
80
81bool BubbleLevelImpl::threadLoop() {
82    bool isLevel;
83
84    while(!exitPending()) {
85        {
86            Mutex::Autolock _l(mStateLock);
87
88            isLevel = false;
89
90            switch (mCmd) {
91            case BL_CMD_POLL_ONCE:
92            case BL_CMD_START_POLL:
93                if (mState == BL_STATE_IDLE) {
94                    mSensorEventQueue->enableSensor(mAccelerometer);
95                    mSensorEventQueue->setEventRate(mAccelerometer,
96                                                    ms2ns(BL_SENSOR_POLL_INTERVAL_MS));
97                    mPollCount = 0;
98                    mLevelCount = 0;
99                    if (mCmd == BL_CMD_START_POLL) {
100                        mState = BL_STATE_POLLING;
101                    } else {
102                        mState = BL_STATE_POLLING_ONCE;
103                    }
104                }
105                if ((mCmd == BL_CMD_START_POLL) && (mState == BL_STATE_POLLING_ONCE)) {
106                    mState = BL_STATE_POLLING;
107                }
108                break;
109            case BL_CMD_STOP_POLL:
110                if (mState == BL_STATE_POLLING ||
111                        mState == BL_STATE_POLLING_ONCE ||
112                        mState == BL_STATE_SLEEPING) {
113                    mSensorEventQueue->disableSensor(mAccelerometer);
114                    mState = BL_STATE_IDLE;
115                }
116                break;
117            case BL_CMD_EXIT:
118                continue;
119            case BL_CMD_NONE:
120                break;
121            default:
122                ALOGE("unknown command: %d", mCmd);
123            }
124            mCmd = BL_CMD_NONE;
125
126            switch (mState) {
127            case BL_STATE_IDLE:
128                mCond.wait(mStateLock);
129                continue;
130
131            case BL_STATE_POLLING:
132            case BL_STATE_POLLING_ONCE:
133                if (mPollCount >= BL_SENSOR_POLL_COUNT) {
134                    // majority vote
135                    isLevel = (mLevelCount > (BL_SENSOR_POLL_COUNT / 2));
136                    if (mState == BL_STATE_POLLING_ONCE) {
137                        mCmd = BL_CMD_STOP_POLL;
138                    }
139                    mState = BL_STATE_SLEEPING;
140                }
141                break;
142            case BL_STATE_SLEEPING:
143                mCond.waitRelative(mStateLock, seconds(mPollIntervalSec));
144                mPollCount = 0;
145                mLevelCount = 0;
146                mState = BL_STATE_POLLING;
147                break;
148
149            default:
150                ALOGE("unknown state: %d", mState);
151                mState = BL_STATE_IDLE;
152                continue;
153            }
154        }
155
156        if (mState == BL_STATE_SLEEPING) {
157            Mutex::Autolock _l(mCallbackLock);
158            if (mCallBack != NULL) {
159                mCallBack(isLevel, mUserData);
160            }
161            continue;
162        }
163        mLooper->pollOnce(BL_SENSOR_POLL_TIMEOUT_MS);
164    }
165    ALOGV("threadLoop EXIT");
166    return false;
167}
168
169int BubbleLevelImpl::setCallback(BubbleLevel_CallBack_t callback, void *userData)
170{
171    Mutex::Autolock _l(mCallbackLock);
172    mCallBack = callback;
173    mUserData = userData;
174    return 0;
175}
176
177int BubbleLevelImpl::setPollInterval(unsigned int seconds)
178{
179    if (seconds < BL_POLL_INTERVAL_MIN_SEC) {
180        return -EINVAL;
181    }
182
183    Mutex::Autolock _l(mStateLock);
184    mPollIntervalSec = seconds;
185    return 0;
186}
187int BubbleLevelImpl::startPolling()
188{
189    Mutex::Autolock _l(mStateLock);
190    if (mCmd != BL_CMD_EXIT) {
191        mCmd = BL_CMD_START_POLL;
192        mCond.signal();
193    }
194    return 0;
195}
196
197int BubbleLevelImpl::stopPolling()
198{
199    Mutex::Autolock _l(mStateLock);
200    if (mCmd != BL_CMD_EXIT) {
201        mCmd = BL_CMD_STOP_POLL;
202        mCond.signal();
203    }
204    return 0;
205}
206
207int BubbleLevelImpl::pollOnce()
208{
209    Mutex::Autolock _l(mStateLock);
210    if (mCmd != BL_CMD_EXIT) {
211        mCmd = BL_CMD_POLL_ONCE;
212        mCond.signal();
213    }
214    return 0;
215}
216
217static int sensor_callback(int fd, int events, void* data)
218{
219    sp<BubbleLevelImpl> bl = sp<BubbleLevelImpl>((BubbleLevelImpl *)data);
220
221    bl->lockState();
222    if (((bl->state() != BubbleLevelImpl::BL_STATE_POLLING) &&
223            (bl->state() != BubbleLevelImpl::BL_STATE_POLLING_ONCE)) ||
224            (bl->pollCount() >= BL_SENSOR_POLL_COUNT)) {
225        bl->unlockState();
226        return 1;
227    }
228    bl->unlockState();
229
230    sp<SensorEventQueue> sensorEventQueue = bl->sensorEventQueue();
231    size_t numSensors = bl->numSensors();
232    bool isLevel = false;
233    ASensorEvent sensorEvents[numSensors];
234    ssize_t ret = sensorEventQueue->read(sensorEvents, numSensors);
235    if (ret > 0) {
236        for (int i = 0; i < ret; i++) {
237            if (sensorEvents[i].type == Sensor::TYPE_ACCELEROMETER) {
238                ALOGV("sensor_callback() azimuth = %f pitch = %f roll = %f",
239                      sensorEvents[i].vector.azimuth,
240                      sensorEvents[i].vector.pitch,
241                      sensorEvents[i].vector.roll);
242
243                if ((sensorEvents[i].vector.roll > 0.0) &&
244                        (sensorEvents[i].vector.azimuth < 1.0) &&
245                        (sensorEvents[i].vector.azimuth > -1.0) &&
246                        (sensorEvents[i].vector.pitch < 1.0) &&
247                        (sensorEvents[i].vector.pitch > -1.0)) {
248                    isLevel = true;
249                }
250                break;
251            }
252        }
253    }
254
255    bl->lockState();
256    bl->incPollCount();
257    if (isLevel) {
258        bl->incLevelCount();
259    }
260    bl->unlockState();
261
262    return 1;
263}
264
265}; // namespace android
266
267extern "C" {
268
269static int bl_set_callback(const struct bubble_level *bubble_level,
270                 BubbleLevel_CallBack_t callback, void *userData)
271{
272    bubble_level_C_impl *bl = (bubble_level_C_impl *)bubble_level;
273    return bl->bubble_level->setCallback(callback, userData);
274}
275
276static int bl_set_poll_interval(const struct bubble_level *bubble_level, unsigned int seconds)
277{
278    bubble_level_C_impl *bl = (bubble_level_C_impl *)bubble_level;
279    return bl->bubble_level->setPollInterval(seconds);
280}
281
282static int bl_start_polling(const struct bubble_level *bubble_level)
283{
284    bubble_level_C_impl *bl = (bubble_level_C_impl *)bubble_level;
285    return bl->bubble_level->startPolling();
286}
287
288static int bl_stop_polling(const struct bubble_level *bubble_level)
289{
290    bubble_level_C_impl *bl = (bubble_level_C_impl *)bubble_level;
291    return bl->bubble_level->stopPolling();
292}
293
294static int bl_poll_once(const struct bubble_level *bubble_level)
295{
296    bubble_level_C_impl *bl = (bubble_level_C_impl *)bubble_level;
297    return bl->bubble_level->pollOnce();
298}
299
300
301struct bubble_level *bubble_level_create()
302{
303    bubble_level_C_impl *bl = new bubble_level_C_impl();
304    bl->bubble_level = new android::BubbleLevelImpl();
305    bl->interface.set_callback = bl_set_callback;
306    bl->interface.set_poll_interval = bl_set_poll_interval;
307    bl->interface.start_polling = bl_start_polling;
308    bl->interface.stop_polling = bl_stop_polling;
309    bl->interface.poll_once = bl_poll_once;
310
311    return (bubble_level *)bl;
312}
313
314void bubble_level_release(const struct bubble_level *bubble_level)
315{
316    bubble_level_C_impl *bl = (bubble_level_C_impl *)bubble_level;
317
318    bl->bubble_level.clear();
319    delete bubble_level;
320}
321
322};
323