C++程序  |  367行  |  10.25 KB

/*
 * Copyright (C) 2012 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#define LOG_TAG "BubbleLevelImpl"
//#define LOG_NDEBUG 0

#include <utils/Log.h>
#include <binder/IServiceManager.h>
#include "BubbleLevelImpl.h"

namespace android {

static int sensor_callback(int fd, int events, void* data);

#define BL_SENSOR_POLL_INTERVAL_MS 20
#define BL_SENSOR_POLL_TIMEOUT_MS (BL_SENSOR_POLL_INTERVAL_MS * 5)
#define BL_SENSOR_POLL_COUNT 10
#define BL_SENSOR_LEVEL_THRESHOLD (2.0)

BubbleLevelImpl::BubbleLevelImpl()
    : Thread(false),
      mState(BL_STATE_IDLE), mCmd(BL_CMD_NONE),
      mPollIntervalSec(BL_POLL_INTERVAL_DEFAULT_SEC), mPollCount(0), mLevelCount(0),
      mCallBack(NULL), mUserData(NULL),
      mNumSensors(0), mAccelerometer(NULL),
      mInitStatus(-ENODEV)
{
    init();
}

int BubbleLevelImpl::init()
{
    if (mInitStatus == 0) {
        return 0;
    }

    if (defaultServiceManager()->checkService(String16("sensorservice")) == 0) {
        ALOGW("CSTOR sensorservice not ready yet");
        return mInitStatus;
    }

    SensorManager& mgr(SensorManager::getInstance());
    Sensor const* const* sensorList;

    mNumSensors = mgr.getSensorList(&sensorList);

    if (mNumSensors <= 0) {
        ALOGE("CSTOR mNumSensors error %d", mNumSensors);
        goto exit;
    }
    mAccelerometer = mgr.getDefaultSensor(Sensor::TYPE_ACCELEROMETER);
    if (mAccelerometer == NULL) {
        ALOGE("CSTOR mAccelerometer error NULL");
        goto exit;
    }

    mSensorEventQueue = mgr.createEventQueue();
    if (mSensorEventQueue == 0) {
        ALOGE("createEventQueue returned 0");
        goto exit;
    }

    mLooper = new Looper(false);
    mLooper->addFd(mSensorEventQueue->getFd(), 0, ALOOPER_EVENT_INPUT, sensor_callback, this);

    mInitStatus = 0;

exit:
    return mInitStatus;
}

BubbleLevelImpl::~BubbleLevelImpl()
{
    {
        Mutex::Autolock _l(mStateLock);
        mCmd = BL_CMD_EXIT;
        mLooper->wake();
        mCond.broadcast();
    }
    requestExitAndWait();
}

void BubbleLevelImpl::onFirstRef()
{
    if (mInitStatus == 0) {
        run("Acc Loop", ANDROID_PRIORITY_URGENT_AUDIO);
    }
}

bool BubbleLevelImpl::threadLoop() {
    bool isLevel;

    while(!exitPending()) {
        {
            Mutex::Autolock _l(mStateLock);

            isLevel = false;

            switch (mCmd) {
            case BL_CMD_POLL_ONCE:
            case BL_CMD_START_POLL:
                if (mState == BL_STATE_IDLE) {
                    mSensorEventQueue->enableSensor(mAccelerometer);
                    mSensorEventQueue->setEventRate(mAccelerometer,
                                                    ms2ns(BL_SENSOR_POLL_INTERVAL_MS));
                    mPollCount = 0;
                    mLevelCount = 0;
                    if (mCmd == BL_CMD_START_POLL) {
                        mState = BL_STATE_POLLING;
                    } else {
                        mState = BL_STATE_POLLING_ONCE;
                    }
                }
                if ((mCmd == BL_CMD_START_POLL) && (mState == BL_STATE_POLLING_ONCE)) {
                    mState = BL_STATE_POLLING;
                }
                break;
            case BL_CMD_STOP_POLL:
                if (mState == BL_STATE_POLLING ||
                        mState == BL_STATE_POLLING_ONCE ||
                        mState == BL_STATE_SLEEPING) {
                    mSensorEventQueue->disableSensor(mAccelerometer);
                    mState = BL_STATE_IDLE;
                }
                break;
            case BL_CMD_EXIT:
                continue;
            case BL_CMD_NONE:
                break;
            default:
                ALOGE("unknown command: %d", mCmd);
            }
            mCmd = BL_CMD_NONE;

            switch (mState) {
            case BL_STATE_IDLE:
                mCond.wait(mStateLock);
                continue;

            case BL_STATE_POLLING:
            case BL_STATE_POLLING_ONCE:
                if (mPollCount >= BL_SENSOR_POLL_COUNT) {
                    // majority vote
                    isLevel = (mLevelCount > (BL_SENSOR_POLL_COUNT / 2));
                    if (mState == BL_STATE_POLLING_ONCE) {
                        mCmd = BL_CMD_STOP_POLL;
                    }
                    mState = BL_STATE_SLEEPING;
                }
                break;
            case BL_STATE_SLEEPING:
                mCond.waitRelative(mStateLock, seconds(mPollIntervalSec));
                mPollCount = 0;
                mLevelCount = 0;
                mState = BL_STATE_POLLING;
                break;

            default:
                ALOGE("unknown state: %d", mState);
                mState = BL_STATE_IDLE;
                continue;
            }
        }

        if (mState == BL_STATE_SLEEPING) {
            Mutex::Autolock _l(mCallbackLock);
            if (mCallBack != NULL) {
                mCallBack(isLevel, mUserData);
            }
            continue;
        }
        mLooper->pollOnce(BL_SENSOR_POLL_TIMEOUT_MS);
    }
    ALOGV("threadLoop EXIT");
    return false;
}

int BubbleLevelImpl::setCallback(BubbleLevel_CallBack_t callback, void *userData)
{
    Mutex::Autolock _l(mCallbackLock);
    if (mInitStatus != 0) {
        return mInitStatus;
    }
    mCallBack = callback;
    mUserData = userData;
    return 0;
}

int BubbleLevelImpl::setPollInterval(unsigned int seconds)
{
    if (seconds < BL_POLL_INTERVAL_MIN_SEC) {
        return -EINVAL;
    }

    Mutex::Autolock _l(mStateLock);
    if (mInitStatus != 0) {
        return mInitStatus;
    }
    mPollIntervalSec = seconds;
    return 0;
}
int BubbleLevelImpl::startPolling()
{
    Mutex::Autolock _l(mStateLock);
    if (mInitStatus != 0) {
        return mInitStatus;
    }
    if (mCmd != BL_CMD_EXIT) {
        mCmd = BL_CMD_START_POLL;
        mCond.signal();
    }
    return 0;
}

int BubbleLevelImpl::stopPolling()
{
    Mutex::Autolock _l(mStateLock);
    if (mInitStatus != 0) {
        return mInitStatus;
    }
    if (mCmd != BL_CMD_EXIT) {
        mCmd = BL_CMD_STOP_POLL;
        mCond.signal();
    }
    return 0;
}

int BubbleLevelImpl::pollOnce()
{
    Mutex::Autolock _l(mStateLock);
    if (mInitStatus != 0) {
        return mInitStatus;
    }
    if (mCmd != BL_CMD_EXIT) {
        mCmd = BL_CMD_POLL_ONCE;
        mCond.signal();
    }
    return 0;
}

static int sensor_callback(int fd, int events, void* data)
{
    sp<BubbleLevelImpl> bl = sp<BubbleLevelImpl>((BubbleLevelImpl *)data);

    bl->lockState();
    if (((bl->state() != BubbleLevelImpl::BL_STATE_POLLING) &&
            (bl->state() != BubbleLevelImpl::BL_STATE_POLLING_ONCE)) ||
            (bl->pollCount() >= BL_SENSOR_POLL_COUNT)) {
        bl->unlockState();
        return 1;
    }
    bl->unlockState();

    sp<SensorEventQueue> sensorEventQueue = bl->sensorEventQueue();
    size_t numSensors = bl->numSensors();
    bool isLevel = false;
    ASensorEvent sensorEvents[numSensors];
    ssize_t ret = sensorEventQueue->read(sensorEvents, numSensors);
    if (ret > 0) {
        for (int i = 0; i < ret; i++) {
            if (sensorEvents[i].type == Sensor::TYPE_ACCELEROMETER) {
                ALOGV("sensor_callback() azimuth = %f pitch = %f roll = %f",
                      sensorEvents[i].vector.azimuth,
                      sensorEvents[i].vector.pitch,
                      sensorEvents[i].vector.roll);

                if ((sensorEvents[i].vector.roll > 0.0) &&
                        (sensorEvents[i].vector.azimuth < BL_SENSOR_LEVEL_THRESHOLD) &&
                        (sensorEvents[i].vector.azimuth > -BL_SENSOR_LEVEL_THRESHOLD) &&
                        (sensorEvents[i].vector.pitch < BL_SENSOR_LEVEL_THRESHOLD) &&
                        (sensorEvents[i].vector.pitch > -BL_SENSOR_LEVEL_THRESHOLD)) {
                    isLevel = true;
                }
                break;
            }
        }
    }

    bl->lockState();
    bl->incPollCount();
    if (isLevel) {
        bl->incLevelCount();
    }
    bl->unlockState();

    return 1;
}

}; // namespace android

extern "C" {

static int bl_set_callback(const struct bubble_level *bubble_level,
                 BubbleLevel_CallBack_t callback, void *userData)
{
    bubble_level_C_impl *bl = (bubble_level_C_impl *)bubble_level;
    return bl->bubble_level->setCallback(callback, userData);
}

static int bl_set_poll_interval(const struct bubble_level *bubble_level, unsigned int seconds)
{
    bubble_level_C_impl *bl = (bubble_level_C_impl *)bubble_level;
    return bl->bubble_level->setPollInterval(seconds);
}

static int bl_start_polling(const struct bubble_level *bubble_level)
{
    bubble_level_C_impl *bl = (bubble_level_C_impl *)bubble_level;
    return bl->bubble_level->startPolling();
}

static int bl_stop_polling(const struct bubble_level *bubble_level)
{
    bubble_level_C_impl *bl = (bubble_level_C_impl *)bubble_level;
    return bl->bubble_level->stopPolling();
}

static int bl_poll_once(const struct bubble_level *bubble_level)
{
    bubble_level_C_impl *bl = (bubble_level_C_impl *)bubble_level;
    return bl->bubble_level->pollOnce();
}


struct bubble_level *bubble_level_create()
{
    bubble_level_C_impl *bl = new bubble_level_C_impl();
    bl->bubble_level = new android::BubbleLevelImpl();
    if (bl->bubble_level->initStatus() != 0) {
        bubble_level_release((struct bubble_level *)bl);
        return NULL;
    }
    bl->interface.set_callback = bl_set_callback;
    bl->interface.set_poll_interval = bl_set_poll_interval;
    bl->interface.start_polling = bl_start_polling;
    bl->interface.stop_polling = bl_stop_polling;
    bl->interface.poll_once = bl_poll_once;

    return (struct bubble_level *)bl;
}

void bubble_level_release(const struct bubble_level *bubble_level)
{
    bubble_level_C_impl *bl = (bubble_level_C_impl *)bubble_level;

    if (bl == NULL)
        return;

    bl->bubble_level.clear();
    delete bubble_level;
}

};