Source code

Revision control

Copy as Markdown

Other Tools

/* 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 "Hal.h"
#include <sensorsapi.h>
#include <sensors.h>
#include <portabledevicetypes.h>
#define MEAN_GRAVITY 9.80665
#define DEFAULT_SENSOR_POLL 100
using namespace mozilla::hal;
namespace mozilla {
namespace hal_impl {
static RefPtr<ISensor> sAccelerometer;
class SensorEvent final : public ISensorEvents {
public:
SensorEvent() : mCount(0) {}
// IUnknown interface
STDMETHODIMP_(ULONG) AddRef() { return InterlockedIncrement(&mCount); }
STDMETHODIMP_(ULONG) Release() {
ULONG count = InterlockedDecrement(&mCount);
if (!count) {
delete this;
return 0;
}
return count;
}
STDMETHODIMP QueryInterface(REFIID iid, void** ppv) {
if (iid == IID_IUnknown) {
*ppv = static_cast<IUnknown*>(this);
} else if (iid == IID_ISensorEvents) {
*ppv = static_cast<ISensorEvents*>(this);
} else {
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
// ISensorEvents interface
STDMETHODIMP OnEvent(ISensor* aSensor, REFGUID aId,
IPortableDeviceValues* aData) {
return S_OK;
}
STDMETHODIMP OnLeave(REFSENSOR_ID aId) { return S_OK; }
STDMETHODIMP OnStateChanged(ISensor* aSensor, SensorState state) {
return S_OK;
}
STDMETHODIMP OnDataUpdated(ISensor* aSensor, ISensorDataReport* aReport) {
PROPVARIANT v;
HRESULT hr;
nsTArray<float> values;
// X-axis acceleration in g's
hr = aReport->GetSensorValue(SENSOR_DATA_TYPE_ACCELERATION_X_G, &v);
if (FAILED(hr)) {
return hr;
}
values.AppendElement(float(-v.dblVal * MEAN_GRAVITY));
// Y-axis acceleration in g's
hr = aReport->GetSensorValue(SENSOR_DATA_TYPE_ACCELERATION_Y_G, &v);
if (FAILED(hr)) {
return hr;
}
values.AppendElement(float(-v.dblVal * MEAN_GRAVITY));
// Z-axis acceleration in g's
hr = aReport->GetSensorValue(SENSOR_DATA_TYPE_ACCELERATION_Z_G, &v);
if (FAILED(hr)) {
return hr;
}
values.AppendElement(float(-v.dblVal * MEAN_GRAVITY));
hal::SensorData sdata(hal::SENSOR_ACCELERATION, PR_Now(), values);
hal::NotifySensorChange(sdata);
return S_OK;
}
private:
ULONG mCount;
};
void EnableSensorNotifications(SensorType aSensor) {
if (aSensor != SENSOR_ACCELERATION) {
return;
}
if (sAccelerometer) {
return;
}
RefPtr<ISensorManager> manager;
if (FAILED(CoCreateInstance(CLSID_SensorManager, nullptr,
CLSCTX_INPROC_SERVER, IID_ISensorManager,
getter_AddRefs(manager)))) {
return;
}
// accelerometer event
RefPtr<ISensorCollection> collection;
if (FAILED(manager->GetSensorsByType(SENSOR_TYPE_ACCELEROMETER_3D,
getter_AddRefs(collection)))) {
return;
}
ULONG count = 0;
collection->GetCount(&count);
if (!count) {
return;
}
RefPtr<ISensor> sensor;
collection->GetAt(0, getter_AddRefs(sensor));
if (!sensor) {
return;
}
// Set report interval to 100ms if possible.
// Default value depends on drivers.
RefPtr<IPortableDeviceValues> values;
if (SUCCEEDED(CoCreateInstance(
CLSID_PortableDeviceValues, nullptr, CLSCTX_INPROC_SERVER,
IID_IPortableDeviceValues, getter_AddRefs(values)))) {
if (SUCCEEDED(values->SetUnsignedIntegerValue(
SENSOR_PROPERTY_CURRENT_REPORT_INTERVAL, DEFAULT_SENSOR_POLL))) {
RefPtr<IPortableDeviceValues> returns;
sensor->SetProperties(values, getter_AddRefs(returns));
}
}
RefPtr<SensorEvent> event = new SensorEvent();
RefPtr<ISensorEvents> sensorEvents;
if (FAILED(event->QueryInterface(IID_ISensorEvents,
getter_AddRefs(sensorEvents)))) {
return;
}
if (FAILED(sensor->SetEventSink(sensorEvents))) {
return;
}
sAccelerometer = sensor;
}
void DisableSensorNotifications(SensorType aSensor) {
if (aSensor == SENSOR_ACCELERATION && sAccelerometer) {
sAccelerometer->SetEventSink(nullptr);
sAccelerometer = nullptr;
}
}
} // namespace hal_impl
} // namespace mozilla