OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 // | |
5 // This file is based on the SMSLib library. | |
6 // | |
7 // SMSLib Sudden Motion Sensor Access Library | |
8 // Copyright (c) 2010 Suitable Systems | |
9 // All rights reserved. | |
10 // | |
11 // Developed by: Daniel Griscom | |
12 // Suitable Systems | |
13 // http://www.suitable.com | |
14 // | |
15 // Permission is hereby granted, free of charge, to any person obtaining a | |
16 // copy of this software and associated documentation files (the | |
17 // "Software"), to deal with the Software without restriction, including | |
18 // without limitation the rights to use, copy, modify, merge, publish, | |
19 // distribute, sublicense, and/or sell copies of the Software, and to | |
20 // permit persons to whom the Software is furnished to do so, subject to | |
21 // the following conditions: | |
22 // | |
23 // - Redistributions of source code must retain the above copyright notice, | |
24 // this list of conditions and the following disclaimers. | |
25 // | |
26 // - Redistributions in binary form must reproduce the above copyright | |
27 // notice, this list of conditions and the following disclaimers in the | |
28 // documentation and/or other materials provided with the distribution. | |
29 // | |
30 // - Neither the names of Suitable Systems nor the names of its | |
31 // contributors may be used to endorse or promote products derived from | |
32 // this Software without specific prior written permission. | |
33 // | |
34 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | |
35 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
36 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |
37 // IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR | |
38 // ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | |
39 // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | |
40 // SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE. | |
41 // | |
42 // For more information about SMSLib, see | |
43 // <http://www.suitable.com/tools/smslib.html> | |
44 // or contact | |
45 // Daniel Griscom | |
46 // Suitable Systems | |
47 // 1 Centre Street, Suite 204 | |
48 // Wakefield, MA 01880 | |
49 // (781) 665-0053 | |
50 | 4 |
51 #include "content/browser/device_orientation/accelerometer_mac.h" | 5 #include "content/browser/device_orientation/accelerometer_mac.h" |
52 | 6 |
53 #include <math.h> | 7 #include <math.h> |
54 #include <sys/sysctl.h> | |
55 | 8 |
56 #include "base/logging.h" | 9 #include "base/logging.h" |
57 #include "base/mac/scoped_cftyperef.h" | |
58 #include "base/memory/scoped_ptr.h" | |
59 #include "content/browser/device_orientation/orientation.h" | 10 #include "content/browser/device_orientation/orientation.h" |
| 11 #include "third_party/sudden_motion_sensor/sudden_motion_sensor_mac.h" |
60 | 12 |
61 namespace device_orientation { | 13 namespace device_orientation { |
62 | 14 |
63 struct AccelerometerMac::GenericMacbookSensor { | |
64 // Name of device to be read. | |
65 const char* service_name; | |
66 | |
67 // Number of bytes of the axis data. | |
68 int axis_size; | |
69 | |
70 // Default calibration value for zero g. | |
71 float zero_g; | |
72 | |
73 // Default calibration value for one g (negative when axis is inverted). | |
74 float one_g; | |
75 | |
76 // Kernel function index. | |
77 unsigned int function; | |
78 | |
79 // Size of the sensor record to be sent/received. | |
80 unsigned int record_size; | |
81 }; | |
82 | |
83 struct AccelerometerMac::AxisData { | |
84 // Location of the first byte representing the axis in the sensor data. | |
85 int index; | |
86 | |
87 // Axis inversion flag. The value changes often between models. | |
88 bool inverted; | |
89 }; | |
90 | |
91 // Sudden Motion Sensor descriptor. | |
92 struct AccelerometerMac::SensorDescriptor { | |
93 // Prefix of model to be tested. | |
94 const char* model_name; | |
95 | |
96 // Board id of model, or NULL if it doesn't matter. | |
97 const char* board_id; | |
98 | |
99 // Axis-specific data (x,y,z order). | |
100 AxisData axis[3]; | |
101 }; | |
102 | |
103 // Typical sensor parameters in MacBook models. | |
104 const AccelerometerMac::GenericMacbookSensor | |
105 AccelerometerMac::kGenericSensor = { | |
106 "SMCMotionSensor", 2, | |
107 0, 251, | |
108 5, 40 | |
109 }; | |
110 | |
111 // Supported sensor descriptors. Add entries here to enhance compatibility. | |
112 // Tested in order; place more specific entries before more general ones. (All | |
113 // non-tested entries from SMSLib have been removed.) | |
114 const AccelerometerMac::SensorDescriptor | |
115 AccelerometerMac::kSupportedSensors[] = { | |
116 // Tested by tommyw on a 13" MacBook. | |
117 { "MacBook1,1", NULL, { { 0, true }, { 2, true }, { 4, false } } }, | |
118 | |
119 // Tested by S.Selz. (via avi) on a 13" MacBook. | |
120 { "MacBook2,1", NULL, { { 0, true }, { 2, false }, { 4, true } } }, | |
121 | |
122 // Tested by verhees on a 13" MacBook. | |
123 { "MacBook3,1", NULL, { { 0, true }, { 2, true }, { 4, false } } }, | |
124 | |
125 // Tested by adlr on a 13" MacBook. | |
126 { "MacBook4,1", NULL, { { 0, true }, { 2, true }, { 4, false } } }, | |
127 | |
128 // Tested by thakis on a 13" MacBook. | |
129 { "MacBook5,1", NULL, { { 0, true }, { 2, true }, { 4, false } } }, | |
130 | |
131 // Tested by Adam Gerson (via avi) on a 13" MacBook. | |
132 { "MacBook5,2", NULL, { { 0, false }, { 2, true }, { 4, true } } }, | |
133 | |
134 // Tested by tommyw on a 13" MacBook. | |
135 { "MacBook6,1", NULL, { { 0, true }, { 2, true }, { 4, false } } }, | |
136 | |
137 // Tested by avi on a 13" MacBook. | |
138 { "MacBook7,1", NULL, { { 0, true }, { 2, true }, { 4, false } } }, | |
139 | |
140 // Tested by crc on a 13" MacBook Air. | |
141 { "MacBookAir1,1", NULL, { { 0, true }, { 2, true }, { 4, false } } }, | |
142 | |
143 // Tested by sfiera, pjw on a 13" MacBook Air. | |
144 { "MacBookAir2,1", NULL, { { 0, true }, { 2, true }, { 4, false } } }, | |
145 | |
146 // Note: | |
147 // - MacBookAir3,1 (11" MacBook Air, late 2010) | |
148 // - MacBookAir3,2 (13" MacBook Air, late 2010) | |
149 // - MacBookAir4,1 (11" MacBook Air, mid 2011) | |
150 // - MacBookAir4,2 (13" MacBook Air, mid 2011) | |
151 // have no accelerometer sensors. | |
152 | |
153 // Tested by crc on a 15" MacBook Pro. | |
154 { "MacBookPro1,1", NULL, { { 0, true }, { 2, true }, { 4, false } } }, | |
155 | |
156 // Tested by Raul Cuza (via avi) on a 17" MacBook Pro. | |
157 { "MacBookPro1,2", NULL, { { 0, true }, { 2, true }, { 4, false } } }, | |
158 | |
159 // Tested by L.V. (via avi) on a 17" MacBook Pro. | |
160 { "MacBookPro2,1", NULL, { { 0, true }, { 2, false }, { 4, true } } }, | |
161 | |
162 // Tested by leandrogracia on a 15" MacBook Pro. | |
163 { "MacBookPro2,2", NULL, { { 0, true }, { 2, true }, { 4, false } } }, | |
164 | |
165 // Tested by S.Som. (via avi) on a 17" MacBook Pro. | |
166 { "MacBookPro3,1", "Mac-F42388C8", | |
167 { { 0, true }, { 2, false }, { 4, true } } }, | |
168 | |
169 // Tested by leandrogracia on a 15" MacBook Pro. | |
170 { "MacBookPro3,1", NULL, { { 0, false }, { 2, true }, { 4, true } } }, | |
171 | |
172 // Tested by leandrogracia on a 15" MacBook Pro. | |
173 // Tested by Eric Shapiro (via avi) on a 17" MacBook Pro. | |
174 { "MacBookPro4,1", NULL, { { 0, true }, { 2, true }, { 4, false } } }, | |
175 | |
176 // Tested by leandrogracia on a 15" MacBook Pro. | |
177 { "MacBookPro5,1", NULL, { { 0, false }, { 2, false }, { 4, false } } }, | |
178 | |
179 // Tested by S.Selz. (via avi) on a 17" MacBook Pro. | |
180 { "MacBookPro5,2", NULL, { { 0, false }, { 2, false }, { 4, false } } }, | |
181 | |
182 // Tested by dmaclach on a 15" MacBook Pro. | |
183 { "MacBookPro5,3", NULL, { { 2, false }, { 0, false }, { 4, true } } }, | |
184 | |
185 // Tested by leandrogracia on a 15" MacBook Pro. | |
186 { "MacBookPro5,4", NULL, { { 0, false }, { 2, false }, { 4, false } } }, | |
187 | |
188 // Tested by leandrogracia on a 13" MacBook Pro. | |
189 { "MacBookPro5,5", NULL, { { 0, true }, { 2, true }, { 4, false } } }, | |
190 | |
191 // Tested by khom, leadpipe on a 17" MacBook Pro. | |
192 { "MacBookPro6,1", NULL, { { 0, false }, { 2, false }, { 4, false } } }, | |
193 | |
194 // Tested by leandrogracia on a 15" MacBook Pro. | |
195 { "MacBookPro6,2", NULL, { { 0, true }, { 2, false }, { 4, true } } }, | |
196 | |
197 // Tested by leandrogracia on a 13" MacBook Pro. | |
198 { "MacBookPro7,1", NULL, { { 0, true }, { 2, true }, { 4, false } } }, | |
199 | |
200 // Tested by avi on a 13" MacBook Pro. | |
201 { "MacBookPro8,1", NULL, { { 0, false }, { 2, false }, { 4, false } } }, | |
202 | |
203 // Tested by avi on a 15" MacBook Pro. | |
204 { "MacBookPro8,2", NULL, { { 0, false }, { 2, false }, { 4, false } } }, | |
205 | |
206 // Tested by avi on a 17" MacBook Pro. | |
207 { "MacBookPro8,3", NULL, { { 0, false }, { 2, false }, { 4, false } } }, | |
208 | |
209 // Generic MacBook accelerometer sensor data, to be used for future models | |
210 // until they can be tested and their data entered. Note that this generic | |
211 // configuration may well have problems with inverted axes. | |
212 { "", NULL, { { 0, true }, { 2, true }, { 4, false } } } | |
213 }; | |
214 | |
215 // Create a AccelerometerMac object and return NULL if no valid sensor found. | 15 // Create a AccelerometerMac object and return NULL if no valid sensor found. |
216 DataFetcher* AccelerometerMac::Create() { | 16 DataFetcher* AccelerometerMac::Create() { |
217 scoped_ptr<AccelerometerMac> accelerometer(new AccelerometerMac); | 17 scoped_ptr<AccelerometerMac> accelerometer(new AccelerometerMac); |
218 return accelerometer->Init() ? accelerometer.release() : NULL; | 18 return accelerometer->Init() ? accelerometer.release() : NULL; |
219 } | 19 } |
220 | 20 |
221 AccelerometerMac::~AccelerometerMac() { | 21 AccelerometerMac::~AccelerometerMac() { |
222 IOServiceClose(io_connection_); | |
223 } | 22 } |
224 | 23 |
225 AccelerometerMac::AccelerometerMac() | 24 AccelerometerMac::AccelerometerMac() { |
226 : sensor_(NULL), | |
227 io_connection_(0) { | |
228 } | 25 } |
229 | 26 |
230 // Retrieve per-axis accelerometer values. | 27 // Retrieve per-axis orientation values. |
231 // | 28 // |
232 // Axes and angles are defined according to the W3C DeviceOrientation Draft. | 29 // Axes and angles are defined according to the W3C DeviceOrientation Draft. |
233 // See here: http://dev.w3.org/geo/api/spec-source-orientation.html | 30 // See here: http://dev.w3.org/geo/api/spec-source-orientation.html |
234 // | 31 // |
235 // Note: only beta and gamma angles are provided. Alpha is set to zero. | 32 // Note: only beta and gamma angles are provided. Alpha is set to zero. |
236 // | 33 // |
237 // Returns false in case of error or non-properly initialized object. | 34 // Returns false in case of error. |
238 // | 35 // |
239 bool AccelerometerMac::GetOrientation(Orientation* orientation) { | 36 bool AccelerometerMac::GetOrientation(Orientation* orientation) { |
240 DCHECK(sensor_); | 37 DCHECK(sudden_motion_sensor_.get()); |
241 | 38 |
242 // Reset output record memory buffer. | 39 // Retrieve per-axis calibrated values. |
243 std::fill(output_record_.begin(), output_record_.end(), 0x00); | 40 float axis_value[3]; |
244 | 41 if (!sudden_motion_sensor_->ReadSensorValues(axis_value)) |
245 // Read record data from memory. | |
246 const size_t kInputSize = kGenericSensor.record_size; | |
247 size_t output_size = kGenericSensor.record_size; | |
248 | |
249 if (IOConnectCallStructMethod(io_connection_, kGenericSensor.function, | |
250 static_cast<const char *>(&input_record_[0]), kInputSize, | |
251 &output_record_[0], &output_size) != KERN_SUCCESS) { | |
252 return false; | 42 return false; |
253 } | |
254 | |
255 // Calculate per-axis calibrated values. | |
256 float axis_value[3]; | |
257 | |
258 for (int i = 0; i < 3; ++i) { | |
259 int sensor_value = 0; | |
260 int size = kGenericSensor.axis_size; | |
261 int index = sensor_->axis[i].index; | |
262 | |
263 // Important Note: Little endian is assumed as this code is Mac-only | |
264 // and PowerPC is currently not supported. | |
265 memcpy(&sensor_value, &output_record_[index], size); | |
266 | |
267 sensor_value = ExtendSign(sensor_value, size); | |
268 | |
269 // Correct value using the current calibration. | |
270 axis_value[i] = static_cast<float>(sensor_value - kGenericSensor.zero_g) / | |
271 kGenericSensor.one_g; | |
272 | |
273 // Make sure we reject any NaN or infinite values. | |
274 if (!isfinite(axis_value[i])) | |
275 return false; | |
276 | |
277 // Clamp value to the [-1, 1] range. | |
278 if (axis_value[i] < -1.0) | |
279 axis_value[i] = -1.0; | |
280 else if (axis_value[i] > 1.0) | |
281 axis_value[i] = 1.0; | |
282 | |
283 // Apply axis inversion. | |
284 if (sensor_->axis[i].inverted) | |
285 axis_value[i] = -axis_value[i]; | |
286 } | |
287 | 43 |
288 // Transform the accelerometer values to W3C draft angles. | 44 // Transform the accelerometer values to W3C draft angles. |
289 // | 45 // |
290 // Accelerometer values are just dot products of the sensor axes | 46 // Accelerometer values are just dot products of the sensor axes |
291 // by the gravity vector 'g' with the result for the z axis inverted. | 47 // by the gravity vector 'g' with the result for the z axis inverted. |
292 // | 48 // |
293 // To understand this transformation calculate the 3rd row of the z-x-y | 49 // To understand this transformation calculate the 3rd row of the z-x-y |
294 // Euler angles rotation matrix (because of the 'g' vector, only 3rd row | 50 // Euler angles rotation matrix (because of the 'g' vector, only 3rd row |
295 // affects to the result). Note that z-x-y matrix means R = Ry * Rx * Rz. | 51 // affects to the result). Note that z-x-y matrix means R = Ry * Rx * Rz. |
296 // Then, assume alpha = 0 and you get this: | 52 // Then, assume alpha = 0 and you get this: |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
330 DCHECK_LT(orientation->gamma_, 90.0); | 86 DCHECK_LT(orientation->gamma_, 90.0); |
331 | 87 |
332 orientation->can_provide_alpha_ = false; | 88 orientation->can_provide_alpha_ = false; |
333 orientation->can_provide_beta_ = true; | 89 orientation->can_provide_beta_ = true; |
334 orientation->can_provide_gamma_ = true; | 90 orientation->can_provide_gamma_ = true; |
335 orientation->can_provide_absolute_ = false; | 91 orientation->can_provide_absolute_ = false; |
336 | 92 |
337 return true; | 93 return true; |
338 } | 94 } |
339 | 95 |
340 // Probe the local hardware looking for a supported sensor device | |
341 // and initialize an I/O connection to it. | |
342 bool AccelerometerMac::Init() { | 96 bool AccelerometerMac::Init() { |
343 // Request model name from the kernel. | 97 sudden_motion_sensor_.reset(SuddenMotionSensor::Create()); |
344 char local_model[32]; // size from SMSLib | 98 return sudden_motion_sensor_.get() != NULL; |
345 size_t local_model_size = sizeof(local_model); | |
346 int params[2] = { CTL_HW, HW_MODEL }; | |
347 if (sysctl(params, 2, local_model, &local_model_size, NULL, 0) != 0) | |
348 return NULL; | |
349 | |
350 const SensorDescriptor* sensor_candidate = NULL; | |
351 | |
352 // Look for the current model in the supported sensor list. | |
353 base::mac::ScopedCFTypeRef<CFDataRef> board_id_data; | |
354 const int kNumSensors = arraysize(kSupportedSensors); | |
355 | |
356 for (int i = 0; i < kNumSensors; ++i) { | |
357 // Check if the supported sensor model name is a prefix | |
358 // of the local hardware model (empty names are accepted). | |
359 const char* p1 = kSupportedSensors[i].model_name; | |
360 for (const char* p2 = local_model; *p1 != '\0' && *p1 == *p2; ++p1, ++p2) | |
361 continue; | |
362 if (*p1 != '\0') | |
363 continue; | |
364 | |
365 // Check the board id. | |
366 if (kSupportedSensors[i].board_id) { | |
367 if (!board_id_data.get()) { | |
368 CFMutableDictionaryRef dict = | |
369 IOServiceMatching("IOPlatformExpertDevice"); | |
370 if (!dict) | |
371 continue; | |
372 | |
373 io_service_t platform_expert = | |
374 IOServiceGetMatchingService(kIOMasterPortDefault, dict); | |
375 if (!platform_expert) | |
376 continue; | |
377 | |
378 board_id_data.reset((CFDataRef) | |
379 IORegistryEntryCreateCFProperty(platform_expert, | |
380 CFSTR("board-id"), | |
381 kCFAllocatorDefault, | |
382 0)); | |
383 IOObjectRelease(platform_expert); | |
384 if (!board_id_data.get()) | |
385 continue; | |
386 } | |
387 | |
388 if (strcmp(kSupportedSensors[i].board_id, | |
389 (const char*)CFDataGetBytePtr(board_id_data)) != 0) { | |
390 continue; | |
391 } | |
392 } | |
393 | |
394 // Local hardware found in the supported sensor list. | |
395 sensor_candidate = &kSupportedSensors[i]; | |
396 | |
397 // Get a dictionary of the services matching to the one in the sensor. | |
398 CFMutableDictionaryRef dict = | |
399 IOServiceMatching(kGenericSensor.service_name); | |
400 if (!dict) | |
401 continue; | |
402 | |
403 // Get the first matching service. | |
404 io_service_t device = IOServiceGetMatchingService(kIOMasterPortDefault, | |
405 dict); | |
406 if (!device) | |
407 continue; | |
408 | |
409 // Try to open device. | |
410 kern_return_t result; | |
411 result = IOServiceOpen(device, mach_task_self(), 0, &io_connection_); | |
412 IOObjectRelease(device); | |
413 if (result != KERN_SUCCESS || io_connection_ == 0) | |
414 return false; | |
415 | |
416 // Local sensor service confirmed by IOKit. | |
417 sensor_ = sensor_candidate; | |
418 break; | |
419 } | |
420 | |
421 if (sensor_ == NULL) | |
422 return false; | |
423 | |
424 // Allocate and initialize input/output records. | |
425 input_record_.resize(kGenericSensor.record_size, 0x01); | |
426 output_record_.resize(kGenericSensor.record_size, 0x00); | |
427 | |
428 // Try to retrieve the current orientation. | |
429 Orientation test_orientation; | |
430 return GetOrientation(&test_orientation); | |
431 } | |
432 | |
433 // Extend the sign of an integer of less than 32 bits to a 32-bit integer. | |
434 int AccelerometerMac::ExtendSign(int value, size_t size) { | |
435 switch (size) { | |
436 case 1: | |
437 if (value & 0x00000080) | |
438 return value | 0xffffff00; | |
439 break; | |
440 | |
441 case 2: | |
442 if (value & 0x00008000) | |
443 return value | 0xffff0000; | |
444 break; | |
445 | |
446 case 3: | |
447 if (value & 0x00800000) | |
448 return value | 0xff000000; | |
449 break; | |
450 | |
451 default: | |
452 LOG(FATAL) << "Invalid integer size for sign extension: " << size; | |
453 } | |
454 | |
455 return value; | |
456 } | 99 } |
457 | 100 |
458 } // namespace device_orientation | 101 } // namespace device_orientation |
OLD | NEW |