OVR_Linux_DeviceManager.cpp
Go to the documentation of this file.
00001 /************************************************************************************
00002 
00003 Filename    :   OVR_Linux_DeviceManager.h
00004 Content     :   Linux implementation of DeviceManager.
00005 Created     :   
00006 Authors     :   
00007 
00008 Copyright   :   Copyright 2012 Oculus VR, Inc. All Rights reserved.
00009 
00010 Use of this software is subject to the terms of the Oculus license
00011 agreement provided at the time of installation or download, or which
00012 otherwise accompanies this software in either electronic or hard copy form.
00013 
00014 *************************************************************************************/
00015 
00016 #include "OVR_Linux_DeviceManager.h"
00017 
00018 // Sensor & HMD Factories
00019 #include "OVR_LatencyTestImpl.h"
00020 #include "OVR_SensorImpl.h"
00021 #include "OVR_Linux_HIDDevice.h"
00022 #include "OVR_Linux_HMDDevice.h"
00023 
00024 #include "Kernel/OVR_Timer.h"
00025 #include "Kernel/OVR_Std.h"
00026 #include "Kernel/OVR_Log.h"
00027 
00028 namespace OVR { namespace Linux {
00029 
00030 
00031 //-------------------------------------------------------------------------------------
00032 // **** Linux::DeviceManager
00033 
00034 DeviceManager::DeviceManager()
00035 {
00036 }
00037 
00038 DeviceManager::~DeviceManager()
00039 {    
00040 }
00041 
00042 bool DeviceManager::Initialize(DeviceBase*)
00043 {
00044     if (!DeviceManagerImpl::Initialize(0))
00045         return false;
00046 
00047     pThread = *new DeviceManagerThread();
00048     if (!pThread || !pThread->Start())
00049         return false;
00050 
00051     // Wait for the thread to be fully up and running.
00052     pThread->StartupEvent.Wait();
00053 
00054     // Do this now that we know the thread's run loop.
00055     HidDeviceManager = *HIDDeviceManager::CreateInternal(this);
00056          
00057     pCreateDesc->pDevice = this;
00058     LogText("OVR::DeviceManager - initialized.\n");
00059     return true;
00060 }
00061 
00062 void DeviceManager::Shutdown()
00063 {   
00064     LogText("OVR::DeviceManager - shutting down.\n");
00065 
00066     // Set Manager shutdown marker variable; this prevents
00067     // any existing DeviceHandle objects from accessing device.
00068     pCreateDesc->pLock->pManager = 0;
00069 
00070     // Push for thread shutdown *WITH NO WAIT*.
00071     // This will have the following effect:
00072     //  - Exit command will get enqueued, which will be executed later on the thread itself.
00073     //  - Beyond this point, this DeviceManager object may be deleted by our caller.
00074     //  - Other commands, such as CreateDevice, may execute before ExitCommand, but they will
00075     //    fail gracefully due to pLock->pManager == 0. Future commands can't be enqued
00076     //    after pManager is null.
00077     //  - Once ExitCommand executes, ThreadCommand::Run loop will exit and release the last
00078     //    reference to the thread object.
00079     pThread->PushExitCommand(false);
00080     pThread.Clear();
00081 
00082     DeviceManagerImpl::Shutdown();
00083 }
00084 
00085 ThreadCommandQueue* DeviceManager::GetThreadQueue()
00086 {
00087     return pThread;
00088 }
00089 
00090 ThreadId DeviceManager::GetThreadId() const
00091 {
00092     return pThread->GetThreadId();
00093 }
00094 
00095 bool DeviceManager::GetDeviceInfo(DeviceInfo* info) const
00096 {
00097     if ((info->InfoClassType != Device_Manager) &&
00098         (info->InfoClassType != Device_None))
00099         return false;
00100     
00101     info->Type    = Device_Manager;
00102     info->Version = 0;
00103     OVR_strcpy(info->ProductName, DeviceInfo::MaxNameLength, "DeviceManager");
00104     OVR_strcpy(info->Manufacturer,DeviceInfo::MaxNameLength, "Oculus VR, Inc.");        
00105     return true;
00106 }
00107 
00108 DeviceEnumerator<> DeviceManager::EnumerateDevicesEx(const DeviceEnumerationArgs& args)
00109 {
00110     // TBD: Can this be avoided in the future, once proper device notification is in place?
00111     pThread->PushCall((DeviceManagerImpl*)this,
00112                       &DeviceManager::EnumerateAllFactoryDevices, true);
00113 
00114     return DeviceManagerImpl::EnumerateDevicesEx(args);
00115 }
00116 
00117 
00118 //-------------------------------------------------------------------------------------
00119 // ***** DeviceManager Thread 
00120 
00121 DeviceManagerThread::DeviceManagerThread()
00122     : Thread(ThreadStackSize)
00123 {
00124     int result = pipe(CommandFd);
00125     OVR_ASSERT(!result);
00126 
00127     AddSelectFd(NULL, CommandFd[0]);
00128 }
00129 
00130 DeviceManagerThread::~DeviceManagerThread()
00131 {
00132     if (CommandFd[0])
00133     {
00134         RemoveSelectFd(NULL, CommandFd[0]);
00135         close(CommandFd[0]);
00136         close(CommandFd[1]);
00137     }
00138 }
00139 
00140 bool DeviceManagerThread::AddSelectFd(Notifier* notify, int fd)
00141 {
00142     struct pollfd pfd;
00143     pfd.fd = fd;
00144     pfd.events = POLLIN|POLLHUP|POLLERR;
00145     pfd.revents = 0;
00146 
00147     FdNotifiers.PushBack(notify);
00148     PollFds.PushBack(pfd);
00149 
00150     OVR_ASSERT(FdNotifiers.GetSize() == PollFds.GetSize());
00151     return true;
00152 }
00153 
00154 bool DeviceManagerThread::RemoveSelectFd(Notifier* notify, int fd)
00155 {
00156     // [0] is reserved for thread commands with notify of null, but we still
00157     // can use this function to remove it.
00158     for (UPInt i = 0; i < FdNotifiers.GetSize(); i++)
00159     {
00160         if ((FdNotifiers[i] == notify) && (PollFds[i].fd == fd))
00161         {
00162             FdNotifiers.RemoveAt(i);
00163             PollFds.RemoveAt(i);
00164             return true;
00165         }
00166     }
00167     return false;
00168 }
00169 
00170 
00171 
00172 int DeviceManagerThread::Run()
00173 {
00174     ThreadCommand::PopBuffer command;
00175 
00176     SetThreadName("OVR::DeviceManagerThread");
00177     LogText("OVR::DeviceManagerThread - running (ThreadId=%p).\n", GetThreadId());
00178     
00179     // Signal to the parent thread that initialization has finished.
00180     StartupEvent.SetEvent();
00181 
00182     while(!IsExiting())
00183     {
00184         // PopCommand will reset event on empty queue.
00185         if (PopCommand(&command))
00186         {
00187             command.Execute();
00188         }
00189         else
00190         {
00191             bool commands = 0;
00192             do
00193             {
00194                 int waitMs = -1;
00195 
00196                 // If devices have time-dependent logic registered, get the longest wait
00197                 // allowed based on current ticks.
00198                 if (!TicksNotifiers.IsEmpty())
00199                 {
00200                     UInt64 ticksMks = Timer::GetTicks();
00201                     int  waitAllowed;
00202 
00203                     for (UPInt j = 0; j < TicksNotifiers.GetSize(); j++)
00204                     {
00205                         waitAllowed = (int)(TicksNotifiers[j]->OnTicks(ticksMks) / Timer::MksPerMs);
00206                         if (waitAllowed < waitMs)
00207                             waitMs = waitAllowed;
00208                     }
00209                 }
00210 
00211                 // wait until there is data available on one of the devices or the timeout expires
00212                 int n = poll(&PollFds[0], PollFds.GetSize(), waitMs);
00213 
00214                 if (n > 0)
00215                 {
00216                     // Iterate backwards through the list so the ordering will not be
00217                     // affected if the called object gets removed during the callback
00218                     // Also, the HID data streams are located toward the back of the list
00219                     // and servicing them first will allow a disconnect to be handled
00220                     // and cleaned directly at the device first instead of the general HID monitor
00221                     for (int i=PollFds.GetSize()-1; i>=0; i--)
00222                     {
00223                         if (PollFds[i].revents & POLLERR)
00224                         {
00225                             OVR_DEBUG_LOG(("poll: error on [%d]: %d", i, PollFds[i].fd));
00226                         }
00227                         else if (PollFds[i].revents & POLLIN)
00228                         {
00229                             if (FdNotifiers[i])
00230                                 FdNotifiers[i]->OnEvent(i, PollFds[i].fd);
00231                             else if (i == 0) // command
00232                             {
00233                                 char dummy[128];
00234                                 read(PollFds[i].fd, dummy, 128);
00235                                 commands = 1;
00236                             }
00237                         }
00238 
00239                         if (PollFds[i].revents & POLLHUP)
00240                             PollFds[i].events = 0;
00241 
00242                         if (PollFds[i].revents != 0)
00243                         {
00244                             n--;
00245                             if (n == 0)
00246                                 break;
00247                         }
00248                     }
00249                 }
00250             } while (PollFds.GetSize() > 0 && !commands);
00251         }
00252     }
00253 
00254     LogText("OVR::DeviceManagerThread - exiting (ThreadId=%p).\n", GetThreadId());
00255     return 0;
00256 }
00257 
00258 bool DeviceManagerThread::AddTicksNotifier(Notifier* notify)
00259 {
00260      TicksNotifiers.PushBack(notify);
00261      return true;
00262 }
00263 
00264 bool DeviceManagerThread::RemoveTicksNotifier(Notifier* notify)
00265 {
00266     for (UPInt i = 0; i < TicksNotifiers.GetSize(); i++)
00267     {
00268         if (TicksNotifiers[i] == notify)
00269         {
00270             TicksNotifiers.RemoveAt(i);
00271             return true;
00272         }
00273     }
00274     return false;
00275 }
00276 
00277 } // namespace Linux
00278 
00279 
00280 //-------------------------------------------------------------------------------------
00281 // ***** Creation
00282 
00283 
00284 // Creates a new DeviceManager and initializes OVR.
00285 DeviceManager* DeviceManager::Create()
00286 {
00287     if (!System::IsInitialized())
00288     {
00289         // Use custom message, since Log is not yet installed.
00290         OVR_DEBUG_STATEMENT(Log::GetDefaultLog()->
00291             LogMessage(Log_Debug, "DeviceManager::Create failed - OVR::System not initialized"); );
00292         return 0;
00293     }
00294 
00295     Ptr<Linux::DeviceManager> manager = *new Linux::DeviceManager;
00296 
00297     if (manager)
00298     {
00299         if (manager->Initialize(0))
00300         {            
00301             manager->AddFactory(&LatencyTestDeviceFactory::Instance);
00302             manager->AddFactory(&SensorDeviceFactory::Instance);
00303             manager->AddFactory(&Linux::HMDDeviceFactory::Instance);
00304 
00305             manager->AddRef();
00306         }
00307         else
00308         {
00309             manager.Clear();
00310         }
00311 
00312     }    
00313 
00314     return manager.GetPtr();
00315 }
00316 
00317 
00318 } // namespace OVR
00319 


oculus_sdk
Author(s):
autogenerated on Mon Oct 6 2014 03:01:18