oculus1
diff libovr/Src/linux/OVR_Linux_DeviceManager.cpp @ 1:e2f9e4603129
added LibOVR and started a simple vr wrapper.
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sat, 14 Sep 2013 16:14:59 +0300 |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/libovr/Src/linux/OVR_Linux_DeviceManager.cpp Sat Sep 14 16:14:59 2013 +0300 1.3 @@ -0,0 +1,319 @@ 1.4 +/************************************************************************************ 1.5 + 1.6 +Filename : OVR_Linux_DeviceManager.h 1.7 +Content : Linux implementation of DeviceManager. 1.8 +Created : 1.9 +Authors : 1.10 + 1.11 +Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved. 1.12 + 1.13 +Use of this software is subject to the terms of the Oculus license 1.14 +agreement provided at the time of installation or download, or which 1.15 +otherwise accompanies this software in either electronic or hard copy form. 1.16 + 1.17 +*************************************************************************************/ 1.18 + 1.19 +#include "OVR_Linux_DeviceManager.h" 1.20 + 1.21 +// Sensor & HMD Factories 1.22 +#include "OVR_LatencyTestImpl.h" 1.23 +#include "OVR_SensorImpl.h" 1.24 +#include "OVR_Linux_HIDDevice.h" 1.25 +#include "OVR_Linux_HMDDevice.h" 1.26 + 1.27 +#include "Kernel/OVR_Timer.h" 1.28 +#include "Kernel/OVR_Std.h" 1.29 +#include "Kernel/OVR_Log.h" 1.30 + 1.31 +namespace OVR { namespace Linux { 1.32 + 1.33 + 1.34 +//------------------------------------------------------------------------------------- 1.35 +// **** Linux::DeviceManager 1.36 + 1.37 +DeviceManager::DeviceManager() 1.38 +{ 1.39 +} 1.40 + 1.41 +DeviceManager::~DeviceManager() 1.42 +{ 1.43 +} 1.44 + 1.45 +bool DeviceManager::Initialize(DeviceBase*) 1.46 +{ 1.47 + if (!DeviceManagerImpl::Initialize(0)) 1.48 + return false; 1.49 + 1.50 + pThread = *new DeviceManagerThread(); 1.51 + if (!pThread || !pThread->Start()) 1.52 + return false; 1.53 + 1.54 + // Wait for the thread to be fully up and running. 1.55 + pThread->StartupEvent.Wait(); 1.56 + 1.57 + // Do this now that we know the thread's run loop. 1.58 + HidDeviceManager = *HIDDeviceManager::CreateInternal(this); 1.59 + 1.60 + pCreateDesc->pDevice = this; 1.61 + LogText("OVR::DeviceManager - initialized.\n"); 1.62 + return true; 1.63 +} 1.64 + 1.65 +void DeviceManager::Shutdown() 1.66 +{ 1.67 + LogText("OVR::DeviceManager - shutting down.\n"); 1.68 + 1.69 + // Set Manager shutdown marker variable; this prevents 1.70 + // any existing DeviceHandle objects from accessing device. 1.71 + pCreateDesc->pLock->pManager = 0; 1.72 + 1.73 + // Push for thread shutdown *WITH NO WAIT*. 1.74 + // This will have the following effect: 1.75 + // - Exit command will get enqueued, which will be executed later on the thread itself. 1.76 + // - Beyond this point, this DeviceManager object may be deleted by our caller. 1.77 + // - Other commands, such as CreateDevice, may execute before ExitCommand, but they will 1.78 + // fail gracefully due to pLock->pManager == 0. Future commands can't be enqued 1.79 + // after pManager is null. 1.80 + // - Once ExitCommand executes, ThreadCommand::Run loop will exit and release the last 1.81 + // reference to the thread object. 1.82 + pThread->PushExitCommand(false); 1.83 + pThread.Clear(); 1.84 + 1.85 + DeviceManagerImpl::Shutdown(); 1.86 +} 1.87 + 1.88 +ThreadCommandQueue* DeviceManager::GetThreadQueue() 1.89 +{ 1.90 + return pThread; 1.91 +} 1.92 + 1.93 +ThreadId DeviceManager::GetThreadId() const 1.94 +{ 1.95 + return pThread->GetThreadId(); 1.96 +} 1.97 + 1.98 +bool DeviceManager::GetDeviceInfo(DeviceInfo* info) const 1.99 +{ 1.100 + if ((info->InfoClassType != Device_Manager) && 1.101 + (info->InfoClassType != Device_None)) 1.102 + return false; 1.103 + 1.104 + info->Type = Device_Manager; 1.105 + info->Version = 0; 1.106 + OVR_strcpy(info->ProductName, DeviceInfo::MaxNameLength, "DeviceManager"); 1.107 + OVR_strcpy(info->Manufacturer,DeviceInfo::MaxNameLength, "Oculus VR, Inc."); 1.108 + return true; 1.109 +} 1.110 + 1.111 +DeviceEnumerator<> DeviceManager::EnumerateDevicesEx(const DeviceEnumerationArgs& args) 1.112 +{ 1.113 + // TBD: Can this be avoided in the future, once proper device notification is in place? 1.114 + pThread->PushCall((DeviceManagerImpl*)this, 1.115 + &DeviceManager::EnumerateAllFactoryDevices, true); 1.116 + 1.117 + return DeviceManagerImpl::EnumerateDevicesEx(args); 1.118 +} 1.119 + 1.120 + 1.121 +//------------------------------------------------------------------------------------- 1.122 +// ***** DeviceManager Thread 1.123 + 1.124 +DeviceManagerThread::DeviceManagerThread() 1.125 + : Thread(ThreadStackSize) 1.126 +{ 1.127 + int result = pipe(CommandFd); 1.128 + OVR_ASSERT(!result); 1.129 + 1.130 + AddSelectFd(NULL, CommandFd[0]); 1.131 +} 1.132 + 1.133 +DeviceManagerThread::~DeviceManagerThread() 1.134 +{ 1.135 + if (CommandFd[0]) 1.136 + { 1.137 + RemoveSelectFd(NULL, CommandFd[0]); 1.138 + close(CommandFd[0]); 1.139 + close(CommandFd[1]); 1.140 + } 1.141 +} 1.142 + 1.143 +bool DeviceManagerThread::AddSelectFd(Notifier* notify, int fd) 1.144 +{ 1.145 + struct pollfd pfd; 1.146 + pfd.fd = fd; 1.147 + pfd.events = POLLIN|POLLHUP|POLLERR; 1.148 + pfd.revents = 0; 1.149 + 1.150 + FdNotifiers.PushBack(notify); 1.151 + PollFds.PushBack(pfd); 1.152 + 1.153 + OVR_ASSERT(FdNotifiers.GetSize() == PollFds.GetSize()); 1.154 + return true; 1.155 +} 1.156 + 1.157 +bool DeviceManagerThread::RemoveSelectFd(Notifier* notify, int fd) 1.158 +{ 1.159 + // [0] is reserved for thread commands with notify of null, but we still 1.160 + // can use this function to remove it. 1.161 + for (UPInt i = 0; i < FdNotifiers.GetSize(); i++) 1.162 + { 1.163 + if ((FdNotifiers[i] == notify) && (PollFds[i].fd == fd)) 1.164 + { 1.165 + FdNotifiers.RemoveAt(i); 1.166 + PollFds.RemoveAt(i); 1.167 + return true; 1.168 + } 1.169 + } 1.170 + return false; 1.171 +} 1.172 + 1.173 + 1.174 + 1.175 +int DeviceManagerThread::Run() 1.176 +{ 1.177 + ThreadCommand::PopBuffer command; 1.178 + 1.179 + SetThreadName("OVR::DeviceManagerThread"); 1.180 + LogText("OVR::DeviceManagerThread - running (ThreadId=%p).\n", GetThreadId()); 1.181 + 1.182 + // Signal to the parent thread that initialization has finished. 1.183 + StartupEvent.SetEvent(); 1.184 + 1.185 + while(!IsExiting()) 1.186 + { 1.187 + // PopCommand will reset event on empty queue. 1.188 + if (PopCommand(&command)) 1.189 + { 1.190 + command.Execute(); 1.191 + } 1.192 + else 1.193 + { 1.194 + bool commands = 0; 1.195 + do 1.196 + { 1.197 + int waitMs = -1; 1.198 + 1.199 + // If devices have time-dependent logic registered, get the longest wait 1.200 + // allowed based on current ticks. 1.201 + if (!TicksNotifiers.IsEmpty()) 1.202 + { 1.203 + UInt64 ticksMks = Timer::GetTicks(); 1.204 + int waitAllowed; 1.205 + 1.206 + for (UPInt j = 0; j < TicksNotifiers.GetSize(); j++) 1.207 + { 1.208 + waitAllowed = (int)(TicksNotifiers[j]->OnTicks(ticksMks) / Timer::MksPerMs); 1.209 + if (waitAllowed < waitMs) 1.210 + waitMs = waitAllowed; 1.211 + } 1.212 + } 1.213 + 1.214 + // wait until there is data available on one of the devices or the timeout expires 1.215 + int n = poll(&PollFds[0], PollFds.GetSize(), waitMs); 1.216 + 1.217 + if (n > 0) 1.218 + { 1.219 + // Iterate backwards through the list so the ordering will not be 1.220 + // affected if the called object gets removed during the callback 1.221 + // Also, the HID data streams are located toward the back of the list 1.222 + // and servicing them first will allow a disconnect to be handled 1.223 + // and cleaned directly at the device first instead of the general HID monitor 1.224 + for (int i=PollFds.GetSize()-1; i>=0; i--) 1.225 + { 1.226 + if (PollFds[i].revents & POLLERR) 1.227 + { 1.228 + OVR_DEBUG_LOG(("poll: error on [%d]: %d", i, PollFds[i].fd)); 1.229 + } 1.230 + else if (PollFds[i].revents & POLLIN) 1.231 + { 1.232 + if (FdNotifiers[i]) 1.233 + FdNotifiers[i]->OnEvent(i, PollFds[i].fd); 1.234 + else if (i == 0) // command 1.235 + { 1.236 + char dummy[128]; 1.237 + read(PollFds[i].fd, dummy, 128); 1.238 + commands = 1; 1.239 + } 1.240 + } 1.241 + 1.242 + if (PollFds[i].revents & POLLHUP) 1.243 + PollFds[i].events = 0; 1.244 + 1.245 + if (PollFds[i].revents != 0) 1.246 + { 1.247 + n--; 1.248 + if (n == 0) 1.249 + break; 1.250 + } 1.251 + } 1.252 + } 1.253 + } while (PollFds.GetSize() > 0 && !commands); 1.254 + } 1.255 + } 1.256 + 1.257 + LogText("OVR::DeviceManagerThread - exiting (ThreadId=%p).\n", GetThreadId()); 1.258 + return 0; 1.259 +} 1.260 + 1.261 +bool DeviceManagerThread::AddTicksNotifier(Notifier* notify) 1.262 +{ 1.263 + TicksNotifiers.PushBack(notify); 1.264 + return true; 1.265 +} 1.266 + 1.267 +bool DeviceManagerThread::RemoveTicksNotifier(Notifier* notify) 1.268 +{ 1.269 + for (UPInt i = 0; i < TicksNotifiers.GetSize(); i++) 1.270 + { 1.271 + if (TicksNotifiers[i] == notify) 1.272 + { 1.273 + TicksNotifiers.RemoveAt(i); 1.274 + return true; 1.275 + } 1.276 + } 1.277 + return false; 1.278 +} 1.279 + 1.280 +} // namespace Linux 1.281 + 1.282 + 1.283 +//------------------------------------------------------------------------------------- 1.284 +// ***** Creation 1.285 + 1.286 + 1.287 +// Creates a new DeviceManager and initializes OVR. 1.288 +DeviceManager* DeviceManager::Create() 1.289 +{ 1.290 + if (!System::IsInitialized()) 1.291 + { 1.292 + // Use custom message, since Log is not yet installed. 1.293 + OVR_DEBUG_STATEMENT(Log::GetDefaultLog()-> 1.294 + LogMessage(Log_Debug, "DeviceManager::Create failed - OVR::System not initialized"); ); 1.295 + return 0; 1.296 + } 1.297 + 1.298 + Ptr<Linux::DeviceManager> manager = *new Linux::DeviceManager; 1.299 + 1.300 + if (manager) 1.301 + { 1.302 + if (manager->Initialize(0)) 1.303 + { 1.304 + manager->AddFactory(&LatencyTestDeviceFactory::Instance); 1.305 + manager->AddFactory(&SensorDeviceFactory::Instance); 1.306 + manager->AddFactory(&Linux::HMDDeviceFactory::Instance); 1.307 + 1.308 + manager->AddRef(); 1.309 + } 1.310 + else 1.311 + { 1.312 + manager.Clear(); 1.313 + } 1.314 + 1.315 + } 1.316 + 1.317 + return manager.GetPtr(); 1.318 +} 1.319 + 1.320 + 1.321 +} // namespace OVR 1.322 +