Bike-X  0.8
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
OVR_SensorImpl.cpp
Go to the documentation of this file.
1 /************************************************************************************
2 
3 Filename : OVR_SensorImpl.cpp
4 Content : Oculus Sensor device implementation.
5 Created : March 7, 2013
6 Authors : Lee Cooper, Dov Katz
7 
8 Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
9 
10 Licensed under the Oculus VR Rift SDK License Version 3.1 (the "License");
11 you may not use the Oculus VR Rift SDK except in compliance with the License,
12 which is provided at the time of installation or download, or which
13 otherwise accompanies this software in either electronic or hard copy form.
14 
15 You may obtain a copy of the License at
16 
17 http://www.oculusvr.com/licenses/LICENSE-3.1
18 
19 Unless required by applicable law or agreed to in writing, the Oculus VR SDK
20 distributed under the License is distributed on an "AS IS" BASIS,
21 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22 See the License for the specific language governing permissions and
23 limitations under the License.
24 
25 *************************************************************************************/
26 
27 #include "OVR_SensorImpl.h"
28 #include "OVR_Sensor2Impl.h"
29 #include "OVR_SensorImpl_Common.h"
30 #include "OVR_JSON.h"
31 #include "OVR_Profile.h"
32 #include "Kernel/OVR_Alg.h"
33 #include <time.h>
34 
35 // HMDDeviceDesc can be created/updated through Sensor carrying DisplayInfo.
36 
37 #include "Kernel/OVR_Timer.h"
38 
39 //extern FILE *SF_LOG_fp;
40 
41 namespace OVR {
42 
43 using namespace Alg;
44 
45 //-------------------------------------------------------------------------------------
46 // ***** Oculus Sensor-specific packet data structures
47 
48 enum {
53 
55 
57  Sensor_MaxReportRate = 1000 // Hz
58 };
59 
60 
61 // Messages we care for
63 {
68 };
69 
70 
72 {
77 
78  TrackerSample Samples[3];
79 
80  SInt16 MagX, MagY, MagZ;
81 
82  TrackerMessageType Decode(const UByte* buffer, int size)
83  {
84  if (size < 62)
86 
87  SampleCount = buffer[1];
88  Timestamp = DecodeUInt16(buffer + 2);
89  LastCommandID = DecodeUInt16(buffer + 4);
90  Temperature = DecodeSInt16(buffer + 6);
91 
92  //if (SampleCount > 2)
93  // OVR_DEBUG_LOG_TEXT(("TackerSensor::Decode SampleCount=%d\n", SampleCount));
94 
95  // Only unpack as many samples as there actually are
96  int iterationCount = (SampleCount > 2) ? 3 : SampleCount;
97 
98  for (int i = 0; i < iterationCount; i++)
99  {
100  UnpackSensor(buffer + 8 + 16 * i, &Samples[i].AccelX, &Samples[i].AccelY, &Samples[i].AccelZ);
101  UnpackSensor(buffer + 16 + 16 * i, &Samples[i].GyroX, &Samples[i].GyroY, &Samples[i].GyroZ);
102  }
103 
104  MagX = DecodeSInt16(buffer + 56);
105  MagY = DecodeSInt16(buffer + 58);
106  MagZ = DecodeSInt16(buffer + 60);
107 
108  return TrackerMessage_Sensors;
109  }
110 };
111 
113 {
116 };
117 
118 
119 //-------------------------------------------------------------------------------------
120 // ***** SensorDisplayInfoImpl
122  : CommandId(0), DistortionType(Base_None)
123 {
124  memset(Buffer, 0, PacketSize);
125  Buffer[0] = 9;
126 }
127 
129 {
130  CommandId = Buffer[1] | (UInt16(Buffer[2]) << 8);
131  DistortionType = Buffer[3];
134  HScreenSize = DecodeUInt32(Buffer+8) * (1/1000000.f);
135  VScreenSize = DecodeUInt32(Buffer+12) * (1/1000000.f);
136  VCenter = DecodeUInt32(Buffer+16) * (1/1000000.f);
137  LensSeparation = DecodeUInt32(Buffer+20) * (1/1000000.f);
138 
139 #if 0
140  // These are not well-measured on most devices - probably best to ignore them.
141  OutsideLensSurfaceToScreen[0] = DecodeUInt32(Buffer+24) * (1/1000000.f);
142  OutsideLensSurfaceToScreen[1] = DecodeUInt32(Buffer+28) * (1/1000000.f);
143  // TODO: add spline-based distortion.
144  // TODO: currently these values are all zeros in the HMD itself.
145  DistortionK[0] = DecodeFloat(Buffer+32);
146  DistortionK[1] = DecodeFloat(Buffer+36);
147  DistortionK[2] = DecodeFloat(Buffer+40);
148  DistortionK[3] = DecodeFloat(Buffer+44);
149  DistortionK[4] = DecodeFloat(Buffer+48);
150  DistortionK[5] = DecodeFloat(Buffer+52);
151 #else
152  // The above are either measured poorly, or don't have values at all.
153  // To remove the temptation to use them, set them to junk.
154  OutsideLensSurfaceToScreen[0] = -1.0f;
155  OutsideLensSurfaceToScreen[1] = -1.0f;
156  DistortionK[0] = -1.0f;
157  DistortionK[1] = -1.0f;
158  DistortionK[2] = -1.0f;
159  DistortionK[3] = -1.0f;
160  DistortionK[4] = -1.0f;
161  DistortionK[5] = -1.0f;
162 #endif
163 }
164 
165 
166 //-------------------------------------------------------------------------------------
167 // ***** SensorDeviceFactory
168 
170 {
171  static SensorDeviceFactory instance;
172  return instance;
173 }
174 
176 {
177 
178  class SensorEnumerator : public HIDEnumerateVisitor
179  {
180  // Assign not supported; suppress MSVC warning.
181  void operator = (const SensorEnumerator&) { }
182 
183  DeviceFactory* pFactory;
184  EnumerateVisitor& ExternalVisitor;
185  public:
186  SensorEnumerator(DeviceFactory* factory, EnumerateVisitor& externalVisitor)
187  : pFactory(factory), ExternalVisitor(externalVisitor) { }
188 
189  virtual bool MatchVendorProduct(UInt16 vendorId, UInt16 productId)
190  {
191  return pFactory->MatchVendorProduct(vendorId, productId);
192  }
193 
194  virtual void Visit(HIDDevice& device, const HIDDeviceDesc& desc)
195  {
196 
197  if (desc.ProductId == Sensor_BootLoader)
198  { // If we find a sensor in boot loader mode then notify the app
199  // about the existence of the device, but don't allow the app
200  // to create or access the device
201  BootLoaderDeviceCreateDesc createDesc(pFactory, desc);
202  ExternalVisitor.Visit(createDesc);
203  return;
204  }
205 
206  SensorDeviceCreateDesc createDesc(pFactory, desc);
207  ExternalVisitor.Visit(createDesc);
208 
209  // Check if the sensor returns DisplayInfo. If so, try to use it to override potentially
210  // mismatching monitor information (in case wrong EDID is reported by splitter),
211  // or to create a new "virtualized" HMD Device.
212 
213  SensorDisplayInfoImpl displayInfo;
214 
216  {
217  displayInfo.Unpack();
218 
219  // If we got display info, try to match / create HMDDevice as well
220  // so that sensor settings give preference.
222  {
223  SensorDeviceImpl::EnumerateHMDFromSensorDisplayInfo(displayInfo, ExternalVisitor);
224  }
225  }
226  }
227  };
228 
229  //double start = Timer::GetProfileSeconds();
230 
231  SensorEnumerator sensorEnumerator(this, visitor);
232  GetManagerImpl()->GetHIDDeviceManager()->Enumerate(&sensorEnumerator);
233 
234  //double totalSeconds = Timer::GetProfileSeconds() - start;
235 }
236 
238 {
239  return ((vendorId == Sensor_VendorId) && (productId == Sensor_Tracker_ProductId)) ||
240  ((vendorId == Sensor_VendorId) && (productId == Sensor_Tracker2_ProductId)) ||
241  ((vendorId == Sensor_VendorId) && (productId == Sensor_KTracker_ProductId));
242 }
243 
245 {
246  if (MatchVendorProduct(desc.VendorId, desc.ProductId))
247  {
248  if (desc.ProductId == Sensor_BootLoader)
249  { // If we find a sensor in boot loader mode then notify the app
250  // about the existence of the device, but don't allow them
251  // to create or access the device
252  BootLoaderDeviceCreateDesc createDesc(this, desc);
253  pdevMgr->AddDevice_NeedsLock(createDesc);
254  return false; // return false to allow upstream boot loader factories to catch the device
255  }
256  else
257  {
258  SensorDeviceCreateDesc createDesc(this, desc);
259  return pdevMgr->AddDevice_NeedsLock(createDesc).GetPtr() != NULL;
260  }
261  }
262  return false;
263 }
264 
265 //-------------------------------------------------------------------------------------
266 // ***** SensorDeviceCreateDesc
267 
269 {
271  {
272  return new Sensor2DeviceImpl(this);
273  }
274 
275  return new SensorDeviceImpl(this);
276 }
277 
279 {
280  if ((info->InfoClassType != Device_Sensor) &&
281  (info->InfoClassType != Device_None))
282  return false;
283 
284  info->Type = Device_Sensor;
285  info->ProductName = HIDDesc.Product;
287  info->Version = HIDDesc.VersionNumber;
288 
289  if (info->InfoClassType == Device_Sensor)
290  {
291  SensorInfo* sinfo = (SensorInfo*)info;
292  sinfo->VendorId = HIDDesc.VendorId;
293  sinfo->ProductId = HIDDesc.ProductId;
296  }
297  return true;
298 }
299 
300 //-------------------------------------------------------------------------------------
301 // ***** SensorDevice
302 
304  : OVR::HIDDeviceImpl<OVR::SensorDevice>(createDesc, 0),
305  Coordinates(SensorDevice::Coord_Sensor),
306  HWCoordinates(SensorDevice::Coord_HMD), // HW reports HMD coordinates by default.
307  NextKeepAliveTickSeconds(0),
308  FullTimestamp(0),
309  MaxValidRange(SensorRangeImpl::GetMaxSensorRange()),
310  magCalibrated(false)
311 {
312  SequenceValid = false;
313  LastSampleCount = 0;
314  LastTimestamp = 0;
315 
316  OldCommandId = 0;
317 
318  PrevAbsoluteTime = 0.0;
319 
320 #ifdef OVR_OS_ANDROID
321  pPhoneSensors = PhoneSensors::Create();
322 #endif
323 }
324 
326 {
327  // Check that Shutdown() was called.
328  OVR_ASSERT(!pCreateDesc->pDevice);
329 }
330 
331 
332 // Internal creation APIs.
334 {
336  {
337  openDevice();
338  return true;
339  }
340 
341  return false;
342 }
343 
345 {
346 
347  // Read the currently configured range from sensor.
348  SensorRangeImpl sr(SensorRange(), 0);
349 
351  {
352  sr.Unpack();
354  // Increase the magnetometer range, since the default value is not enough in practice
357  }
358 
359  // Read the currently configured calibration from sensor.
362  {
363  sc.Unpack();
369  }
370 
371  // If the sensor has "DisplayInfo" data, use HMD coordinate frame by default.
372  SensorDisplayInfoImpl displayInfo;
374  {
375  displayInfo.Unpack();
378  }
379 
380  // Read/Apply sensor config.
383 
384  // Set Keep-alive at 10 seconds.
385  SensorKeepAliveImpl skeepAlive(10 * 1000);
387 
388  // Load mag calibration
389  MagCalibrationReport report;
390  bool res = GetMagCalibrationReport(&report);
391  if (res && report.Version > 0)
392  {
393  magCalibration = report.Calibration;
394  magCalibrated = true;
395  }
396 }
397 
399 {
400  LogText("OVR::SensorDevice - Lost connection to '%s'\n", getHIDDesc()->Path.ToCStr());
402 }
403 
405 {
407 
408  LogText("OVR::SensorDevice - Closed '%s'\n", getHIDDesc()->Path.ToCStr());
409 }
410 
412 {
413 
414  bool processed = false;
415  if (!processed)
416  {
417  TrackerMessage message;
418  if (decodeTrackerMessage(&message, pData, length))
419  {
420  processed = true;
421  onTrackerMessage(&message);
422  }
423  }
424 }
425 
426 double SensorDeviceImpl::OnTicks(double tickSeconds)
427 {
428  if (tickSeconds >= NextKeepAliveTickSeconds)
429  {
430  // Use 3-seconds keep alive by default.
431  double keepAliveDelta = 3.0;
432 
433  // Set Keep-alive at 10 seconds.
434  SensorKeepAliveImpl skeepAlive(10 * 1000);
435  // OnTicks is called from background thread so we don't need to add this to the command queue.
437 
438  // Emit keep-alive every few seconds.
439  NextKeepAliveTickSeconds = tickSeconds + keepAliveDelta;
440  }
441  return NextKeepAliveTickSeconds - tickSeconds;
442 }
443 
444 bool SensorDeviceImpl::SetRange(const SensorRange& range, bool waitFlag)
445 {
446  bool result = 0;
447  ThreadCommandQueue * threadQueue = GetManagerImpl()->GetThreadQueue();
448 
449  if (!waitFlag)
450  {
451  return threadQueue->PushCall(this, &SensorDeviceImpl::setRange, range);
452  }
453 
454  if (!threadQueue->PushCallAndWaitResult(this,
456  &result,
457  range))
458  {
459  return false;
460  }
461 
462  return result;
463 }
464 
466 {
467  Lock::Locker lockScope(GetLock());
468  *range = CurrentRange;
469 }
470 
472 {
473  SensorRangeImpl sr(range);
474 
476  {
477  Lock::Locker lockScope(GetLock());
479  return true;
480  }
481 
482  return false;
483 }
484 
485 void SensorDeviceImpl::SetCoordinateFrame(CoordinateFrame coordframe)
486 {
487  // Push call with wait.
489  PushCall(this, &SensorDeviceImpl::setCoordinateFrame, coordframe, true);
490 }
491 
493 {
494  return Coordinates;
495 }
496 
497 Void SensorDeviceImpl::setCoordinateFrame(CoordinateFrame coordframe)
498 {
499 
500  Coordinates = coordframe;
501 
502  // Read the original coordinate frame, then try to change it.
503  SensorConfigImpl scfg;
505  {
506  scfg.Unpack();
507  }
508 
509  scfg.SetSensorCoordinates(coordframe == Coord_Sensor);
510  scfg.Pack();
511 
513 
514  // Re-read the state, in case of older firmware that doesn't support Sensor coordinates.
516  {
517  scfg.Unpack();
519  }
520  else
521  {
523  }
524  return 0;
525 }
526 
527 void SensorDeviceImpl::SetReportRate(unsigned rateHz)
528 {
529  // Push call with wait.
531  PushCall(this, &SensorDeviceImpl::setReportRate, rateHz, true);
532 }
533 
535 {
536  // Read the original configuration
537  SensorConfigImpl scfg;
539  {
540  scfg.Unpack();
541  return Sensor_MaxReportRate / (scfg.PacketInterval + 1);
542  }
543  return 0; // error
544 }
545 
547 {
548  // Read the original configuration
549  SensorConfigImpl scfg;
551  {
552  scfg.Unpack();
553  }
554 
555  if (rateHz > Sensor_MaxReportRate)
556  rateHz = Sensor_MaxReportRate;
557  else if (rateHz == 0)
558  rateHz = Sensor_DefaultReportRate;
559 
560  scfg.PacketInterval = UInt16((Sensor_MaxReportRate / rateHz) - 1);
561 
562  scfg.Pack();
563 
565  return 0;
566 }
567 
569  Matrix4f* AccelMatrix, Matrix4f* GyroMatrix,
570  float* Temperature)
571 {
572  *AccelOffset = AccelCalibrationOffset;
573  *GyroOffset = GyroCalibrationOffset;
574  *AccelMatrix = AccelCalibrationMatrix;
575  *GyroMatrix = GyroCalibrationMatrix;
576  *Temperature = CalibrationTemperature;
577 }
578 
580 {
581  return magCalibrated;
582 }
583 
585 {
586  // Push call with wait.
588  PushCall(this, &SensorDeviceImpl::setOnboardCalibrationEnabled, enabled, true);
589 }
590 
592 {
593  // Read the original configuration
594  SensorConfigImpl scfg;
596  {
597  scfg.Unpack();
598  }
599 
600  if (enabled)
602  else
604 
605  scfg.Pack();
606 
608  return 0;
609 }
610 
612 {
613  if (handler)
614  SequenceValid = false;
616 }
617 
618 // Sensor reports data in the following coordinate system:
619 // Accelerometer: 10^-4 m/s^2; X forward, Y right, Z Down.
620 // Gyro: 10^-4 rad/s; X positive roll right, Y positive pitch up; Z positive yaw right.
621 
622 
623 // We need to convert it to the following RHS coordinate system:
624 // X right, Y Up, Z Back (out of screen)
625 //
627  bool convertHMDToSensor = false)
628 {
629  const TrackerSample& sample = update.Samples[sampleNumber];
630  float ax = (float)sample.AccelX;
631  float ay = (float)sample.AccelY;
632  float az = (float)sample.AccelZ;
633 
634  Vector3f val = convertHMDToSensor ? Vector3f(ax, az, -ay) : Vector3f(ax, ay, az);
635  return val * 0.0001f;
636 }
637 
638 
640  Matrix4f magCalibration,
641  bool convertHMDToSensor = false)
642 {
643  float mx = (float)update.MagX;
644  float my = (float)update.MagY;
645  float mz = (float)update.MagZ;
646  // Note: Y and Z are swapped in comparison to the Accel.
647  // This accounts for DK1 sensor firmware axis swap, which should be undone in future releases.
648  Vector3f mag = convertHMDToSensor ? Vector3f(mx, my, -mz) : Vector3f(mx, mz, my);
649  mag *= 0.0001f;
650  // Apply calibration
651  return magCalibration.Transform(mag);
652 }
653 
655  bool convertHMDToSensor = false)
656 {
657  const TrackerSample& sample = update.Samples[sampleNumber];
658  float gx = (float)sample.GyroX;
659  float gy = (float)sample.GyroY;
660  float gz = (float)sample.GyroZ;
661 
662  Vector3f val = convertHMDToSensor ? Vector3f(gx, gz, -gy) : Vector3f(gx, gy, gz);
663  return val * 0.0001f;
664 }
665 
667 {
668  memset(message, 0, sizeof(TrackerMessage));
669 
670  if (size < 4)
671  {
672  message->Type = TrackerMessage_SizeError;
673  return false;
674  }
675 
676  switch (buffer[0])
677  {
679  message->Type = message->Sensors.Decode(buffer, size);
680  break;
681 
682  default:
683  message->Type = TrackerMessage_Unknown;
684  break;
685  }
686 
687  return (message->Type < TrackerMessage_Unknown) && (message->Type != TrackerMessage_None);
688 }
689 
691 {
692  if (message->Type != TrackerMessage_Sensors)
693  return;
694 
695  const double timeUnit = (1.0 / 1000.0);
696  double scaledTimeUnit = timeUnit;
697  TrackerSensors& s = message->Sensors;
698  // DK1 timestamps the first sample, so the actual device time will be later
699  // by the time we get the message if there are multiple samples.
700  int timestampAdjust = (s.SampleCount > 0) ? s.SampleCount-1 : 0;
701 
702  const double now = Timer::GetSeconds();
703  double absoluteTimeSeconds = 0.0;
704 
705 
706  if (SequenceValid)
707  {
708  unsigned timestampDelta;
709 
710  if (s.Timestamp < LastTimestamp)
711  {
712  // The timestamp rolled around the 16 bit counter, so FullTimeStamp
713  // needs a high word increment.
714  FullTimestamp += 0x10000;
715  timestampDelta = ((((int)s.Timestamp) + 0x10000) - (int)LastTimestamp);
716  }
717  else
718  {
719  timestampDelta = (s.Timestamp - LastTimestamp);
720  }
721  // Update the low word of FullTimeStamp
722  FullTimestamp = ( FullTimestamp & ~0xffff ) | s.Timestamp;
723 
724  double deviceTime = (FullTimestamp + timestampAdjust) * timeUnit;
725  absoluteTimeSeconds = TimeFilter.SampleToSystemTime(deviceTime, now, PrevAbsoluteTime);
726  scaledTimeUnit = TimeFilter.ScaleTimeUnit(timeUnit);
727  PrevAbsoluteTime = absoluteTimeSeconds;
728 
729  // If we missed a small number of samples, generate the sample that would have immediately
730  // proceeded the current one. Re-use the IMU values from the last processed sample.
731  if ((timestampDelta > LastSampleCount) && (timestampDelta <= 254))
732  {
733  if (HandlerRef.HasHandlers())
734  {
735  MessageBodyFrame sensors(this);
736 
737  sensors.AbsoluteTimeSeconds = absoluteTimeSeconds - s.SampleCount * scaledTimeUnit;
738  sensors.TimeDelta = (float)((timestampDelta - LastSampleCount) * scaledTimeUnit);
739  sensors.Acceleration = LastAcceleration;
740  sensors.RotationRate = LastRotationRate;
742  sensors.Temperature = LastTemperature;
743 
744  HandlerRef.Call(sensors);
745  }
746  }
747  }
748  else
749  {
753  LastTemperature = 0;
754  SequenceValid = true;
755 
756  // This is our baseline sensor to host time delta,
757  // it will be adjusted with each new message.
759 
760  double deviceTime = (FullTimestamp + timestampAdjust) * timeUnit;
761  absoluteTimeSeconds = TimeFilter.SampleToSystemTime(deviceTime, now, PrevAbsoluteTime);
762  scaledTimeUnit = TimeFilter.ScaleTimeUnit(timeUnit);
763  PrevAbsoluteTime = absoluteTimeSeconds;
764  }
765 
768 
769  bool convertHMDToSensor = (Coordinates == Coord_Sensor) && (HWCoordinates == Coord_HMD);
770 
771 #ifdef OVR_OS_ANDROID
772  // LDC - Normally we get the coordinate system from the tracker.
773  // Since KTracker doesn't store it we'll always assume HMD coordinate system.
774  convertHMDToSensor = false;
775 #endif
776 
777  if (HandlerRef.HasHandlers())
778  {
779  MessageBodyFrame sensors(this);
780  UByte iterations = s.SampleCount;
781 
782  if (s.SampleCount > 3)
783  {
784  iterations = 3;
785  sensors.TimeDelta = (float)((s.SampleCount - 2) * scaledTimeUnit);
786  }
787  else
788  {
789  sensors.TimeDelta = (float)scaledTimeUnit;
790  }
791 
792  for (UByte i = 0; i < iterations; i++)
793  {
794  sensors.AbsoluteTimeSeconds = absoluteTimeSeconds - ( iterations - 1 - i ) * scaledTimeUnit;
795  sensors.Acceleration = AccelFromBodyFrameUpdate(s, i, convertHMDToSensor);
796  sensors.RotationRate = EulerFromBodyFrameUpdate(s, i, convertHMDToSensor);
797  sensors.MagneticField = MagFromBodyFrameUpdate(s, magCalibration, convertHMDToSensor);
798 
799 #ifdef OVR_OS_ANDROID
800  replaceWithPhoneMag(&(sensors.MagneticField));
801 #endif
802  sensors.Temperature = s.Temperature * 0.01f;
803  HandlerRef.Call(sensors);
804  // TimeDelta for the last two sample is always fixed.
805  sensors.TimeDelta = (float)scaledTimeUnit;
806  }
807 
808  LastAcceleration = sensors.Acceleration;
809  LastRotationRate = sensors.RotationRate;
811  LastTemperature = sensors.Temperature;
812  }
813  else
814  {
815  UByte i = (s.SampleCount > 3) ? 2 : (s.SampleCount - 1);
816  LastAcceleration = AccelFromBodyFrameUpdate(s, i, convertHMDToSensor);
817  LastRotationRate = EulerFromBodyFrameUpdate(s, i, convertHMDToSensor);
818  LastMagneticField = MagFromBodyFrameUpdate(s, magCalibration, convertHMDToSensor);
819 
820 #ifdef OVR_OS_ANDROID
821  replaceWithPhoneMag(&LastMagneticField);
822 #endif
823  LastTemperature = s.Temperature * 0.01f;
824  }
825 }
826 
827 
828 #ifdef OVR_OS_ANDROID
829 
830 void SensorDeviceImpl::replaceWithPhoneMag(Vector3f* val)
831 {
832 
833  // Native calibrated.
834  pPhoneSensors->SetMagSource(PhoneSensors::MagnetometerSource_Native);
835 
836  Vector3f magPhone;
837  pPhoneSensors->GetLatestMagValue(&magPhone);
838 
839  // Phone value is in micro-Tesla. Convert it to Gauss and flip axes.
840  magPhone *= 10000.0f/1000000.0f;
841 
842  Vector3f res;
843  res.x = -magPhone.y;
844  res.y = magPhone.x;
845  res.z = magPhone.z;
846 
847  *val = res;
848 }
849 #endif
850 
852 
853 // Writes the current calibration for a particular device to a device profile file
855 {
856  // Get device info
857  SensorInfo sinfo;
858  GetDeviceInfo(&sinfo);
859 
860  // A named calibration may be specified for calibration in different
861  // environments, otherwise the default calibration is used
862  const char* calibrationName = "default";
863 
864  // Generate a mag calibration event
865  JSON* calibration = JSON::CreateObject();
866  // (hardcoded for now) the measurement and representation method
867  calibration->AddStringItem("Version", "2.0");
868  calibration->AddStringItem("Name", "default");
869 
870  // time stamp the calibration
871  char time_str[64];
872 
873 #ifdef OVR_OS_WIN32
874  struct tm caltime;
875  time_t now = time(0);
876  localtime_s(&caltime, &now);
877  strftime(time_str, 64, "%Y-%m-%d %H:%M:%S", &caltime);
878 #else
879  struct tm* caltime;
880  time_t now = time(0);
881  caltime = localtime(&now);
882  strftime(time_str, 64, "%Y-%m-%d %H:%M:%S", caltime);
883 #endif
884 
885  calibration->AddStringItem("Time", time_str);
886 
887  // write the full calibration matrix
888  char matrix[256];
889  data.Calibration.ToString(matrix, 256);
890  calibration->AddStringItem("CalibrationMatrix", matrix);
891  // save just the offset, for backwards compatibility
892  // this can be removed when we don't want to support 0.2.4 anymore
893  Vector3f center(data.Calibration.M[0][3], data.Calibration.M[1][3], data.Calibration.M[2][3]);
894  Matrix4f tmp = data.Calibration; tmp.M[0][3] = tmp.M[1][3] = tmp.M[2][3] = 0; tmp.M[3][3] = 1;
895  center = tmp.Inverted().Transform(center);
896  Matrix4f oldcalmat; oldcalmat.M[0][3] = center.x; oldcalmat.M[1][3] = center.y; oldcalmat.M[2][3] = center.z;
897  oldcalmat.ToString(matrix, 256);
898  calibration->AddStringItem("Calibration", matrix);
899 
900  String path = GetBaseOVRPath(true);
901  path += "/Devices.json";
902 
903  // Look for a preexisting device file to edit
904  Ptr<JSON> root = *JSON::Load(path);
905  if (root)
906  { // Quick sanity check of the file type and format before we parse it
907  JSON* version = root->GetFirstItem();
908  if (version && version->Name == "Oculus Device Profile Version")
909  {
910  int major = atoi(version->Value.ToCStr());
912  {
913  // don't use the file on unsupported major version number
914  root->Release();
915  root = NULL;
916  }
917  }
918  else
919  {
920  root->Release();
921  root = NULL;
922  }
923  }
924 
925  JSON* device = NULL;
926  if (root)
927  {
928  device = root->GetFirstItem(); // skip the header
929  device = root->GetNextItem(device);
930  while (device)
931  { // Search for a previous calibration with the same name for this device
932  // and remove it before adding the new one
933  if (device->Name == "Device")
934  {
935  JSON* item = device->GetItemByName("Serial");
936  if (item && item->Value == sinfo.SerialNumber)
937  { // found an entry for this device
938  item = device->GetNextItem(item);
939  while (item)
940  {
941  if (item->Name == "MagCalibration")
942  {
943  JSON* name = item->GetItemByName("Name");
944  if (name && name->Value == calibrationName)
945  { // found a calibration of the same name
946  item->RemoveNode();
947  item->Release();
948  break;
949  }
950  }
951  item = device->GetNextItem(item);
952  }
953 
954 
955  /*
956  this is removed temporarily, since this is a sensor fusion setting, not sensor itself
957  should be moved to the correct place when Brant has finished the user profile implementation
958  // update the auto-mag flag
959  item = device->GetItemByName("EnableYawCorrection");
960  if (item)
961  item->dValue = (double)EnableYawCorrection;
962  else
963  device->AddBoolItem("EnableYawCorrection", EnableYawCorrection);*/
964 
965  break;
966  }
967  }
968 
969  device = root->GetNextItem(device);
970  }
971  }
972  else
973  { // Create a new device root
974  root = *JSON::CreateObject();
975  root->AddStringItem("Oculus Device Profile Version", "1.0");
976  }
977 
978  if (device == NULL)
979  {
980  device = JSON::CreateObject();
981  device->AddStringItem("Product", sinfo.ProductName);
982  device->AddNumberItem("ProductID", sinfo.ProductId);
983  device->AddStringItem("Serial", sinfo.SerialNumber);
984  // removed temporarily, see above
985  //device->AddBoolItem("EnableYawCorrection", EnableYawCorrection);
986 
987  root->AddItem("Device", device);
988  }
989 
990  // Create and the add the new calibration event to the device
991  device->AddItem("MagCalibration", calibration);
992  return root->Save(path);
993 }
994 
995 // Loads a saved calibration for the specified device from the device profile file
997 {
998  data->Version = 0;
999  data->Calibration.SetIdentity();
1000 
1001  // Get device info
1002  SensorInfo sinfo;
1003  GetDeviceInfo(&sinfo);
1004 
1005  // A named calibration may be specified for calibration in different
1006  // environments, otherwise the default calibration is used
1007  const char* calibrationName = "default";
1008 
1009  String path = GetBaseOVRPath(true);
1010  path += "/Devices.json";
1011 
1012  // Load the device profiles
1013  Ptr<JSON> root = *JSON::Load(path);
1014  if (root == NULL)
1015  return false;
1016 
1017  // Quick sanity check of the file type and format before we parse it
1018  JSON* version = root->GetFirstItem();
1019  if (version && version->Name == "Oculus Device Profile Version")
1020  {
1021  int major = atoi(version->Value.ToCStr());
1023  return false; // don't parse the file on unsupported major version number
1024  }
1025  else
1026  {
1027  return false;
1028  }
1029 
1030  JSON* device = root->GetNextItem(version);
1031  while (device)
1032  { // Search for a previous calibration with the same name for this device
1033  // and remove it before adding the new one
1034  if (device->Name == "Device")
1035  {
1036  JSON* item = device->GetItemByName("Serial");
1037  if (item && item->Value == sinfo.SerialNumber)
1038  { // found an entry for this device
1039 
1040  JSON* autoyaw = device->GetItemByName("EnableYawCorrection");
1041  // as a temporary HACK, return no calibration if EnableYawCorrection is off
1042  // this will force disable yaw correction in SensorFusion
1043  // proper solution would load the value in the Profile, which SensorFusion can access
1044  if (autoyaw && autoyaw->dValue == 0)
1045  return true;
1046 
1047  item = device->GetNextItem(item);
1048  while (item)
1049  {
1050  if (item->Name == "MagCalibration")
1051  {
1052  JSON* calibration = item;
1053  JSON* name = calibration->GetItemByName("Name");
1054  if (name && name->Value == calibrationName)
1055  { // found a calibration with this name
1056 
1057  int major = 0;
1058  JSON* version = calibration->GetItemByName("Version");
1059  if (version)
1060  major = atoi(version->Value.ToCStr());
1061 
1062  if (major > data->Version && major <= 2)
1063  {
1064  time_t now;
1065  time(&now);
1066 
1067  // parse the calibration time
1068  //time_t calibration_time = now;
1069  JSON* caltime = calibration->GetItemByName("Time");
1070  if (caltime)
1071  {
1072  const char* caltime_str = caltime->Value.ToCStr();
1073 
1074  tm ct;
1075  memset(&ct, 0, sizeof(tm));
1076 
1077 #ifdef OVR_OS_WIN32
1078  struct tm nowtime;
1079  localtime_s(&nowtime, &now);
1080  ct.tm_isdst = nowtime.tm_isdst;
1081  sscanf_s(caltime_str, "%d-%d-%d %d:%d:%d",
1082  &ct.tm_year, &ct.tm_mon, &ct.tm_mday,
1083  &ct.tm_hour, &ct.tm_min, &ct.tm_sec);
1084 #else
1085  struct tm* nowtime = localtime(&now);
1086  ct.tm_isdst = nowtime->tm_isdst;
1087  sscanf(caltime_str, "%d-%d-%d %d:%d:%d",
1088  &ct.tm_year, &ct.tm_mon, &ct.tm_mday,
1089  &ct.tm_hour, &ct.tm_min, &ct.tm_sec);
1090 #endif
1091  ct.tm_year -= 1900;
1092  ct.tm_mon--;
1093  //calibration_time = mktime(&ct);
1094  }
1095 
1096  // parse the calibration matrix
1097  JSON* cal = calibration->GetItemByName("CalibrationMatrix");
1098  if (!cal)
1099  cal = calibration->GetItemByName("Calibration");
1100  if (cal)
1101  {
1102  data->Calibration = Matrix4f::FromString(cal->Value.ToCStr());
1103  data->Version = (UByte)major;
1104  }
1105  }
1106  }
1107  }
1108  item = device->GetNextItem(item);
1109  }
1110 
1111  return true;
1112  }
1113  }
1114 
1115  device = root->GetNextItem(device);
1116  }
1117 
1118  return true;
1119 }
1120 
1121 
1123 {
1124  bool result;
1125  if (!GetManagerImpl()->GetThreadQueue()->
1126  PushCallAndWaitResult(this, &Sensor2DeviceImpl::setSerialReport, &result, data))
1127  {
1128  return false;
1129  }
1130 
1131  return result;
1132 }
1133 
1135 {
1136  SerialImpl di(data);
1138 }
1139 
1141 {
1142  bool result;
1143  if (!GetManagerImpl()->GetThreadQueue()->
1144  PushCallAndWaitResult(this, &Sensor2DeviceImpl::getSerialReport, &result, data))
1145  {
1146  return false;
1147  }
1148 
1149  return result;
1150 }
1151 
1153 {
1154  SerialImpl di;
1156  {
1157  di.Unpack();
1158  *data = di.Settings;
1159  return true;
1160  }
1161 
1162  return false;
1163 }
1164 
1165 } // namespace OVR
virtual bool GetDeviceInfo(DeviceInfo *info) const
DeviceType Type
Definition: OVR_Device.h:152
bool PushCall(R(C::*fn)(), bool wait=false)
void LogText(const char *fmt,...) OVR_LOG_VAARG_ATTRIBUTE(1
void onTrackerMessage(TrackerMessage *message)
Vector3f MagFromBodyFrameUpdate(const Tracker2Sensors &update)
bool decodeTrackerMessage(TrackerMessage *message, UByte *buffer, int size)
TrackerSample Samples[3]
double ScaleTimeUnit(double deviceClockDelta)
const DeviceType InfoClassType
Definition: OVR_Device.h:149
virtual bool MatchVendorProduct(UInt16 vendorId, UInt16 productId) const
virtual bool Initialize(DeviceBase *parent)
float DecodeFloat(const UByte *buffer)
Definition: OVR_Alg.h:1006
virtual void GetRange(SensorRange *range) const
DeviceManagerImpl * GetManagerImpl()
SensorTimeFilter TimeFilter
bool setSerialReport(const SerialReport &data)
virtual bool GetDeviceInfo(DeviceInfo *info) const
#define NULL
TrackerMessageType Type
virtual unsigned GetReportRate() const
SensorDeviceImpl(SensorDeviceCreateDesc *createDesc)
virtual ThreadCommandQueue * GetThreadQueue()=0
Ptr< DeviceCreateDesc > pCreateDesc
unsigned Version
Definition: OVR_Device.h:156
uint16_t UInt16
Definition: OVR_Types.h:251
float MaxMagneticField
Definition: OVR_Device.h:472
Matrix4 Inverted() const
Definition: OVR_Math.h:1452
UInt32 DecodeUInt32(const UByte *buffer)
Definition: OVR_Alg.h:996
virtual void AddMessageHandler(MessageHandler *handler)
virtual bool DetectHIDDevice(DeviceManager *pdevMgr, const HIDDeviceDesc &desc)
bool GetSerialReport(SerialReport *data)
uint32_t UInt32
Definition: OVR_Types.h:253
Lock * GetLock() const
virtual DeviceBase * NewDeviceInstance()
virtual void SetReportRate(unsigned rateHz)
virtual double OnTicks(double tickSeconds)
static SensorDeviceFactory & GetInstance()
UInt16 DecodeUInt16(const UByte *buffer)
Definition: OVR_Alg.h:986
void SetIdentity()
Definition: OVR_Math.h:1299
String Name
Definition: OVR_JSON.h:65
bool SetFeatureReport(UByte *data, UInt32 length)
virtual bool Enumerate(HIDEnumerateVisitor *enumVisitor)=0
static void EnumerateHMDFromSensorDisplayInfo(const SensorDisplayInfoImpl &displayInfo, DeviceFactory::EnumerateVisitor &visitor)
Void setReportRate(unsigned rateHz)
static Matrix4 FromString(const char *src)
Definition: OVR_Math.h:1282
String GetBaseOVRPath(bool create_dir)
Definition: OVR_Profile.cpp:64
uint8_t UByte
Definition: OVR_Types.h:249
virtual bool SetMagCalibrationReport(const MagCalibrationReport &data)
Vector3f AccelFromBodyFrameUpdate(const Tracker2Sensors &update, UByte sampleNumber)
double SampleToSystemTime(double sampleDeviceTime, double systemTime, double prevResult, const char *debugTag="")
String Value
Definition: OVR_JSON.h:66
bool HasHandlers() const
TrackerMessageType Decode(const UByte *buffer, int size)
bool setRange(const SensorRange &range)
void GetSensorRange(SensorRange *r)
virtual void OnInputReport(UByte *pData, UInt32 length)
virtual void SetOnboardCalibrationEnabled(bool enabled)
#define major(dev)
Definition: OVR_Types.h:61
const char * ToCStr() const
Definition: OVR_String.h:186
CoordinateFrame HWCoordinates
TrackerSensors Sensors
void RemoveNode()
Definition: OVR_List.h:58
virtual void GetFactoryCalibration(Vector3f *AccelOffset, Vector3f *GyroOffset, Matrix4f *AccelMatrix, Matrix4f *GyroMatrix, float *Temperature)
bool getSerialReport(SerialReport *data)
static SensorRange GetMaxSensorRange()
virtual bool IsMagCalibrated()
static JSON * Load(const char *path, const char **perror=0)
Definition: OVR_JSON.cpp:1132
virtual void Shutdown()
String ProductName
Definition: OVR_Device.h:154
String SerialNumber
Definition: OVR_Device.h:489
virtual CoordinateFrame GetCoordinateFrame() const
static JSON * CreateObject()
Definition: OVR_JSON.h:74
UByte Buffer[PacketSize]
#define OVR_ASSERT(p)
void SetSensorCoordinates(bool sensorCoordinates)
virtual void EnumerateDevices(EnumerateVisitor &visitor)
void AddItem(const char *string, JSON *item)
Definition: OVR_JSON.cpp:921
T M[4][4]
Definition: OVR_Math.h:1197
MessageHandlerRef HandlerRef
virtual HIDDeviceManager * GetHIDDeviceManager() const
TrackerMessageType
bool GetFeatureReport(UByte *data, UInt32 length)
JSON * GetNextItem(JSON *item)
Definition: OVR_JSON.h:115
DeviceManagerImpl * GetManagerImpl() const
virtual Ptr< DeviceCreateDesc > AddDevice_NeedsLock(const DeviceCreateDesc &createDesc)=0
int16_t SInt16
Definition: OVR_Types.h:250
virtual void SetCoordinateFrame(CoordinateFrame coordframe)
Vector3f EulerFromBodyFrameUpdate(const Tracker2Sensors &update, UByte sampleNumber)
void AddNumberItem(const char *name, double n)
Definition: OVR_JSON.h:123
CoordinateFrame Coordinates
virtual void openDevice()
void AddStringItem(const char *name, const char *s)
Definition: OVR_JSON.h:124
__BEGIN_NAMESPACE_STD void void __END_NAMESPACE_STD void __BEGIN_NAMESPACE_STD void * memset(void *__s, int __c, size_t __n) __THROW __nonnull((1))
void UnpackSensor(const UByte *buffer, SInt32 *x, SInt32 *y, SInt32 *z)
static double OVR_STDCALL GetSeconds()
Definition: OVR_Timer.cpp:51
const int MAX_DEVICE_PROFILE_MAJOR_VERSION
virtual void AddMessageHandler(MessageHandler *handler)
Void setCoordinateFrame(CoordinateFrame coordframe)
String Manufacturer
Definition: OVR_Device.h:155
virtual bool SetFeatureReport(UByte *data, UInt32 length)=0
void ToString(char *dest, UPInt destsize) const
Definition: OVR_Math.h:1274
virtual bool SetRange(const SensorRange &range, bool waitFlag)
Void setOnboardCalibrationEnabled(bool enabled)
bool SetSerialReport(const SerialReport &data)
double dValue
Definition: OVR_JSON.h:67
void Call(const Message &msg)
SInt16 DecodeSInt16(const UByte *buffer)
Definition: OVR_Alg.h:991
SerialReport Settings
Definition: OVR_Device.h:533
Vector3< float > Vector3f
Definition: OVR_Math.h:554
JSON * GetItemByName(const char *name)
Definition: OVR_JSON.cpp:897
virtual bool GetMagCalibrationReport(MagCalibrationReport *data)
Vector3< T > Transform(const Vector3< T > &v) const
Definition: OVR_Math.h:1405
UInt16 ProductId
Definition: OVR_Device.h:485
SensorRange MaxRanges
Definition: OVR_Device.h:487
bool PushCallAndWaitResult(R(C::*fn)(), R *ret)
virtual bool GetFeatureReport(UByte *data, UInt32 length)=0
UByte Buffer[PacketSize]
Definition: OVR_Device.h:531
UByte Buffer[PacketSize]