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. 4 5 #include "data_fetcher_shared_memory.h" 6 7 #include "base/logging.h" 8 #include "base/metrics/histogram.h" 9 #include "third_party/sudden_motion_sensor/sudden_motion_sensor_mac.h" 10 11 namespace { 12 13 const double kMeanGravity = 9.80665; 14 15 void FetchMotion(SuddenMotionSensor* sensor, 16 content::DeviceMotionHardwareBuffer* buffer) { 17 DCHECK(buffer); 18 19 float axis_value[3]; 20 if (!sensor->ReadSensorValues(axis_value)) 21 return; 22 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(); 32 } 33 34 void FetchOrientation(SuddenMotionSensor* sensor, 35 content::DeviceOrientationHardwareBuffer* buffer) { 36 DCHECK(buffer); 37 38 // Retrieve per-axis calibrated values. 39 float axis_value[3]; 40 if (!sensor->ReadSensorValues(axis_value)) 41 return; 42 43 // Transform the accelerometer values to W3C draft angles. 44 // 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. 47 // 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: 52 // 53 // x_acc = sin(gamma) 54 // y_acc = - cos(gamma) * sin(beta) 55 // z_acc = cos(beta) * cos(gamma) 56 // 57 // After that the rest is just a bit of trigonometry. 58 // 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 61 // the equations. 62 // 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]); 66 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. 70 if (beta == 180.0) 71 beta = -180; // -180 == 180 (upside-down) 72 if (gamma == 90.0) 73 gamma = nextafter(90, 0); 74 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); 80 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(); 88 } 89 90 } // namespace 91 92 namespace content { 93 94 DataFetcherSharedMemory::DataFetcherSharedMemory() { 95 } 96 97 DataFetcherSharedMemory::~DataFetcherSharedMemory() { 98 } 99 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); 105 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_); 110 } 111 112 DataFetcherSharedMemory::FetcherType DataFetcherSharedMemory::GetType() const { 113 return FETCHER_TYPE_POLLING_CALLBACK; 114 } 115 116 bool DataFetcherSharedMemory::Start(ConsumerType consumer_type, void* buffer) { 117 DCHECK(base::MessageLoop::current() == GetPollingMessageLoop()); 118 DCHECK(buffer); 119 120 if (!sudden_motion_sensor_) 121 sudden_motion_sensor_.reset(SuddenMotionSensor::Create()); 122 bool sudden_motion_sensor_available = sudden_motion_sensor_.get() != NULL; 123 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(); 134 } 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(); 147 } else { 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(); 152 } 153 return sudden_motion_sensor_available; 154 default: 155 NOTREACHED(); 156 } 157 return false; 158 } 159 160 bool DataFetcherSharedMemory::Stop(ConsumerType consumer_type) { 161 DCHECK(base::MessageLoop::current() == GetPollingMessageLoop()); 162 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; 170 } 171 return true; 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; 178 } 179 return true; 180 default: 181 NOTREACHED(); 182 } 183 return false; 184 } 185 186 } // namespace content 187