CocoaSensor.mm (4301B)
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" 8 9 #include <mach/mach.h> 10 #include <cmath> 11 #import <IOKit/IOKitLib.h> 12 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); 30 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; 35 36 float lux = ceil(static_cast<float>(term4 + term3 + term2 + term1 - 0.19)); 37 return lux > 0 ? lux : 0; 38 } 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); 49 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]; 57 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 } 71 72 hal::SensorData sdata(sensor, PR_Now(), values); 73 hal::NotifySensorChange(sdata); 74 } 75 } 76 void EnableSensorNotifications(SensorType aSensor) { 77 if (aSensor == SENSOR_ACCELERATION) { 78 int result = smsStartup(nil, nil); 79 80 if (result != SMS_SUCCESS) { 81 return; 82 } 83 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; 105 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"_ns); 112 } 113 } 114 } 115 void DisableSensorNotifications(SensorType aSensor) { 116 if (!sActiveSensors[aSensor] || 117 (aSensor != SENSOR_ACCELERATION && aSensor != SENSOR_LIGHT)) { 118 return; 119 } 120 121 sActiveSensors[aSensor] = false; 122 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 } 138 } 139 } // namespace hal_impl 140 } // namespace mozilla