michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* Copyright 2012 Mozilla Foundation and Mozilla contributors michael@0: * michael@0: * Licensed under the Apache License, Version 2.0 (the "License"); michael@0: * you may not use this file except in compliance with the License. michael@0: * You may obtain a copy of the License at michael@0: * michael@0: * http://www.apache.org/licenses/LICENSE-2.0 michael@0: * michael@0: * Unless required by applicable law or agreed to in writing, software michael@0: * distributed under the License is distributed on an "AS IS" BASIS, michael@0: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. michael@0: * See the License for the specific language governing permissions and michael@0: * limitations under the License. michael@0: */ michael@0: michael@0: #include michael@0: #include michael@0: michael@0: #include "mozilla/DebugOnly.h" michael@0: michael@0: #include "base/basictypes.h" michael@0: #include "base/thread.h" michael@0: michael@0: #include "Hal.h" michael@0: #include "HalSensor.h" michael@0: #include "hardware/sensors.h" michael@0: #include "nsThreadUtils.h" michael@0: michael@0: #undef LOG michael@0: michael@0: #include michael@0: michael@0: using namespace mozilla::hal; michael@0: michael@0: #define LOGE(args...) __android_log_print(ANDROID_LOG_ERROR, "GonkSensor" , ## args) michael@0: #define LOGW(args...) __android_log_print(ANDROID_LOG_WARN, "GonkSensor" , ## args) michael@0: michael@0: namespace mozilla { michael@0: michael@0: // The value from SensorDevice.h (Android) michael@0: #define DEFAULT_DEVICE_POLL_RATE 200000000 /*200ms*/ michael@0: // ProcessOrientation.cpp needs smaller poll rate to detect delay between michael@0: // different orientation angles michael@0: #define ACCELEROMETER_POLL_RATE 66667000 /*66.667ms*/ michael@0: michael@0: double radToDeg(double a) { michael@0: return a * (180.0 / M_PI); michael@0: } michael@0: michael@0: static SensorType michael@0: HardwareSensorToHalSensor(int type) michael@0: { michael@0: switch(type) { michael@0: case SENSOR_TYPE_ORIENTATION: michael@0: return SENSOR_ORIENTATION; michael@0: case SENSOR_TYPE_ACCELEROMETER: michael@0: return SENSOR_ACCELERATION; michael@0: case SENSOR_TYPE_PROXIMITY: michael@0: return SENSOR_PROXIMITY; michael@0: case SENSOR_TYPE_LIGHT: michael@0: return SENSOR_LIGHT; michael@0: case SENSOR_TYPE_GYROSCOPE: michael@0: return SENSOR_GYROSCOPE; michael@0: case SENSOR_TYPE_LINEAR_ACCELERATION: michael@0: return SENSOR_LINEAR_ACCELERATION; michael@0: default: michael@0: return SENSOR_UNKNOWN; michael@0: } michael@0: } michael@0: michael@0: static SensorAccuracyType michael@0: HardwareStatusToHalAccuracy(int status) { michael@0: return static_cast(status); michael@0: } michael@0: michael@0: static int michael@0: HalSensorToHardwareSensor(SensorType type) michael@0: { michael@0: switch(type) { michael@0: case SENSOR_ORIENTATION: michael@0: return SENSOR_TYPE_ORIENTATION; michael@0: case SENSOR_ACCELERATION: michael@0: return SENSOR_TYPE_ACCELEROMETER; michael@0: case SENSOR_PROXIMITY: michael@0: return SENSOR_TYPE_PROXIMITY; michael@0: case SENSOR_LIGHT: michael@0: return SENSOR_TYPE_LIGHT; michael@0: case SENSOR_GYROSCOPE: michael@0: return SENSOR_TYPE_GYROSCOPE; michael@0: case SENSOR_LINEAR_ACCELERATION: michael@0: return SENSOR_TYPE_LINEAR_ACCELERATION; michael@0: default: michael@0: return -1; michael@0: } michael@0: } michael@0: michael@0: static int michael@0: SensorseventStatus(const sensors_event_t& data) michael@0: { michael@0: int type = data.type; michael@0: switch(type) { michael@0: case SENSOR_ORIENTATION: michael@0: return data.orientation.status; michael@0: case SENSOR_LINEAR_ACCELERATION: michael@0: case SENSOR_ACCELERATION: michael@0: return data.acceleration.status; michael@0: case SENSOR_GYROSCOPE: michael@0: return data.gyro.status; michael@0: } michael@0: michael@0: return SENSOR_STATUS_UNRELIABLE; michael@0: } michael@0: michael@0: class SensorRunnable : public nsRunnable michael@0: { michael@0: public: michael@0: SensorRunnable(const sensors_event_t& data, const sensor_t* sensors, ssize_t size) michael@0: { michael@0: mSensorData.sensor() = HardwareSensorToHalSensor(data.type); michael@0: mSensorData.accuracy() = HardwareStatusToHalAccuracy(SensorseventStatus(data)); michael@0: mSensorData.timestamp() = data.timestamp; michael@0: if (mSensorData.sensor() == SENSOR_GYROSCOPE) { michael@0: // libhardware returns gyro as rad. convert. michael@0: mSensorValues.AppendElement(radToDeg(data.data[0])); michael@0: mSensorValues.AppendElement(radToDeg(data.data[1])); michael@0: mSensorValues.AppendElement(radToDeg(data.data[2])); michael@0: } else if (mSensorData.sensor() == SENSOR_PROXIMITY) { michael@0: mSensorValues.AppendElement(data.data[0]); michael@0: mSensorValues.AppendElement(0); michael@0: michael@0: // Determine the maxRange for this sensor. michael@0: for (ssize_t i = 0; i < size; i++) { michael@0: if (sensors[i].type == SENSOR_TYPE_PROXIMITY) { michael@0: mSensorValues.AppendElement(sensors[i].maxRange); michael@0: } michael@0: } michael@0: } else if (mSensorData.sensor() == SENSOR_LIGHT) { michael@0: mSensorValues.AppendElement(data.data[0]); michael@0: } else { michael@0: mSensorValues.AppendElement(data.data[0]); michael@0: mSensorValues.AppendElement(data.data[1]); michael@0: mSensorValues.AppendElement(data.data[2]); michael@0: } michael@0: mSensorData.values() = mSensorValues; michael@0: } michael@0: michael@0: ~SensorRunnable() {} michael@0: michael@0: NS_IMETHOD Run() michael@0: { michael@0: NotifySensorChange(mSensorData); michael@0: return NS_OK; michael@0: } michael@0: michael@0: private: michael@0: SensorData mSensorData; michael@0: InfallibleTArray mSensorValues; michael@0: }; michael@0: michael@0: namespace hal_impl { michael@0: michael@0: static DebugOnly sSensorRefCount[NUM_SENSOR_TYPE]; michael@0: static base::Thread* sPollingThread; michael@0: static sensors_poll_device_t* sSensorDevice; michael@0: static sensors_module_t* sSensorModule; michael@0: michael@0: static void michael@0: PollSensors() michael@0: { michael@0: const size_t numEventMax = 16; michael@0: sensors_event_t buffer[numEventMax]; michael@0: const sensor_t* sensors; michael@0: int size = sSensorModule->get_sensors_list(sSensorModule, &sensors); michael@0: michael@0: do { michael@0: // didn't check sSensorDevice because already be done on creating pollingThread. michael@0: int n = sSensorDevice->poll(sSensorDevice, buffer, numEventMax); michael@0: if (n < 0) { michael@0: LOGE("Error polling for sensor data (err=%d)", n); michael@0: break; michael@0: } michael@0: michael@0: for (int i = 0; i < n; ++i) { michael@0: // FIXME: bug 802004, add proper support for the magnetic field sensor. michael@0: if (buffer[i].type == SENSOR_TYPE_MAGNETIC_FIELD) michael@0: continue; michael@0: michael@0: // Bug 938035, transfer HAL data for orientation sensor to meet w3c spec michael@0: // ex: HAL report alpha=90 means East but alpha=90 means West in w3c spec michael@0: if (buffer[i].type == SENSOR_TYPE_ORIENTATION) { michael@0: buffer[i].orientation.azimuth = 360 - buffer[i].orientation.azimuth; michael@0: buffer[i].orientation.pitch = -buffer[i].orientation.pitch; michael@0: buffer[i].orientation.roll = -buffer[i].orientation.roll; michael@0: } michael@0: michael@0: if (HardwareSensorToHalSensor(buffer[i].type) == SENSOR_UNKNOWN) { michael@0: // Emulator is broken and gives us events without types set michael@0: int index; michael@0: for (index = 0; index < size; index++) { michael@0: if (sensors[index].handle == buffer[i].sensor) { michael@0: break; michael@0: } michael@0: } michael@0: if (index < size && michael@0: HardwareSensorToHalSensor(sensors[index].type) != SENSOR_UNKNOWN) { michael@0: buffer[i].type = sensors[index].type; michael@0: } else { michael@0: LOGW("Could not determine sensor type of event"); michael@0: continue; michael@0: } michael@0: } michael@0: michael@0: NS_DispatchToMainThread(new SensorRunnable(buffer[i], sensors, size)); michael@0: } michael@0: } while (true); michael@0: } michael@0: michael@0: static void michael@0: SwitchSensor(bool aActivate, sensor_t aSensor, pthread_t aThreadId) michael@0: { michael@0: int index = HardwareSensorToHalSensor(aSensor.type); michael@0: michael@0: MOZ_ASSERT(sSensorRefCount[index] || aActivate); michael@0: michael@0: sSensorDevice->activate(sSensorDevice, aSensor.handle, aActivate); michael@0: michael@0: if (aActivate) { michael@0: if (aSensor.type == SENSOR_TYPE_ACCELEROMETER) { michael@0: sSensorDevice->setDelay(sSensorDevice, aSensor.handle, michael@0: ACCELEROMETER_POLL_RATE); michael@0: } else { michael@0: sSensorDevice->setDelay(sSensorDevice, aSensor.handle, michael@0: DEFAULT_DEVICE_POLL_RATE); michael@0: } michael@0: } michael@0: michael@0: if (aActivate) { michael@0: sSensorRefCount[index]++; michael@0: } else { michael@0: sSensorRefCount[index]--; michael@0: } michael@0: } michael@0: michael@0: static void michael@0: SetSensorState(SensorType aSensor, bool activate) michael@0: { michael@0: int type = HalSensorToHardwareSensor(aSensor); michael@0: const sensor_t* sensors = nullptr; michael@0: michael@0: int size = sSensorModule->get_sensors_list(sSensorModule, &sensors); michael@0: for (ssize_t i = 0; i < size; i++) { michael@0: if (sensors[i].type == type) { michael@0: SwitchSensor(activate, sensors[i], pthread_self()); michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: michael@0: void michael@0: EnableSensorNotifications(SensorType aSensor) michael@0: { michael@0: if (!sSensorModule) { michael@0: hw_get_module(SENSORS_HARDWARE_MODULE_ID, michael@0: (hw_module_t const**)&sSensorModule); michael@0: if (!sSensorModule) { michael@0: LOGE("Can't get sensor HAL module\n"); michael@0: return; michael@0: } michael@0: michael@0: sensors_open(&sSensorModule->common, &sSensorDevice); michael@0: if (!sSensorDevice) { michael@0: sSensorModule = nullptr; michael@0: LOGE("Can't get sensor poll device from module \n"); michael@0: return; michael@0: } michael@0: michael@0: sensor_t const* sensors; michael@0: int count = sSensorModule->get_sensors_list(sSensorModule, &sensors); michael@0: for (size_t i=0 ; iactivate(sSensorDevice, sensors[i].handle, 0); michael@0: } michael@0: } michael@0: michael@0: if (!sPollingThread) { michael@0: sPollingThread = new base::Thread("GonkSensors"); michael@0: MOZ_ASSERT(sPollingThread); michael@0: // sPollingThread never terminates because poll may never return michael@0: sPollingThread->Start(); michael@0: sPollingThread->message_loop()->PostTask(FROM_HERE, michael@0: NewRunnableFunction(PollSensors)); michael@0: } michael@0: michael@0: SetSensorState(aSensor, true); michael@0: } michael@0: michael@0: void michael@0: DisableSensorNotifications(SensorType aSensor) michael@0: { michael@0: if (!sSensorModule) { michael@0: return; michael@0: } michael@0: SetSensorState(aSensor, false); michael@0: } michael@0: michael@0: } // hal_impl michael@0: } // mozilla