Bug 1883912: Enable Intl.ListFormat test for "unit" style. r=spidermonkey-reviewers...
[gecko.git] / hal / cocoa / CocoaSensor.mm
blobecc39272dc02f7f6db0867ec3c161d09bf1ab017
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3  * You can obtain one at http://mozilla.org/MPL/2.0/. */
4 #include "Hal.h"
5 #include "nsITimer.h"
6 #include "smslib.h"
7 #include "nsComponentManagerUtils.h"
9 #include <mach/mach.h>
10 #include <cmath>
11 #import <IOKit/IOKitLib.h>
13 #define MEAN_GRAVITY 9.80665
14 #define DEFAULT_SENSOR_POLL 100
15 using namespace mozilla::hal;
16 namespace mozilla {
17 namespace hal_impl {
18 static nsITimer* sUpdateTimer = nullptr;
19 static bool sActiveSensors[NUM_SENSOR_TYPE];
20 static io_connect_t sDataPort = IO_OBJECT_NULL;
21 static uint64_t sLastMean = -1;
22 static float LMUvalueToLux(uint64_t aValue) {
23   // Conversion formula from regression. See Bug 793728.
24   // -3*(10^-27)*x^4 + 2.6*(10^-19)*x^3 + -3.4*(10^-12)*x^2 + 3.9*(10^-5)*x -
25   // 0.19
26   long double powerC4 = 1 / pow((long double)10, 27);
27   long double powerC3 = 1 / pow((long double)10, 19);
28   long double powerC2 = 1 / pow((long double)10, 12);
29   long double powerC1 = 1 / pow((long double)10, 5);
31   long double term4 = -3.0 * powerC4 * pow(aValue, 4);
32   long double term3 = 2.6 * powerC3 * pow(aValue, 3);
33   long double term2 = -3.4 * powerC2 * pow(aValue, 2);
34   long double term1 = 3.9 * powerC1 * aValue;
36   float lux = ceil(static_cast<float>(term4 + term3 + term2 + term1 - 0.19));
37   return lux > 0 ? lux : 0;
39 void UpdateHandler(nsITimer* aTimer, void* aClosure) {
40   for (int i = 0; i < NUM_SENSOR_TYPE; i++) {
41     if (!sActiveSensors[i]) {
42       continue;
43     }
44     SensorType sensor = static_cast<SensorType>(i);
45     nsTArray<float> values;
46     if (sensor == SENSOR_ACCELERATION) {
47       sms_acceleration accel;
48       smsGetData(&accel);
50       values.AppendElement(accel.x * MEAN_GRAVITY);
51       values.AppendElement(accel.y * MEAN_GRAVITY);
52       values.AppendElement(accel.z * MEAN_GRAVITY);
53     } else if (sensor == SENSOR_LIGHT && sDataPort != IO_OBJECT_NULL) {
54       kern_return_t kr;
55       uint32_t outputs = 2;
56       uint64_t lightLMU[outputs];
58       kr = IOConnectCallMethod(sDataPort, 0, nil, 0, nil, 0, lightLMU, &outputs,
59                                nil, 0);
60       if (kr == KERN_SUCCESS) {
61         uint64_t mean = (lightLMU[0] + lightLMU[1]) / 2;
62         if (mean == sLastMean) {
63           continue;
64         }
65         sLastMean = mean;
66         values.AppendElement(LMUvalueToLux(mean));
67       } else if (kr == kIOReturnBusy) {
68         continue;
69       }
70     }
72     hal::SensorData sdata(sensor, PR_Now(), values);
73     hal::NotifySensorChange(sdata);
74   }
76 void EnableSensorNotifications(SensorType aSensor) {
77   if (aSensor == SENSOR_ACCELERATION) {
78     int result = smsStartup(nil, nil);
80     if (result != SMS_SUCCESS) {
81       return;
82     }
84     if (!smsLoadCalibration()) {
85       return;
86     }
87   } else if (aSensor == SENSOR_LIGHT) {
88     io_service_t serviceObject;
89     serviceObject = IOServiceGetMatchingService(
90         kIOMasterPortDefault, IOServiceMatching("AppleLMUController"));
91     if (!serviceObject) {
92       return;
93     }
94     kern_return_t kr;
95     kr = IOServiceOpen(serviceObject, mach_task_self(), 0, &sDataPort);
96     IOObjectRelease(serviceObject);
97     if (kr != KERN_SUCCESS) {
98       return;
99     }
100   } else {
101     NS_WARNING("EnableSensorNotifications called on an unknown sensor type");
102     return;
103   }
104   sActiveSensors[aSensor] = true;
106   if (!sUpdateTimer) {
107     CallCreateInstance("@mozilla.org/timer;1", &sUpdateTimer);
108     if (sUpdateTimer) {
109       sUpdateTimer->InitWithNamedFuncCallback(
110           UpdateHandler, nullptr, DEFAULT_SENSOR_POLL,
111           nsITimer::TYPE_REPEATING_SLACK, "hal_impl::UpdateHandler");
112     }
113   }
115 void DisableSensorNotifications(SensorType aSensor) {
116   if (!sActiveSensors[aSensor] ||
117       (aSensor != SENSOR_ACCELERATION && aSensor != SENSOR_LIGHT)) {
118     return;
119   }
121   sActiveSensors[aSensor] = false;
123   if (aSensor == SENSOR_ACCELERATION) {
124     smsShutdown();
125   } else if (aSensor == SENSOR_LIGHT) {
126     IOServiceClose(sDataPort);
127   }
128   // If all sensors are disabled, cancel the update timer.
129   if (sUpdateTimer) {
130     for (int i = 0; i < NUM_SENSOR_TYPE; i++) {
131       if (sActiveSensors[i]) {
132         return;
133       }
134     }
135     sUpdateTimer->Cancel();
136     NS_RELEASE(sUpdateTimer);
137   }
139 }  // namespace hal_impl
140 }  // namespace mozilla