oculus1

annotate libovr/Src/OVR_SensorImpl.cpp @ 23:0c76f70fb7e9

merged
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 28 Sep 2013 04:13:33 +0300
parents
children
rev   line source
nuclear@1 1 /************************************************************************************
nuclear@1 2
nuclear@1 3 Filename : OVR_SensorImpl.cpp
nuclear@1 4 Content : Oculus Sensor device implementation.
nuclear@1 5 Created : March 7, 2013
nuclear@1 6 Authors : Lee Cooper
nuclear@1 7
nuclear@1 8 Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
nuclear@1 9
nuclear@1 10 Use of this software is subject to the terms of the Oculus license
nuclear@1 11 agreement provided at the time of installation or download, or which
nuclear@1 12 otherwise accompanies this software in either electronic or hard copy form.
nuclear@1 13
nuclear@1 14 *************************************************************************************/
nuclear@1 15
nuclear@1 16 #include "OVR_SensorImpl.h"
nuclear@1 17
nuclear@1 18 // HMDDeviceDesc can be created/updated through Sensor carrying DisplayInfo.
nuclear@1 19
nuclear@1 20 #include "Kernel/OVR_Timer.h"
nuclear@1 21
nuclear@1 22 namespace OVR {
nuclear@1 23
nuclear@1 24 //-------------------------------------------------------------------------------------
nuclear@1 25 // ***** Oculus Sensor-specific packet data structures
nuclear@1 26
nuclear@1 27 enum {
nuclear@1 28 Sensor_VendorId = Oculus_VendorId,
nuclear@1 29 Sensor_ProductId = 0x0001,
nuclear@1 30
nuclear@1 31 // ST's VID used originally; should be removed in the future
nuclear@1 32 Sensor_OldVendorId = 0x0483,
nuclear@1 33 Sensor_OldProductId = 0x5750,
nuclear@1 34
nuclear@1 35 Sensor_DefaultReportRate = 500, // Hz
nuclear@1 36 Sensor_MaxReportRate = 1000 // Hz
nuclear@1 37 };
nuclear@1 38
nuclear@1 39 // Reported data is little-endian now
nuclear@1 40 static UInt16 DecodeUInt16(const UByte* buffer)
nuclear@1 41 {
nuclear@1 42 return (UInt16(buffer[1]) << 8) | UInt16(buffer[0]);
nuclear@1 43 }
nuclear@1 44
nuclear@1 45 static SInt16 DecodeSInt16(const UByte* buffer)
nuclear@1 46 {
nuclear@1 47 return (SInt16(buffer[1]) << 8) | SInt16(buffer[0]);
nuclear@1 48 }
nuclear@1 49
nuclear@1 50 static UInt32 DecodeUInt32(const UByte* buffer)
nuclear@1 51 {
nuclear@1 52 return (buffer[0]) | UInt32(buffer[1] << 8) | UInt32(buffer[2] << 16) | UInt32(buffer[3] << 24);
nuclear@1 53 }
nuclear@1 54
nuclear@1 55 static float DecodeFloat(const UByte* buffer)
nuclear@1 56 {
nuclear@1 57 union {
nuclear@1 58 UInt32 U;
nuclear@1 59 float F;
nuclear@1 60 };
nuclear@1 61
nuclear@1 62 U = DecodeUInt32(buffer);
nuclear@1 63 return F;
nuclear@1 64 }
nuclear@1 65
nuclear@1 66
nuclear@1 67 static void UnpackSensor(const UByte* buffer, SInt32* x, SInt32* y, SInt32* z)
nuclear@1 68 {
nuclear@1 69 // Sign extending trick
nuclear@1 70 // from http://graphics.stanford.edu/~seander/bithacks.html#FixedSignExtend
nuclear@1 71 struct {SInt32 x:21;} s;
nuclear@1 72
nuclear@1 73 *x = s.x = (buffer[0] << 13) | (buffer[1] << 5) | ((buffer[2] & 0xF8) >> 3);
nuclear@1 74 *y = s.x = ((buffer[2] & 0x07) << 18) | (buffer[3] << 10) | (buffer[4] << 2) |
nuclear@1 75 ((buffer[5] & 0xC0) >> 6);
nuclear@1 76 *z = s.x = ((buffer[5] & 0x3F) << 15) | (buffer[6] << 7) | (buffer[7] >> 1);
nuclear@1 77 }
nuclear@1 78
nuclear@1 79 // Messages we care for
nuclear@1 80 enum TrackerMessageType
nuclear@1 81 {
nuclear@1 82 TrackerMessage_None = 0,
nuclear@1 83 TrackerMessage_Sensors = 1,
nuclear@1 84 TrackerMessage_Unknown = 0x100,
nuclear@1 85 TrackerMessage_SizeError = 0x101,
nuclear@1 86 };
nuclear@1 87
nuclear@1 88 struct TrackerSample
nuclear@1 89 {
nuclear@1 90 SInt32 AccelX, AccelY, AccelZ;
nuclear@1 91 SInt32 GyroX, GyroY, GyroZ;
nuclear@1 92 };
nuclear@1 93
nuclear@1 94
nuclear@1 95 struct TrackerSensors
nuclear@1 96 {
nuclear@1 97 UByte SampleCount;
nuclear@1 98 UInt16 Timestamp;
nuclear@1 99 UInt16 LastCommandID;
nuclear@1 100 SInt16 Temperature;
nuclear@1 101
nuclear@1 102 TrackerSample Samples[3];
nuclear@1 103
nuclear@1 104 SInt16 MagX, MagY, MagZ;
nuclear@1 105
nuclear@1 106 TrackerMessageType Decode(const UByte* buffer, int size)
nuclear@1 107 {
nuclear@1 108 if (size < 62)
nuclear@1 109 return TrackerMessage_SizeError;
nuclear@1 110
nuclear@1 111 SampleCount = buffer[1];
nuclear@1 112 Timestamp = DecodeUInt16(buffer + 2);
nuclear@1 113 LastCommandID = DecodeUInt16(buffer + 4);
nuclear@1 114 Temperature = DecodeSInt16(buffer + 6);
nuclear@1 115
nuclear@1 116 //if (SampleCount > 2)
nuclear@1 117 // OVR_DEBUG_LOG_TEXT(("TackerSensor::Decode SampleCount=%d\n", SampleCount));
nuclear@1 118
nuclear@1 119 // Only unpack as many samples as there actually are
nuclear@1 120 UByte iterationCount = (SampleCount > 2) ? 3 : SampleCount;
nuclear@1 121
nuclear@1 122 for (UByte i = 0; i < iterationCount; i++)
nuclear@1 123 {
nuclear@1 124 UnpackSensor(buffer + 8 + 16 * i, &Samples[i].AccelX, &Samples[i].AccelY, &Samples[i].AccelZ);
nuclear@1 125 UnpackSensor(buffer + 16 + 16 * i, &Samples[i].GyroX, &Samples[i].GyroY, &Samples[i].GyroZ);
nuclear@1 126 }
nuclear@1 127
nuclear@1 128 MagX = DecodeSInt16(buffer + 56);
nuclear@1 129 MagY = DecodeSInt16(buffer + 58);
nuclear@1 130 MagZ = DecodeSInt16(buffer + 60);
nuclear@1 131
nuclear@1 132 return TrackerMessage_Sensors;
nuclear@1 133 }
nuclear@1 134 };
nuclear@1 135
nuclear@1 136 struct TrackerMessage
nuclear@1 137 {
nuclear@1 138 TrackerMessageType Type;
nuclear@1 139 TrackerSensors Sensors;
nuclear@1 140 };
nuclear@1 141
nuclear@1 142 bool DecodeTrackerMessage(TrackerMessage* message, UByte* buffer, int size)
nuclear@1 143 {
nuclear@1 144 memset(message, 0, sizeof(TrackerMessage));
nuclear@1 145
nuclear@1 146 if (size < 4)
nuclear@1 147 {
nuclear@1 148 message->Type = TrackerMessage_SizeError;
nuclear@1 149 return false;
nuclear@1 150 }
nuclear@1 151
nuclear@1 152 switch (buffer[0])
nuclear@1 153 {
nuclear@1 154 case TrackerMessage_Sensors:
nuclear@1 155 message->Type = message->Sensors.Decode(buffer, size);
nuclear@1 156 break;
nuclear@1 157
nuclear@1 158 default:
nuclear@1 159 message->Type = TrackerMessage_Unknown;
nuclear@1 160 break;
nuclear@1 161 }
nuclear@1 162
nuclear@1 163 return (message->Type < TrackerMessage_Unknown) && (message->Type != TrackerMessage_None);
nuclear@1 164 }
nuclear@1 165
nuclear@1 166
nuclear@1 167 // ***** SensorRangeImpl Implementation
nuclear@1 168
nuclear@1 169 // Sensor HW only accepts specific maximum range values, used to maximize
nuclear@1 170 // the 16-bit sensor outputs. Use these ramps to specify and report appropriate values.
nuclear@1 171 static const UInt16 AccelRangeRamp[] = { 2, 4, 8, 16 };
nuclear@1 172 static const UInt16 GyroRangeRamp[] = { 250, 500, 1000, 2000 };
nuclear@1 173 static const UInt16 MagRangeRamp[] = { 880, 1300, 1900, 2500 };
nuclear@1 174
nuclear@1 175 static UInt16 SelectSensorRampValue(const UInt16* ramp, unsigned count,
nuclear@1 176 float val, float factor, const char* label)
nuclear@1 177 {
nuclear@1 178 UInt16 threshold = (UInt16)(val * factor);
nuclear@1 179
nuclear@1 180 for (unsigned i = 0; i<count; i++)
nuclear@1 181 {
nuclear@1 182 if (ramp[i] >= threshold)
nuclear@1 183 return ramp[i];
nuclear@1 184 }
nuclear@1 185 OVR_DEBUG_LOG(("SensorDevice::SetRange - %s clamped to %0.4f",
nuclear@1 186 label, float(ramp[count-1]) / factor));
nuclear@1 187 OVR_UNUSED2(factor, label);
nuclear@1 188 return ramp[count-1];
nuclear@1 189 }
nuclear@1 190
nuclear@1 191 // SensorScaleImpl provides buffer packing logic for the Sensor Range
nuclear@1 192 // record that can be applied to DK1 sensor through Get/SetFeature. We expose this
nuclear@1 193 // through SensorRange class, which has different units.
nuclear@1 194 struct SensorRangeImpl
nuclear@1 195 {
nuclear@1 196 enum { PacketSize = 8 };
nuclear@1 197 UByte Buffer[PacketSize];
nuclear@1 198
nuclear@1 199 UInt16 CommandId;
nuclear@1 200 UInt16 AccelScale;
nuclear@1 201 UInt16 GyroScale;
nuclear@1 202 UInt16 MagScale;
nuclear@1 203
nuclear@1 204 SensorRangeImpl(const SensorRange& r, UInt16 commandId = 0)
nuclear@1 205 {
nuclear@1 206 SetSensorRange(r, commandId);
nuclear@1 207 }
nuclear@1 208
nuclear@1 209 void SetSensorRange(const SensorRange& r, UInt16 commandId = 0)
nuclear@1 210 {
nuclear@1 211 CommandId = commandId;
nuclear@1 212 AccelScale = SelectSensorRampValue(AccelRangeRamp, sizeof(AccelRangeRamp)/sizeof(AccelRangeRamp[0]),
nuclear@1 213 r.MaxAcceleration, (1.0f / 9.81f), "MaxAcceleration");
nuclear@1 214 GyroScale = SelectSensorRampValue(GyroRangeRamp, sizeof(GyroRangeRamp)/sizeof(GyroRangeRamp[0]),
nuclear@1 215 r.MaxRotationRate, Math<float>::RadToDegreeFactor, "MaxRotationRate");
nuclear@1 216 MagScale = SelectSensorRampValue(MagRangeRamp, sizeof(MagRangeRamp)/sizeof(MagRangeRamp[0]),
nuclear@1 217 r.MaxMagneticField, 1000.0f, "MaxMagneticField");
nuclear@1 218 Pack();
nuclear@1 219 }
nuclear@1 220
nuclear@1 221 void GetSensorRange(SensorRange* r)
nuclear@1 222 {
nuclear@1 223 r->MaxAcceleration = AccelScale * 9.81f;
nuclear@1 224 r->MaxRotationRate = DegreeToRad((float)GyroScale);
nuclear@1 225 r->MaxMagneticField= MagScale * 0.001f;
nuclear@1 226 }
nuclear@1 227
nuclear@1 228 static SensorRange GetMaxSensorRange()
nuclear@1 229 {
nuclear@1 230 return SensorRange(AccelRangeRamp[sizeof(AccelRangeRamp)/sizeof(AccelRangeRamp[0]) - 1] * 9.81f,
nuclear@1 231 GyroRangeRamp[sizeof(GyroRangeRamp)/sizeof(GyroRangeRamp[0]) - 1] *
nuclear@1 232 Math<float>::DegreeToRadFactor,
nuclear@1 233 MagRangeRamp[sizeof(MagRangeRamp)/sizeof(MagRangeRamp[0]) - 1] * 0.001f);
nuclear@1 234 }
nuclear@1 235
nuclear@1 236 void Pack()
nuclear@1 237 {
nuclear@1 238 Buffer[0] = 4;
nuclear@1 239 Buffer[1] = UByte(CommandId & 0xFF);
nuclear@1 240 Buffer[2] = UByte(CommandId >> 8);
nuclear@1 241 Buffer[3] = UByte(AccelScale);
nuclear@1 242 Buffer[4] = UByte(GyroScale & 0xFF);
nuclear@1 243 Buffer[5] = UByte(GyroScale >> 8);
nuclear@1 244 Buffer[6] = UByte(MagScale & 0xFF);
nuclear@1 245 Buffer[7] = UByte(MagScale >> 8);
nuclear@1 246 }
nuclear@1 247
nuclear@1 248 void Unpack()
nuclear@1 249 {
nuclear@1 250 CommandId = Buffer[1] | (UInt16(Buffer[2]) << 8);
nuclear@1 251 AccelScale= Buffer[3];
nuclear@1 252 GyroScale = Buffer[4] | (UInt16(Buffer[5]) << 8);
nuclear@1 253 MagScale = Buffer[6] | (UInt16(Buffer[7]) << 8);
nuclear@1 254 }
nuclear@1 255 };
nuclear@1 256
nuclear@1 257
nuclear@1 258 // Sensor configuration command, ReportId == 2.
nuclear@1 259
nuclear@1 260 struct SensorConfigImpl
nuclear@1 261 {
nuclear@1 262 enum { PacketSize = 7 };
nuclear@1 263 UByte Buffer[PacketSize];
nuclear@1 264
nuclear@1 265 // Flag values for Flags.
nuclear@1 266 enum {
nuclear@1 267 Flag_RawMode = 0x01,
nuclear@1 268 Flag_CallibrationTest = 0x02, // Internal test mode
nuclear@1 269 Flag_UseCallibration = 0x04,
nuclear@1 270 Flag_AutoCallibration = 0x08,
nuclear@1 271 Flag_MotionKeepAlive = 0x10,
nuclear@1 272 Flag_CommandKeepAlive = 0x20,
nuclear@1 273 Flag_SensorCoordinates = 0x40
nuclear@1 274 };
nuclear@1 275
nuclear@1 276 UInt16 CommandId;
nuclear@1 277 UByte Flags;
nuclear@1 278 UInt16 PacketInterval;
nuclear@1 279 UInt16 KeepAliveIntervalMs;
nuclear@1 280
nuclear@1 281 SensorConfigImpl() : CommandId(0), Flags(0), PacketInterval(0), KeepAliveIntervalMs(0)
nuclear@1 282 {
nuclear@1 283 memset(Buffer, 0, PacketSize);
nuclear@1 284 Buffer[0] = 2;
nuclear@1 285 }
nuclear@1 286
nuclear@1 287 void SetSensorCoordinates(bool sensorCoordinates)
nuclear@1 288 { Flags = (Flags & ~Flag_SensorCoordinates) | (sensorCoordinates ? Flag_SensorCoordinates : 0); }
nuclear@1 289 bool IsUsingSensorCoordinates() const
nuclear@1 290 { return (Flags & Flag_SensorCoordinates) != 0; }
nuclear@1 291
nuclear@1 292 void Pack()
nuclear@1 293 {
nuclear@1 294 Buffer[0] = 2;
nuclear@1 295 Buffer[1] = UByte(CommandId & 0xFF);
nuclear@1 296 Buffer[2] = UByte(CommandId >> 8);
nuclear@1 297 Buffer[3] = Flags;
nuclear@1 298 Buffer[4] = UByte(PacketInterval);
nuclear@1 299 Buffer[5] = UByte(KeepAliveIntervalMs & 0xFF);
nuclear@1 300 Buffer[6] = UByte(KeepAliveIntervalMs >> 8);
nuclear@1 301 }
nuclear@1 302
nuclear@1 303 void Unpack()
nuclear@1 304 {
nuclear@1 305 CommandId = Buffer[1] | (UInt16(Buffer[2]) << 8);
nuclear@1 306 Flags = Buffer[3];
nuclear@1 307 PacketInterval = Buffer[4];
nuclear@1 308 KeepAliveIntervalMs= Buffer[5] | (UInt16(Buffer[6]) << 8);
nuclear@1 309 }
nuclear@1 310
nuclear@1 311 };
nuclear@1 312
nuclear@1 313
nuclear@1 314 // SensorKeepAlive - feature report that needs to be sent at regular intervals for sensor
nuclear@1 315 // to receive commands.
nuclear@1 316 struct SensorKeepAliveImpl
nuclear@1 317 {
nuclear@1 318 enum { PacketSize = 5 };
nuclear@1 319 UByte Buffer[PacketSize];
nuclear@1 320
nuclear@1 321 UInt16 CommandId;
nuclear@1 322 UInt16 KeepAliveIntervalMs;
nuclear@1 323
nuclear@1 324 SensorKeepAliveImpl(UInt16 interval = 0, UInt16 commandId = 0)
nuclear@1 325 : CommandId(commandId), KeepAliveIntervalMs(interval)
nuclear@1 326 {
nuclear@1 327 Pack();
nuclear@1 328 }
nuclear@1 329
nuclear@1 330 void Pack()
nuclear@1 331 {
nuclear@1 332 Buffer[0] = 8;
nuclear@1 333 Buffer[1] = UByte(CommandId & 0xFF);
nuclear@1 334 Buffer[2] = UByte(CommandId >> 8);
nuclear@1 335 Buffer[3] = UByte(KeepAliveIntervalMs & 0xFF);
nuclear@1 336 Buffer[4] = UByte(KeepAliveIntervalMs >> 8);
nuclear@1 337 }
nuclear@1 338
nuclear@1 339 void Unpack()
nuclear@1 340 {
nuclear@1 341 CommandId = Buffer[1] | (UInt16(Buffer[2]) << 8);
nuclear@1 342 KeepAliveIntervalMs= Buffer[3] | (UInt16(Buffer[4]) << 8);
nuclear@1 343 }
nuclear@1 344 };
nuclear@1 345
nuclear@1 346
nuclear@1 347 //-------------------------------------------------------------------------------------
nuclear@1 348 // ***** SensorDisplayInfoImpl
nuclear@1 349 SensorDisplayInfoImpl::SensorDisplayInfoImpl()
nuclear@1 350 : CommandId(0), DistortionType(Base_None)
nuclear@1 351 {
nuclear@1 352 memset(Buffer, 0, PacketSize);
nuclear@1 353 Buffer[0] = 9;
nuclear@1 354 }
nuclear@1 355
nuclear@1 356 void SensorDisplayInfoImpl::Unpack()
nuclear@1 357 {
nuclear@1 358 CommandId = Buffer[1] | (UInt16(Buffer[2]) << 8);
nuclear@1 359 DistortionType = Buffer[3];
nuclear@1 360 HResolution = DecodeUInt16(Buffer+4);
nuclear@1 361 VResolution = DecodeUInt16(Buffer+6);
nuclear@1 362 HScreenSize = DecodeUInt32(Buffer+8) * (1/1000000.f);
nuclear@1 363 VScreenSize = DecodeUInt32(Buffer+12) * (1/1000000.f);
nuclear@1 364 VCenter = DecodeUInt32(Buffer+16) * (1/1000000.f);
nuclear@1 365 LensSeparation = DecodeUInt32(Buffer+20) * (1/1000000.f);
nuclear@1 366 EyeToScreenDistance[0] = DecodeUInt32(Buffer+24) * (1/1000000.f);
nuclear@1 367 EyeToScreenDistance[1] = DecodeUInt32(Buffer+28) * (1/1000000.f);
nuclear@1 368 DistortionK[0] = DecodeFloat(Buffer+32);
nuclear@1 369 DistortionK[1] = DecodeFloat(Buffer+36);
nuclear@1 370 DistortionK[2] = DecodeFloat(Buffer+40);
nuclear@1 371 DistortionK[3] = DecodeFloat(Buffer+44);
nuclear@1 372 DistortionK[4] = DecodeFloat(Buffer+48);
nuclear@1 373 DistortionK[5] = DecodeFloat(Buffer+52);
nuclear@1 374 }
nuclear@1 375
nuclear@1 376
nuclear@1 377 //-------------------------------------------------------------------------------------
nuclear@1 378 // ***** SensorDeviceFactory
nuclear@1 379
nuclear@1 380 SensorDeviceFactory SensorDeviceFactory::Instance;
nuclear@1 381
nuclear@1 382 void SensorDeviceFactory::EnumerateDevices(EnumerateVisitor& visitor)
nuclear@1 383 {
nuclear@1 384
nuclear@1 385 class SensorEnumerator : public HIDEnumerateVisitor
nuclear@1 386 {
nuclear@1 387 // Assign not supported; suppress MSVC warning.
nuclear@1 388 void operator = (const SensorEnumerator&) { }
nuclear@1 389
nuclear@1 390 DeviceFactory* pFactory;
nuclear@1 391 EnumerateVisitor& ExternalVisitor;
nuclear@1 392 public:
nuclear@1 393 SensorEnumerator(DeviceFactory* factory, EnumerateVisitor& externalVisitor)
nuclear@1 394 : pFactory(factory), ExternalVisitor(externalVisitor) { }
nuclear@1 395
nuclear@1 396 virtual bool MatchVendorProduct(UInt16 vendorId, UInt16 productId)
nuclear@1 397 {
nuclear@1 398 return pFactory->MatchVendorProduct(vendorId, productId);
nuclear@1 399 }
nuclear@1 400
nuclear@1 401 virtual void Visit(HIDDevice& device, const HIDDeviceDesc& desc)
nuclear@1 402 {
nuclear@1 403 SensorDeviceCreateDesc createDesc(pFactory, desc);
nuclear@1 404 ExternalVisitor.Visit(createDesc);
nuclear@1 405
nuclear@1 406 // Check if the sensor returns DisplayInfo. If so, try to use it to override potentially
nuclear@1 407 // mismatching monitor information (in case wrong EDID is reported by splitter),
nuclear@1 408 // or to create a new "virtualized" HMD Device.
nuclear@1 409
nuclear@1 410 SensorDisplayInfoImpl displayInfo;
nuclear@1 411
nuclear@1 412 if (device.GetFeatureReport(displayInfo.Buffer, SensorDisplayInfoImpl::PacketSize))
nuclear@1 413 {
nuclear@1 414 displayInfo.Unpack();
nuclear@1 415
nuclear@1 416 // If we got display info, try to match / create HMDDevice as well
nuclear@1 417 // so that sensor settings give preference.
nuclear@1 418 if (displayInfo.DistortionType & SensorDisplayInfoImpl::Mask_BaseFmt)
nuclear@1 419 {
nuclear@1 420 SensorDeviceImpl::EnumerateHMDFromSensorDisplayInfo(displayInfo, ExternalVisitor);
nuclear@1 421 }
nuclear@1 422 }
nuclear@1 423 }
nuclear@1 424 };
nuclear@1 425
nuclear@1 426 //double start = Timer::GetProfileSeconds();
nuclear@1 427
nuclear@1 428 SensorEnumerator sensorEnumerator(this, visitor);
nuclear@1 429 GetManagerImpl()->GetHIDDeviceManager()->Enumerate(&sensorEnumerator);
nuclear@1 430
nuclear@1 431 //double totalSeconds = Timer::GetProfileSeconds() - start;
nuclear@1 432 }
nuclear@1 433
nuclear@1 434 bool SensorDeviceFactory::MatchVendorProduct(UInt16 vendorId, UInt16 productId) const
nuclear@1 435 {
nuclear@1 436 return ((vendorId == Sensor_VendorId) && (productId == Sensor_ProductId)) ||
nuclear@1 437 ((vendorId == Sensor_OldVendorId) && (productId == Sensor_OldProductId));
nuclear@1 438 }
nuclear@1 439
nuclear@1 440 bool SensorDeviceFactory::DetectHIDDevice(DeviceManager* pdevMgr, const HIDDeviceDesc& desc)
nuclear@1 441 {
nuclear@1 442 if (MatchVendorProduct(desc.VendorId, desc.ProductId))
nuclear@1 443 {
nuclear@1 444 SensorDeviceCreateDesc createDesc(this, desc);
nuclear@1 445 return pdevMgr->AddDevice_NeedsLock(createDesc).GetPtr() != NULL;
nuclear@1 446 }
nuclear@1 447 return false;
nuclear@1 448 }
nuclear@1 449
nuclear@1 450 //-------------------------------------------------------------------------------------
nuclear@1 451 // ***** SensorDeviceCreateDesc
nuclear@1 452
nuclear@1 453 DeviceBase* SensorDeviceCreateDesc::NewDeviceInstance()
nuclear@1 454 {
nuclear@1 455 return new SensorDeviceImpl(this);
nuclear@1 456 }
nuclear@1 457
nuclear@1 458 bool SensorDeviceCreateDesc::GetDeviceInfo(DeviceInfo* info) const
nuclear@1 459 {
nuclear@1 460 if ((info->InfoClassType != Device_Sensor) &&
nuclear@1 461 (info->InfoClassType != Device_None))
nuclear@1 462 return false;
nuclear@1 463
nuclear@1 464 OVR_strcpy(info->ProductName, DeviceInfo::MaxNameLength, HIDDesc.Product.ToCStr());
nuclear@1 465 OVR_strcpy(info->Manufacturer, DeviceInfo::MaxNameLength, HIDDesc.Manufacturer.ToCStr());
nuclear@1 466 info->Type = Device_Sensor;
nuclear@1 467 info->Version = 0;
nuclear@1 468
nuclear@1 469 if (info->InfoClassType == Device_Sensor)
nuclear@1 470 {
nuclear@1 471 SensorInfo* sinfo = (SensorInfo*)info;
nuclear@1 472 sinfo->VendorId = HIDDesc.VendorId;
nuclear@1 473 sinfo->ProductId = HIDDesc.ProductId;
nuclear@1 474 sinfo->MaxRanges = SensorRangeImpl::GetMaxSensorRange();
nuclear@1 475 OVR_strcpy(sinfo->SerialNumber, sizeof(sinfo->SerialNumber),HIDDesc.SerialNumber.ToCStr());
nuclear@1 476 }
nuclear@1 477 return true;
nuclear@1 478 }
nuclear@1 479
nuclear@1 480
nuclear@1 481 //-------------------------------------------------------------------------------------
nuclear@1 482 // ***** SensorDevice
nuclear@1 483
nuclear@1 484 SensorDeviceImpl::SensorDeviceImpl(SensorDeviceCreateDesc* createDesc)
nuclear@1 485 : OVR::HIDDeviceImpl<OVR::SensorDevice>(createDesc, 0),
nuclear@1 486 Coordinates(SensorDevice::Coord_Sensor),
nuclear@1 487 HWCoordinates(SensorDevice::Coord_HMD), // HW reports HMD coordinates by default.
nuclear@1 488 NextKeepAliveTicks(0),
nuclear@1 489 MaxValidRange(SensorRangeImpl::GetMaxSensorRange())
nuclear@1 490 {
nuclear@1 491 SequenceValid = false;
nuclear@1 492 LastSampleCount= 0;
nuclear@1 493 LastTimestamp = 0;
nuclear@1 494
nuclear@1 495 OldCommandId = 0;
nuclear@1 496 }
nuclear@1 497
nuclear@1 498 SensorDeviceImpl::~SensorDeviceImpl()
nuclear@1 499 {
nuclear@1 500 // Check that Shutdown() was called.
nuclear@1 501 OVR_ASSERT(!pCreateDesc->pDevice);
nuclear@1 502 }
nuclear@1 503
nuclear@1 504 // Internal creation APIs.
nuclear@1 505 bool SensorDeviceImpl::Initialize(DeviceBase* parent)
nuclear@1 506 {
nuclear@1 507 if (HIDDeviceImpl<OVR::SensorDevice>::Initialize(parent))
nuclear@1 508 {
nuclear@1 509 openDevice();
nuclear@1 510
nuclear@1 511 LogText("OVR::SensorDevice initialized.\n");
nuclear@1 512
nuclear@1 513 return true;
nuclear@1 514 }
nuclear@1 515
nuclear@1 516 return false;
nuclear@1 517 }
nuclear@1 518
nuclear@1 519 void SensorDeviceImpl::openDevice()
nuclear@1 520 {
nuclear@1 521
nuclear@1 522 // Read the currently configured range from sensor.
nuclear@1 523 SensorRangeImpl sr(SensorRange(), 0);
nuclear@1 524
nuclear@1 525 if (GetInternalDevice()->GetFeatureReport(sr.Buffer, SensorRangeImpl::PacketSize))
nuclear@1 526 {
nuclear@1 527 sr.Unpack();
nuclear@1 528 sr.GetSensorRange(&CurrentRange);
nuclear@1 529 }
nuclear@1 530
nuclear@1 531
nuclear@1 532 // If the sensor has "DisplayInfo" data, use HMD coordinate frame by default.
nuclear@1 533 SensorDisplayInfoImpl displayInfo;
nuclear@1 534 if (GetInternalDevice()->GetFeatureReport(displayInfo.Buffer, SensorDisplayInfoImpl::PacketSize))
nuclear@1 535 {
nuclear@1 536 displayInfo.Unpack();
nuclear@1 537 Coordinates = (displayInfo.DistortionType & SensorDisplayInfoImpl::Mask_BaseFmt) ?
nuclear@1 538 Coord_HMD : Coord_Sensor;
nuclear@1 539 }
nuclear@1 540
nuclear@1 541 // Read/Apply sensor config.
nuclear@1 542 setCoordinateFrame(Coordinates);
nuclear@1 543 setReportRate(Sensor_DefaultReportRate);
nuclear@1 544
nuclear@1 545 // Set Keep-alive at 10 seconds.
nuclear@1 546 SensorKeepAliveImpl skeepAlive(10 * 1000);
nuclear@1 547 GetInternalDevice()->SetFeatureReport(skeepAlive.Buffer, SensorKeepAliveImpl::PacketSize);
nuclear@1 548 }
nuclear@1 549
nuclear@1 550 void SensorDeviceImpl::closeDeviceOnError()
nuclear@1 551 {
nuclear@1 552 LogText("OVR::SensorDevice - Lost connection to '%s'\n", getHIDDesc()->Path.ToCStr());
nuclear@1 553 NextKeepAliveTicks = 0;
nuclear@1 554 }
nuclear@1 555
nuclear@1 556 void SensorDeviceImpl::Shutdown()
nuclear@1 557 {
nuclear@1 558 HIDDeviceImpl<OVR::SensorDevice>::Shutdown();
nuclear@1 559
nuclear@1 560 LogText("OVR::SensorDevice - Closed '%s'\n", getHIDDesc()->Path.ToCStr());
nuclear@1 561 }
nuclear@1 562
nuclear@1 563
nuclear@1 564 void SensorDeviceImpl::OnInputReport(UByte* pData, UInt32 length)
nuclear@1 565 {
nuclear@1 566
nuclear@1 567 bool processed = false;
nuclear@1 568 if (!processed)
nuclear@1 569 {
nuclear@1 570
nuclear@1 571 TrackerMessage message;
nuclear@1 572 if (DecodeTrackerMessage(&message, pData, length))
nuclear@1 573 {
nuclear@1 574 processed = true;
nuclear@1 575 onTrackerMessage(&message);
nuclear@1 576 }
nuclear@1 577 }
nuclear@1 578 }
nuclear@1 579
nuclear@1 580 UInt64 SensorDeviceImpl::OnTicks(UInt64 ticksMks)
nuclear@1 581 {
nuclear@1 582
nuclear@1 583 if (ticksMks >= NextKeepAliveTicks)
nuclear@1 584 {
nuclear@1 585 // Use 3-seconds keep alive by default.
nuclear@1 586 UInt64 keepAliveDelta = Timer::MksPerSecond * 3;
nuclear@1 587
nuclear@1 588 // Set Keep-alive at 10 seconds.
nuclear@1 589 SensorKeepAliveImpl skeepAlive(10 * 1000);
nuclear@1 590 // OnTicks is called from background thread so we don't need to add this to the command queue.
nuclear@1 591 GetInternalDevice()->SetFeatureReport(skeepAlive.Buffer, SensorKeepAliveImpl::PacketSize);
nuclear@1 592
nuclear@1 593 // Emit keep-alive every few seconds.
nuclear@1 594 NextKeepAliveTicks = ticksMks + keepAliveDelta;
nuclear@1 595 }
nuclear@1 596 return NextKeepAliveTicks - ticksMks;
nuclear@1 597 }
nuclear@1 598
nuclear@1 599 bool SensorDeviceImpl::SetRange(const SensorRange& range, bool waitFlag)
nuclear@1 600 {
nuclear@1 601 bool result = 0;
nuclear@1 602 ThreadCommandQueue * threadQueue = GetManagerImpl()->GetThreadQueue();
nuclear@1 603
nuclear@1 604 if (!waitFlag)
nuclear@1 605 {
nuclear@1 606 return threadQueue->PushCall(this, &SensorDeviceImpl::setRange, range);
nuclear@1 607 }
nuclear@1 608
nuclear@1 609 if (!threadQueue->PushCallAndWaitResult(this,
nuclear@1 610 &SensorDeviceImpl::setRange,
nuclear@1 611 &result,
nuclear@1 612 range))
nuclear@1 613 {
nuclear@1 614 return false;
nuclear@1 615 }
nuclear@1 616
nuclear@1 617 return result;
nuclear@1 618 }
nuclear@1 619
nuclear@1 620 void SensorDeviceImpl::GetRange(SensorRange* range) const
nuclear@1 621 {
nuclear@1 622 Lock::Locker lockScope(GetLock());
nuclear@1 623 *range = CurrentRange;
nuclear@1 624 }
nuclear@1 625
nuclear@1 626 bool SensorDeviceImpl::setRange(const SensorRange& range)
nuclear@1 627 {
nuclear@1 628 SensorRangeImpl sr(range);
nuclear@1 629
nuclear@1 630 if (GetInternalDevice()->SetFeatureReport(sr.Buffer, SensorRangeImpl::PacketSize))
nuclear@1 631 {
nuclear@1 632 Lock::Locker lockScope(GetLock());
nuclear@1 633 sr.GetSensorRange(&CurrentRange);
nuclear@1 634 return true;
nuclear@1 635 }
nuclear@1 636
nuclear@1 637 return false;
nuclear@1 638 }
nuclear@1 639
nuclear@1 640 void SensorDeviceImpl::SetCoordinateFrame(CoordinateFrame coordframe)
nuclear@1 641 {
nuclear@1 642 // Push call with wait.
nuclear@1 643 GetManagerImpl()->GetThreadQueue()->
nuclear@1 644 PushCall(this, &SensorDeviceImpl::setCoordinateFrame, coordframe, true);
nuclear@1 645 }
nuclear@1 646
nuclear@1 647 SensorDevice::CoordinateFrame SensorDeviceImpl::GetCoordinateFrame() const
nuclear@1 648 {
nuclear@1 649 return Coordinates;
nuclear@1 650 }
nuclear@1 651
nuclear@1 652 Void SensorDeviceImpl::setCoordinateFrame(CoordinateFrame coordframe)
nuclear@1 653 {
nuclear@1 654
nuclear@1 655 Coordinates = coordframe;
nuclear@1 656
nuclear@1 657 // Read the original coordinate frame, then try to change it.
nuclear@1 658 SensorConfigImpl scfg;
nuclear@1 659 if (GetInternalDevice()->GetFeatureReport(scfg.Buffer, SensorConfigImpl::PacketSize))
nuclear@1 660 {
nuclear@1 661 scfg.Unpack();
nuclear@1 662 }
nuclear@1 663
nuclear@1 664 scfg.SetSensorCoordinates(coordframe == Coord_Sensor);
nuclear@1 665 scfg.Pack();
nuclear@1 666
nuclear@1 667 GetInternalDevice()->SetFeatureReport(scfg.Buffer, SensorConfigImpl::PacketSize);
nuclear@1 668
nuclear@1 669 // Re-read the state, in case of older firmware that doesn't support Sensor coordinates.
nuclear@1 670 if (GetInternalDevice()->GetFeatureReport(scfg.Buffer, SensorConfigImpl::PacketSize))
nuclear@1 671 {
nuclear@1 672 scfg.Unpack();
nuclear@1 673 HWCoordinates = scfg.IsUsingSensorCoordinates() ? Coord_Sensor : Coord_HMD;
nuclear@1 674 }
nuclear@1 675 else
nuclear@1 676 {
nuclear@1 677 HWCoordinates = Coord_HMD;
nuclear@1 678 }
nuclear@1 679 return 0;
nuclear@1 680 }
nuclear@1 681
nuclear@1 682 void SensorDeviceImpl::SetReportRate(unsigned rateHz)
nuclear@1 683 {
nuclear@1 684 // Push call with wait.
nuclear@1 685 GetManagerImpl()->GetThreadQueue()->
nuclear@1 686 PushCall(this, &SensorDeviceImpl::setReportRate, rateHz, true);
nuclear@1 687 }
nuclear@1 688
nuclear@1 689 unsigned SensorDeviceImpl::GetReportRate() const
nuclear@1 690 {
nuclear@1 691 // Read the original configuration
nuclear@1 692 SensorConfigImpl scfg;
nuclear@1 693 if (GetInternalDevice()->GetFeatureReport(scfg.Buffer, SensorConfigImpl::PacketSize))
nuclear@1 694 {
nuclear@1 695 scfg.Unpack();
nuclear@1 696 return Sensor_MaxReportRate / (scfg.PacketInterval + 1);
nuclear@1 697 }
nuclear@1 698 return 0; // error
nuclear@1 699 }
nuclear@1 700
nuclear@1 701 Void SensorDeviceImpl::setReportRate(unsigned rateHz)
nuclear@1 702 {
nuclear@1 703 // Read the original configuration
nuclear@1 704 SensorConfigImpl scfg;
nuclear@1 705 if (GetInternalDevice()->GetFeatureReport(scfg.Buffer, SensorConfigImpl::PacketSize))
nuclear@1 706 {
nuclear@1 707 scfg.Unpack();
nuclear@1 708 }
nuclear@1 709
nuclear@1 710 if (rateHz > Sensor_MaxReportRate)
nuclear@1 711 rateHz = Sensor_MaxReportRate;
nuclear@1 712 else if (rateHz == 0)
nuclear@1 713 rateHz = Sensor_DefaultReportRate;
nuclear@1 714
nuclear@1 715 scfg.PacketInterval = UInt16((Sensor_MaxReportRate / rateHz) - 1);
nuclear@1 716
nuclear@1 717 scfg.Pack();
nuclear@1 718
nuclear@1 719 GetInternalDevice()->SetFeatureReport(scfg.Buffer, SensorConfigImpl::PacketSize);
nuclear@1 720 return 0;
nuclear@1 721 }
nuclear@1 722
nuclear@1 723 void SensorDeviceImpl::SetMessageHandler(MessageHandler* handler)
nuclear@1 724 {
nuclear@1 725 if (handler)
nuclear@1 726 {
nuclear@1 727 SequenceValid = false;
nuclear@1 728 DeviceBase::SetMessageHandler(handler);
nuclear@1 729 }
nuclear@1 730 else
nuclear@1 731 {
nuclear@1 732 DeviceBase::SetMessageHandler(handler);
nuclear@1 733 }
nuclear@1 734 }
nuclear@1 735
nuclear@1 736 // Sensor reports data in the following coordinate system:
nuclear@1 737 // Accelerometer: 10^-4 m/s^2; X forward, Y right, Z Down.
nuclear@1 738 // Gyro: 10^-4 rad/s; X positive roll right, Y positive pitch up; Z positive yaw right.
nuclear@1 739
nuclear@1 740
nuclear@1 741 // We need to convert it to the following RHS coordinate system:
nuclear@1 742 // X right, Y Up, Z Back (out of screen)
nuclear@1 743 //
nuclear@1 744 Vector3f AccelFromBodyFrameUpdate(const TrackerSensors& update, UByte sampleNumber,
nuclear@1 745 bool convertHMDToSensor = false)
nuclear@1 746 {
nuclear@1 747 const TrackerSample& sample = update.Samples[sampleNumber];
nuclear@1 748 float ax = (float)sample.AccelX;
nuclear@1 749 float ay = (float)sample.AccelY;
nuclear@1 750 float az = (float)sample.AccelZ;
nuclear@1 751
nuclear@1 752 Vector3f val = convertHMDToSensor ? Vector3f(ax, az, -ay) : Vector3f(ax, ay, az);
nuclear@1 753 return val * 0.0001f;
nuclear@1 754 }
nuclear@1 755
nuclear@1 756
nuclear@1 757 Vector3f MagFromBodyFrameUpdate(const TrackerSensors& update,
nuclear@1 758 bool convertHMDToSensor = false)
nuclear@1 759 {
nuclear@1 760 // Note: Y and Z are swapped in comparison to the Accel.
nuclear@1 761 // This accounts for DK1 sensor firmware axis swap, which should be undone in future releases.
nuclear@1 762 if (!convertHMDToSensor)
nuclear@1 763 {
nuclear@1 764 return Vector3f( (float)update.MagX,
nuclear@1 765 (float)update.MagZ,
nuclear@1 766 (float)update.MagY) * 0.0001f;
nuclear@1 767 }
nuclear@1 768
nuclear@1 769 return Vector3f( (float)update.MagX,
nuclear@1 770 (float)update.MagY,
nuclear@1 771 -(float)update.MagZ) * 0.0001f;
nuclear@1 772 }
nuclear@1 773
nuclear@1 774 Vector3f EulerFromBodyFrameUpdate(const TrackerSensors& update, UByte sampleNumber,
nuclear@1 775 bool convertHMDToSensor = false)
nuclear@1 776 {
nuclear@1 777 const TrackerSample& sample = update.Samples[sampleNumber];
nuclear@1 778 float gx = (float)sample.GyroX;
nuclear@1 779 float gy = (float)sample.GyroY;
nuclear@1 780 float gz = (float)sample.GyroZ;
nuclear@1 781
nuclear@1 782 Vector3f val = convertHMDToSensor ? Vector3f(gx, gz, -gy) : Vector3f(gx, gy, gz);
nuclear@1 783 return val * 0.0001f;
nuclear@1 784 }
nuclear@1 785
nuclear@1 786
nuclear@1 787 void SensorDeviceImpl::onTrackerMessage(TrackerMessage* message)
nuclear@1 788 {
nuclear@1 789 if (message->Type != TrackerMessage_Sensors)
nuclear@1 790 return;
nuclear@1 791
nuclear@1 792 const float timeUnit = (1.0f / 1000.f);
nuclear@1 793 TrackerSensors& s = message->Sensors;
nuclear@1 794
nuclear@1 795
nuclear@1 796 // Call OnMessage() within a lock to avoid conflicts with handlers.
nuclear@1 797 Lock::Locker scopeLock(HandlerRef.GetLock());
nuclear@1 798
nuclear@1 799
nuclear@1 800 if (SequenceValid)
nuclear@1 801 {
nuclear@1 802 unsigned timestampDelta;
nuclear@1 803
nuclear@1 804 if (s.Timestamp < LastTimestamp)
nuclear@1 805 timestampDelta = ((((int)s.Timestamp) + 0x10000) - (int)LastTimestamp);
nuclear@1 806 else
nuclear@1 807 timestampDelta = (s.Timestamp - LastTimestamp);
nuclear@1 808
nuclear@1 809 // If we missed a small number of samples, replicate the last sample.
nuclear@1 810 if ((timestampDelta > LastSampleCount) && (timestampDelta <= 254))
nuclear@1 811 {
nuclear@1 812 if (HandlerRef.GetHandler())
nuclear@1 813 {
nuclear@1 814 MessageBodyFrame sensors(this);
nuclear@1 815 sensors.TimeDelta = (timestampDelta - LastSampleCount) * timeUnit;
nuclear@1 816 sensors.Acceleration = LastAcceleration;
nuclear@1 817 sensors.RotationRate = LastRotationRate;
nuclear@1 818 sensors.MagneticField = LastMagneticField;
nuclear@1 819 sensors.Temperature = LastTemperature;
nuclear@1 820
nuclear@1 821 HandlerRef.GetHandler()->OnMessage(sensors);
nuclear@1 822 }
nuclear@1 823 }
nuclear@1 824 }
nuclear@1 825 else
nuclear@1 826 {
nuclear@1 827 LastAcceleration = Vector3f(0);
nuclear@1 828 LastRotationRate = Vector3f(0);
nuclear@1 829 LastMagneticField= Vector3f(0);
nuclear@1 830 LastTemperature = 0;
nuclear@1 831 SequenceValid = true;
nuclear@1 832 }
nuclear@1 833
nuclear@1 834 LastSampleCount = s.SampleCount;
nuclear@1 835 LastTimestamp = s.Timestamp;
nuclear@1 836
nuclear@1 837 bool convertHMDToSensor = (Coordinates == Coord_Sensor) && (HWCoordinates == Coord_HMD);
nuclear@1 838
nuclear@1 839 if (HandlerRef.GetHandler())
nuclear@1 840 {
nuclear@1 841 MessageBodyFrame sensors(this);
nuclear@1 842 UByte iterations = s.SampleCount;
nuclear@1 843
nuclear@1 844 if (s.SampleCount > 3)
nuclear@1 845 {
nuclear@1 846 iterations = 3;
nuclear@1 847 sensors.TimeDelta = (s.SampleCount - 2) * timeUnit;
nuclear@1 848 }
nuclear@1 849 else
nuclear@1 850 {
nuclear@1 851 sensors.TimeDelta = timeUnit;
nuclear@1 852 }
nuclear@1 853
nuclear@1 854 for (UByte i = 0; i < iterations; i++)
nuclear@1 855 {
nuclear@1 856 sensors.Acceleration = AccelFromBodyFrameUpdate(s, i, convertHMDToSensor);
nuclear@1 857 sensors.RotationRate = EulerFromBodyFrameUpdate(s, i, convertHMDToSensor);
nuclear@1 858 sensors.MagneticField= MagFromBodyFrameUpdate(s, convertHMDToSensor);
nuclear@1 859 sensors.Temperature = s.Temperature * 0.01f;
nuclear@1 860 HandlerRef.GetHandler()->OnMessage(sensors);
nuclear@1 861 // TimeDelta for the last two sample is always fixed.
nuclear@1 862 sensors.TimeDelta = timeUnit;
nuclear@1 863 }
nuclear@1 864
nuclear@1 865 LastAcceleration = sensors.Acceleration;
nuclear@1 866 LastRotationRate = sensors.RotationRate;
nuclear@1 867 LastMagneticField= sensors.MagneticField;
nuclear@1 868 LastTemperature = sensors.Temperature;
nuclear@1 869 }
nuclear@1 870 else
nuclear@1 871 {
nuclear@1 872 UByte i = (s.SampleCount > 3) ? 2 : (s.SampleCount - 1);
nuclear@1 873 LastAcceleration = AccelFromBodyFrameUpdate(s, i, convertHMDToSensor);
nuclear@1 874 LastRotationRate = EulerFromBodyFrameUpdate(s, i, convertHMDToSensor);
nuclear@1 875 LastMagneticField = MagFromBodyFrameUpdate(s, convertHMDToSensor);
nuclear@1 876 LastTemperature = s.Temperature * 0.01f;
nuclear@1 877 }
nuclear@1 878 }
nuclear@1 879
nuclear@1 880 } // namespace OVR
nuclear@1 881
nuclear@1 882