diff options
author | Brad Davis <[email protected]> | 2014-05-23 02:01:10 -0700 |
---|---|---|
committer | Brad Davis <[email protected]> | 2014-05-23 02:01:10 -0700 |
commit | ca79271759ff7eecd22ec5c4db438370fe51d687 (patch) | |
tree | 952f1ab2378ca9bd2aa3e3fb38a746cd824f9373 /LibOVR/Src | |
parent | 1393f96fa857a59ca495e51ce8c704eb36e3eed7 (diff) |
Adding 0.3.2 OSX files
Diffstat (limited to 'LibOVR/Src')
-rw-r--r-- | LibOVR/Src/OVR_OSX_DeviceManager.cpp | 360 | ||||
-rw-r--r-- | LibOVR/Src/OVR_OSX_DeviceManager.h | 128 | ||||
-rw-r--r-- | LibOVR/Src/OVR_OSX_HIDDevice.cpp | 924 | ||||
-rw-r--r-- | LibOVR/Src/OVR_OSX_HIDDevice.h | 160 | ||||
-rw-r--r-- | LibOVR/Src/OVR_OSX_HMDDevice.cpp | 264 | ||||
-rw-r--r-- | LibOVR/Src/OVR_OSX_HMDDevice.h | 153 | ||||
-rw-r--r-- | LibOVR/Src/OVR_OSX_SensorDevice.cpp | 58 |
7 files changed, 2047 insertions, 0 deletions
diff --git a/LibOVR/Src/OVR_OSX_DeviceManager.cpp b/LibOVR/Src/OVR_OSX_DeviceManager.cpp new file mode 100644 index 0000000..078936a --- /dev/null +++ b/LibOVR/Src/OVR_OSX_DeviceManager.cpp @@ -0,0 +1,360 @@ +/************************************************************************************ + +Filename : OVR_OSX_DeviceManager.cpp +Content : OSX specific DeviceManager implementation. +Created : March 14, 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_OSX_DeviceManager.h" + +// Sensor & HMD Factories +#include "OVR_LatencyTestImpl.h" +#include "OVR_SensorImpl.h" +#include "OVR_OSX_HMDDevice.h" +#include "OVR_OSX_HIDDevice.h" + +#include "Kernel/OVR_Timer.h" +#include "Kernel/OVR_Std.h" +#include "Kernel/OVR_Log.h" + +#include <IOKit/hid/IOHIDManager.h> +#include <IOKit/hid/IOHIDKeys.h> + + +namespace OVR { namespace OSX { + +//------------------------------------------------------------------------------------- +// **** OSX::DeviceManager + +DeviceManager::DeviceManager() +{ +} + +DeviceManager::~DeviceManager() +{ + OVR_DEBUG_LOG(("OSX::DeviceManager::~DeviceManager was called")); +} + +bool DeviceManager::Initialize(DeviceBase*) +{ + if (!DeviceManagerImpl::Initialize(0)) + return false; + + // Start the background thread. + pThread = *new DeviceManagerThread(); + if (!pThread || !pThread->Start()) + return false; + + // Wait for the thread to be fully up and running. + pThread->StartupEvent.Wait(); + + // Do this now that we know the thread's run loop. + HidDeviceManager = *HIDDeviceManager::CreateInternal(this); + + CGDisplayRegisterReconfigurationCallback(displayReconfigurationCallBack, this); + + pCreateDesc->pDevice = this; + LogText("OVR::DeviceManager - initialized.\n"); + + return true; +} + +void DeviceManager::Shutdown() +{ + LogText("OVR::DeviceManager - shutting down.\n"); + + CGDisplayRemoveReconfigurationCallback(displayReconfigurationCallBack, this); + + // Set Manager shutdown marker variable; this prevents + // any existing DeviceHandle objects from accessing device. + pCreateDesc->pLock->pManager = 0; + + // Push for thread shutdown *WITH NO WAIT*. + // This will have the following effect: + // - Exit command will get enqueued, which will be executed later on the thread itself. + // - Beyond this point, this DeviceManager object may be deleted by our caller. + // - Other commands, such as CreateDevice, may execute before ExitCommand, but they will + // fail gracefully due to pLock->pManager == 0. Future commands can't be enqued + // after pManager is null. + // - Once ExitCommand executes, ThreadCommand::Run loop will exit and release the last + // reference to the thread object. + pThread->Shutdown(); + pThread.Clear(); + + DeviceManagerImpl::Shutdown(); +} + +ThreadCommandQueue* DeviceManager::GetThreadQueue() +{ + return pThread; +} + +ThreadId DeviceManager::GetThreadId() const +{ + return pThread->GetThreadId(); +} + +bool DeviceManager::GetDeviceInfo(DeviceInfo* info) const +{ + if ((info->InfoClassType != Device_Manager) && + (info->InfoClassType != Device_None)) + return false; + + info->Type = Device_Manager; + info->Version = 0; + info->ProductName = "DeviceManager"; + info->Manufacturer = "Oculus VR, Inc."; + return true; +} + +DeviceEnumerator<> DeviceManager::EnumerateDevicesEx(const DeviceEnumerationArgs& args) +{ + // TBD: Can this be avoided in the future, once proper device notification is in place? + pThread->PushCall((DeviceManagerImpl*)this, + &DeviceManager::EnumerateAllFactoryDevices, true); + + return DeviceManagerImpl::EnumerateDevicesEx(args); +} + +void DeviceManager::displayReconfigurationCallBack (CGDirectDisplayID display, + CGDisplayChangeSummaryFlags flags, + void *userInfo) +{ + DeviceManager* manager = reinterpret_cast<DeviceManager*>(userInfo); + OVR_UNUSED(manager); + + if (flags & kCGDisplayAddFlag) + { + LogText("Display Added, id = %d\n", int(display)); + manager->EnumerateDevices<HMDDevice>(); + } + else if (flags & kCGDisplayRemoveFlag) + { + LogText("Display Removed, id = %d\n", int(display)); + manager->EnumerateDevices<HMDDevice>(); + } +} + +//------------------------------------------------------------------------------------- +// ***** DeviceManager Thread + +DeviceManagerThread::DeviceManagerThread() + : Thread(ThreadStackSize) +{ +} + +DeviceManagerThread::~DeviceManagerThread() +{ +} + +int DeviceManagerThread::Run() +{ + + SetThreadName("OVR::DeviceManagerThread"); + LogText("OVR::DeviceManagerThread - running (ThreadId=0x%p).\n", GetThreadId()); + + // Store out the run loop ref. + RunLoop = CFRunLoopGetCurrent(); + + // Create a 'source' to enable us to signal the run loop to process the command queue. + CFRunLoopSourceContext sourceContext; + memset(&sourceContext, 0, sizeof(sourceContext)); + sourceContext.version = 0; + sourceContext.info = this; + sourceContext.perform = &staticCommandQueueSourceCallback; + + CommandQueueSource = CFRunLoopSourceCreate(kCFAllocatorDefault, 0 , &sourceContext); + + CFRunLoopAddSource(RunLoop, CommandQueueSource, kCFRunLoopDefaultMode); + + + // Signal to the parent thread that initialization has finished. + StartupEvent.SetEvent(); + + + ThreadCommand::PopBuffer command; + + while(!IsExiting()) + { + // PopCommand will reset event on empty queue. + if (PopCommand(&command)) + { + command.Execute(); + } + else + { + SInt32 exitReason = 0; + do { + + UInt32 waitMs = INT_MAX; + + // If devices have time-dependent logic registered, get the longest wait + // allowed based on current ticks. + if (!TicksNotifiers.IsEmpty()) + { + double timeSeconds = Timer::GetSeconds(); + unsigned waitAllowed; + + for (UPInt j = 0; j < TicksNotifiers.GetSize(); j++) + { + waitAllowed = (unsigned)(TicksNotifiers[j]->OnTicks(timeSeconds) * Timer::MsPerSecond); + if (waitAllowed < (unsigned)waitMs) + waitMs = waitAllowed; + } + } + + // Enter blocking run loop. We may continue until we timeout in which + // case it's time to service the ticks. Or if commands arrive in the command + // queue then the source callback will call 'CFRunLoopStop' causing this + // to return. + CFTimeInterval blockInterval = 0.001 * (double) waitMs; + exitReason = CFRunLoopRunInMode(kCFRunLoopDefaultMode, blockInterval, false); + + if (exitReason == kCFRunLoopRunFinished) + { + // Maybe this will occur during shutdown? + break; + } + else if (exitReason == kCFRunLoopRunStopped ) + { + // Commands need processing or we're being shutdown. + break; + } + else if (exitReason == kCFRunLoopRunTimedOut) + { + // Timed out so that we can service our ticks callbacks. + continue; + } + else if (exitReason == kCFRunLoopRunHandledSource) + { + // Should never occur since the last param when we call + // 'CFRunLoopRunInMode' is false. + OVR_ASSERT(false); + break; + } + else + { + OVR_ASSERT_LOG(false, ("CFRunLoopRunInMode returned unexpected code")); + break; + } + } + while(true); + } + } + + + CFRunLoopRemoveSource(RunLoop, CommandQueueSource, kCFRunLoopDefaultMode); + CFRelease(CommandQueueSource); + + LogText("OVR::DeviceManagerThread - exiting (ThreadId=0x%p).\n", GetThreadId()); + + return 0; +} + +void DeviceManagerThread::staticCommandQueueSourceCallback(void* pContext) +{ + DeviceManagerThread* pThread = (DeviceManagerThread*) pContext; + pThread->commandQueueSourceCallback(); +} + +void DeviceManagerThread::commandQueueSourceCallback() +{ + CFRunLoopStop(RunLoop); +} + +bool DeviceManagerThread::AddTicksNotifier(Notifier* notify) +{ + TicksNotifiers.PushBack(notify); + return true; +} + +bool DeviceManagerThread::RemoveTicksNotifier(Notifier* notify) +{ + for (UPInt i = 0; i < TicksNotifiers.GetSize(); i++) + { + if (TicksNotifiers[i] == notify) + { + TicksNotifiers.RemoveAt(i); + return true; + } + } + return false; +} + +void DeviceManagerThread::Shutdown() +{ + // Push for thread shutdown *WITH NO WAIT*. + // This will have the following effect: + // - Exit command will get enqueued, which will be executed later on the thread itself. + // - Beyond this point, this DeviceManager object may be deleted by our caller. + // - Other commands, such as CreateDevice, may execute before ExitCommand, but they will + // fail gracefully due to pLock->pManager == 0. Future commands can't be enqued + // after pManager is null. + // - Once ExitCommand executes, ThreadCommand::Run loop will exit and release the last + // reference to the thread object. + PushExitCommand(false); + + // make sure CFRunLoopRunInMode is woken up + CFRunLoopSourceSignal(CommandQueueSource); + CFRunLoopWakeUp(RunLoop); +} + +} // namespace OSX + + +//------------------------------------------------------------------------------------- +// ***** Creation + +// Creates a new DeviceManager and initializes OVR. +DeviceManager* DeviceManager::Create() +{ + + if (!System::IsInitialized()) + { + // Use custom message, since Log is not yet installed. + OVR_DEBUG_STATEMENT(Log::GetDefaultLog()-> + LogMessage(Log_Debug, "DeviceManager::Create failed - OVR::System not initialized"); ); + return 0; + } + + Ptr<OSX::DeviceManager> manager = *new OSX::DeviceManager; + + if (manager) + { + if (manager->Initialize(0)) + { + manager->AddFactory(&LatencyTestDeviceFactory::GetInstance()); + manager->AddFactory(&SensorDeviceFactory::GetInstance()); + manager->AddFactory(&OSX::HMDDeviceFactory::GetInstance()); + + manager->AddRef(); + } + else + { + manager.Clear(); + } + } + + return manager.GetPtr(); +} + +} // namespace OVR diff --git a/LibOVR/Src/OVR_OSX_DeviceManager.h b/LibOVR/Src/OVR_OSX_DeviceManager.h new file mode 100644 index 0000000..61af848 --- /dev/null +++ b/LibOVR/Src/OVR_OSX_DeviceManager.h @@ -0,0 +1,128 @@ +/************************************************************************************ + +Filename : OVR_OSX_DeviceManager.h +Content : OSX specific DeviceManager header. +Created : March 14, 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. + +*************************************************************************************/ + +#ifndef OVR_OSX_DeviceManager_h +#define OVR_OSX_DeviceManager_h + +#include "OVR_DeviceImpl.h" + +#include "Kernel/OVR_Timer.h" + +#include <ApplicationServices/ApplicationServices.h> +#include <IOKit/hid/IOHIDManager.h> + +namespace OVR { namespace OSX { + +class DeviceManagerThread; + +//------------------------------------------------------------------------------------- +// ***** OSX DeviceManager + +class DeviceManager : public DeviceManagerImpl +{ +public: + DeviceManager(); + ~DeviceManager(); + + // Initialize/Shutdown manager thread. + virtual bool Initialize(DeviceBase* parent); + virtual void Shutdown(); + + virtual ThreadCommandQueue* GetThreadQueue(); + virtual ThreadId GetThreadId() const; + + virtual DeviceEnumerator<> EnumerateDevicesEx(const DeviceEnumerationArgs& args); + + virtual bool GetDeviceInfo(DeviceInfo* info) const; + +protected: + static void displayReconfigurationCallBack (CGDirectDisplayID display, + CGDisplayChangeSummaryFlags flags, + void *userInfo); + +public: // data + Ptr<DeviceManagerThread> pThread; +}; + +//------------------------------------------------------------------------------------- +// ***** Device Manager Background Thread + +class DeviceManagerThread : public Thread, public ThreadCommandQueue +{ + friend class DeviceManager; + enum { ThreadStackSize = 32 * 1024 }; +public: + DeviceManagerThread(); + ~DeviceManagerThread(); + + virtual int Run(); + + // ThreadCommandQueue notifications for CommandEvent handling. + virtual void OnPushNonEmpty_Locked() + { + CFRunLoopSourceSignal(CommandQueueSource); + CFRunLoopWakeUp(RunLoop); + } + + virtual void OnPopEmpty_Locked() {} + + + // Notifier used for different updates (EVENT or regular timing or messages). + class Notifier + { + public: + + // Called when timing ticks are updated. // Returns the largest number of microseconds + // this function can wait till next call. + virtual double OnTicks(double tickSeconds) + { OVR_UNUSED1(tickSeconds); return 1000.0; } + }; + + // Add notifier that will be called at regular intervals. + bool AddTicksNotifier(Notifier* notify); + bool RemoveTicksNotifier(Notifier* notify); + + CFRunLoopRef GetRunLoop() + { return RunLoop; } + + void Shutdown(); +private: + CFRunLoopRef RunLoop; + + CFRunLoopSourceRef CommandQueueSource; + + static void staticCommandQueueSourceCallback(void* pContext); + void commandQueueSourceCallback(); + + Event StartupEvent; + + // Ticks notifiers. Used for time-dependent events such as keep-alive. + Array<Notifier*> TicksNotifiers; +}; + +}} // namespace OSX::OVR + +#endif // OVR_OSX_DeviceManager_h diff --git a/LibOVR/Src/OVR_OSX_HIDDevice.cpp b/LibOVR/Src/OVR_OSX_HIDDevice.cpp new file mode 100644 index 0000000..af840e0 --- /dev/null +++ b/LibOVR/Src/OVR_OSX_HIDDevice.cpp @@ -0,0 +1,924 @@ +/************************************************************************************ +Filename : OVR_OSX_HIDDevice.cpp +Content : OSX HID device implementation. +Created : February 26, 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_OSX_HIDDevice.h" + +#include <IOKit/usb/IOUSBLib.h> + +namespace OVR { namespace OSX { + + +//------------------------------------------------------------------------------------- +// **** OSX::DeviceManager + +HIDDeviceManager::HIDDeviceManager(DeviceManager* manager) + : DevManager(manager) +{ + HIDManager = NULL; +} + +HIDDeviceManager::~HIDDeviceManager() +{ +} + +CFRunLoopRef HIDDeviceManager::getRunLoop() +{ + if (DevManager != NULL) + { + return DevManager->pThread->GetRunLoop(); + } + + return CFRunLoopGetCurrent(); +} + +bool HIDDeviceManager::initializeManager() +{ + if (HIDManager != NULL) + { + return true; + } + + HIDManager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone); + + if (!HIDManager) + { + return false; + } + + // Create a Matching Dictionary + CFMutableDictionaryRef matchDict = + CFDictionaryCreateMutable(kCFAllocatorDefault, + 2, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + + // Specify a device manufacturer in the Matching Dictionary + UInt32 vendorId = Oculus_VendorId; + CFNumberRef vendorIdRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &vendorId); + CFDictionarySetValue(matchDict, + CFSTR(kIOHIDVendorIDKey), + vendorIdRef); + // Register the Matching Dictionary to the HID Manager + IOHIDManagerSetDeviceMatching(HIDManager, matchDict); + CFRelease(vendorIdRef); + CFRelease(matchDict); + + // Register a callback for USB device detection with the HID Manager + IOHIDManagerRegisterDeviceMatchingCallback(HIDManager, &staticDeviceMatchingCallback, this); + + IOHIDManagerScheduleWithRunLoop(HIDManager, getRunLoop(), kCFRunLoopDefaultMode); + + return true; +} + +bool HIDDeviceManager::Initialize() +{ + return initializeManager(); +} + +void HIDDeviceManager::Shutdown() +{ + OVR_ASSERT_LOG(HIDManager, ("Should have called 'Initialize' before 'Shutdown'.")); + CFRelease(HIDManager); + + LogText("OVR::OSX::HIDDeviceManager - shutting down.\n"); +} + +bool HIDDeviceManager::getIntProperty(IOHIDDeviceRef device, CFStringRef propertyName, SInt32* pResult) +{ + + CFTypeRef ref = IOHIDDeviceGetProperty(device, propertyName); + + if (!ref) + { + return false; + } + + if (CFGetTypeID(ref) != CFNumberGetTypeID()) + { + return false; + } + + CFNumberGetValue((CFNumberRef) ref, kCFNumberSInt32Type, pResult); + + return true; +} + +bool HIDDeviceManager::initVendorProductVersion(IOHIDDeviceRef device, HIDDeviceDesc* pDevDesc) +{ + + if (!getVendorId(device, &(pDevDesc->VendorId))) + { + return false; + } + + if (!getProductId(device, &(pDevDesc->ProductId))) + { + return false; + } + + SInt32 result; + if (!getIntProperty(device, CFSTR(kIOHIDVersionNumberKey), &result)) + { + return false; + } + pDevDesc->VersionNumber = result; + + return true; +} + +bool HIDDeviceManager::initUsage(IOHIDDeviceRef device, HIDDeviceDesc* pDevDesc) +{ + + SInt32 result; + + if (!getIntProperty(device, CFSTR(kIOHIDPrimaryUsagePageKey), &result)) + { + return false; + } + + pDevDesc->UsagePage = result; + + + if (!getIntProperty(device, CFSTR(kIOHIDPrimaryUsageKey), &result)) + { + return false; + } + + pDevDesc->Usage = result; + + return true; +} + +bool HIDDeviceManager::initSerialNumber(IOHIDDeviceRef device, HIDDeviceDesc* pDevDesc) +{ + return getSerialNumberString(device, &(pDevDesc->SerialNumber)); +} + +bool HIDDeviceManager::initStrings(IOHIDDeviceRef device, HIDDeviceDesc* pDevDesc) +{ + + // Regardless of whether they fail we'll try and get the remaining. + getStringProperty(device, CFSTR(kIOHIDManufacturerKey), &(pDevDesc->Manufacturer)); + getStringProperty(device, CFSTR(kIOHIDProductKey), &(pDevDesc->Product)); + + return true; +} + +bool HIDDeviceManager::getStringProperty(IOHIDDeviceRef device, + CFStringRef propertyName, + String* pResult) +{ + + CFStringRef str = (CFStringRef) IOHIDDeviceGetProperty(device, propertyName); + + if (!str) + { + return false; + } + + CFIndex length = CFStringGetLength(str); + CFRange range = CFRangeMake(0, length); + + // Test the conversion first to get required buffer size. + CFIndex bufferLength; + CFIndex numberOfChars = CFStringGetBytes(str, + range, + kCFStringEncodingUTF8, + (char) '?', + FALSE, + NULL, + 0, + &bufferLength); + + if (numberOfChars == 0) + { + return false; + } + + // Now allocate buffer. + char* buffer = new char[bufferLength+1]; + + numberOfChars = CFStringGetBytes(str, + range, + kCFStringEncodingUTF8, + (char) '?', + FALSE, + (UInt8*) buffer, + bufferLength, + NULL); + OVR_ASSERT_LOG(numberOfChars != 0, ("CFStringGetBytes failed.")); + + buffer[bufferLength] = '\0'; + *pResult = String(buffer); + + return true; +} + +bool HIDDeviceManager::getVendorId(IOHIDDeviceRef device, UInt16* pResult) +{ + SInt32 result; + + if (!getIntProperty(device, CFSTR(kIOHIDVendorIDKey), &result)) + { + return false; + } + + *pResult = result; + + return true; +} + +bool HIDDeviceManager::getProductId(IOHIDDeviceRef device, UInt16* pResult) +{ + SInt32 result; + + if (!getIntProperty(device, CFSTR(kIOHIDProductIDKey), &result)) + { + return false; + } + + *pResult = result; + + return true; +} + +bool HIDDeviceManager::getLocationId(IOHIDDeviceRef device, SInt32* pResult) +{ + SInt32 result; + + if (!getIntProperty(device, CFSTR(kIOHIDLocationIDKey), &result)) + { + return false; + } + + *pResult = result; + + return true; +} + +bool HIDDeviceManager::getSerialNumberString(IOHIDDeviceRef device, String* pResult) +{ + + if (!getStringProperty(device, CFSTR(kIOHIDSerialNumberKey), pResult)) + { + return false; + } + + return true; +} + +bool HIDDeviceManager::getPath(IOHIDDeviceRef device, String* pPath) +{ + + String transport; + if (!getStringProperty(device, CFSTR(kIOHIDTransportKey), &transport)) + { + return false; + } + + UInt16 vendorId; + if (!getVendorId(device, &vendorId)) + { + return false; + } + + UInt16 productId; + if (!getProductId(device, &productId)) + { + return false; + } + + String serialNumber; + if (!getSerialNumberString(device, &serialNumber)) + { + return false; + } + + + StringBuffer buffer; + buffer.AppendFormat("%s:vid=%04hx:pid=%04hx:ser=%s", + transport.ToCStr(), + vendorId, + productId, + serialNumber.ToCStr()); + + *pPath = String(buffer); + + return true; +} + +bool HIDDeviceManager::Enumerate(HIDEnumerateVisitor* enumVisitor) +{ + if (!initializeManager()) + { + return false; + } + + + CFSetRef deviceSet = IOHIDManagerCopyDevices(HIDManager); + if (!deviceSet) + return false; + + CFIndex deviceCount = CFSetGetCount(deviceSet); + + // Allocate a block of memory and read the set into it. + IOHIDDeviceRef* devices = (IOHIDDeviceRef*) OVR_ALLOC(sizeof(IOHIDDeviceRef) * deviceCount); + CFSetGetValues(deviceSet, (const void **) devices); + + + // Iterate over devices. + for (CFIndex deviceIndex = 0; deviceIndex < deviceCount; deviceIndex++) + { + IOHIDDeviceRef hidDev = devices[deviceIndex]; + + if (!hidDev) + { + continue; + } + + HIDDeviceDesc devDesc; + + if (getPath(hidDev, &(devDesc.Path)) && + initVendorProductVersion(hidDev, &devDesc) && + enumVisitor->MatchVendorProduct(devDesc.VendorId, devDesc.ProductId) && + initUsage(hidDev, &devDesc)) + { + initStrings(hidDev, &devDesc); + initSerialNumber(hidDev, &devDesc); + + // Look for the device to check if it is already opened. + Ptr<DeviceCreateDesc> existingDevice = DevManager->FindHIDDevice(devDesc, true); + // if device exists and it is opened then most likely the CreateHIDFile + // will fail; therefore, we just set Enumerated to 'true' and continue. + if (existingDevice && existingDevice->pDevice) + { + existingDevice->Enumerated = true; + continue; + } + + // Construct minimal device that the visitor callback can get feature reports from. + OSX::HIDDevice device(this, hidDev); + + enumVisitor->Visit(device, devDesc); + } + } + + OVR_FREE(devices); + CFRelease(deviceSet); + + return true; +} + +OVR::HIDDevice* HIDDeviceManager::Open(const String& path) +{ + + Ptr<OSX::HIDDevice> device = *new OSX::HIDDevice(this); + + if (!device->HIDInitialize(path)) + { + return NULL; + } + + device->AddRef(); + + return device; +} + +bool HIDDeviceManager::getFullDesc(IOHIDDeviceRef device, HIDDeviceDesc* desc) +{ + + if (!initVendorProductVersion(device, desc)) + { + return false; + } + + if (!initUsage(device, desc)) + { + return false; + } + + if (!initSerialNumber(device, desc)) + { + return false; + } + + initStrings(device, desc); + + return true; +} + +// New USB device specified in the matching dictionary has been added (callback function) +void HIDDeviceManager::staticDeviceMatchingCallback(void *inContext, + IOReturn inResult, + void *inSender, + IOHIDDeviceRef inIOHIDDeviceRef) +{ + OVR_UNUSED(inResult); + OVR_UNUSED(inSender); + HIDDeviceManager* hidMgr = static_cast<HIDDeviceManager*>(inContext); + HIDDeviceDesc hidDevDesc; + hidMgr->getPath(inIOHIDDeviceRef, &hidDevDesc.Path); + hidMgr->getFullDesc(inIOHIDDeviceRef, &hidDevDesc); + + hidMgr->DevManager->DetectHIDDevice(hidDevDesc); +} + +//------------------------------------------------------------------------------------- +// **** OSX::HIDDevice + +HIDDevice::HIDDevice(HIDDeviceManager* manager) + : InMinimalMode(false), HIDManager(manager) +{ + Device = NULL; + RepluggedNotificationPort = 0; +} + +// This is a minimal constructor used during enumeration for us to pass +// a HIDDevice to the visit function (so that it can query feature reports). +HIDDevice::HIDDevice(HIDDeviceManager* manager, IOHIDDeviceRef device) +: InMinimalMode(true), HIDManager(manager), Device(device) +{ + RepluggedNotificationPort = 0; +} + +HIDDevice::~HIDDevice() +{ + if (!InMinimalMode) + { + HIDShutdown(); + } +} + +bool HIDDevice::HIDInitialize(const String& path) +{ + + DevDesc.Path = path; + + if (!openDevice()) + { + LogText("OVR::OSX::HIDDevice - Failed to open HIDDevice: %s", path.ToCStr()); + return false; + } + + // Setup notification for when a device is unplugged and plugged back in. + if (!setupDevicePluggedInNotification()) + { + LogText("OVR::OSX::HIDDevice - Failed to setup notification for when device plugged back in."); + closeDevice(false); + return false; + } + + HIDManager->DevManager->pThread->AddTicksNotifier(this); + + + LogText("OVR::OSX::HIDDevice - Opened '%s'\n" + " Manufacturer:'%s' Product:'%s' Serial#:'%s'\n", + DevDesc.Path.ToCStr(), + DevDesc.Manufacturer.ToCStr(), DevDesc.Product.ToCStr(), + DevDesc.SerialNumber.ToCStr()); + + return true; +} + +bool HIDDevice::initInfo() +{ + // Device must have been successfully opened. + OVR_ASSERT(Device); + + + // Get report lengths. + SInt32 bufferLength; + bool getResult = HIDManager->getIntProperty(Device, CFSTR(kIOHIDMaxInputReportSizeKey), &bufferLength); + OVR_ASSERT(getResult); + InputReportBufferLength = (UInt16) bufferLength; + + getResult = HIDManager->getIntProperty(Device, CFSTR(kIOHIDMaxOutputReportSizeKey), &bufferLength); + OVR_ASSERT(getResult); + OutputReportBufferLength = (UInt16) bufferLength; + + getResult = HIDManager->getIntProperty(Device, CFSTR(kIOHIDMaxFeatureReportSizeKey), &bufferLength); + OVR_ASSERT(getResult); + FeatureReportBufferLength = (UInt16) bufferLength; + + + if (ReadBufferSize < InputReportBufferLength) + { + OVR_ASSERT_LOG(false, ("Input report buffer length is bigger than read buffer.")); + return false; + } + + // Get device desc. + if (!HIDManager->getFullDesc(Device, &DevDesc)) + { + OVR_ASSERT_LOG(false, ("Failed to get device desc while initializing device.")); + return false; + } + + return true; +} + +void HIDDevice::staticDeviceAddedCallback(void* pContext, io_iterator_t iterator) +{ + HIDDevice* pDevice = (HIDDevice*) pContext; + pDevice->deviceAddedCallback(iterator); +} + +void HIDDevice::deviceAddedCallback(io_iterator_t iterator) +{ + + if (Device == NULL) + { + if (openDevice()) + { + LogText("OVR::OSX::HIDDevice - Reopened device : %s", DevDesc.Path.ToCStr()); + + Ptr<DeviceCreateDesc> existingHIDDev = HIDManager->DevManager->FindHIDDevice(DevDesc, true); + if (existingHIDDev && existingHIDDev->pDevice) + { + HIDManager->DevManager->CallOnDeviceAdded(existingHIDDev); + } + } + } + + // Reset callback. + while (IOIteratorNext(iterator)) + ; +} + +bool HIDDevice::openDevice() +{ + + // Have to iterate through devices again to generate paths. + CFSetRef deviceSet = IOHIDManagerCopyDevices(HIDManager->HIDManager); + CFIndex deviceCount = CFSetGetCount(deviceSet); + + // Allocate a block of memory and read the set into it. + IOHIDDeviceRef* devices = (IOHIDDeviceRef*) OVR_ALLOC(sizeof(IOHIDDeviceRef) * deviceCount); + CFSetGetValues(deviceSet, (const void **) devices); + + + // Iterate over devices. + IOHIDDeviceRef device = NULL; + + for (CFIndex deviceIndex = 0; deviceIndex < deviceCount; deviceIndex++) + { + IOHIDDeviceRef tmpDevice = devices[deviceIndex]; + + if (!tmpDevice) + { + continue; + } + + String path; + if (!HIDManager->getPath(tmpDevice, &path)) + { + continue; + } + + if (path == DevDesc.Path) + { + device = tmpDevice; + break; + } + } + + + OVR_FREE(devices); + + if (!device) + { + CFRelease(deviceSet); + return false; + } + + // Attempt to open device. + if (IOHIDDeviceOpen(device, kIOHIDOptionsTypeSeizeDevice) + != kIOReturnSuccess) + { + CFRelease(deviceSet); + return false; + } + + // Retain the device before we release the set. + CFRetain(device); + CFRelease(deviceSet); + + + Device = device; + + + if (!initInfo()) + { + IOHIDDeviceClose(Device, kIOHIDOptionsTypeSeizeDevice); + CFRelease(Device); + Device = NULL; + return false; + } + + + // Setup the Run Loop and callbacks. + IOHIDDeviceScheduleWithRunLoop(Device, + HIDManager->getRunLoop(), + kCFRunLoopDefaultMode); + + IOHIDDeviceRegisterInputReportCallback(Device, + ReadBuffer, + ReadBufferSize, + staticHIDReportCallback, + this); + + IOHIDDeviceRegisterRemovalCallback(Device, + staticDeviceRemovedCallback, + this); + + return true; +} + +void HIDDevice::HIDShutdown() +{ + + HIDManager->DevManager->pThread->RemoveTicksNotifier(this); + + if (Device != NULL) // Device may already have been closed if unplugged. + { + closeDevice(false); + } + + IOObjectRelease(RepluggedNotification); + if (RepluggedNotificationPort) + IONotificationPortDestroy(RepluggedNotificationPort); + + LogText("OVR::OSX::HIDDevice - HIDShutdown '%s'\n", DevDesc.Path.ToCStr()); +} + +bool HIDDevice::setupDevicePluggedInNotification() +{ + + // Setup notification when devices are plugged in. + RepluggedNotificationPort = IONotificationPortCreate(kIOMasterPortDefault); + + CFRunLoopSourceRef notificationRunLoopSource = + IONotificationPortGetRunLoopSource(RepluggedNotificationPort); + + CFRunLoopAddSource(HIDManager->getRunLoop(), + notificationRunLoopSource, + kCFRunLoopDefaultMode); + + CFMutableDictionaryRef matchingDict = IOServiceMatching(kIOUSBDeviceClassName); + + // Have to specify vendorId and productId. Doesn't seem to accept additional + // things like serial number. + SInt32 vendorId = DevDesc.VendorId; + CFNumberRef numberRef = CFNumberCreate(kCFAllocatorDefault, + kCFNumberSInt32Type, + &vendorId); + CFDictionarySetValue(matchingDict, CFSTR(kUSBVendorID), numberRef); + CFRelease(numberRef); + + SInt32 deviceProductId = DevDesc.ProductId; + numberRef = CFNumberCreate(kCFAllocatorDefault, + kCFNumberSInt32Type, + &deviceProductId); + CFDictionarySetValue(matchingDict, CFSTR(kUSBProductID), numberRef); + CFRelease(numberRef); + + kern_return_t result = + IOServiceAddMatchingNotification(RepluggedNotificationPort, + kIOMatchedNotification, + matchingDict, + staticDeviceAddedCallback, + this, + &RepluggedNotification); + + if (result != KERN_SUCCESS) + { + CFRelease(RepluggedNotificationPort); + RepluggedNotificationPort = 0; + return false; + } + + // Iterate through to arm. + while (IOIteratorNext(RepluggedNotification)) + { + } + + return true; +} + +void HIDDevice::closeDevice(bool wasUnplugged) +{ + OVR_ASSERT(Device != NULL); + + if (!wasUnplugged) + { + // Clear the registered callbacks. + IOHIDDeviceRegisterInputReportCallback(Device, + ReadBuffer, + InputReportBufferLength, + NULL, + this); + + IOHIDDeviceRegisterRemovalCallback(Device, NULL, this); + + IOHIDDeviceUnscheduleFromRunLoop(Device, + HIDManager->getRunLoop(), + kCFRunLoopDefaultMode); + IOHIDDeviceClose(Device, kIOHIDOptionsTypeNone); + } + + CFRelease(Device); + Device = NULL; + + LogText("OVR::OSX::HIDDevice - HID Device Closed '%s'\n", DevDesc.Path.ToCStr()); +} + +void HIDDevice::staticHIDReportCallback(void* pContext, + IOReturn result, + void* pSender, + IOHIDReportType reportType, + uint32_t reportId, + uint8_t* pReport, + CFIndex reportLength) +{ + OVR_UNUSED(result); + OVR_UNUSED(pSender); + OVR_UNUSED(reportType); + OVR_UNUSED(reportId); + + HIDDevice* pDevice = (HIDDevice*) pContext; + return pDevice->hidReportCallback(pReport, (UInt32)reportLength); +} + +void HIDDevice::hidReportCallback(UByte* pData, UInt32 length) +{ + + // We got data. + if (Handler) + { + Handler->OnInputReport(pData, length); + } +} + +void HIDDevice::staticDeviceRemovedCallback(void* pContext, IOReturn result, void* pSender) +{ + OVR_UNUSED(result); + OVR_UNUSED(pSender); + HIDDevice* pDevice = (HIDDevice*) pContext; + pDevice->deviceRemovedCallback(); +} + +void HIDDevice::deviceRemovedCallback() +{ + Ptr<HIDDevice> _this(this); // prevent from release + + Ptr<DeviceCreateDesc> existingHIDDev = HIDManager->DevManager->FindHIDDevice(DevDesc, true); + if (existingHIDDev && existingHIDDev->pDevice) + { + HIDManager->DevManager->CallOnDeviceRemoved(existingHIDDev); + } + closeDevice(true); +} + +CFStringRef HIDDevice::generateRunLoopModeString(IOHIDDeviceRef device) +{ + const UInt32 safeBuffSize = 256; + char nameBuff[safeBuffSize]; + OVR_sprintf(nameBuff, safeBuffSize, "%016lX", device); + + return CFStringCreateWithCString(NULL, nameBuff, kCFStringEncodingASCII); +} + +bool HIDDevice::SetFeatureReport(UByte* data, UInt32 length) +{ + + if (!Device) + return false; + + UByte reportID = data[0]; + + if (reportID == 0) + { + // Not using reports so remove from data packet. + data++; + length--; + } + + IOReturn result = IOHIDDeviceSetReport( Device, + kIOHIDReportTypeFeature, + reportID, + data, + length); + + return (result == kIOReturnSuccess); +} + +bool HIDDevice::GetFeatureReport(UByte* data, UInt32 length) +{ + if (!Device) + return false; + + CFIndex bufferLength = length; + + // Report id is in first byte of the buffer. + IOReturn result = IOHIDDeviceGetReport(Device, kIOHIDReportTypeFeature, data[0], data, &bufferLength); + + return (result == kIOReturnSuccess); +} + +double HIDDevice::OnTicks(double tickSeconds) +{ + + if (Handler) + { + return Handler->OnTicks(tickSeconds); + } + + return DeviceManagerThread::Notifier::OnTicks(tickSeconds); +} + +HIDDeviceManager* HIDDeviceManager::CreateInternal(OSX::DeviceManager* devManager) +{ + + if (!System::IsInitialized()) + { + // Use custom message, since Log is not yet installed. + OVR_DEBUG_STATEMENT(Log::GetDefaultLog()-> + LogMessage(Log_Debug, "HIDDeviceManager::Create failed - OVR::System not initialized"); ); + return 0; + } + + Ptr<OSX::HIDDeviceManager> manager = *new OSX::HIDDeviceManager(devManager); + + if (manager) + { + if (manager->Initialize()) + { + manager->AddRef(); + } + else + { + manager.Clear(); + } + } + + return manager.GetPtr(); +} + +} // namespace OSX + +//------------------------------------------------------------------------------------- +// ***** Creation + +// Creates a new HIDDeviceManager and initializes OVR. +HIDDeviceManager* HIDDeviceManager::Create(Ptr<OVR::DeviceManager>& deviceManager) +{ + + if (!System::IsInitialized()) + { + // Use custom message, since Log is not yet installed. + OVR_DEBUG_STATEMENT(Log::GetDefaultLog()-> + LogMessage(Log_Debug, "HIDDeviceManager::Create failed - OVR::System not initialized"); ); + return 0; + } + + Ptr<OSX::DeviceManager> deviceManagerOSX = *new OSX::DeviceManager; + + if (!deviceManagerOSX) + { + return NULL; + } + + if (!deviceManagerOSX->Initialize(NULL)) + { + return NULL; + } + + deviceManager = deviceManagerOSX; + + return deviceManagerOSX->GetHIDDeviceManager(); +} + +} // namespace OVR diff --git a/LibOVR/Src/OVR_OSX_HIDDevice.h b/LibOVR/Src/OVR_OSX_HIDDevice.h new file mode 100644 index 0000000..c6140cb --- /dev/null +++ b/LibOVR/Src/OVR_OSX_HIDDevice.h @@ -0,0 +1,160 @@ +/************************************************************************************ +Filename : OVR_OSX_HIDDevice.h +Content : OSX HID device implementation. +Created : February 26, 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. + +*************************************************************************************/ + +#ifndef OVR_OSX_HIDDevice_h +#define OVR_OSX_HIDDevice_h + +#include "OVR_HIDDevice.h" + +#include "OVR_OSX_DeviceManager.h" + +#include <IOKit/IOKitLib.h> + +namespace OVR { namespace OSX { + +class HIDDeviceManager; + +//------------------------------------------------------------------------------------- +// ***** OSX HIDDevice + +class HIDDevice : public OVR::HIDDevice, public DeviceManagerThread::Notifier +{ +private: + friend class HIDDeviceManager; + +public: + HIDDevice(HIDDeviceManager* manager); + + // This is a minimal constructor used during enumeration for us to pass + // a HIDDevice to the visit function (so that it can query feature reports). + HIDDevice(HIDDeviceManager* manager, IOHIDDeviceRef device); + + virtual ~HIDDevice(); + + bool HIDInitialize(const String& path); + void HIDShutdown(); + + virtual bool SetFeatureReport(UByte* data, UInt32 length); + virtual bool GetFeatureReport(UByte* data, UInt32 length); + + bool Write(UByte* data, UInt32 length); + + bool Read(UByte* pData, UInt32 length, UInt32 timeoutMilliS); + bool ReadBlocking(UByte* pData, UInt32 length); + + + // DeviceManagerThread::Notifier + double OnTicks(double tickSeconds); + +private: + bool initInfo(); + bool openDevice(); + void closeDevice(bool wasUnplugged); + bool setupDevicePluggedInNotification(); + CFStringRef generateRunLoopModeString(IOHIDDeviceRef device); + + static void staticHIDReportCallback(void* pContext, + IOReturn result, + void* pSender, + IOHIDReportType reportType, + uint32_t reportId, + uint8_t* pReport, + CFIndex reportLength); + void hidReportCallback(UByte* pData, UInt32 length); + + static void staticDeviceRemovedCallback(void* pContext, + IOReturn result, + void* pSender); + void deviceRemovedCallback(); + + static void staticDeviceAddedCallback(void* pContext, + io_iterator_t iterator); + void deviceAddedCallback(io_iterator_t iterator); + + bool InMinimalMode; + HIDDeviceManager* HIDManager; + IOHIDDeviceRef Device; + HIDDeviceDesc DevDesc; + + enum { ReadBufferSize = 96 }; + UByte ReadBuffer[ReadBufferSize]; + + UInt16 InputReportBufferLength; + UInt16 OutputReportBufferLength; + UInt16 FeatureReportBufferLength; + + IONotificationPortRef RepluggedNotificationPort; + io_iterator_t RepluggedNotification; +}; + + +//------------------------------------------------------------------------------------- +// ***** OSX HIDDeviceManager + +class HIDDeviceManager : public OVR::HIDDeviceManager +{ + friend class HIDDevice; + +public: + HIDDeviceManager(OSX::DeviceManager* Manager); + virtual ~HIDDeviceManager(); + + virtual bool Initialize(); + virtual void Shutdown(); + + virtual bool Enumerate(HIDEnumerateVisitor* enumVisitor); + virtual OVR::HIDDevice* Open(const String& path); + + static HIDDeviceManager* CreateInternal(DeviceManager* manager); + +private: + CFRunLoopRef getRunLoop(); + bool initializeManager(); + bool initVendorProductVersion(IOHIDDeviceRef device, HIDDeviceDesc* pDevDesc); + bool initUsage(IOHIDDeviceRef device, HIDDeviceDesc* pDevDesc); + bool initStrings(IOHIDDeviceRef device, HIDDeviceDesc* pDevDesc); + bool initSerialNumber(IOHIDDeviceRef device, HIDDeviceDesc* pDevDesc); + bool getVendorId(IOHIDDeviceRef device, UInt16* pResult); + bool getProductId(IOHIDDeviceRef device, UInt16* pResult); + bool getLocationId(IOHIDDeviceRef device, SInt32* pResult); + bool getSerialNumberString(IOHIDDeviceRef device, String* pResult); + bool getPath(IOHIDDeviceRef device, String* pPath); + bool getIntProperty(IOHIDDeviceRef device, CFStringRef key, int32_t* pResult); + bool getStringProperty(IOHIDDeviceRef device, CFStringRef propertyName, String* pResult); + bool getFullDesc(IOHIDDeviceRef device, HIDDeviceDesc* desc); + + static void staticDeviceMatchingCallback(void *inContext, + IOReturn inResult, + void *inSender, + IOHIDDeviceRef inIOHIDDeviceRef); + + DeviceManager* DevManager; + + IOHIDManagerRef HIDManager; +}; + +}} // namespace OVR::OSX + +#endif // OVR_OSX_HIDDevice_h diff --git a/LibOVR/Src/OVR_OSX_HMDDevice.cpp b/LibOVR/Src/OVR_OSX_HMDDevice.cpp new file mode 100644 index 0000000..e16de81 --- /dev/null +++ b/LibOVR/Src/OVR_OSX_HMDDevice.cpp @@ -0,0 +1,264 @@ +/************************************************************************************ + +Filename : OVR_OSX_HMDDevice.cpp +Content : OSX Interface to HMD - detects HMD display +Created : September 21, 2012 +Authors : Michael Antonov + +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_OSX_HMDDevice.h" + +#include "OVR_OSX_DeviceManager.h" +#include "Util/Util_Render_Stereo.h" + +#include "OVR_OSX_HMDDevice.h" +#include <ApplicationServices/ApplicationServices.h> +#include <CoreFoundation/CoreFoundation.h> +#include <CoreFoundation/CFString.h> +#include <IOKit/graphics/IOGraphicsLib.h> + +namespace OVR { namespace OSX { + +using namespace OVR::Util::Render; + +//------------------------------------------------------------------------------------- + +HMDDeviceCreateDesc::HMDDeviceCreateDesc(DeviceFactory* factory, + UInt32 vend, UInt32 prod, const String& displayDeviceName, int dispId) + : DeviceCreateDesc(factory, Device_HMD), + DisplayDeviceName(displayDeviceName), + Contents(0), + DisplayId(dispId) +{ + OVR_UNUSED(vend); + OVR_UNUSED(prod); + DeviceId = DisplayDeviceName; + + Desktop.X = 0; + Desktop.Y = 0; + ResolutionInPixels = Sizei(0); + ScreenSizeInMeters = Sizef(0.0f); + VCenterFromTopInMeters = 0.0f; + LensSeparationInMeters = 0.0f; +} + +HMDDeviceCreateDesc::HMDDeviceCreateDesc(const HMDDeviceCreateDesc& other) + : DeviceCreateDesc(other.pFactory, Device_HMD), + DeviceId(other.DeviceId), DisplayDeviceName(other.DisplayDeviceName), + Contents(other.Contents), + DisplayId(other.DisplayId) +{ + Desktop.X = other.Desktop.X; + Desktop.Y = other.Desktop.Y; + ResolutionInPixels = other.ResolutionInPixels; + ScreenSizeInMeters = other.ScreenSizeInMeters; + VCenterFromTopInMeters = other.VCenterFromTopInMeters; + LensSeparationInMeters = other.LensSeparationInMeters; +} + +HMDDeviceCreateDesc::MatchResult HMDDeviceCreateDesc::MatchDevice(const DeviceCreateDesc& other, + DeviceCreateDesc** pcandidate) const +{ + if ((other.Type != Device_HMD) || (other.pFactory != pFactory)) + return Match_None; + + // There are several reasons we can come in here: + // a) Matching this HMD Monitor created desc to OTHER HMD Monitor desc + // - Require exact device DeviceId/DeviceName match + // b) Matching SensorDisplayInfo created desc to OTHER HMD Monitor desc + // - This DeviceId is empty; becomes candidate + // c) Matching this HMD Monitor created desc to SensorDisplayInfo desc + // - This other.DeviceId is empty; becomes candidate + + const HMDDeviceCreateDesc& s2 = (const HMDDeviceCreateDesc&) other; + + if ((DeviceId == s2.DeviceId) && + (DisplayId == s2.DisplayId)) + { + // Non-null DeviceId may match while size is different if screen size was overwritten + // by SensorDisplayInfo in prior iteration. + if (!DeviceId.IsEmpty() || + (ScreenSizeInMeters == s2.ScreenSizeInMeters) ) + { + *pcandidate = 0; + return Match_Found; + } + } + + + // DisplayInfo takes precedence, although we try to match it first. + if ((ResolutionInPixels == s2.ResolutionInPixels) && + (ScreenSizeInMeters == s2.ScreenSizeInMeters)) + { + if (DeviceId.IsEmpty() && !s2.DeviceId.IsEmpty()) + { + *pcandidate = const_cast<DeviceCreateDesc*>((const DeviceCreateDesc*)this); + return Match_Candidate; + } + + *pcandidate = 0; + return Match_Found; + } + + // SensorDisplayInfo may override resolution settings, so store as candidiate. + if (s2.DeviceId.IsEmpty() && s2.DisplayId == 0) + { + *pcandidate = const_cast<DeviceCreateDesc*>((const DeviceCreateDesc*)this); + return Match_Candidate; + } + // OTHER HMD Monitor desc may initialize DeviceName/Id + else if (DeviceId.IsEmpty() && DisplayId == 0) + { + *pcandidate = const_cast<DeviceCreateDesc*>((const DeviceCreateDesc*)this); + return Match_Candidate; + } + + return Match_None; +} + + +bool HMDDeviceCreateDesc::UpdateMatchedCandidate(const DeviceCreateDesc& other, bool* newDeviceFlag) +{ + // This candidate was the the "best fit" to apply sensor DisplayInfo to. + OVR_ASSERT(other.Type == Device_HMD); + + const HMDDeviceCreateDesc& s2 = (const HMDDeviceCreateDesc&) other; + + // Force screen size on resolution from SensorDisplayInfo. + // We do this because USB detection is more reliable as compared to HDMI EDID, + // which may be corrupted by splitter reporting wrong monitor + if (s2.DeviceId.IsEmpty() && s2.DisplayId == 0) + { + ScreenSizeInMeters = s2.ScreenSizeInMeters; + Contents |= Contents_Screen; + + if (s2.Contents & HMDDeviceCreateDesc::Contents_Distortion) + { + memcpy(DistortionK, s2.DistortionK, sizeof(float)*4); + // TODO: DistortionEqn + Contents |= Contents_Distortion; + } + DeviceId = s2.DeviceId; + DisplayId = s2.DisplayId; + DisplayDeviceName = s2.DisplayDeviceName; + Desktop.X = s2.Desktop.X; + Desktop.Y = s2.Desktop.Y; + if (newDeviceFlag) *newDeviceFlag = true; + } + else if (DeviceId.IsEmpty()) + { + // This branch is executed when 'fake' HMD descriptor is being replaced by + // the real one. + DeviceId = s2.DeviceId; + DisplayId = s2.DisplayId; + DisplayDeviceName = s2.DisplayDeviceName; + Desktop.X = s2.Desktop.X; + Desktop.Y = s2.Desktop.Y; + + // ScreenSize and Resolution are NOT assigned here, since they may have + // come from a sensor DisplayInfo (which has precedence over HDMI). + + if (newDeviceFlag) *newDeviceFlag = true; + } + else + { + if (newDeviceFlag) *newDeviceFlag = false; + } + + return true; +} + + +//------------------------------------------------------------------------------------- + + +//------------------------------------------------------------------------------------- +// ***** HMDDeviceFactory + +HMDDeviceFactory &HMDDeviceFactory::GetInstance() +{ + static HMDDeviceFactory instance; + return instance; +} + +void HMDDeviceFactory::EnumerateDevices(EnumerateVisitor& visitor) +{ + CGDirectDisplayID Displays[32]; + uint32_t NDisplays = 0; + CGGetOnlineDisplayList(32, Displays, &NDisplays); + + for (unsigned int i = 0; i < NDisplays; i++) + { + io_service_t port = CGDisplayIOServicePort(Displays[i]); + CFDictionaryRef DispInfo = IODisplayCreateInfoDictionary(port, kIODisplayMatchingInfo); + + uint32_t vendor = CGDisplayVendorNumber(Displays[i]); + uint32_t product = CGDisplayModelNumber(Displays[i]); + + CGRect desktop = CGDisplayBounds(Displays[i]); + + if (vendor == 16082 && ( (product == 1)||(product == 2) ) ) // 7" or HD + { + char idstring[9]; + idstring[0] = 'A'-1+((vendor>>10) & 31); + idstring[1] = 'A'-1+((vendor>>5) & 31); + idstring[2] = 'A'-1+((vendor>>0) & 31); + snprintf(idstring+3, 5, "%04d", product); + + HMDDeviceCreateDesc hmdCreateDesc(this, vendor, product, idstring, Displays[i]); + + // Hard-coded defaults in case the device doesn't have the data itself. + if (product == 3) + { // DK2 prototypes and variants (default to HmdType_DK2) + hmdCreateDesc.SetScreenParameters(desktop.origin.x, desktop.origin.y, + 1920, 1080, 0.12576f, 0.07074f, 0.12576f*0.5f, 0.0635f ); + } + else if (product == 2) + { // HD Prototypes (default to HmdType_DKHDProto) + hmdCreateDesc.SetScreenParameters(desktop.origin.x, desktop.origin.y, + 1920, 1080, 0.12096f, 0.06804f, 0.06804f*0.5f, 0.0635f); + } + else if (product == 1) + { // DK1 + hmdCreateDesc.SetScreenParameters(desktop.origin.x, desktop.origin.y, + 1280, 800, 0.14976f, 0.0936f, 0.0936f*0.5f, 0.0635f); + } + else + { // Future Oculus HMD devices (default to DK1 dimensions) + hmdCreateDesc.SetScreenParameters(desktop.origin.x, desktop.origin.y, + 1280, 800, 0.14976f, 0.0936f, 0.0936f*0.5f, 0.0635f); + } + + OVR_DEBUG_LOG_TEXT(("DeviceManager - HMD Found %x:%x\n", vendor, product)); + + // Notify caller about detected device. This will call EnumerateAddDevice + // if the this is the first time device was detected. + visitor.Visit(hmdCreateDesc); + } + CFRelease(DispInfo); + } +} + +#include "OVR_Common_HMDDevice.cpp" + +}} // namespace OVR::OSX + + diff --git a/LibOVR/Src/OVR_OSX_HMDDevice.h b/LibOVR/Src/OVR_OSX_HMDDevice.h new file mode 100644 index 0000000..dd5c0fe --- /dev/null +++ b/LibOVR/Src/OVR_OSX_HMDDevice.h @@ -0,0 +1,153 @@ +/************************************************************************************ + +Filename : OVR_OSX_HMDDevice.h +Content : OSX HMDDevice implementation +Created : September 21, 2012 +Authors : Michael Antonov + +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. + +*************************************************************************************/ + +#ifndef OVR_OSX_HMDDevice_h +#define OVR_OSX_HMDDevice_h + +#include "OVR_DeviceImpl.h" +#include "Kernel/OVR_String.h" +#include "OVR_Profile.h" + +namespace OVR { namespace OSX { + +class HMDDevice; + + +//------------------------------------------------------------------------------------- + +// HMDDeviceFactory enumerates attached Oculus HMD devices. +// +// This is currently done by matching monitor device strings. + +class HMDDeviceFactory : public DeviceFactory +{ +public: + static HMDDeviceFactory &GetInstance(); + + // Enumerates devices, creating and destroying relevant objects in manager. + virtual void EnumerateDevices(EnumerateVisitor& visitor); + +protected: + DeviceManager* getManager() const { return (DeviceManager*) pManager; } +}; + + +class HMDDeviceCreateDesc : public DeviceCreateDesc +{ + friend class HMDDevice; + +protected: + enum + { + Contents_Screen = 1, + Contents_Distortion = 2, + }; + String DeviceId; + String DisplayDeviceName; + struct + { + int X, Y; + } Desktop; + unsigned int Contents; + + Sizei ResolutionInPixels; + Sizef ScreenSizeInMeters; + float VCenterFromTopInMeters; + float LensSeparationInMeters; + + // TODO: update these to splines. + DistortionEqnType DistortionEqn; + float DistortionK[4]; + + int DisplayId; + +public: + HMDDeviceCreateDesc(DeviceFactory* factory, + UInt32 vendor, UInt32 product, const String& displayDeviceName, int dispId); + HMDDeviceCreateDesc(const HMDDeviceCreateDesc& other); + + virtual DeviceCreateDesc* Clone() const + { + return new HMDDeviceCreateDesc(*this); + } + + virtual DeviceBase* NewDeviceInstance(); + + virtual MatchResult MatchDevice(const DeviceCreateDesc& other, + DeviceCreateDesc**) const; + + virtual bool UpdateMatchedCandidate(const DeviceCreateDesc&, bool* newDeviceFlag = NULL); + + virtual bool GetDeviceInfo(DeviceInfo* info) const; + + void SetScreenParameters(int x, int y, + int hres, int vres, + float hsize, float vsize, + float vCenterFromTopInMeters, float lensSeparationInMeters); + void SetDistortion(const float* dks); + + HmdTypeEnum GetHmdType() const; +}; + + +//------------------------------------------------------------------------------------- + +// HMDDevice represents an Oculus HMD device unit. An instance of this class +// is typically created from the DeviceManager. +// After HMD device is created, we its sensor data can be obtained by +// first creating a Sensor object and then wrappig it in SensorFusion. + +class HMDDevice : public DeviceImpl<OVR::HMDDevice> +{ +public: + HMDDevice(HMDDeviceCreateDesc* createDesc); + ~HMDDevice(); + + virtual bool Initialize(DeviceBase* parent); + virtual void Shutdown(); + + // Requests the currently used default profile. This profile affects the + // settings reported by HMDInfo. + virtual Profile* GetProfile(); + virtual const char* GetProfileName(); + virtual bool SetProfileName(const char* name); + + // Query associated sensor. + virtual OVR::SensorDevice* GetSensor(); + +protected: + HMDDeviceCreateDesc* getDesc() const { return (HMDDeviceCreateDesc*)pCreateDesc.GetPtr(); } + + // User name for the profile used with this device. + String ProfileName; + mutable Ptr<Profile> pCachedProfile; +}; + + +}} // namespace OVR::OSX + +#endif // OVR_OSX_HMDDevice_h + diff --git a/LibOVR/Src/OVR_OSX_SensorDevice.cpp b/LibOVR/Src/OVR_OSX_SensorDevice.cpp new file mode 100644 index 0000000..9b783c6 --- /dev/null +++ b/LibOVR/Src/OVR_OSX_SensorDevice.cpp @@ -0,0 +1,58 @@ +/************************************************************************************ + +Filename : OVR_OSX_SensorDevice.cpp +Content : OSX SensorDevice implementation +Created : March 14, 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_OSX_HMDDevice.h" +#include "OVR_SensorImpl.h" +#include "OVR_DeviceImpl.h" + +namespace OVR { namespace OSX { + +} // namespace OSX + +//------------------------------------------------------------------------------------- +void SensorDeviceImpl::EnumerateHMDFromSensorDisplayInfo(const SensorDisplayInfoImpl& displayInfo, + DeviceFactory::EnumerateVisitor& visitor) +{ + + OSX::HMDDeviceCreateDesc hmdCreateDesc(&OSX::HMDDeviceFactory::GetInstance(), 1, 1, "", 0); + + hmdCreateDesc.SetScreenParameters( 0, 0, + displayInfo.HResolution, displayInfo.VResolution, + displayInfo.HScreenSize, displayInfo.VScreenSize, + displayInfo.VCenter, displayInfo.LensSeparation); + + if ((displayInfo.DistortionType & SensorDisplayInfoImpl::Mask_BaseFmt) == SensorDisplayInfoImpl::Base_Distortion) + { + hmdCreateDesc.SetDistortion(displayInfo.DistortionK); + // TODO: add DistortionEqn + } + + visitor.Visit(hmdCreateDesc); +} + +} // namespace OVR + + |