gecko/hal/gonk/GonkSensor.cpp

243 lines
5.7 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <pthread.h>
#include <stdio.h>
#include "Hal.h"
#include "HalSensor.h"
#include "hardware/sensors.h"
#include "mozilla/Util.h"
#include "SensorDevice.h"
#include "nsThreadUtils.h"
using namespace mozilla::hal;
using namespace android;
namespace mozilla {
#define DEFAULT_DEVICE_POLL_RATE 100000000 /*100ms*/
double radToDeg(double a) {
return a * (180.0 / M_PI);
}
static SensorType
HardwareSensorToHalSensor(int type)
{
switch(type) {
case SENSOR_TYPE_ORIENTATION:
return SENSOR_ORIENTATION;
case SENSOR_TYPE_ACCELEROMETER:
return SENSOR_ACCELERATION;
case SENSOR_TYPE_PROXIMITY:
return SENSOR_PROXIMITY;
case SENSOR_TYPE_GYROSCOPE:
return SENSOR_GYROSCOPE;
case SENSOR_TYPE_LINEAR_ACCELERATION:
return SENSOR_LINEAR_ACCELERATION;
default:
return SENSOR_UNKNOWN;
}
}
static SensorAccuracyType
HardwareStatusToHalAccuracy(int status) {
return static_cast<SensorAccuracyType>(status);
}
static int
HalSensorToHardwareSensor(SensorType type)
{
switch(type) {
case SENSOR_ORIENTATION:
return SENSOR_TYPE_ORIENTATION;
case SENSOR_ACCELERATION:
return SENSOR_TYPE_ACCELEROMETER;
case SENSOR_PROXIMITY:
return SENSOR_TYPE_PROXIMITY;
case SENSOR_GYROSCOPE:
return SENSOR_TYPE_GYROSCOPE;
case SENSOR_LINEAR_ACCELERATION:
return SENSOR_TYPE_LINEAR_ACCELERATION;
default:
return -1;
}
}
static int
SensorseventStatus(const sensors_event_t& data)
{
int type = data.type;
switch(type) {
case SENSOR_ORIENTATION:
return data.orientation.status;
case SENSOR_LINEAR_ACCELERATION:
case SENSOR_ACCELERATION:
return data.acceleration.status;
case SENSOR_GYROSCOPE:
return data.gyro.status;
}
return SENSOR_STATUS_UNRELIABLE;
}
class SensorRunnable : public nsRunnable
{
public:
SensorRunnable(const sensors_event_t& data)
{
mSensorData.sensor() = HardwareSensorToHalSensor(data.type);
mSensorData.accuracy() = HardwareStatusToHalAccuracy(SensorseventStatus(data));
mSensorData.timestamp() = data.timestamp;
if (mSensorData.sensor() == SENSOR_GYROSCOPE) {
// libhardware returns gyro as rad. convert.
mSensorValues.AppendElement(radToDeg(data.data[0]));
mSensorValues.AppendElement(radToDeg(data.data[1]));
mSensorValues.AppendElement(radToDeg(data.data[2]));
} else {
mSensorValues.AppendElement(data.data[0]);
mSensorValues.AppendElement(data.data[1]);
mSensorValues.AppendElement(data.data[2]);
}
mSensorData.values() = mSensorValues;
}
~SensorRunnable() {}
NS_IMETHOD Run()
{
NotifySensorChange(mSensorData);
return NS_OK;
}
private:
SensorData mSensorData;
InfallibleTArray<float> mSensorValues;
};
namespace hal_impl {
static pthread_t sThread;
static bool sInitialized = false;
static bool sContinue = true;
static int sActivatedSensors = 0;
static nsCOMPtr<nsIThread> sSwitchThread;
static void*
UpdateSensorData(void* /*unused*/)
{
SensorDevice &device = SensorDevice::getInstance();
const size_t numEventMax = 16;
sensors_event_t buffer[numEventMax];
int count = 0;
while (sContinue) {
count = device.poll(buffer, numEventMax);
if (count < 0) {
continue;
}
for (int i=0; i<count; i++) {
if (SensorseventStatus(buffer[i]) == SENSOR_STATUS_UNRELIABLE) {
continue;
}
NS_DispatchToMainThread(new SensorRunnable(buffer[i]));
}
}
return NULL;
}
static void
InitializeResources()
{
sInitialized = true;
sContinue = true;
pthread_create(&sThread, NULL, &UpdateSensorData, NULL);
NS_NewThread(getter_AddRefs(sSwitchThread));
}
static void
ReleaseResources()
{
sContinue = false;
pthread_join(sThread, NULL);
sSwitchThread->Shutdown();
sInitialized = false;
}
// This class is used as a runnable on the sSwitchThread
class SensorInfo {
public:
NS_INLINE_DECL_REFCOUNTING(SensorInfo)
SensorInfo(bool aActivate, sensor_t aSensor, pthread_t aThreadId) :
activate(aActivate), sensor(aSensor), threadId(aThreadId) { }
void Switch() {
SensorDevice& device = SensorDevice::getInstance();
device.activate((void*)threadId, sensor.handle, activate);
device.setDelay((void*)threadId, sensor.handle, DEFAULT_DEVICE_POLL_RATE);
}
protected:
SensorInfo() { };
bool activate;
sensor_t sensor;
pthread_t threadId;
};
static void
SensorSwitch(SensorType aSensor, bool activate)
{
int type = HalSensorToHardwareSensor(aSensor);
const sensor_t* sensors = NULL;
SensorDevice& device = SensorDevice::getInstance();
size_t size = device.getSensorList(&sensors);
for (size_t i = 0; i < size; i++) {
if (sensors[i].type == type) {
// Post an event to the activation thread
nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethod(new SensorInfo(activate, sensors[i], pthread_self()),
&SensorInfo::Switch);
sSwitchThread->Dispatch(event, NS_DISPATCH_NORMAL);
break;
}
}
}
void
EnableSensorNotifications(SensorType aSensor)
{
if (!sInitialized) {
InitializeResources();
}
SensorSwitch(aSensor, true);
sActivatedSensors++;
}
void
DisableSensorNotifications(SensorType aSensor)
{
if (!sInitialized) {
NS_WARNING("Disable sensors without initializing first");
return;
}
SensorSwitch(aSensor, false);
sActivatedSensors--;
if (!sActivatedSensors) {
ReleaseResources();
}
}
} // hal_impl
} // mozilla