1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/device_sensors/data_fetcher_shared_memory.h"
7 #include "base/logging.h"
8 #include "base/metrics/histogram.h"
9 #include "content/browser/device_sensors/ambient_light_mac.h"
10 #include "third_party/sudden_motion_sensor/sudden_motion_sensor_mac.h"
14 const double kMeanGravity
= 9.80665;
16 double LMUvalueToLux(uint64_t raw_value
) {
17 // Conversion formula from regression.
18 // https://bugzilla.mozilla.org/show_bug.cgi?id=793728
19 // Let x = raw_value, then
20 // lux = -2.978303814*(10^-27)*x^4 + 2.635687683*(10^-19)*x^3 -
21 // 3.459747434*(10^-12)*x^2 + 3.905829689*(10^-5)*x - 0.1932594532
23 static const long double k4
= pow(10.L
, -7);
24 static const long double k3
= pow(10.L
, -4);
25 static const long double k2
= pow(10.L
, -2);
26 static const long double k1
= pow(10.L
, 5);
27 long double scaled_value
= raw_value
/ k1
;
29 long double lux_value
=
30 (-3 * k4
* pow(scaled_value
, 4)) + (2.6 * k3
* pow(scaled_value
, 3)) +
31 (-3.4 * k2
* pow(scaled_value
, 2)) + (3.9 * scaled_value
) - 0.19;
33 double lux
= ceil(static_cast<double>(lux_value
));
34 return lux
> 0 ? lux
: 0;
37 void FetchLight(content::AmbientLightSensor
* sensor
,
38 content::DeviceLightHardwareBuffer
* buffer
) {
41 // Macbook pro has 2 lux values, left and right, we take the average.
42 // The raw sensor values are converted to lux using LMUvalueToLux(raw_value)
43 // similar to how it is done in Firefox.
44 uint64_t lux_value
[2];
45 if (!sensor
->ReadSensorValue(lux_value
))
47 uint64_t mean
= (lux_value
[0] + lux_value
[1]) / 2;
48 double lux
= LMUvalueToLux(mean
);
49 buffer
->seqlock
.WriteBegin();
50 buffer
->data
.value
= lux
;
51 buffer
->seqlock
.WriteEnd();
54 void FetchMotion(SuddenMotionSensor
* sensor
,
55 content::DeviceMotionHardwareBuffer
* buffer
) {
60 if (!sensor
->ReadSensorValues(axis_value
))
63 buffer
->seqlock
.WriteBegin();
64 buffer
->data
.accelerationIncludingGravityX
= axis_value
[0] * kMeanGravity
;
65 buffer
->data
.hasAccelerationIncludingGravityX
= true;
66 buffer
->data
.accelerationIncludingGravityY
= axis_value
[1] * kMeanGravity
;
67 buffer
->data
.hasAccelerationIncludingGravityY
= true;
68 buffer
->data
.accelerationIncludingGravityZ
= axis_value
[2] * kMeanGravity
;
69 buffer
->data
.hasAccelerationIncludingGravityZ
= true;
70 buffer
->data
.allAvailableSensorsAreActive
= true;
71 buffer
->seqlock
.WriteEnd();
74 void FetchOrientation(SuddenMotionSensor
* sensor
,
75 content::DeviceOrientationHardwareBuffer
* buffer
) {
79 // Retrieve per-axis calibrated values.
81 if (!sensor
->ReadSensorValues(axis_value
))
84 // Transform the accelerometer values to W3C draft angles.
86 // Accelerometer values are just dot products of the sensor axes
87 // by the gravity vector 'g' with the result for the z axis inverted.
89 // To understand this transformation calculate the 3rd row of the z-x-y
90 // Euler angles rotation matrix (because of the 'g' vector, only 3rd row
91 // affects to the result). Note that z-x-y matrix means R = Ry * Rx * Rz.
92 // Then, assume alpha = 0 and you get this:
95 // y_acc = - cos(gamma) * sin(beta)
96 // z_acc = cos(beta) * cos(gamma)
98 // After that the rest is just a bit of trigonometry.
100 // Also note that alpha can't be provided but it's assumed to be always zero.
101 // This is necessary in order to provide enough information to solve
104 const double kRad2deg
= 180.0 / M_PI
;
105 double beta
= kRad2deg
* atan2(-axis_value
[1], axis_value
[2]);
106 double gamma
= kRad2deg
* asin(axis_value
[0]);
108 // Make sure that the interval boundaries comply with the specification. At
109 // this point, beta is [-180, 180] and gamma is [-90, 90], but the spec has
110 // the upper bound open on both.
112 beta
= -180; // -180 == 180 (upside-down)
114 gamma
= nextafter(90, 0);
116 // At this point, DCHECKing is paranoia. Never hurts.
117 DCHECK_GE(beta
, -180.0);
118 DCHECK_LT(beta
, 180.0);
119 DCHECK_GE(gamma
, -90.0);
120 DCHECK_LT(gamma
, 90.0);
122 buffer
->seqlock
.WriteBegin();
123 buffer
->data
.beta
= beta
;
124 buffer
->data
.hasBeta
= true;
125 buffer
->data
.gamma
= gamma
;
126 buffer
->data
.hasGamma
= true;
127 buffer
->data
.allAvailableSensorsAreActive
= true;
128 buffer
->seqlock
.WriteEnd();
135 DataFetcherSharedMemory::DataFetcherSharedMemory() {
138 DataFetcherSharedMemory::~DataFetcherSharedMemory() {
141 void DataFetcherSharedMemory::Fetch(unsigned consumer_bitmask
) {
142 DCHECK(base::MessageLoop::current() == GetPollingMessageLoop());
143 DCHECK(consumer_bitmask
& CONSUMER_TYPE_ORIENTATION
||
144 consumer_bitmask
& CONSUMER_TYPE_MOTION
||
145 consumer_bitmask
& CONSUMER_TYPE_LIGHT
);
147 if (consumer_bitmask
& CONSUMER_TYPE_ORIENTATION
)
148 FetchOrientation(sudden_motion_sensor_
.get(), orientation_buffer_
);
149 if (consumer_bitmask
& CONSUMER_TYPE_MOTION
)
150 FetchMotion(sudden_motion_sensor_
.get(), motion_buffer_
);
151 if (consumer_bitmask
& CONSUMER_TYPE_LIGHT
)
152 FetchLight(ambient_light_sensor_
.get(), light_buffer_
);
155 DataFetcherSharedMemory::FetcherType
DataFetcherSharedMemory::GetType() const {
156 return FETCHER_TYPE_POLLING_CALLBACK
;
159 bool DataFetcherSharedMemory::Start(ConsumerType consumer_type
, void* buffer
) {
160 DCHECK(base::MessageLoop::current() == GetPollingMessageLoop());
163 switch (consumer_type
) {
164 case CONSUMER_TYPE_MOTION
: {
165 if (!sudden_motion_sensor_
)
166 sudden_motion_sensor_
.reset(SuddenMotionSensor::Create());
167 bool sudden_motion_sensor_available
=
168 sudden_motion_sensor_
.get() != nullptr;
170 motion_buffer_
= static_cast<DeviceMotionHardwareBuffer
*>(buffer
);
171 UMA_HISTOGRAM_BOOLEAN("InertialSensor.MotionMacAvailable",
172 sudden_motion_sensor_available
);
173 if (!sudden_motion_sensor_available
) {
174 // No motion sensor available, fire an all-null event.
175 motion_buffer_
->seqlock
.WriteBegin();
176 motion_buffer_
->data
.allAvailableSensorsAreActive
= true;
177 motion_buffer_
->seqlock
.WriteEnd();
179 return sudden_motion_sensor_available
;
181 case CONSUMER_TYPE_ORIENTATION
: {
182 if (!sudden_motion_sensor_
)
183 sudden_motion_sensor_
.reset(SuddenMotionSensor::Create());
184 bool sudden_motion_sensor_available
=
185 sudden_motion_sensor_
.get() != nullptr;
187 orientation_buffer_
=
188 static_cast<DeviceOrientationHardwareBuffer
*>(buffer
);
189 UMA_HISTOGRAM_BOOLEAN("InertialSensor.OrientationMacAvailable",
190 sudden_motion_sensor_available
);
191 if (sudden_motion_sensor_available
) {
192 // On Mac we cannot provide absolute orientation.
193 orientation_buffer_
->seqlock
.WriteBegin();
194 orientation_buffer_
->data
.absolute
= false;
195 orientation_buffer_
->data
.hasAbsolute
= true;
196 orientation_buffer_
->seqlock
.WriteEnd();
198 // No motion sensor available, fire an all-null event.
199 orientation_buffer_
->seqlock
.WriteBegin();
200 orientation_buffer_
->data
.allAvailableSensorsAreActive
= true;
201 orientation_buffer_
->seqlock
.WriteEnd();
203 return sudden_motion_sensor_available
;
205 case CONSUMER_TYPE_LIGHT
: {
206 if (!ambient_light_sensor_
)
207 ambient_light_sensor_
= AmbientLightSensor::Create();
208 bool ambient_light_sensor_available
=
209 ambient_light_sensor_
.get() != nullptr;
211 light_buffer_
= static_cast<DeviceLightHardwareBuffer
*>(buffer
);
212 if (!ambient_light_sensor_available
) {
213 light_buffer_
->seqlock
.WriteBegin();
214 light_buffer_
->data
.value
= std::numeric_limits
<double>::infinity();
215 light_buffer_
->seqlock
.WriteEnd();
217 return ambient_light_sensor_available
;
225 bool DataFetcherSharedMemory::Stop(ConsumerType consumer_type
) {
226 DCHECK(base::MessageLoop::current() == GetPollingMessageLoop());
228 switch (consumer_type
) {
229 case CONSUMER_TYPE_MOTION
:
230 if (motion_buffer_
) {
231 motion_buffer_
->seqlock
.WriteBegin();
232 motion_buffer_
->data
.allAvailableSensorsAreActive
= false;
233 motion_buffer_
->seqlock
.WriteEnd();
234 motion_buffer_
= nullptr;
237 case CONSUMER_TYPE_ORIENTATION
:
238 if (orientation_buffer_
) {
239 orientation_buffer_
->seqlock
.WriteBegin();
240 orientation_buffer_
->data
.allAvailableSensorsAreActive
= false;
241 orientation_buffer_
->seqlock
.WriteEnd();
242 orientation_buffer_
= nullptr;
245 case CONSUMER_TYPE_LIGHT
:
247 light_buffer_
->seqlock
.WriteBegin();
248 light_buffer_
->data
.value
= -1;
249 light_buffer_
->seqlock
.WriteEnd();
250 light_buffer_
= nullptr;
259 } // namespace content