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 "data_fetcher_shared_memory.h"
7 #include "base/logging.h"
8 #include "base/metrics/histogram.h"
9 #include "third_party/sudden_motion_sensor/sudden_motion_sensor_mac.h"
13 const double kMeanGravity
= 9.80665;
15 void FetchMotion(SuddenMotionSensor
* sensor
,
16 content::DeviceMotionHardwareBuffer
* buffer
) {
20 if (!sensor
->ReadSensorValues(axis_value
))
23 buffer
->seqlock
.WriteBegin();
24 buffer
->data
.accelerationIncludingGravityX
= axis_value
[0] * kMeanGravity
;
25 buffer
->data
.hasAccelerationIncludingGravityX
= true;
26 buffer
->data
.accelerationIncludingGravityY
= axis_value
[1] * kMeanGravity
;
27 buffer
->data
.hasAccelerationIncludingGravityY
= true;
28 buffer
->data
.accelerationIncludingGravityZ
= axis_value
[2] * kMeanGravity
;
29 buffer
->data
.hasAccelerationIncludingGravityZ
= true;
30 buffer
->data
.allAvailableSensorsAreActive
= true;
31 buffer
->seqlock
.WriteEnd();
34 void FetchOrientation(SuddenMotionSensor
* sensor
,
35 content::DeviceOrientationHardwareBuffer
* buffer
) {
38 // Retrieve per-axis calibrated values.
40 if (!sensor
->ReadSensorValues(axis_value
))
43 // Transform the accelerometer values to W3C draft angles.
45 // Accelerometer values are just dot products of the sensor axes
46 // by the gravity vector 'g' with the result for the z axis inverted.
48 // To understand this transformation calculate the 3rd row of the z-x-y
49 // Euler angles rotation matrix (because of the 'g' vector, only 3rd row
50 // affects to the result). Note that z-x-y matrix means R = Ry * Rx * Rz.
51 // Then, assume alpha = 0 and you get this:
54 // y_acc = - cos(gamma) * sin(beta)
55 // z_acc = cos(beta) * cos(gamma)
57 // After that the rest is just a bit of trigonometry.
59 // Also note that alpha can't be provided but it's assumed to be always zero.
60 // This is necessary in order to provide enough information to solve
63 const double kRad2deg
= 180.0 / M_PI
;
64 double beta
= kRad2deg
* atan2(-axis_value
[1], axis_value
[2]);
65 double gamma
= kRad2deg
* asin(axis_value
[0]);
67 // Make sure that the interval boundaries comply with the specification. At
68 // this point, beta is [-180, 180] and gamma is [-90, 90], but the spec has
69 // the upper bound open on both.
71 beta
= -180; // -180 == 180 (upside-down)
73 gamma
= nextafter(90, 0);
75 // At this point, DCHECKing is paranoia. Never hurts.
76 DCHECK_GE(beta
, -180.0);
77 DCHECK_LT(beta
, 180.0);
78 DCHECK_GE(gamma
, -90.0);
79 DCHECK_LT(gamma
, 90.0);
81 buffer
->seqlock
.WriteBegin();
82 buffer
->data
.beta
= beta
;
83 buffer
->data
.hasBeta
= true;
84 buffer
->data
.gamma
= gamma
;
85 buffer
->data
.hasGamma
= true;
86 buffer
->data
.allAvailableSensorsAreActive
= true;
87 buffer
->seqlock
.WriteEnd();
94 DataFetcherSharedMemory::DataFetcherSharedMemory() {
97 DataFetcherSharedMemory::~DataFetcherSharedMemory() {
100 void DataFetcherSharedMemory::Fetch(unsigned consumer_bitmask
) {
101 DCHECK(base::MessageLoop::current() == GetPollingMessageLoop());
102 DCHECK(sudden_motion_sensor_
);
103 DCHECK(consumer_bitmask
& CONSUMER_TYPE_ORIENTATION
||
104 consumer_bitmask
& CONSUMER_TYPE_MOTION
);
106 if (consumer_bitmask
& CONSUMER_TYPE_ORIENTATION
)
107 FetchOrientation(sudden_motion_sensor_
.get(), orientation_buffer_
);
108 if (consumer_bitmask
& CONSUMER_TYPE_MOTION
)
109 FetchMotion(sudden_motion_sensor_
.get(), motion_buffer_
);
112 DataFetcherSharedMemory::FetcherType
DataFetcherSharedMemory::GetType() const {
113 return FETCHER_TYPE_POLLING_CALLBACK
;
116 bool DataFetcherSharedMemory::Start(ConsumerType consumer_type
, void* buffer
) {
117 DCHECK(base::MessageLoop::current() == GetPollingMessageLoop());
120 if (!sudden_motion_sensor_
)
121 sudden_motion_sensor_
.reset(SuddenMotionSensor::Create());
122 bool sudden_motion_sensor_available
= sudden_motion_sensor_
.get() != NULL
;
124 switch (consumer_type
) {
125 case CONSUMER_TYPE_MOTION
:
126 motion_buffer_
= static_cast<DeviceMotionHardwareBuffer
*>(buffer
);
127 UMA_HISTOGRAM_BOOLEAN("InertialSensor.MotionMacAvailable",
128 sudden_motion_sensor_available
);
129 if (!sudden_motion_sensor_available
) {
130 // No motion sensor available, fire an all-null event.
131 motion_buffer_
->seqlock
.WriteBegin();
132 motion_buffer_
->data
.allAvailableSensorsAreActive
= true;
133 motion_buffer_
->seqlock
.WriteEnd();
135 return sudden_motion_sensor_available
;
136 case CONSUMER_TYPE_ORIENTATION
:
137 orientation_buffer_
=
138 static_cast<DeviceOrientationHardwareBuffer
*>(buffer
);
139 UMA_HISTOGRAM_BOOLEAN("InertialSensor.OrientationMacAvailable",
140 sudden_motion_sensor_available
);
141 if (sudden_motion_sensor_available
) {
142 // On Mac we cannot provide absolute orientation.
143 orientation_buffer_
->seqlock
.WriteBegin();
144 orientation_buffer_
->data
.absolute
= false;
145 orientation_buffer_
->data
.hasAbsolute
= true;
146 orientation_buffer_
->seqlock
.WriteEnd();
148 // No motion sensor available, fire an all-null event.
149 orientation_buffer_
->seqlock
.WriteBegin();
150 orientation_buffer_
->data
.allAvailableSensorsAreActive
= true;
151 orientation_buffer_
->seqlock
.WriteEnd();
153 return sudden_motion_sensor_available
;
160 bool DataFetcherSharedMemory::Stop(ConsumerType consumer_type
) {
161 DCHECK(base::MessageLoop::current() == GetPollingMessageLoop());
163 switch (consumer_type
) {
164 case CONSUMER_TYPE_MOTION
:
165 if (motion_buffer_
) {
166 motion_buffer_
->seqlock
.WriteBegin();
167 motion_buffer_
->data
.allAvailableSensorsAreActive
= false;
168 motion_buffer_
->seqlock
.WriteEnd();
169 motion_buffer_
= NULL
;
172 case CONSUMER_TYPE_ORIENTATION
:
173 if (orientation_buffer_
) {
174 orientation_buffer_
->seqlock
.WriteBegin();
175 orientation_buffer_
->data
.allAvailableSensorsAreActive
= false;
176 orientation_buffer_
->seqlock
.WriteEnd();
177 orientation_buffer_
= NULL
;
186 } // namespace content