diff options
author | Sven Gothel <[email protected]> | 2014-06-19 17:03:28 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2014-06-19 17:03:28 +0200 |
commit | d9a584844a60542519d813b5dc1a62428f14a0ae (patch) | |
tree | 942c10a5ebcd0aab65e9d6facb59778468f39d3b /LibOVR/Src/OVR_LatencyTestImpl.cpp |
Add OculusSDK 0.3.2 Linux Source Code w/o Samples, docs or binaries (libs or tools)
Diffstat (limited to 'LibOVR/Src/OVR_LatencyTestImpl.cpp')
-rw-r--r-- | LibOVR/Src/OVR_LatencyTestImpl.cpp | 773 |
1 files changed, 773 insertions, 0 deletions
diff --git a/LibOVR/Src/OVR_LatencyTestImpl.cpp b/LibOVR/Src/OVR_LatencyTestImpl.cpp new file mode 100644 index 0000000..015d9e4 --- /dev/null +++ b/LibOVR/Src/OVR_LatencyTestImpl.cpp @@ -0,0 +1,773 @@ +/************************************************************************************ + +Filename : OVR_LatencyTestImpl.cpp +Content : Oculus Latency Tester device implementation. +Created : March 7, 2013 +Authors : Lee Cooper + +Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.1 (the "License"); +you may not use the Oculus VR Rift SDK except in compliance with the License, +which is provided at the time of installation or download, or which +otherwise accompanies this software in either electronic or hard copy form. + +You may obtain a copy of the License at + +http://www.oculusvr.com/licenses/LICENSE-3.1 + +Unless required by applicable law or agreed to in writing, the Oculus VR SDK +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +*************************************************************************************/ + +#include "OVR_LatencyTestImpl.h" +#include "Kernel/OVR_Alg.h" + +namespace OVR { + +using namespace Alg; + +//------------------------------------------------------------------------------------- +// ***** Oculus Latency Tester specific packet data structures + +enum { + LatencyTester_VendorId = Oculus_VendorId, + LatencyTester_ProductId = 0x0101, +}; + +static void UnpackSamples(const UByte* buffer, UByte* r, UByte* g, UByte* b) +{ + *r = buffer[0]; + *g = buffer[1]; + *b = buffer[2]; +} + +// Messages we handle. +enum LatencyTestMessageType +{ + LatencyTestMessage_None = 0, + LatencyTestMessage_Samples = 1, + LatencyTestMessage_ColorDetected = 2, + LatencyTestMessage_TestStarted = 3, + LatencyTestMessage_Button = 4, + LatencyTestMessage_Unknown = 0x100, + LatencyTestMessage_SizeError = 0x101, +}; + +struct LatencyTestSample +{ + UByte Value[3]; +}; + +struct LatencyTestSamples +{ + UByte SampleCount; + UInt16 Timestamp; + + LatencyTestSample Samples[20]; + + LatencyTestMessageType Decode(const UByte* buffer, int size) + { + if (size < 64) + { + return LatencyTestMessage_SizeError; + } + + SampleCount = buffer[1]; + Timestamp = DecodeUInt16(buffer + 2); + + for (UByte i = 0; i < SampleCount; i++) + { + UnpackSamples(buffer + 4 + (3 * i), &Samples[i].Value[0], &Samples[i].Value[1], &Samples[i].Value[2]); + } + + return LatencyTestMessage_Samples; + } +}; + +struct LatencyTestSamplesMessage +{ + LatencyTestMessageType Type; + LatencyTestSamples Samples; +}; + +bool DecodeLatencyTestSamplesMessage(LatencyTestSamplesMessage* message, UByte* buffer, int size) +{ + memset(message, 0, sizeof(LatencyTestSamplesMessage)); + + if (size < 64) + { + message->Type = LatencyTestMessage_SizeError; + return false; + } + + switch (buffer[0]) + { + case LatencyTestMessage_Samples: + message->Type = message->Samples.Decode(buffer, size); + break; + + default: + message->Type = LatencyTestMessage_Unknown; + break; + } + + return (message->Type < LatencyTestMessage_Unknown) && (message->Type != LatencyTestMessage_None); +} + +struct LatencyTestColorDetected +{ + UInt16 CommandID; + UInt16 Timestamp; + UInt16 Elapsed; + UByte TriggerValue[3]; + UByte TargetValue[3]; + + LatencyTestMessageType Decode(const UByte* buffer, int size) + { + if (size < 13) + return LatencyTestMessage_SizeError; + + CommandID = DecodeUInt16(buffer + 1); + Timestamp = DecodeUInt16(buffer + 3); + Elapsed = DecodeUInt16(buffer + 5); + memcpy(TriggerValue, buffer + 7, 3); + memcpy(TargetValue, buffer + 10, 3); + + return LatencyTestMessage_ColorDetected; + } +}; + +struct LatencyTestColorDetectedMessage +{ + LatencyTestMessageType Type; + LatencyTestColorDetected ColorDetected; +}; + +bool DecodeLatencyTestColorDetectedMessage(LatencyTestColorDetectedMessage* message, UByte* buffer, int size) +{ + memset(message, 0, sizeof(LatencyTestColorDetectedMessage)); + + if (size < 13) + { + message->Type = LatencyTestMessage_SizeError; + return false; + } + + switch (buffer[0]) + { + case LatencyTestMessage_ColorDetected: + message->Type = message->ColorDetected.Decode(buffer, size); + break; + + default: + message->Type = LatencyTestMessage_Unknown; + break; + } + + return (message->Type < LatencyTestMessage_Unknown) && (message->Type != LatencyTestMessage_None); +} + +struct LatencyTestStarted +{ + UInt16 CommandID; + UInt16 Timestamp; + UByte TargetValue[3]; + + LatencyTestMessageType Decode(const UByte* buffer, int size) + { + if (size < 8) + return LatencyTestMessage_SizeError; + + CommandID = DecodeUInt16(buffer + 1); + Timestamp = DecodeUInt16(buffer + 3); + memcpy(TargetValue, buffer + 5, 3); + + return LatencyTestMessage_TestStarted; + } +}; + +struct LatencyTestStartedMessage +{ + LatencyTestMessageType Type; + LatencyTestStarted TestStarted; +}; + +bool DecodeLatencyTestStartedMessage(LatencyTestStartedMessage* message, UByte* buffer, int size) +{ + memset(message, 0, sizeof(LatencyTestStartedMessage)); + + if (size < 8) + { + message->Type = LatencyTestMessage_SizeError; + return false; + } + + switch (buffer[0]) + { + case LatencyTestMessage_TestStarted: + message->Type = message->TestStarted.Decode(buffer, size); + break; + + default: + message->Type = LatencyTestMessage_Unknown; + break; + } + + return (message->Type < LatencyTestMessage_Unknown) && (message->Type != LatencyTestMessage_None); +} + +struct LatencyTestButton +{ + UInt16 CommandID; + UInt16 Timestamp; + + LatencyTestMessageType Decode(const UByte* buffer, int size) + { + if (size < 5) + return LatencyTestMessage_SizeError; + + CommandID = DecodeUInt16(buffer + 1); + Timestamp = DecodeUInt16(buffer + 3); + + return LatencyTestMessage_Button; + } +}; + +struct LatencyTestButtonMessage +{ + LatencyTestMessageType Type; + LatencyTestButton Button; +}; + +bool DecodeLatencyTestButtonMessage(LatencyTestButtonMessage* message, UByte* buffer, int size) +{ + memset(message, 0, sizeof(LatencyTestButtonMessage)); + + if (size < 5) + { + message->Type = LatencyTestMessage_SizeError; + return false; + } + + switch (buffer[0]) + { + case LatencyTestMessage_Button: + message->Type = message->Button.Decode(buffer, size); + break; + + default: + message->Type = LatencyTestMessage_Unknown; + break; + } + + return (message->Type < LatencyTestMessage_Unknown) && (message->Type != LatencyTestMessage_None); +} + +struct LatencyTestConfigurationImpl +{ + enum { PacketSize = 5 }; + UByte Buffer[PacketSize]; + + OVR::LatencyTestConfiguration Configuration; + + LatencyTestConfigurationImpl(const OVR::LatencyTestConfiguration& configuration) + : Configuration(configuration) + { + Pack(); + } + + void Pack() + { + Buffer[0] = 5; + Buffer[1] = UByte(Configuration.SendSamples); + Buffer[2] = Configuration.Threshold.R; + Buffer[3] = Configuration.Threshold.G; + Buffer[4] = Configuration.Threshold.B; + } + + void Unpack() + { + Configuration.SendSamples = Buffer[1] != 0 ? true : false; + Configuration.Threshold.R = Buffer[2]; + Configuration.Threshold.G = Buffer[3]; + Configuration.Threshold.B = Buffer[4]; + } +}; + +struct LatencyTestCalibrateImpl +{ + enum { PacketSize = 4 }; + UByte Buffer[PacketSize]; + + Color CalibrationColor; + + LatencyTestCalibrateImpl(const Color& calibrationColor) + : CalibrationColor(calibrationColor) + { + Pack(); + } + + void Pack() + { + Buffer[0] = 7; + Buffer[1] = CalibrationColor.R; + Buffer[2] = CalibrationColor.G; + Buffer[3] = CalibrationColor.B; + } + + void Unpack() + { + CalibrationColor.R = Buffer[1]; + CalibrationColor.G = Buffer[2]; + CalibrationColor.B = Buffer[3]; + } +}; + +struct LatencyTestStartTestImpl +{ + enum { PacketSize = 6 }; + UByte Buffer[PacketSize]; + + Color TargetColor; + + LatencyTestStartTestImpl(const Color& targetColor) + : TargetColor(targetColor) + { + Pack(); + } + + void Pack() + { + UInt16 commandID = 1; + + Buffer[0] = 8; + EncodeUInt16(Buffer+1, commandID); + Buffer[3] = TargetColor.R; + Buffer[4] = TargetColor.G; + Buffer[5] = TargetColor.B; + } + + void Unpack() + { +// UInt16 commandID = DecodeUInt16(Buffer+1); + TargetColor.R = Buffer[3]; + TargetColor.G = Buffer[4]; + TargetColor.B = Buffer[5]; + } +}; + +struct LatencyTestDisplayImpl +{ + enum { PacketSize = 6 }; + UByte Buffer[PacketSize]; + + OVR::LatencyTestDisplay Display; + + LatencyTestDisplayImpl(const OVR::LatencyTestDisplay& display) + : Display(display) + { + Pack(); + } + + void Pack() + { + Buffer[0] = 9; + Buffer[1] = Display.Mode; + EncodeUInt32(Buffer+2, Display.Value); + } + + void Unpack() + { + Display.Mode = Buffer[1]; + Display.Value = DecodeUInt32(Buffer+2); + } +}; + +//------------------------------------------------------------------------------------- +// ***** LatencyTestDeviceFactory + +LatencyTestDeviceFactory &LatencyTestDeviceFactory::GetInstance() +{ + static LatencyTestDeviceFactory instance; + return instance; +} + +void LatencyTestDeviceFactory::EnumerateDevices(EnumerateVisitor& visitor) +{ + + class LatencyTestEnumerator : public HIDEnumerateVisitor + { + // Assign not supported; suppress MSVC warning. + void operator = (const LatencyTestEnumerator&) { } + + DeviceFactory* pFactory; + EnumerateVisitor& ExternalVisitor; + public: + LatencyTestEnumerator(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) + { + OVR_UNUSED(device); + + LatencyTestDeviceCreateDesc createDesc(pFactory, desc); + ExternalVisitor.Visit(createDesc); + } + }; + + LatencyTestEnumerator latencyTestEnumerator(this, visitor); + GetManagerImpl()->GetHIDDeviceManager()->Enumerate(&latencyTestEnumerator); +} + +bool LatencyTestDeviceFactory::MatchVendorProduct(UInt16 vendorId, UInt16 productId) const +{ + return ((vendorId == LatencyTester_VendorId) && (productId == LatencyTester_ProductId)); +} + +bool LatencyTestDeviceFactory::DetectHIDDevice(DeviceManager* pdevMgr, + const HIDDeviceDesc& desc) +{ + if (MatchVendorProduct(desc.VendorId, desc.ProductId)) + { + LatencyTestDeviceCreateDesc createDesc(this, desc); + return pdevMgr->AddDevice_NeedsLock(createDesc).GetPtr() != NULL; + } + return false; +} + +//------------------------------------------------------------------------------------- +// ***** LatencyTestDeviceCreateDesc + +DeviceBase* LatencyTestDeviceCreateDesc::NewDeviceInstance() +{ + return new LatencyTestDeviceImpl(this); +} + +bool LatencyTestDeviceCreateDesc::GetDeviceInfo(DeviceInfo* info) const +{ + if ((info->InfoClassType != Device_LatencyTester) && + (info->InfoClassType != Device_None)) + return false; + + info->Type = Device_LatencyTester; + info->ProductName = HIDDesc.Product; + info->Manufacturer = HIDDesc.Manufacturer; + info->Version = HIDDesc.VersionNumber; + + if (info->InfoClassType == Device_LatencyTester) + { + SensorInfo* sinfo = (SensorInfo*)info; + sinfo->VendorId = HIDDesc.VendorId; + sinfo->ProductId = HIDDesc.ProductId; + sinfo->SerialNumber = HIDDesc.SerialNumber; + } + return true; +} + +//------------------------------------------------------------------------------------- +// ***** LatencyTestDevice + +LatencyTestDeviceImpl::LatencyTestDeviceImpl(LatencyTestDeviceCreateDesc* createDesc) + : OVR::HIDDeviceImpl<OVR::LatencyTestDevice>(createDesc, 0) +{ +} + +LatencyTestDeviceImpl::~LatencyTestDeviceImpl() +{ + // Check that Shutdown() was called. + OVR_ASSERT(!pCreateDesc->pDevice); +} + +// Internal creation APIs. +bool LatencyTestDeviceImpl::Initialize(DeviceBase* parent) +{ + if (HIDDeviceImpl<OVR::LatencyTestDevice>::Initialize(parent)) + { + LogText("OVR::LatencyTestDevice initialized.\n"); + return true; + } + + return false; +} + +void LatencyTestDeviceImpl::Shutdown() +{ + HIDDeviceImpl<OVR::LatencyTestDevice>::Shutdown(); + + LogText("OVR::LatencyTestDevice - Closed '%s'\n", getHIDDesc()->Path.ToCStr()); +} + +void LatencyTestDeviceImpl::OnInputReport(UByte* pData, UInt32 length) +{ + + bool processed = false; + if (!processed) + { + LatencyTestSamplesMessage message; + if (DecodeLatencyTestSamplesMessage(&message, pData, length)) + { + processed = true; + onLatencyTestSamplesMessage(&message); + } + } + + if (!processed) + { + LatencyTestColorDetectedMessage message; + if (DecodeLatencyTestColorDetectedMessage(&message, pData, length)) + { + processed = true; + onLatencyTestColorDetectedMessage(&message); + } + } + + if (!processed) + { + LatencyTestStartedMessage message; + if (DecodeLatencyTestStartedMessage(&message, pData, length)) + { + processed = true; + onLatencyTestStartedMessage(&message); + } + } + + if (!processed) + { + LatencyTestButtonMessage message; + if (DecodeLatencyTestButtonMessage(&message, pData, length)) + { + processed = true; + onLatencyTestButtonMessage(&message); + } + } +} + +bool LatencyTestDeviceImpl::SetConfiguration(const OVR::LatencyTestConfiguration& configuration, bool waitFlag) +{ + bool result = false; + ThreadCommandQueue* queue = GetManagerImpl()->GetThreadQueue(); + + if (GetManagerImpl()->GetThreadId() != OVR::GetCurrentThreadId()) + { + if (!waitFlag) + { + return queue->PushCall(this, &LatencyTestDeviceImpl::setConfiguration, configuration); + } + + if (!queue->PushCallAndWaitResult( this, + &LatencyTestDeviceImpl::setConfiguration, + &result, + configuration)) + { + return false; + } + } + else + return setConfiguration(configuration); + + return result; +} + +bool LatencyTestDeviceImpl::setConfiguration(const OVR::LatencyTestConfiguration& configuration) +{ + LatencyTestConfigurationImpl ltc(configuration); + return GetInternalDevice()->SetFeatureReport(ltc.Buffer, LatencyTestConfigurationImpl::PacketSize); +} + +bool LatencyTestDeviceImpl::GetConfiguration(OVR::LatencyTestConfiguration* configuration) +{ + bool result = false; + + ThreadCommandQueue* pQueue = this->GetManagerImpl()->GetThreadQueue(); + if (!pQueue->PushCallAndWaitResult(this, &LatencyTestDeviceImpl::getConfiguration, &result, configuration)) + return false; + + return result; +} + +bool LatencyTestDeviceImpl::getConfiguration(OVR::LatencyTestConfiguration* configuration) +{ + LatencyTestConfigurationImpl ltc(*configuration); + if (GetInternalDevice()->GetFeatureReport(ltc.Buffer, LatencyTestConfigurationImpl::PacketSize)) + { + ltc.Unpack(); + *configuration = ltc.Configuration; + return true; + } + + return false; +} + +bool LatencyTestDeviceImpl::SetCalibrate(const Color& calibrationColor, bool waitFlag) +{ + bool result = false; + ThreadCommandQueue* queue = GetManagerImpl()->GetThreadQueue(); + + if (!waitFlag) + { + return queue->PushCall(this, &LatencyTestDeviceImpl::setCalibrate, calibrationColor); + } + + if (!queue->PushCallAndWaitResult( this, + &LatencyTestDeviceImpl::setCalibrate, + &result, + calibrationColor)) + { + return false; + } + + return result; +} + +bool LatencyTestDeviceImpl::setCalibrate(const Color& calibrationColor) +{ + LatencyTestCalibrateImpl ltc(calibrationColor); + return GetInternalDevice()->SetFeatureReport(ltc.Buffer, LatencyTestCalibrateImpl::PacketSize); +} + +bool LatencyTestDeviceImpl::SetStartTest(const Color& targetColor, bool waitFlag) +{ + bool result = false; + ThreadCommandQueue* queue = GetManagerImpl()->GetThreadQueue(); + + if (!waitFlag) + { + return queue->PushCall(this, &LatencyTestDeviceImpl::setStartTest, targetColor); + } + + if (!queue->PushCallAndWaitResult( this, + &LatencyTestDeviceImpl::setStartTest, + &result, + targetColor)) + { + return false; + } + + return result; +} + +bool LatencyTestDeviceImpl::setStartTest(const Color& targetColor) +{ + LatencyTestStartTestImpl ltst(targetColor); + return GetInternalDevice()->SetFeatureReport(ltst.Buffer, LatencyTestStartTestImpl::PacketSize); +} + +bool LatencyTestDeviceImpl::SetDisplay(const OVR::LatencyTestDisplay& display, bool waitFlag) +{ + bool result = false; + ThreadCommandQueue * queue = GetManagerImpl()->GetThreadQueue(); + + if (!waitFlag) + { + return queue->PushCall(this, &LatencyTestDeviceImpl::setDisplay, display); + } + + if (!queue->PushCallAndWaitResult( this, + &LatencyTestDeviceImpl::setDisplay, + &result, + display)) + { + return false; + } + + return result; +} + +bool LatencyTestDeviceImpl::setDisplay(const OVR::LatencyTestDisplay& display) +{ + LatencyTestDisplayImpl ltd(display); + return GetInternalDevice()->SetFeatureReport(ltd.Buffer, LatencyTestDisplayImpl::PacketSize); +} + +void LatencyTestDeviceImpl::onLatencyTestSamplesMessage(LatencyTestSamplesMessage* message) +{ + + if (message->Type != LatencyTestMessage_Samples) + return; + + LatencyTestSamples& s = message->Samples; + + // Call OnMessage() within a lock to avoid conflicts with handlers. + Lock::Locker scopeLock(HandlerRef.GetLock()); + + if (HandlerRef.HasHandlers()) + { + MessageLatencyTestSamples samples(this); + for (UByte i = 0; i < s.SampleCount; i++) + { + samples.Samples.PushBack(Color(s.Samples[i].Value[0], s.Samples[i].Value[1], s.Samples[i].Value[2])); + } + + HandlerRef.Call(samples); + } +} + +void LatencyTestDeviceImpl::onLatencyTestColorDetectedMessage(LatencyTestColorDetectedMessage* message) +{ + if (message->Type != LatencyTestMessage_ColorDetected) + return; + + LatencyTestColorDetected& s = message->ColorDetected; + + // Call OnMessage() within a lock to avoid conflicts with handlers. + Lock::Locker scopeLock(HandlerRef.GetLock()); + + if (HandlerRef.HasHandlers()) + { + MessageLatencyTestColorDetected detected(this); + detected.Elapsed = s.Elapsed; + detected.DetectedValue = Color(s.TriggerValue[0], s.TriggerValue[1], s.TriggerValue[2]); + detected.TargetValue = Color(s.TargetValue[0], s.TargetValue[1], s.TargetValue[2]); + + HandlerRef.Call(detected); + } +} + +void LatencyTestDeviceImpl::onLatencyTestStartedMessage(LatencyTestStartedMessage* message) +{ + if (message->Type != LatencyTestMessage_TestStarted) + return; + + LatencyTestStarted& ts = message->TestStarted; + + // Call OnMessage() within a lock to avoid conflicts with handlers. + Lock::Locker scopeLock(HandlerRef.GetLock()); + + if (HandlerRef.HasHandlers()) + { + MessageLatencyTestStarted started(this); + started.TargetValue = Color(ts.TargetValue[0], ts.TargetValue[1], ts.TargetValue[2]); + + HandlerRef.Call(started); + } +} + +void LatencyTestDeviceImpl::onLatencyTestButtonMessage(LatencyTestButtonMessage* message) +{ + if (message->Type != LatencyTestMessage_Button) + return; + +// LatencyTestButton& s = message->Button; + + // Call OnMessage() within a lock to avoid conflicts with handlers. + Lock::Locker scopeLock(HandlerRef.GetLock()); + + if (HandlerRef.HasHandlers()) + { + MessageLatencyTestButton button(this); + + HandlerRef.Call(button); + } +} + +} // namespace OVR |