aboutsummaryrefslogtreecommitdiffstats
path: root/LibOVR/Src/OVR_SensorImpl.cpp
diff options
context:
space:
mode:
authorBrad Davis <[email protected]>2013-07-03 09:16:03 -0700
committerBrad Davis <[email protected]>2013-07-03 09:16:03 -0700
commitd46694c91c2bec4eb1e282c0c0101e6dab26e082 (patch)
treeeb5fba71edf1aedc0d6af9406881004289433b20 /LibOVR/Src/OVR_SensorImpl.cpp
parent7fa8be4bc565adc9911c95c814480cc48bf2d13c (diff)
SDK 0.2.3
Diffstat (limited to 'LibOVR/Src/OVR_SensorImpl.cpp')
-rw-r--r--LibOVR/Src/OVR_SensorImpl.cpp1764
1 files changed, 882 insertions, 882 deletions
diff --git a/LibOVR/Src/OVR_SensorImpl.cpp b/LibOVR/Src/OVR_SensorImpl.cpp
index fb322df..ced6541 100644
--- a/LibOVR/Src/OVR_SensorImpl.cpp
+++ b/LibOVR/Src/OVR_SensorImpl.cpp
@@ -1,882 +1,882 @@
-/************************************************************************************
-
-Filename : OVR_SensorImpl.cpp
-Content : Oculus Sensor device implementation.
-Created : March 7, 2013
-Authors : Lee Cooper
-
-Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-*************************************************************************************/
-
-#include "OVR_SensorImpl.h"
-
-// HMDDeviceDesc can be created/updated through Sensor carrying DisplayInfo.
-
-#include "Kernel/OVR_Timer.h"
-
-namespace OVR {
-
-//-------------------------------------------------------------------------------------
-// ***** Oculus Sensor-specific packet data structures
-
-enum {
- Sensor_VendorId = Oculus_VendorId,
- Sensor_ProductId = 0x0001,
-
- // ST's VID used originally; should be removed in the future
- Sensor_OldVendorId = 0x0483,
- Sensor_OldProductId = 0x5750,
-
- Sensor_DefaultReportRate = 500, // Hz
- Sensor_MaxReportRate = 1000 // Hz
-};
-
-// Reported data is little-endian now
-static UInt16 DecodeUInt16(const UByte* buffer)
-{
- return (UInt16(buffer[1]) << 8) | UInt16(buffer[0]);
-}
-
-static SInt16 DecodeSInt16(const UByte* buffer)
-{
- return (SInt16(buffer[1]) << 8) | SInt16(buffer[0]);
-}
-
-static UInt32 DecodeUInt32(const UByte* buffer)
-{
- return (buffer[0]) | UInt32(buffer[1] << 8) | UInt32(buffer[2] << 16) | UInt32(buffer[3] << 24);
-}
-
-static float DecodeFloat(const UByte* buffer)
-{
- union {
- UInt32 U;
- float F;
- };
-
- U = DecodeUInt32(buffer);
- return F;
-}
-
-
-static void UnpackSensor(const UByte* buffer, SInt32* x, SInt32* y, SInt32* z)
-{
- // Sign extending trick
- // from http://graphics.stanford.edu/~seander/bithacks.html#FixedSignExtend
- struct {SInt32 x:21;} s;
-
- *x = s.x = (buffer[0] << 13) | (buffer[1] << 5) | ((buffer[2] & 0xF8) >> 3);
- *y = s.x = ((buffer[2] & 0x07) << 18) | (buffer[3] << 10) | (buffer[4] << 2) |
- ((buffer[5] & 0xC0) >> 6);
- *z = s.x = ((buffer[5] & 0x3F) << 15) | (buffer[6] << 7) | (buffer[7] >> 1);
-}
-
-// Messages we care for
-enum TrackerMessageType
-{
- TrackerMessage_None = 0,
- TrackerMessage_Sensors = 1,
- TrackerMessage_Unknown = 0x100,
- TrackerMessage_SizeError = 0x101,
-};
-
-struct TrackerSample
-{
- SInt32 AccelX, AccelY, AccelZ;
- SInt32 GyroX, GyroY, GyroZ;
-};
-
-
-struct TrackerSensors
-{
- UByte SampleCount;
- UInt16 Timestamp;
- UInt16 LastCommandID;
- SInt16 Temperature;
-
- TrackerSample Samples[3];
-
- SInt16 MagX, MagY, MagZ;
-
- TrackerMessageType Decode(const UByte* buffer, int size)
- {
- if (size < 62)
- return TrackerMessage_SizeError;
-
- SampleCount = buffer[1];
- Timestamp = DecodeUInt16(buffer + 2);
- LastCommandID = DecodeUInt16(buffer + 4);
- Temperature = DecodeSInt16(buffer + 6);
-
- //if (SampleCount > 2)
- // OVR_DEBUG_LOG_TEXT(("TackerSensor::Decode SampleCount=%d\n", SampleCount));
-
- // Only unpack as many samples as there actually are
- UByte iterationCount = (SampleCount > 2) ? 3 : SampleCount;
-
- for (UByte i = 0; i < iterationCount; i++)
- {
- UnpackSensor(buffer + 8 + 16 * i, &Samples[i].AccelX, &Samples[i].AccelY, &Samples[i].AccelZ);
- UnpackSensor(buffer + 16 + 16 * i, &Samples[i].GyroX, &Samples[i].GyroY, &Samples[i].GyroZ);
- }
-
- MagX = DecodeSInt16(buffer + 56);
- MagY = DecodeSInt16(buffer + 58);
- MagZ = DecodeSInt16(buffer + 60);
-
- return TrackerMessage_Sensors;
- }
-};
-
-struct TrackerMessage
-{
- TrackerMessageType Type;
- TrackerSensors Sensors;
-};
-
-bool DecodeTrackerMessage(TrackerMessage* message, UByte* buffer, int size)
-{
- memset(message, 0, sizeof(TrackerMessage));
-
- if (size < 4)
- {
- message->Type = TrackerMessage_SizeError;
- return false;
- }
-
- switch (buffer[0])
- {
- case TrackerMessage_Sensors:
- message->Type = message->Sensors.Decode(buffer, size);
- break;
-
- default:
- message->Type = TrackerMessage_Unknown;
- break;
- }
-
- return (message->Type < TrackerMessage_Unknown) && (message->Type != TrackerMessage_None);
-}
-
-
-// ***** SensorRangeImpl Implementation
-
-// Sensor HW only accepts specific maximum range values, used to maximize
-// the 16-bit sensor outputs. Use these ramps to specify and report appropriate values.
-static const UInt16 AccelRangeRamp[] = { 2, 4, 8, 16 };
-static const UInt16 GyroRangeRamp[] = { 250, 500, 1000, 2000 };
-static const UInt16 MagRangeRamp[] = { 880, 1300, 1900, 2500 };
-
-static UInt16 SelectSensorRampValue(const UInt16* ramp, unsigned count,
- float val, float factor, const char* label)
-{
- UInt16 threshold = (UInt16)(val * factor);
-
- for (unsigned i = 0; i<count; i++)
- {
- if (ramp[i] >= threshold)
- return ramp[i];
- }
- OVR_DEBUG_LOG(("SensorDevice::SetRange - %s clamped to %0.4f",
- label, float(ramp[count-1]) / factor));
- OVR_UNUSED2(factor, label);
- return ramp[count-1];
-}
-
-// SensorScaleImpl provides buffer packing logic for the Sensor Range
-// record that can be applied to DK1 sensor through Get/SetFeature. We expose this
-// through SensorRange class, which has different units.
-struct SensorRangeImpl
-{
- enum { PacketSize = 8 };
- UByte Buffer[PacketSize];
-
- UInt16 CommandId;
- UInt16 AccelScale;
- UInt16 GyroScale;
- UInt16 MagScale;
-
- SensorRangeImpl(const SensorRange& r, UInt16 commandId = 0)
- {
- SetSensorRange(r, commandId);
- }
-
- void SetSensorRange(const SensorRange& r, UInt16 commandId = 0)
- {
- CommandId = commandId;
- AccelScale = SelectSensorRampValue(AccelRangeRamp, sizeof(AccelRangeRamp)/sizeof(AccelRangeRamp[0]),
- r.MaxAcceleration, (1.0f / 9.81f), "MaxAcceleration");
- GyroScale = SelectSensorRampValue(GyroRangeRamp, sizeof(GyroRangeRamp)/sizeof(GyroRangeRamp[0]),
- r.MaxRotationRate, Math<float>::RadToDegreeFactor, "MaxRotationRate");
- MagScale = SelectSensorRampValue(MagRangeRamp, sizeof(MagRangeRamp)/sizeof(MagRangeRamp[0]),
- r.MaxMagneticField, 1000.0f, "MaxMagneticField");
- Pack();
- }
-
- void GetSensorRange(SensorRange* r)
- {
- r->MaxAcceleration = AccelScale * 9.81f;
- r->MaxRotationRate = DegreeToRad((float)GyroScale);
- r->MaxMagneticField= MagScale * 0.001f;
- }
-
- static SensorRange GetMaxSensorRange()
- {
- return SensorRange(AccelRangeRamp[sizeof(AccelRangeRamp)/sizeof(AccelRangeRamp[0]) - 1] * 9.81f,
- GyroRangeRamp[sizeof(GyroRangeRamp)/sizeof(GyroRangeRamp[0]) - 1] *
- Math<float>::DegreeToRadFactor,
- MagRangeRamp[sizeof(MagRangeRamp)/sizeof(MagRangeRamp[0]) - 1] * 0.001f);
- }
-
- void Pack()
- {
- Buffer[0] = 4;
- Buffer[1] = UByte(CommandId & 0xFF);
- Buffer[2] = UByte(CommandId >> 8);
- Buffer[3] = UByte(AccelScale);
- Buffer[4] = UByte(GyroScale & 0xFF);
- Buffer[5] = UByte(GyroScale >> 8);
- Buffer[6] = UByte(MagScale & 0xFF);
- Buffer[7] = UByte(MagScale >> 8);
- }
-
- void Unpack()
- {
- CommandId = Buffer[1] | (UInt16(Buffer[2]) << 8);
- AccelScale= Buffer[3];
- GyroScale = Buffer[4] | (UInt16(Buffer[5]) << 8);
- MagScale = Buffer[6] | (UInt16(Buffer[7]) << 8);
- }
-};
-
-
-// Sensor configuration command, ReportId == 2.
-
-struct SensorConfigImpl
-{
- enum { PacketSize = 7 };
- UByte Buffer[PacketSize];
-
- // Flag values for Flags.
- enum {
- Flag_RawMode = 0x01,
- Flag_CallibrationTest = 0x02, // Internal test mode
- Flag_UseCallibration = 0x04,
- Flag_AutoCallibration = 0x08,
- Flag_MotionKeepAlive = 0x10,
- Flag_CommandKeepAlive = 0x20,
- Flag_SensorCoordinates = 0x40
- };
-
- UInt16 CommandId;
- UByte Flags;
- UInt16 PacketInterval;
- UInt16 KeepAliveIntervalMs;
-
- SensorConfigImpl() : CommandId(0), Flags(0), PacketInterval(0), KeepAliveIntervalMs(0)
- {
- memset(Buffer, 0, PacketSize);
- Buffer[0] = 2;
- }
-
- void SetSensorCoordinates(bool sensorCoordinates)
- { Flags = (Flags & ~Flag_SensorCoordinates) | (sensorCoordinates ? Flag_SensorCoordinates : 0); }
- bool IsUsingSensorCoordinates() const
- { return (Flags & Flag_SensorCoordinates) != 0; }
-
- void Pack()
- {
- Buffer[0] = 2;
- Buffer[1] = UByte(CommandId & 0xFF);
- Buffer[2] = UByte(CommandId >> 8);
- Buffer[3] = Flags;
- Buffer[4] = UByte(PacketInterval);
- Buffer[5] = UByte(KeepAliveIntervalMs & 0xFF);
- Buffer[6] = UByte(KeepAliveIntervalMs >> 8);
- }
-
- void Unpack()
- {
- CommandId = Buffer[1] | (UInt16(Buffer[2]) << 8);
- Flags = Buffer[3];
- PacketInterval = Buffer[4];
- KeepAliveIntervalMs= Buffer[5] | (UInt16(Buffer[6]) << 8);
- }
-
-};
-
-
-// SensorKeepAlive - feature report that needs to be sent at regular intervals for sensor
-// to receive commands.
-struct SensorKeepAliveImpl
-{
- enum { PacketSize = 5 };
- UByte Buffer[PacketSize];
-
- UInt16 CommandId;
- UInt16 KeepAliveIntervalMs;
-
- SensorKeepAliveImpl(UInt16 interval = 0, UInt16 commandId = 0)
- : CommandId(commandId), KeepAliveIntervalMs(interval)
- {
- Pack();
- }
-
- void Pack()
- {
- Buffer[0] = 8;
- Buffer[1] = UByte(CommandId & 0xFF);
- Buffer[2] = UByte(CommandId >> 8);
- Buffer[3] = UByte(KeepAliveIntervalMs & 0xFF);
- Buffer[4] = UByte(KeepAliveIntervalMs >> 8);
- }
-
- void Unpack()
- {
- CommandId = Buffer[1] | (UInt16(Buffer[2]) << 8);
- KeepAliveIntervalMs= Buffer[3] | (UInt16(Buffer[4]) << 8);
- }
-};
-
-
-//-------------------------------------------------------------------------------------
-// ***** SensorDisplayInfoImpl
-SensorDisplayInfoImpl::SensorDisplayInfoImpl()
- : CommandId(0), DistortionType(Base_None)
-{
- memset(Buffer, 0, PacketSize);
- Buffer[0] = 9;
-}
-
-void SensorDisplayInfoImpl::Unpack()
-{
- CommandId = Buffer[1] | (UInt16(Buffer[2]) << 8);
- DistortionType = Buffer[3];
- HResolution = DecodeUInt16(Buffer+4);
- VResolution = DecodeUInt16(Buffer+6);
- HScreenSize = DecodeUInt32(Buffer+8) * (1/1000000.f);
- VScreenSize = DecodeUInt32(Buffer+12) * (1/1000000.f);
- VCenter = DecodeUInt32(Buffer+16) * (1/1000000.f);
- LensSeparation = DecodeUInt32(Buffer+20) * (1/1000000.f);
- EyeToScreenDistance[0] = DecodeUInt32(Buffer+24) * (1/1000000.f);
- EyeToScreenDistance[1] = DecodeUInt32(Buffer+28) * (1/1000000.f);
- DistortionK[0] = DecodeFloat(Buffer+32);
- DistortionK[1] = DecodeFloat(Buffer+36);
- DistortionK[2] = DecodeFloat(Buffer+40);
- DistortionK[3] = DecodeFloat(Buffer+44);
- DistortionK[4] = DecodeFloat(Buffer+48);
- DistortionK[5] = DecodeFloat(Buffer+52);
-}
-
-
-//-------------------------------------------------------------------------------------
-// ***** SensorDeviceFactory
-
-SensorDeviceFactory SensorDeviceFactory::Instance;
-
-void SensorDeviceFactory::EnumerateDevices(EnumerateVisitor& visitor)
-{
-
- class SensorEnumerator : public HIDEnumerateVisitor
- {
- // Assign not supported; suppress MSVC warning.
- void operator = (const SensorEnumerator&) { }
-
- DeviceFactory* pFactory;
- EnumerateVisitor& ExternalVisitor;
- public:
- SensorEnumerator(DeviceFactory* factory, EnumerateVisitor& externalVisitor)
- : pFactory(factory), ExternalVisitor(externalVisitor) { }
-
- virtual bool MatchVendorProduct(UInt16 vendorId, UInt16 productId)
- {
- return pFactory->MatchVendorProduct(vendorId, productId);
- }
-
- virtual void Visit(HIDDevice& device, const HIDDeviceDesc& desc)
- {
- SensorDeviceCreateDesc createDesc(pFactory, desc);
- ExternalVisitor.Visit(createDesc);
-
- // Check if the sensor returns DisplayInfo. If so, try to use it to override potentially
- // mismatching monitor information (in case wrong EDID is reported by splitter),
- // or to create a new "virtualized" HMD Device.
-
- SensorDisplayInfoImpl displayInfo;
-
- if (device.GetFeatureReport(displayInfo.Buffer, SensorDisplayInfoImpl::PacketSize))
- {
- displayInfo.Unpack();
-
- // If we got display info, try to match / create HMDDevice as well
- // so that sensor settings give preference.
- if (displayInfo.DistortionType & SensorDisplayInfoImpl::Mask_BaseFmt)
- {
- SensorDeviceImpl::EnumerateHMDFromSensorDisplayInfo(displayInfo, ExternalVisitor);
- }
- }
- }
- };
-
- //double start = Timer::GetProfileSeconds();
-
- SensorEnumerator sensorEnumerator(this, visitor);
- GetManagerImpl()->GetHIDDeviceManager()->Enumerate(&sensorEnumerator);
-
- //double totalSeconds = Timer::GetProfileSeconds() - start;
-}
-
-bool SensorDeviceFactory::MatchVendorProduct(UInt16 vendorId, UInt16 productId) const
-{
- return ((vendorId == Sensor_VendorId) && (productId == Sensor_ProductId)) ||
- ((vendorId == Sensor_OldVendorId) && (productId == Sensor_OldProductId));
-}
-
-bool SensorDeviceFactory::DetectHIDDevice(DeviceManager* pdevMgr, const HIDDeviceDesc& desc)
-{
- if (MatchVendorProduct(desc.VendorId, desc.ProductId))
- {
- SensorDeviceCreateDesc createDesc(this, desc);
- return pdevMgr->AddDevice_NeedsLock(createDesc).GetPtr() != NULL;
- }
- return false;
-}
-
-//-------------------------------------------------------------------------------------
-// ***** SensorDeviceCreateDesc
-
-DeviceBase* SensorDeviceCreateDesc::NewDeviceInstance()
-{
- return new SensorDeviceImpl(this);
-}
-
-bool SensorDeviceCreateDesc::GetDeviceInfo(DeviceInfo* info) const
-{
- if ((info->InfoClassType != Device_Sensor) &&
- (info->InfoClassType != Device_None))
- return false;
-
- OVR_strcpy(info->ProductName, DeviceInfo::MaxNameLength, HIDDesc.Product.ToCStr());
- OVR_strcpy(info->Manufacturer, DeviceInfo::MaxNameLength, HIDDesc.Manufacturer.ToCStr());
- info->Type = Device_Sensor;
- info->Version = 0;
-
- if (info->InfoClassType == Device_Sensor)
- {
- SensorInfo* sinfo = (SensorInfo*)info;
- sinfo->VendorId = HIDDesc.VendorId;
- sinfo->ProductId = HIDDesc.ProductId;
- sinfo->MaxRanges = SensorRangeImpl::GetMaxSensorRange();
- OVR_strcpy(sinfo->SerialNumber, sizeof(sinfo->SerialNumber),HIDDesc.SerialNumber.ToCStr());
- }
- return true;
-}
-
-
-//-------------------------------------------------------------------------------------
-// ***** SensorDevice
-
-SensorDeviceImpl::SensorDeviceImpl(SensorDeviceCreateDesc* createDesc)
- : OVR::HIDDeviceImpl<OVR::SensorDevice>(createDesc, 0),
- Coordinates(SensorDevice::Coord_Sensor),
- HWCoordinates(SensorDevice::Coord_HMD), // HW reports HMD coordinates by default.
- NextKeepAliveTicks(0),
- MaxValidRange(SensorRangeImpl::GetMaxSensorRange())
-{
- SequenceValid = false;
- LastSampleCount= 0;
- LastTimestamp = 0;
-
- OldCommandId = 0;
-}
-
-SensorDeviceImpl::~SensorDeviceImpl()
-{
- // Check that Shutdown() was called.
- OVR_ASSERT(!pCreateDesc->pDevice);
-}
-
-// Internal creation APIs.
-bool SensorDeviceImpl::Initialize(DeviceBase* parent)
-{
- if (HIDDeviceImpl<OVR::SensorDevice>::Initialize(parent))
- {
- openDevice();
-
- LogText("OVR::SensorDevice initialized.\n");
-
- return true;
- }
-
- return false;
-}
-
-void SensorDeviceImpl::openDevice()
-{
-
- // Read the currently configured range from sensor.
- SensorRangeImpl sr(SensorRange(), 0);
-
- if (GetInternalDevice()->GetFeatureReport(sr.Buffer, SensorRangeImpl::PacketSize))
- {
- sr.Unpack();
- sr.GetSensorRange(&CurrentRange);
- }
-
-
- // If the sensor has "DisplayInfo" data, use HMD coordinate frame by default.
- SensorDisplayInfoImpl displayInfo;
- if (GetInternalDevice()->GetFeatureReport(displayInfo.Buffer, SensorDisplayInfoImpl::PacketSize))
- {
- displayInfo.Unpack();
- Coordinates = (displayInfo.DistortionType & SensorDisplayInfoImpl::Mask_BaseFmt) ?
- Coord_HMD : Coord_Sensor;
- }
-
- // Read/Apply sensor config.
- setCoordinateFrame(Coordinates);
- setReportRate(Sensor_DefaultReportRate);
-
- // Set Keep-alive at 10 seconds.
- SensorKeepAliveImpl skeepAlive(10 * 1000);
- GetInternalDevice()->SetFeatureReport(skeepAlive.Buffer, SensorKeepAliveImpl::PacketSize);
-}
-
-void SensorDeviceImpl::closeDeviceOnError()
-{
- LogText("OVR::SensorDevice - Lost connection to '%s'\n", getHIDDesc()->Path.ToCStr());
- NextKeepAliveTicks = 0;
-}
-
-void SensorDeviceImpl::Shutdown()
-{
- HIDDeviceImpl<OVR::SensorDevice>::Shutdown();
-
- LogText("OVR::SensorDevice - Closed '%s'\n", getHIDDesc()->Path.ToCStr());
-}
-
-
-void SensorDeviceImpl::OnInputReport(UByte* pData, UInt32 length)
-{
-
- bool processed = false;
- if (!processed)
- {
-
- TrackerMessage message;
- if (DecodeTrackerMessage(&message, pData, length))
- {
- processed = true;
- onTrackerMessage(&message);
- }
- }
-}
-
-UInt64 SensorDeviceImpl::OnTicks(UInt64 ticksMks)
-{
-
- if (ticksMks >= NextKeepAliveTicks)
- {
- // Use 3-seconds keep alive by default.
- UInt64 keepAliveDelta = Timer::MksPerSecond * 3;
-
- // Set Keep-alive at 10 seconds.
- SensorKeepAliveImpl skeepAlive(10 * 1000);
- // OnTicks is called from background thread so we don't need to add this to the command queue.
- GetInternalDevice()->SetFeatureReport(skeepAlive.Buffer, SensorKeepAliveImpl::PacketSize);
-
- // Emit keep-alive every few seconds.
- NextKeepAliveTicks = ticksMks + keepAliveDelta;
- }
- return NextKeepAliveTicks - ticksMks;
-}
-
-bool SensorDeviceImpl::SetRange(const SensorRange& range, bool waitFlag)
-{
- bool result = 0;
- ThreadCommandQueue * threadQueue = GetManagerImpl()->GetThreadQueue();
-
- if (!waitFlag)
- {
- return threadQueue->PushCall(this, &SensorDeviceImpl::setRange, range);
- }
-
- if (!threadQueue->PushCallAndWaitResult(this,
- &SensorDeviceImpl::setRange,
- &result,
- range))
- {
- return false;
- }
-
- return result;
-}
-
-void SensorDeviceImpl::GetRange(SensorRange* range) const
-{
- Lock::Locker lockScope(GetLock());
- *range = CurrentRange;
-}
-
-bool SensorDeviceImpl::setRange(const SensorRange& range)
-{
- SensorRangeImpl sr(range);
-
- if (GetInternalDevice()->SetFeatureReport(sr.Buffer, SensorRangeImpl::PacketSize))
- {
- Lock::Locker lockScope(GetLock());
- sr.GetSensorRange(&CurrentRange);
- return true;
- }
-
- return false;
-}
-
-void SensorDeviceImpl::SetCoordinateFrame(CoordinateFrame coordframe)
-{
- // Push call with wait.
- GetManagerImpl()->GetThreadQueue()->
- PushCall(this, &SensorDeviceImpl::setCoordinateFrame, coordframe, true);
-}
-
-SensorDevice::CoordinateFrame SensorDeviceImpl::GetCoordinateFrame() const
-{
- return Coordinates;
-}
-
-Void SensorDeviceImpl::setCoordinateFrame(CoordinateFrame coordframe)
-{
-
- Coordinates = coordframe;
-
- // Read the original coordinate frame, then try to change it.
- SensorConfigImpl scfg;
- if (GetInternalDevice()->GetFeatureReport(scfg.Buffer, SensorConfigImpl::PacketSize))
- {
- scfg.Unpack();
- }
-
- scfg.SetSensorCoordinates(coordframe == Coord_Sensor);
- scfg.Pack();
-
- GetInternalDevice()->SetFeatureReport(scfg.Buffer, SensorConfigImpl::PacketSize);
-
- // Re-read the state, in case of older firmware that doesn't support Sensor coordinates.
- if (GetInternalDevice()->GetFeatureReport(scfg.Buffer, SensorConfigImpl::PacketSize))
- {
- scfg.Unpack();
- HWCoordinates = scfg.IsUsingSensorCoordinates() ? Coord_Sensor : Coord_HMD;
- }
- else
- {
- HWCoordinates = Coord_HMD;
- }
- return 0;
-}
-
-void SensorDeviceImpl::SetReportRate(unsigned rateHz)
-{
- // Push call with wait.
- GetManagerImpl()->GetThreadQueue()->
- PushCall(this, &SensorDeviceImpl::setReportRate, rateHz, true);
-}
-
-unsigned SensorDeviceImpl::GetReportRate() const
-{
- // Read the original configuration
- SensorConfigImpl scfg;
- if (GetInternalDevice()->GetFeatureReport(scfg.Buffer, SensorConfigImpl::PacketSize))
- {
- scfg.Unpack();
- return Sensor_MaxReportRate / (scfg.PacketInterval + 1);
- }
- return 0; // error
-}
-
-Void SensorDeviceImpl::setReportRate(unsigned rateHz)
-{
- // Read the original configuration
- SensorConfigImpl scfg;
- if (GetInternalDevice()->GetFeatureReport(scfg.Buffer, SensorConfigImpl::PacketSize))
- {
- scfg.Unpack();
- }
-
- if (rateHz > Sensor_MaxReportRate)
- rateHz = Sensor_MaxReportRate;
- else if (rateHz == 0)
- rateHz = Sensor_DefaultReportRate;
-
- scfg.PacketInterval = UInt16((Sensor_MaxReportRate / rateHz) - 1);
-
- scfg.Pack();
-
- GetInternalDevice()->SetFeatureReport(scfg.Buffer, SensorConfigImpl::PacketSize);
- return 0;
-}
-
-void SensorDeviceImpl::SetMessageHandler(MessageHandler* handler)
-{
- if (handler)
- {
- SequenceValid = false;
- DeviceBase::SetMessageHandler(handler);
- }
- else
- {
- DeviceBase::SetMessageHandler(handler);
- }
-}
-
-// Sensor reports data in the following coordinate system:
-// Accelerometer: 10^-4 m/s^2; X forward, Y right, Z Down.
-// Gyro: 10^-4 rad/s; X positive roll right, Y positive pitch up; Z positive yaw right.
-
-
-// We need to convert it to the following RHS coordinate system:
-// X right, Y Up, Z Back (out of screen)
-//
-Vector3f AccelFromBodyFrameUpdate(const TrackerSensors& update, UByte sampleNumber,
- bool convertHMDToSensor = false)
-{
- const TrackerSample& sample = update.Samples[sampleNumber];
- float ax = (float)sample.AccelX;
- float ay = (float)sample.AccelY;
- float az = (float)sample.AccelZ;
-
- Vector3f val = convertHMDToSensor ? Vector3f(ax, az, -ay) : Vector3f(ax, ay, az);
- return val * 0.0001f;
-}
-
-
-Vector3f MagFromBodyFrameUpdate(const TrackerSensors& update,
- bool convertHMDToSensor = false)
-{
- // Note: Y and Z are swapped in comparison to the Accel.
- // This accounts for DK1 sensor firmware axis swap, which should be undone in future releases.
- if (!convertHMDToSensor)
- {
- return Vector3f( (float)update.MagX,
- (float)update.MagZ,
- (float)update.MagY) * 0.0001f;
- }
-
- return Vector3f( (float)update.MagX,
- (float)update.MagY,
- -(float)update.MagZ) * 0.0001f;
-}
-
-Vector3f EulerFromBodyFrameUpdate(const TrackerSensors& update, UByte sampleNumber,
- bool convertHMDToSensor = false)
-{
- const TrackerSample& sample = update.Samples[sampleNumber];
- float gx = (float)sample.GyroX;
- float gy = (float)sample.GyroY;
- float gz = (float)sample.GyroZ;
-
- Vector3f val = convertHMDToSensor ? Vector3f(gx, gz, -gy) : Vector3f(gx, gy, gz);
- return val * 0.0001f;
-}
-
-
-void SensorDeviceImpl::onTrackerMessage(TrackerMessage* message)
-{
- if (message->Type != TrackerMessage_Sensors)
- return;
-
- const float timeUnit = (1.0f / 1000.f);
- TrackerSensors& s = message->Sensors;
-
-
- // Call OnMessage() within a lock to avoid conflicts with handlers.
- Lock::Locker scopeLock(HandlerRef.GetLock());
-
-
- if (SequenceValid)
- {
- unsigned timestampDelta;
-
- if (s.Timestamp < LastTimestamp)
- timestampDelta = ((((int)s.Timestamp) + 0x10000) - (int)LastTimestamp);
- else
- timestampDelta = (s.Timestamp - LastTimestamp);
-
- // If we missed a small number of samples, replicate the last sample.
- if ((timestampDelta > LastSampleCount) && (timestampDelta <= 254))
- {
- if (HandlerRef.GetHandler())
- {
- MessageBodyFrame sensors(this);
- sensors.TimeDelta = (timestampDelta - LastSampleCount) * timeUnit;
- sensors.Acceleration = LastAcceleration;
- sensors.RotationRate = LastRotationRate;
- sensors.MagneticField = LastMagneticField;
- sensors.Temperature = LastTemperature;
-
- HandlerRef.GetHandler()->OnMessage(sensors);
- }
- }
- }
- else
- {
- LastAcceleration = Vector3f(0);
- LastRotationRate = Vector3f(0);
- LastMagneticField= Vector3f(0);
- LastTemperature = 0;
- SequenceValid = true;
- }
-
- LastSampleCount = s.SampleCount;
- LastTimestamp = s.Timestamp;
-
- bool convertHMDToSensor = (Coordinates == Coord_Sensor) && (HWCoordinates == Coord_HMD);
-
- if (HandlerRef.GetHandler())
- {
- MessageBodyFrame sensors(this);
- UByte iterations = s.SampleCount;
-
- if (s.SampleCount > 3)
- {
- iterations = 3;
- sensors.TimeDelta = (s.SampleCount - 2) * timeUnit;
- }
- else
- {
- sensors.TimeDelta = timeUnit;
- }
-
- for (UByte i = 0; i < iterations; i++)
- {
- sensors.Acceleration = AccelFromBodyFrameUpdate(s, i, convertHMDToSensor);
- sensors.RotationRate = EulerFromBodyFrameUpdate(s, i, convertHMDToSensor);
- sensors.MagneticField= MagFromBodyFrameUpdate(s, convertHMDToSensor);
- sensors.Temperature = s.Temperature * 0.01f;
- HandlerRef.GetHandler()->OnMessage(sensors);
- // TimeDelta for the last two sample is always fixed.
- sensors.TimeDelta = timeUnit;
- }
-
- LastAcceleration = sensors.Acceleration;
- LastRotationRate = sensors.RotationRate;
- LastMagneticField= sensors.MagneticField;
- LastTemperature = sensors.Temperature;
- }
- else
- {
- UByte i = (s.SampleCount > 3) ? 2 : (s.SampleCount - 1);
- LastAcceleration = AccelFromBodyFrameUpdate(s, i, convertHMDToSensor);
- LastRotationRate = EulerFromBodyFrameUpdate(s, i, convertHMDToSensor);
- LastMagneticField = MagFromBodyFrameUpdate(s, convertHMDToSensor);
- LastTemperature = s.Temperature * 0.01f;
- }
-}
-
-} // namespace OVR
-
-
+/************************************************************************************
+
+Filename : OVR_SensorImpl.cpp
+Content : Oculus Sensor device implementation.
+Created : March 7, 2013
+Authors : Lee Cooper
+
+Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+*************************************************************************************/
+
+#include "OVR_SensorImpl.h"
+
+// HMDDeviceDesc can be created/updated through Sensor carrying DisplayInfo.
+
+#include "Kernel/OVR_Timer.h"
+
+namespace OVR {
+
+//-------------------------------------------------------------------------------------
+// ***** Oculus Sensor-specific packet data structures
+
+enum {
+ Sensor_VendorId = Oculus_VendorId,
+ Sensor_ProductId = 0x0001,
+
+ // ST's VID used originally; should be removed in the future
+ Sensor_OldVendorId = 0x0483,
+ Sensor_OldProductId = 0x5750,
+
+ Sensor_DefaultReportRate = 500, // Hz
+ Sensor_MaxReportRate = 1000 // Hz
+};
+
+// Reported data is little-endian now
+static UInt16 DecodeUInt16(const UByte* buffer)
+{
+ return (UInt16(buffer[1]) << 8) | UInt16(buffer[0]);
+}
+
+static SInt16 DecodeSInt16(const UByte* buffer)
+{
+ return (SInt16(buffer[1]) << 8) | SInt16(buffer[0]);
+}
+
+static UInt32 DecodeUInt32(const UByte* buffer)
+{
+ return (buffer[0]) | UInt32(buffer[1] << 8) | UInt32(buffer[2] << 16) | UInt32(buffer[3] << 24);
+}
+
+static float DecodeFloat(const UByte* buffer)
+{
+ union {
+ UInt32 U;
+ float F;
+ };
+
+ U = DecodeUInt32(buffer);
+ return F;
+}
+
+
+static void UnpackSensor(const UByte* buffer, SInt32* x, SInt32* y, SInt32* z)
+{
+ // Sign extending trick
+ // from http://graphics.stanford.edu/~seander/bithacks.html#FixedSignExtend
+ struct {SInt32 x:21;} s;
+
+ *x = s.x = (buffer[0] << 13) | (buffer[1] << 5) | ((buffer[2] & 0xF8) >> 3);
+ *y = s.x = ((buffer[2] & 0x07) << 18) | (buffer[3] << 10) | (buffer[4] << 2) |
+ ((buffer[5] & 0xC0) >> 6);
+ *z = s.x = ((buffer[5] & 0x3F) << 15) | (buffer[6] << 7) | (buffer[7] >> 1);
+}
+
+// Messages we care for
+enum TrackerMessageType
+{
+ TrackerMessage_None = 0,
+ TrackerMessage_Sensors = 1,
+ TrackerMessage_Unknown = 0x100,
+ TrackerMessage_SizeError = 0x101,
+};
+
+struct TrackerSample
+{
+ SInt32 AccelX, AccelY, AccelZ;
+ SInt32 GyroX, GyroY, GyroZ;
+};
+
+
+struct TrackerSensors
+{
+ UByte SampleCount;
+ UInt16 Timestamp;
+ UInt16 LastCommandID;
+ SInt16 Temperature;
+
+ TrackerSample Samples[3];
+
+ SInt16 MagX, MagY, MagZ;
+
+ TrackerMessageType Decode(const UByte* buffer, int size)
+ {
+ if (size < 62)
+ return TrackerMessage_SizeError;
+
+ SampleCount = buffer[1];
+ Timestamp = DecodeUInt16(buffer + 2);
+ LastCommandID = DecodeUInt16(buffer + 4);
+ Temperature = DecodeSInt16(buffer + 6);
+
+ //if (SampleCount > 2)
+ // OVR_DEBUG_LOG_TEXT(("TackerSensor::Decode SampleCount=%d\n", SampleCount));
+
+ // Only unpack as many samples as there actually are
+ UByte iterationCount = (SampleCount > 2) ? 3 : SampleCount;
+
+ for (UByte i = 0; i < iterationCount; i++)
+ {
+ UnpackSensor(buffer + 8 + 16 * i, &Samples[i].AccelX, &Samples[i].AccelY, &Samples[i].AccelZ);
+ UnpackSensor(buffer + 16 + 16 * i, &Samples[i].GyroX, &Samples[i].GyroY, &Samples[i].GyroZ);
+ }
+
+ MagX = DecodeSInt16(buffer + 56);
+ MagY = DecodeSInt16(buffer + 58);
+ MagZ = DecodeSInt16(buffer + 60);
+
+ return TrackerMessage_Sensors;
+ }
+};
+
+struct TrackerMessage
+{
+ TrackerMessageType Type;
+ TrackerSensors Sensors;
+};
+
+bool DecodeTrackerMessage(TrackerMessage* message, UByte* buffer, int size)
+{
+ memset(message, 0, sizeof(TrackerMessage));
+
+ if (size < 4)
+ {
+ message->Type = TrackerMessage_SizeError;
+ return false;
+ }
+
+ switch (buffer[0])
+ {
+ case TrackerMessage_Sensors:
+ message->Type = message->Sensors.Decode(buffer, size);
+ break;
+
+ default:
+ message->Type = TrackerMessage_Unknown;
+ break;
+ }
+
+ return (message->Type < TrackerMessage_Unknown) && (message->Type != TrackerMessage_None);
+}
+
+
+// ***** SensorRangeImpl Implementation
+
+// Sensor HW only accepts specific maximum range values, used to maximize
+// the 16-bit sensor outputs. Use these ramps to specify and report appropriate values.
+static const UInt16 AccelRangeRamp[] = { 2, 4, 8, 16 };
+static const UInt16 GyroRangeRamp[] = { 250, 500, 1000, 2000 };
+static const UInt16 MagRangeRamp[] = { 880, 1300, 1900, 2500 };
+
+static UInt16 SelectSensorRampValue(const UInt16* ramp, unsigned count,
+ float val, float factor, const char* label)
+{
+ UInt16 threshold = (UInt16)(val * factor);
+
+ for (unsigned i = 0; i<count; i++)
+ {
+ if (ramp[i] >= threshold)
+ return ramp[i];
+ }
+ OVR_DEBUG_LOG(("SensorDevice::SetRange - %s clamped to %0.4f",
+ label, float(ramp[count-1]) / factor));
+ OVR_UNUSED2(factor, label);
+ return ramp[count-1];
+}
+
+// SensorScaleImpl provides buffer packing logic for the Sensor Range
+// record that can be applied to DK1 sensor through Get/SetFeature. We expose this
+// through SensorRange class, which has different units.
+struct SensorRangeImpl
+{
+ enum { PacketSize = 8 };
+ UByte Buffer[PacketSize];
+
+ UInt16 CommandId;
+ UInt16 AccelScale;
+ UInt16 GyroScale;
+ UInt16 MagScale;
+
+ SensorRangeImpl(const SensorRange& r, UInt16 commandId = 0)
+ {
+ SetSensorRange(r, commandId);
+ }
+
+ void SetSensorRange(const SensorRange& r, UInt16 commandId = 0)
+ {
+ CommandId = commandId;
+ AccelScale = SelectSensorRampValue(AccelRangeRamp, sizeof(AccelRangeRamp)/sizeof(AccelRangeRamp[0]),
+ r.MaxAcceleration, (1.0f / 9.81f), "MaxAcceleration");
+ GyroScale = SelectSensorRampValue(GyroRangeRamp, sizeof(GyroRangeRamp)/sizeof(GyroRangeRamp[0]),
+ r.MaxRotationRate, Math<float>::RadToDegreeFactor, "MaxRotationRate");
+ MagScale = SelectSensorRampValue(MagRangeRamp, sizeof(MagRangeRamp)/sizeof(MagRangeRamp[0]),
+ r.MaxMagneticField, 1000.0f, "MaxMagneticField");
+ Pack();
+ }
+
+ void GetSensorRange(SensorRange* r)
+ {
+ r->MaxAcceleration = AccelScale * 9.81f;
+ r->MaxRotationRate = DegreeToRad((float)GyroScale);
+ r->MaxMagneticField= MagScale * 0.001f;
+ }
+
+ static SensorRange GetMaxSensorRange()
+ {
+ return SensorRange(AccelRangeRamp[sizeof(AccelRangeRamp)/sizeof(AccelRangeRamp[0]) - 1] * 9.81f,
+ GyroRangeRamp[sizeof(GyroRangeRamp)/sizeof(GyroRangeRamp[0]) - 1] *
+ Math<float>::DegreeToRadFactor,
+ MagRangeRamp[sizeof(MagRangeRamp)/sizeof(MagRangeRamp[0]) - 1] * 0.001f);
+ }
+
+ void Pack()
+ {
+ Buffer[0] = 4;
+ Buffer[1] = UByte(CommandId & 0xFF);
+ Buffer[2] = UByte(CommandId >> 8);
+ Buffer[3] = UByte(AccelScale);
+ Buffer[4] = UByte(GyroScale & 0xFF);
+ Buffer[5] = UByte(GyroScale >> 8);
+ Buffer[6] = UByte(MagScale & 0xFF);
+ Buffer[7] = UByte(MagScale >> 8);
+ }
+
+ void Unpack()
+ {
+ CommandId = Buffer[1] | (UInt16(Buffer[2]) << 8);
+ AccelScale= Buffer[3];
+ GyroScale = Buffer[4] | (UInt16(Buffer[5]) << 8);
+ MagScale = Buffer[6] | (UInt16(Buffer[7]) << 8);
+ }
+};
+
+
+// Sensor configuration command, ReportId == 2.
+
+struct SensorConfigImpl
+{
+ enum { PacketSize = 7 };
+ UByte Buffer[PacketSize];
+
+ // Flag values for Flags.
+ enum {
+ Flag_RawMode = 0x01,
+ Flag_CallibrationTest = 0x02, // Internal test mode
+ Flag_UseCallibration = 0x04,
+ Flag_AutoCallibration = 0x08,
+ Flag_MotionKeepAlive = 0x10,
+ Flag_CommandKeepAlive = 0x20,
+ Flag_SensorCoordinates = 0x40
+ };
+
+ UInt16 CommandId;
+ UByte Flags;
+ UInt16 PacketInterval;
+ UInt16 KeepAliveIntervalMs;
+
+ SensorConfigImpl() : CommandId(0), Flags(0), PacketInterval(0), KeepAliveIntervalMs(0)
+ {
+ memset(Buffer, 0, PacketSize);
+ Buffer[0] = 2;
+ }
+
+ void SetSensorCoordinates(bool sensorCoordinates)
+ { Flags = (Flags & ~Flag_SensorCoordinates) | (sensorCoordinates ? Flag_SensorCoordinates : 0); }
+ bool IsUsingSensorCoordinates() const
+ { return (Flags & Flag_SensorCoordinates) != 0; }
+
+ void Pack()
+ {
+ Buffer[0] = 2;
+ Buffer[1] = UByte(CommandId & 0xFF);
+ Buffer[2] = UByte(CommandId >> 8);
+ Buffer[3] = Flags;
+ Buffer[4] = UByte(PacketInterval);
+ Buffer[5] = UByte(KeepAliveIntervalMs & 0xFF);
+ Buffer[6] = UByte(KeepAliveIntervalMs >> 8);
+ }
+
+ void Unpack()
+ {
+ CommandId = Buffer[1] | (UInt16(Buffer[2]) << 8);
+ Flags = Buffer[3];
+ PacketInterval = Buffer[4];
+ KeepAliveIntervalMs= Buffer[5] | (UInt16(Buffer[6]) << 8);
+ }
+
+};
+
+
+// SensorKeepAlive - feature report that needs to be sent at regular intervals for sensor
+// to receive commands.
+struct SensorKeepAliveImpl
+{
+ enum { PacketSize = 5 };
+ UByte Buffer[PacketSize];
+
+ UInt16 CommandId;
+ UInt16 KeepAliveIntervalMs;
+
+ SensorKeepAliveImpl(UInt16 interval = 0, UInt16 commandId = 0)
+ : CommandId(commandId), KeepAliveIntervalMs(interval)
+ {
+ Pack();
+ }
+
+ void Pack()
+ {
+ Buffer[0] = 8;
+ Buffer[1] = UByte(CommandId & 0xFF);
+ Buffer[2] = UByte(CommandId >> 8);
+ Buffer[3] = UByte(KeepAliveIntervalMs & 0xFF);
+ Buffer[4] = UByte(KeepAliveIntervalMs >> 8);
+ }
+
+ void Unpack()
+ {
+ CommandId = Buffer[1] | (UInt16(Buffer[2]) << 8);
+ KeepAliveIntervalMs= Buffer[3] | (UInt16(Buffer[4]) << 8);
+ }
+};
+
+
+//-------------------------------------------------------------------------------------
+// ***** SensorDisplayInfoImpl
+SensorDisplayInfoImpl::SensorDisplayInfoImpl()
+ : CommandId(0), DistortionType(Base_None)
+{
+ memset(Buffer, 0, PacketSize);
+ Buffer[0] = 9;
+}
+
+void SensorDisplayInfoImpl::Unpack()
+{
+ CommandId = Buffer[1] | (UInt16(Buffer[2]) << 8);
+ DistortionType = Buffer[3];
+ HResolution = DecodeUInt16(Buffer+4);
+ VResolution = DecodeUInt16(Buffer+6);
+ HScreenSize = DecodeUInt32(Buffer+8) * (1/1000000.f);
+ VScreenSize = DecodeUInt32(Buffer+12) * (1/1000000.f);
+ VCenter = DecodeUInt32(Buffer+16) * (1/1000000.f);
+ LensSeparation = DecodeUInt32(Buffer+20) * (1/1000000.f);
+ EyeToScreenDistance[0] = DecodeUInt32(Buffer+24) * (1/1000000.f);
+ EyeToScreenDistance[1] = DecodeUInt32(Buffer+28) * (1/1000000.f);
+ DistortionK[0] = DecodeFloat(Buffer+32);
+ DistortionK[1] = DecodeFloat(Buffer+36);
+ DistortionK[2] = DecodeFloat(Buffer+40);
+ DistortionK[3] = DecodeFloat(Buffer+44);
+ DistortionK[4] = DecodeFloat(Buffer+48);
+ DistortionK[5] = DecodeFloat(Buffer+52);
+}
+
+
+//-------------------------------------------------------------------------------------
+// ***** SensorDeviceFactory
+
+SensorDeviceFactory SensorDeviceFactory::Instance;
+
+void SensorDeviceFactory::EnumerateDevices(EnumerateVisitor& visitor)
+{
+
+ class SensorEnumerator : public HIDEnumerateVisitor
+ {
+ // Assign not supported; suppress MSVC warning.
+ void operator = (const SensorEnumerator&) { }
+
+ DeviceFactory* pFactory;
+ EnumerateVisitor& ExternalVisitor;
+ public:
+ SensorEnumerator(DeviceFactory* factory, EnumerateVisitor& externalVisitor)
+ : pFactory(factory), ExternalVisitor(externalVisitor) { }
+
+ virtual bool MatchVendorProduct(UInt16 vendorId, UInt16 productId)
+ {
+ return pFactory->MatchVendorProduct(vendorId, productId);
+ }
+
+ virtual void Visit(HIDDevice& device, const HIDDeviceDesc& desc)
+ {
+ SensorDeviceCreateDesc createDesc(pFactory, desc);
+ ExternalVisitor.Visit(createDesc);
+
+ // Check if the sensor returns DisplayInfo. If so, try to use it to override potentially
+ // mismatching monitor information (in case wrong EDID is reported by splitter),
+ // or to create a new "virtualized" HMD Device.
+
+ SensorDisplayInfoImpl displayInfo;
+
+ if (device.GetFeatureReport(displayInfo.Buffer, SensorDisplayInfoImpl::PacketSize))
+ {
+ displayInfo.Unpack();
+
+ // If we got display info, try to match / create HMDDevice as well
+ // so that sensor settings give preference.
+ if (displayInfo.DistortionType & SensorDisplayInfoImpl::Mask_BaseFmt)
+ {
+ SensorDeviceImpl::EnumerateHMDFromSensorDisplayInfo(displayInfo, ExternalVisitor);
+ }
+ }
+ }
+ };
+
+ //double start = Timer::GetProfileSeconds();
+
+ SensorEnumerator sensorEnumerator(this, visitor);
+ GetManagerImpl()->GetHIDDeviceManager()->Enumerate(&sensorEnumerator);
+
+ //double totalSeconds = Timer::GetProfileSeconds() - start;
+}
+
+bool SensorDeviceFactory::MatchVendorProduct(UInt16 vendorId, UInt16 productId) const
+{
+ return ((vendorId == Sensor_VendorId) && (productId == Sensor_ProductId)) ||
+ ((vendorId == Sensor_OldVendorId) && (productId == Sensor_OldProductId));
+}
+
+bool SensorDeviceFactory::DetectHIDDevice(DeviceManager* pdevMgr, const HIDDeviceDesc& desc)
+{
+ if (MatchVendorProduct(desc.VendorId, desc.ProductId))
+ {
+ SensorDeviceCreateDesc createDesc(this, desc);
+ return pdevMgr->AddDevice_NeedsLock(createDesc).GetPtr() != NULL;
+ }
+ return false;
+}
+
+//-------------------------------------------------------------------------------------
+// ***** SensorDeviceCreateDesc
+
+DeviceBase* SensorDeviceCreateDesc::NewDeviceInstance()
+{
+ return new SensorDeviceImpl(this);
+}
+
+bool SensorDeviceCreateDesc::GetDeviceInfo(DeviceInfo* info) const
+{
+ if ((info->InfoClassType != Device_Sensor) &&
+ (info->InfoClassType != Device_None))
+ return false;
+
+ OVR_strcpy(info->ProductName, DeviceInfo::MaxNameLength, HIDDesc.Product.ToCStr());
+ OVR_strcpy(info->Manufacturer, DeviceInfo::MaxNameLength, HIDDesc.Manufacturer.ToCStr());
+ info->Type = Device_Sensor;
+ info->Version = 0;
+
+ if (info->InfoClassType == Device_Sensor)
+ {
+ SensorInfo* sinfo = (SensorInfo*)info;
+ sinfo->VendorId = HIDDesc.VendorId;
+ sinfo->ProductId = HIDDesc.ProductId;
+ sinfo->MaxRanges = SensorRangeImpl::GetMaxSensorRange();
+ OVR_strcpy(sinfo->SerialNumber, sizeof(sinfo->SerialNumber),HIDDesc.SerialNumber.ToCStr());
+ }
+ return true;
+}
+
+
+//-------------------------------------------------------------------------------------
+// ***** SensorDevice
+
+SensorDeviceImpl::SensorDeviceImpl(SensorDeviceCreateDesc* createDesc)
+ : OVR::HIDDeviceImpl<OVR::SensorDevice>(createDesc, 0),
+ Coordinates(SensorDevice::Coord_Sensor),
+ HWCoordinates(SensorDevice::Coord_HMD), // HW reports HMD coordinates by default.
+ NextKeepAliveTicks(0),
+ MaxValidRange(SensorRangeImpl::GetMaxSensorRange())
+{
+ SequenceValid = false;
+ LastSampleCount= 0;
+ LastTimestamp = 0;
+
+ OldCommandId = 0;
+}
+
+SensorDeviceImpl::~SensorDeviceImpl()
+{
+ // Check that Shutdown() was called.
+ OVR_ASSERT(!pCreateDesc->pDevice);
+}
+
+// Internal creation APIs.
+bool SensorDeviceImpl::Initialize(DeviceBase* parent)
+{
+ if (HIDDeviceImpl<OVR::SensorDevice>::Initialize(parent))
+ {
+ openDevice();
+
+ LogText("OVR::SensorDevice initialized.\n");
+
+ return true;
+ }
+
+ return false;
+}
+
+void SensorDeviceImpl::openDevice()
+{
+
+ // Read the currently configured range from sensor.
+ SensorRangeImpl sr(SensorRange(), 0);
+
+ if (GetInternalDevice()->GetFeatureReport(sr.Buffer, SensorRangeImpl::PacketSize))
+ {
+ sr.Unpack();
+ sr.GetSensorRange(&CurrentRange);
+ }
+
+
+ // If the sensor has "DisplayInfo" data, use HMD coordinate frame by default.
+ SensorDisplayInfoImpl displayInfo;
+ if (GetInternalDevice()->GetFeatureReport(displayInfo.Buffer, SensorDisplayInfoImpl::PacketSize))
+ {
+ displayInfo.Unpack();
+ Coordinates = (displayInfo.DistortionType & SensorDisplayInfoImpl::Mask_BaseFmt) ?
+ Coord_HMD : Coord_Sensor;
+ }
+
+ // Read/Apply sensor config.
+ setCoordinateFrame(Coordinates);
+ setReportRate(Sensor_DefaultReportRate);
+
+ // Set Keep-alive at 10 seconds.
+ SensorKeepAliveImpl skeepAlive(10 * 1000);
+ GetInternalDevice()->SetFeatureReport(skeepAlive.Buffer, SensorKeepAliveImpl::PacketSize);
+}
+
+void SensorDeviceImpl::closeDeviceOnError()
+{
+ LogText("OVR::SensorDevice - Lost connection to '%s'\n", getHIDDesc()->Path.ToCStr());
+ NextKeepAliveTicks = 0;
+}
+
+void SensorDeviceImpl::Shutdown()
+{
+ HIDDeviceImpl<OVR::SensorDevice>::Shutdown();
+
+ LogText("OVR::SensorDevice - Closed '%s'\n", getHIDDesc()->Path.ToCStr());
+}
+
+
+void SensorDeviceImpl::OnInputReport(UByte* pData, UInt32 length)
+{
+
+ bool processed = false;
+ if (!processed)
+ {
+
+ TrackerMessage message;
+ if (DecodeTrackerMessage(&message, pData, length))
+ {
+ processed = true;
+ onTrackerMessage(&message);
+ }
+ }
+}
+
+UInt64 SensorDeviceImpl::OnTicks(UInt64 ticksMks)
+{
+
+ if (ticksMks >= NextKeepAliveTicks)
+ {
+ // Use 3-seconds keep alive by default.
+ UInt64 keepAliveDelta = Timer::MksPerSecond * 3;
+
+ // Set Keep-alive at 10 seconds.
+ SensorKeepAliveImpl skeepAlive(10 * 1000);
+ // OnTicks is called from background thread so we don't need to add this to the command queue.
+ GetInternalDevice()->SetFeatureReport(skeepAlive.Buffer, SensorKeepAliveImpl::PacketSize);
+
+ // Emit keep-alive every few seconds.
+ NextKeepAliveTicks = ticksMks + keepAliveDelta;
+ }
+ return NextKeepAliveTicks - ticksMks;
+}
+
+bool SensorDeviceImpl::SetRange(const SensorRange& range, bool waitFlag)
+{
+ bool result = 0;
+ ThreadCommandQueue * threadQueue = GetManagerImpl()->GetThreadQueue();
+
+ if (!waitFlag)
+ {
+ return threadQueue->PushCall(this, &SensorDeviceImpl::setRange, range);
+ }
+
+ if (!threadQueue->PushCallAndWaitResult(this,
+ &SensorDeviceImpl::setRange,
+ &result,
+ range))
+ {
+ return false;
+ }
+
+ return result;
+}
+
+void SensorDeviceImpl::GetRange(SensorRange* range) const
+{
+ Lock::Locker lockScope(GetLock());
+ *range = CurrentRange;
+}
+
+bool SensorDeviceImpl::setRange(const SensorRange& range)
+{
+ SensorRangeImpl sr(range);
+
+ if (GetInternalDevice()->SetFeatureReport(sr.Buffer, SensorRangeImpl::PacketSize))
+ {
+ Lock::Locker lockScope(GetLock());
+ sr.GetSensorRange(&CurrentRange);
+ return true;
+ }
+
+ return false;
+}
+
+void SensorDeviceImpl::SetCoordinateFrame(CoordinateFrame coordframe)
+{
+ // Push call with wait.
+ GetManagerImpl()->GetThreadQueue()->
+ PushCall(this, &SensorDeviceImpl::setCoordinateFrame, coordframe, true);
+}
+
+SensorDevice::CoordinateFrame SensorDeviceImpl::GetCoordinateFrame() const
+{
+ return Coordinates;
+}
+
+Void SensorDeviceImpl::setCoordinateFrame(CoordinateFrame coordframe)
+{
+
+ Coordinates = coordframe;
+
+ // Read the original coordinate frame, then try to change it.
+ SensorConfigImpl scfg;
+ if (GetInternalDevice()->GetFeatureReport(scfg.Buffer, SensorConfigImpl::PacketSize))
+ {
+ scfg.Unpack();
+ }
+
+ scfg.SetSensorCoordinates(coordframe == Coord_Sensor);
+ scfg.Pack();
+
+ GetInternalDevice()->SetFeatureReport(scfg.Buffer, SensorConfigImpl::PacketSize);
+
+ // Re-read the state, in case of older firmware that doesn't support Sensor coordinates.
+ if (GetInternalDevice()->GetFeatureReport(scfg.Buffer, SensorConfigImpl::PacketSize))
+ {
+ scfg.Unpack();
+ HWCoordinates = scfg.IsUsingSensorCoordinates() ? Coord_Sensor : Coord_HMD;
+ }
+ else
+ {
+ HWCoordinates = Coord_HMD;
+ }
+ return 0;
+}
+
+void SensorDeviceImpl::SetReportRate(unsigned rateHz)
+{
+ // Push call with wait.
+ GetManagerImpl()->GetThreadQueue()->
+ PushCall(this, &SensorDeviceImpl::setReportRate, rateHz, true);
+}
+
+unsigned SensorDeviceImpl::GetReportRate() const
+{
+ // Read the original configuration
+ SensorConfigImpl scfg;
+ if (GetInternalDevice()->GetFeatureReport(scfg.Buffer, SensorConfigImpl::PacketSize))
+ {
+ scfg.Unpack();
+ return Sensor_MaxReportRate / (scfg.PacketInterval + 1);
+ }
+ return 0; // error
+}
+
+Void SensorDeviceImpl::setReportRate(unsigned rateHz)
+{
+ // Read the original configuration
+ SensorConfigImpl scfg;
+ if (GetInternalDevice()->GetFeatureReport(scfg.Buffer, SensorConfigImpl::PacketSize))
+ {
+ scfg.Unpack();
+ }
+
+ if (rateHz > Sensor_MaxReportRate)
+ rateHz = Sensor_MaxReportRate;
+ else if (rateHz == 0)
+ rateHz = Sensor_DefaultReportRate;
+
+ scfg.PacketInterval = UInt16((Sensor_MaxReportRate / rateHz) - 1);
+
+ scfg.Pack();
+
+ GetInternalDevice()->SetFeatureReport(scfg.Buffer, SensorConfigImpl::PacketSize);
+ return 0;
+}
+
+void SensorDeviceImpl::SetMessageHandler(MessageHandler* handler)
+{
+ if (handler)
+ {
+ SequenceValid = false;
+ DeviceBase::SetMessageHandler(handler);
+ }
+ else
+ {
+ DeviceBase::SetMessageHandler(handler);
+ }
+}
+
+// Sensor reports data in the following coordinate system:
+// Accelerometer: 10^-4 m/s^2; X forward, Y right, Z Down.
+// Gyro: 10^-4 rad/s; X positive roll right, Y positive pitch up; Z positive yaw right.
+
+
+// We need to convert it to the following RHS coordinate system:
+// X right, Y Up, Z Back (out of screen)
+//
+Vector3f AccelFromBodyFrameUpdate(const TrackerSensors& update, UByte sampleNumber,
+ bool convertHMDToSensor = false)
+{
+ const TrackerSample& sample = update.Samples[sampleNumber];
+ float ax = (float)sample.AccelX;
+ float ay = (float)sample.AccelY;
+ float az = (float)sample.AccelZ;
+
+ Vector3f val = convertHMDToSensor ? Vector3f(ax, az, -ay) : Vector3f(ax, ay, az);
+ return val * 0.0001f;
+}
+
+
+Vector3f MagFromBodyFrameUpdate(const TrackerSensors& update,
+ bool convertHMDToSensor = false)
+{
+ // Note: Y and Z are swapped in comparison to the Accel.
+ // This accounts for DK1 sensor firmware axis swap, which should be undone in future releases.
+ if (!convertHMDToSensor)
+ {
+ return Vector3f( (float)update.MagX,
+ (float)update.MagZ,
+ (float)update.MagY) * 0.0001f;
+ }
+
+ return Vector3f( (float)update.MagX,
+ (float)update.MagY,
+ -(float)update.MagZ) * 0.0001f;
+}
+
+Vector3f EulerFromBodyFrameUpdate(const TrackerSensors& update, UByte sampleNumber,
+ bool convertHMDToSensor = false)
+{
+ const TrackerSample& sample = update.Samples[sampleNumber];
+ float gx = (float)sample.GyroX;
+ float gy = (float)sample.GyroY;
+ float gz = (float)sample.GyroZ;
+
+ Vector3f val = convertHMDToSensor ? Vector3f(gx, gz, -gy) : Vector3f(gx, gy, gz);
+ return val * 0.0001f;
+}
+
+
+void SensorDeviceImpl::onTrackerMessage(TrackerMessage* message)
+{
+ if (message->Type != TrackerMessage_Sensors)
+ return;
+
+ const float timeUnit = (1.0f / 1000.f);
+ TrackerSensors& s = message->Sensors;
+
+
+ // Call OnMessage() within a lock to avoid conflicts with handlers.
+ Lock::Locker scopeLock(HandlerRef.GetLock());
+
+
+ if (SequenceValid)
+ {
+ unsigned timestampDelta;
+
+ if (s.Timestamp < LastTimestamp)
+ timestampDelta = ((((int)s.Timestamp) + 0x10000) - (int)LastTimestamp);
+ else
+ timestampDelta = (s.Timestamp - LastTimestamp);
+
+ // If we missed a small number of samples, replicate the last sample.
+ if ((timestampDelta > LastSampleCount) && (timestampDelta <= 254))
+ {
+ if (HandlerRef.GetHandler())
+ {
+ MessageBodyFrame sensors(this);
+ sensors.TimeDelta = (timestampDelta - LastSampleCount) * timeUnit;
+ sensors.Acceleration = LastAcceleration;
+ sensors.RotationRate = LastRotationRate;
+ sensors.MagneticField = LastMagneticField;
+ sensors.Temperature = LastTemperature;
+
+ HandlerRef.GetHandler()->OnMessage(sensors);
+ }
+ }
+ }
+ else
+ {
+ LastAcceleration = Vector3f(0);
+ LastRotationRate = Vector3f(0);
+ LastMagneticField= Vector3f(0);
+ LastTemperature = 0;
+ SequenceValid = true;
+ }
+
+ LastSampleCount = s.SampleCount;
+ LastTimestamp = s.Timestamp;
+
+ bool convertHMDToSensor = (Coordinates == Coord_Sensor) && (HWCoordinates == Coord_HMD);
+
+ if (HandlerRef.GetHandler())
+ {
+ MessageBodyFrame sensors(this);
+ UByte iterations = s.SampleCount;
+
+ if (s.SampleCount > 3)
+ {
+ iterations = 3;
+ sensors.TimeDelta = (s.SampleCount - 2) * timeUnit;
+ }
+ else
+ {
+ sensors.TimeDelta = timeUnit;
+ }
+
+ for (UByte i = 0; i < iterations; i++)
+ {
+ sensors.Acceleration = AccelFromBodyFrameUpdate(s, i, convertHMDToSensor);
+ sensors.RotationRate = EulerFromBodyFrameUpdate(s, i, convertHMDToSensor);
+ sensors.MagneticField= MagFromBodyFrameUpdate(s, convertHMDToSensor);
+ sensors.Temperature = s.Temperature * 0.01f;
+ HandlerRef.GetHandler()->OnMessage(sensors);
+ // TimeDelta for the last two sample is always fixed.
+ sensors.TimeDelta = timeUnit;
+ }
+
+ LastAcceleration = sensors.Acceleration;
+ LastRotationRate = sensors.RotationRate;
+ LastMagneticField= sensors.MagneticField;
+ LastTemperature = sensors.Temperature;
+ }
+ else
+ {
+ UByte i = (s.SampleCount > 3) ? 2 : (s.SampleCount - 1);
+ LastAcceleration = AccelFromBodyFrameUpdate(s, i, convertHMDToSensor);
+ LastRotationRate = EulerFromBodyFrameUpdate(s, i, convertHMDToSensor);
+ LastMagneticField = MagFromBodyFrameUpdate(s, convertHMDToSensor);
+ LastTemperature = s.Temperature * 0.01f;
+ }
+}
+
+} // namespace OVR
+
+