10529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// Copyright 2014 The Chromium Authors. All rights reserved.
2424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)// found in the LICENSE file.
4424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
5424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "data_fetcher_shared_memory.h"
6424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
7424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "base/logging.h"
85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/metrics/histogram.h"
9424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "third_party/sudden_motion_sensor/sudden_motion_sensor_mac.h"
10424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
11424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)namespace {
12424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
1358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)const double kMeanGravity = 9.80665;
1458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
15424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)void FetchMotion(SuddenMotionSensor* sensor,
16424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    content::DeviceMotionHardwareBuffer* buffer) {
17424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK(buffer);
18424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
19424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  float axis_value[3];
20424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (!sensor->ReadSensorValues(axis_value))
21424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return;
22424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
23424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  buffer->seqlock.WriteBegin();
2458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  buffer->data.accelerationIncludingGravityX = axis_value[0] * kMeanGravity;
25424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  buffer->data.hasAccelerationIncludingGravityX = true;
2658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  buffer->data.accelerationIncludingGravityY = axis_value[1] * kMeanGravity;
27424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  buffer->data.hasAccelerationIncludingGravityY = true;
2858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  buffer->data.accelerationIncludingGravityZ = axis_value[2] * kMeanGravity;
29424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  buffer->data.hasAccelerationIncludingGravityZ = true;
30424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  buffer->data.allAvailableSensorsAreActive = true;
31424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  buffer->seqlock.WriteEnd();
32424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
33424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
34424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)void FetchOrientation(SuddenMotionSensor* sensor,
35424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    content::DeviceOrientationHardwareBuffer* buffer) {
36424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK(buffer);
37424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
38424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // Retrieve per-axis calibrated values.
39424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  float axis_value[3];
40424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (!sensor->ReadSensorValues(axis_value))
41424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return;
42424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
43424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // Transform the accelerometer values to W3C draft angles.
44424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  //
45424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // Accelerometer values are just dot products of the sensor axes
46424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // by the gravity vector 'g' with the result for the z axis inverted.
47424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  //
48424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // To understand this transformation calculate the 3rd row of the z-x-y
49424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // Euler angles rotation matrix (because of the 'g' vector, only 3rd row
50424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // affects to the result). Note that z-x-y matrix means R = Ry * Rx * Rz.
51424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // Then, assume alpha = 0 and you get this:
52424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  //
53424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // x_acc = sin(gamma)
54424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // y_acc = - cos(gamma) * sin(beta)
55424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // z_acc = cos(beta) * cos(gamma)
56424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  //
57424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // After that the rest is just a bit of trigonometry.
58424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  //
59424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // Also note that alpha can't be provided but it's assumed to be always zero.
60424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // This is necessary in order to provide enough information to solve
61424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // the equations.
62424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  //
63424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  const double kRad2deg = 180.0 / M_PI;
64424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  double beta = kRad2deg * atan2(-axis_value[1], axis_value[2]);
65424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  double gamma = kRad2deg * asin(axis_value[0]);
66424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
67424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // Make sure that the interval boundaries comply with the specification. At
68424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // this point, beta is [-180, 180] and gamma is [-90, 90], but the spec has
69424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // the upper bound open on both.
70424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (beta == 180.0)
71424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    beta = -180;  // -180 == 180 (upside-down)
72424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (gamma == 90.0)
73424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    gamma = nextafter(90, 0);
74424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
75424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // At this point, DCHECKing is paranoia. Never hurts.
76424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK_GE(beta, -180.0);
77424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK_LT(beta,  180.0);
78424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK_GE(gamma, -90.0);
79424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK_LT(gamma,  90.0);
80424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
81424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  buffer->seqlock.WriteBegin();
82424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  buffer->data.beta = beta;
83424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  buffer->data.hasBeta = true;
84424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  buffer->data.gamma = gamma;
85424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  buffer->data.hasGamma = true;
86424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  buffer->data.allAvailableSensorsAreActive = true;
87424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  buffer->seqlock.WriteEnd();
88424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
89424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
90424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}  // namespace
91424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
92424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)namespace content {
93424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
94424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)DataFetcherSharedMemory::DataFetcherSharedMemory() {
95424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
96424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
97424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)DataFetcherSharedMemory::~DataFetcherSharedMemory() {
98424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
99424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
100424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)void DataFetcherSharedMemory::Fetch(unsigned consumer_bitmask) {
101424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK(base::MessageLoop::current() == GetPollingMessageLoop());
102424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK(sudden_motion_sensor_);
10358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DCHECK(consumer_bitmask & CONSUMER_TYPE_ORIENTATION ||
10458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)         consumer_bitmask & CONSUMER_TYPE_MOTION);
105424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
106424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (consumer_bitmask & CONSUMER_TYPE_ORIENTATION)
107424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    FetchOrientation(sudden_motion_sensor_.get(), orientation_buffer_);
10858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (consumer_bitmask & CONSUMER_TYPE_MOTION)
109424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    FetchMotion(sudden_motion_sensor_.get(), motion_buffer_);
110424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
111424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
1128bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)DataFetcherSharedMemory::FetcherType DataFetcherSharedMemory::GetType() const {
1138bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  return FETCHER_TYPE_POLLING_CALLBACK;
114424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
115424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
11658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)bool DataFetcherSharedMemory::Start(ConsumerType consumer_type, void* buffer) {
117424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK(base::MessageLoop::current() == GetPollingMessageLoop());
11858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DCHECK(buffer);
11958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
120effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (!sudden_motion_sensor_)
121effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    sudden_motion_sensor_.reset(SuddenMotionSensor::Create());
122effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  bool sudden_motion_sensor_available = sudden_motion_sensor_.get() != NULL;
123effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
124424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  switch (consumer_type) {
125424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    case CONSUMER_TYPE_MOTION:
12658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      motion_buffer_ = static_cast<DeviceMotionHardwareBuffer*>(buffer);
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      UMA_HISTOGRAM_BOOLEAN("InertialSensor.MotionMacAvailable",
128effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch          sudden_motion_sensor_available);
129effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      if (!sudden_motion_sensor_available) {
130effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        // No motion sensor available, fire an all-null event.
131effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        motion_buffer_->seqlock.WriteBegin();
132effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        motion_buffer_->data.allAvailableSensorsAreActive = true;
133effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        motion_buffer_->seqlock.WriteEnd();
134effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      }
135effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      return sudden_motion_sensor_available;
136424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    case CONSUMER_TYPE_ORIENTATION:
13758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      orientation_buffer_ =
13858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          static_cast<DeviceOrientationHardwareBuffer*>(buffer);
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      UMA_HISTOGRAM_BOOLEAN("InertialSensor.OrientationMacAvailable",
140effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch          sudden_motion_sensor_available);
141effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      if (sudden_motion_sensor_available) {
142effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        // On Mac we cannot provide absolute orientation.
143effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        orientation_buffer_->seqlock.WriteBegin();
144effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        orientation_buffer_->data.absolute = false;
145effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        orientation_buffer_->data.hasAbsolute = true;
146effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        orientation_buffer_->seqlock.WriteEnd();
147effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      } else {
148effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        // No motion sensor available, fire an all-null event.
149effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        orientation_buffer_->seqlock.WriteBegin();
150effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        orientation_buffer_->data.allAvailableSensorsAreActive = true;
151effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        orientation_buffer_->seqlock.WriteEnd();
152effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      }
153effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      return sudden_motion_sensor_available;
154424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    default:
155424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      NOTREACHED();
156424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  }
157424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  return false;
158424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
159424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
160424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)bool DataFetcherSharedMemory::Stop(ConsumerType consumer_type) {
161424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK(base::MessageLoop::current() == GetPollingMessageLoop());
16258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
163424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  switch (consumer_type) {
164424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    case CONSUMER_TYPE_MOTION:
16558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      if (motion_buffer_) {
16658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        motion_buffer_->seqlock.WriteBegin();
16758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        motion_buffer_->data.allAvailableSensorsAreActive = false;
16858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        motion_buffer_->seqlock.WriteEnd();
16958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        motion_buffer_ = NULL;
17058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      }
171424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      return true;
172424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    case CONSUMER_TYPE_ORIENTATION:
17358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      if (orientation_buffer_) {
17458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        orientation_buffer_->seqlock.WriteBegin();
17558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        orientation_buffer_->data.allAvailableSensorsAreActive = false;
17658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        orientation_buffer_->seqlock.WriteEnd();
17758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        orientation_buffer_ = NULL;
17858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      }
179424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      return true;
180424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    default:
181424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      NOTREACHED();
182424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  }
183424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  return false;
184424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
185424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
186424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}  // namespace content
187