OSVR Framework (Internal Development Docs)  0.6-1962-g59773924
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
com_osvr_Multiserver.cpp
Go to the documentation of this file.
1 
12 // Copyright 2014 Sensics, Inc.
13 //
14 // Licensed under the Apache License, Version 2.0 (the "License");
15 // you may not use this file except in compliance with the License.
16 // You may obtain a copy of the License at
17 //
18 // http://www.apache.org/licenses/LICENSE-2.0
19 //
20 // Unless required by applicable law or agreed to in writing, software
21 // distributed under the License is distributed on an "AS IS" BASIS,
22 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23 // See the License for the specific language governing permissions and
24 // limitations under the License.
25 
26 #ifdef __ANDROID__
27 // Define this for verbose output during polling.
28 #define OSVR_MULTISERVER_VERBOSE
29 #endif
30 
31 // Internal Includes
32 #include "VRPNMultiserver.h"
33 #include "DevicesWithParameters.h"
35 #include <osvr/Util/UniquePtr.h>
38 
39 #include "com_osvr_Multiserver_OSVRHackerDevKit_json.h"
40 #include "com_osvr_Multiserver_OneEuroFilter_json.h"
41 #include "com_osvr_Multiserver_RazerHydra_json.h"
42 #include "com_osvr_Multiserver_Sensics_zSight_json.h"
43 
44 // Library/third-party includes
45 #include "hidapi/hidapi.h"
46 #include "vrpn_Connection.h"
47 #include "vrpn_Tracker_RazerHydra.h"
48 #include "vrpn_Tracker_zSight.h"
49 #include "vrpn_Tracker_OSVRHackerDevKit.h"
50 #include "vrpn_Tracker_Filter.h"
51 #include <boost/noncopyable.hpp>
52 
53 #include <json/value.h>
54 #include <json/reader.h>
55 
56 #ifdef OSVR_MULTISERVER_VERBOSE
57 #include <boost/format.hpp>
58 #endif
59 
60 // Standard includes
61 #include <iostream>
62 #include <map>
63 #include <string>
64 #include <sstream>
65 #include <vector>
66 #include <algorithm>
67 
68 #ifdef OSVR_MULTISERVER_VERBOSE
69 #include <iostream>
70 #endif
71 
72 class VRPNHardwareDetect : boost::noncopyable {
73  public:
74  VRPNHardwareDetect(VRPNMultiserverData &data) : m_data(data) {}
75  OSVR_ReturnCode operator()(OSVR_PluginRegContext ctx) {
76  bool gotDevice;
77 #ifdef OSVR_MULTISERVER_VERBOSE
78  bool first = true;
79 #endif
80  do {
81  gotDevice = false;
82  struct hid_device_info *enumData = hid_enumerate(0, 0);
83  for (struct hid_device_info *dev = enumData; dev != nullptr;
84  dev = dev->next) {
85 
86  if (m_isPathHandled(dev->path)) {
87  continue;
88  }
89 
90 #ifdef OSVR_MULTISERVER_VERBOSE
91  if (first) {
92  std::cout << "[OSVR Multiserver] HID Enumeration: "
93  << boost::format("0x%04x") % dev->vendor_id << ":"
94  << boost::format("0x%04x") % dev->product_id
95  << std::endl;
96  }
97 #endif
98 
99  if (gotDevice) {
100  continue;
101  }
102  // Razer Hydra
103  if (dev->vendor_id == 0x1532 && dev->product_id == 0x0300) {
104  // OK, found one half of device, let's find the other half.
105  auto dataDev = dev;
106  auto ctrlDev = dev->next;
107  while (ctrlDev != nullptr &&
108  !(ctrlDev->vendor_id == 0x1532 &&
109  ctrlDev->product_id == 0x0300)) {
110  ctrlDev = ctrlDev->next;
111  }
112  if (!ctrlDev) {
113  std::cout
114  << "com_osvr_Multiserver warning: could only find "
115  "one of two interfaces for the Razer Hydra!"
116  << std::endl;
117  continue;
118  }
119  if (dataDev->interface_number == 1 && ctrlDev->interface_number == 0) {
120  // If we found these reversed, swap them: the data
121  // device should be interface 0, control is interface 1
122  // (if the interface numbers are valid at all)
123  std::swap(dataDev, ctrlDev);
124  }
125 
126  gotDevice = true;
127  m_handlePath(dataDev->path);
128  m_handlePath(ctrlDev->path);
129 
130  auto hydraJsonString = osvr::util::makeString(
131  com_osvr_Multiserver_RazerHydra_json);
132  Json::Value hydraJson;
133  Json::Reader reader;
134  if (!reader.parse(hydraJsonString, hydraJson)) {
135  throw std::logic_error("Faulty JSON file for Hydra - "
136  "should not be possible!");
137  }
139  std::string name;
140  {
141  // Razer Hydra
143  name =
144  reg.useDecoratedName(m_data.getName("RazerHydra"));
145  reg.registerDevice(new vrpn_Tracker_RazerHydra(
146  name.c_str(), ctrlDev->path, dataDev->path,
147  reg.getVRPNConnection()));
148  reg.setDeviceDescriptor(hydraJsonString);
149  }
150  std::string localName = "*" + name;
151 
152  {
153  // Copy semantic paths for corresponding filter: just
154  // want left/$target and right/$target
155  Json::Value filterJson;
156  if (!reader.parse(
158  com_osvr_Multiserver_OneEuroFilter_json),
159  filterJson)) {
160  throw std::logic_error("Faulty JSON file for One "
161  "Euro Filter - should not "
162  "be possible!");
163  }
164  auto &filterSem =
165  (filterJson["semantic"] = Json::objectValue);
166  auto &hydraSem = hydraJson["semantic"];
167  for (auto const &element : {"left", "right"}) {
168  filterSem[element] = Json::objectValue;
169  filterSem[element]["$target"] =
170  hydraSem[element]["$target"];
171  }
172  auto &filterAuto = (filterJson["automaticAliases"] =
173  Json::objectValue);
174  filterAuto["$priority"] =
175  130; // enough to override a normal automatic route.
176  auto &hydraAuto = hydraJson["automaticAliases"];
177  for (auto const &element :
178  {"/me/hands/left", "/me/hands/right"}) {
179  filterAuto[element] = hydraAuto[element];
180  }
181 
182  // Corresponding filter
184  reg.registerDevice(new vrpn_Tracker_FilterOneEuro(
185  reg.useDecoratedName(
186  m_data.getName("OneEuroFilter")).c_str(),
187  reg.getVRPNConnection(), localName.c_str(), 2, 1.15,
188  1.0, 1.2, 1.5, 5.0, 1.2));
189 
190  reg.setDeviceDescriptor(filterJson.toStyledString());
191  }
192  continue;
193  }
194 
195  // OSVR Hacker Dev Kit
196  if ((dev->vendor_id == 0x1532 && dev->product_id == 0x0b00) ||
197  (dev->vendor_id == 0x03EB && dev->product_id == 0x2421)) {
198  gotDevice = true;
199  m_handlePath(dev->path);
201  auto name = m_data.getName("OSVRHackerDevKit");
202  auto decName = reg.useDecoratedName(name);
204  vrpn_Tracker_OSVRHackerDevKit>(name);
205  reg.setDeviceDescriptor(osvr::util::makeString(
206  com_osvr_Multiserver_OSVRHackerDevKit_json));
207  {
209  reg2.registerDevice(
210  new vrpn_Tracker_DeadReckoning_Rotation(
211  reg2.useDecoratedName(m_data.getName(
212  "OSVRHackerDevKitPrediction")),
213  reg2.getVRPNConnection(), "*" + decName, 1,
214  32.0e-3, false));
215  reg2.setDeviceDescriptor(osvr::util::makeString(
216  com_osvr_Multiserver_OSVRHackerDevKit_json));
217  }
218  continue;
219  }
220 
221  //Sensics zSight (This block adds detection of Sensics zSight 1280 dual input device by osvr server)
222  //you can add other zSight devices by adding vendor id and product id in if block.
223  #if defined(_WIN32) && defined(VRPN_USE_DIRECTINPUT) && defined(VRPN_HAVE_ATLBASE)
224  if ((dev->vendor_id == 0x16d0 && dev->product_id == 0x0515)) {
225  gotDevice = true;
226  m_handlePath(dev->path);
228  auto name = m_data.getName("Sensics_zSight");
229  auto decName = reg.useDecoratedName(name);
231  vrpn_Tracker_zSight>(name);
232  reg.setDeviceDescriptor(osvr::util::makeString(
233  com_osvr_Multiserver_Sensics_zSight_json));
234  continue;
235  }
236  #endif
237  }
238  hid_free_enumeration(enumData);
239 
240 #ifdef OSVR_MULTISERVER_VERBOSE
241  first = false;
242 #endif
243 
244  } while (gotDevice);
245  return OSVR_RETURN_SUCCESS;
246  }
247 
248  private:
249  bool m_isPathHandled(const char *path) {
250  return std::find(begin(m_handledPaths), end(m_handledPaths),
251  std::string(path)) != end(m_handledPaths);
252  }
253  void m_handlePath(const char *path) {
254  m_handledPaths.push_back(std::string(path));
255  }
256  VRPNMultiserverData &m_data;
257  std::vector<std::string> m_handledPaths;
258 };
259 
260 OSVR_PLUGIN(com_osvr_Multiserver) {
261  osvr::pluginkit::PluginContext context(ctx);
262 
263  VRPNMultiserverData &data =
264  *context.registerObjectForDeletion(new VRPNMultiserverData);
265  context.registerHardwareDetectCallback(new VRPNHardwareDetect(data));
266 
268  ctx, "YEI_3Space_Sensor", &wrappedConstructor<&createYEI>, &data);
269 
270  return OSVR_RETURN_SUCCESS;
271 }
vrpn_Connection * getVRPNConnection()
Get the vrpn_Connection object to use in constructing your object.
std::string makeString(const char(&arrayLiteral)[N])
Safely and easily convert a literal array of characters (like from osvr_json_to_c) into a std::string...
Header to bring unique_ptr into the osvr namespace.
C++ wrapper class for the opaque plugin context.
Definition: PluginKit.h:59
T * constructAndRegisterDevice(std::string const &name)
Constructs and registers your custom device with the server and takes ownership of the object...
OSVR_ReturnCode osvrRegisterDriverInstantiationCallback(OSVR_PluginRegContext ctx, const char *name, OSVR_DriverInstantiationCallback cb, void *userData=NULL)
Register an instantiation callback (constructor) for a driver type. The given constructor may be call...
Header with a convenience function to make a std::string out of a non-null-terminated char array (str...
#define OSVR_RETURN_SUCCESS
The "success" value for an OSVR_ReturnCode.
Definition: ReturnCodesC.h:45
Header including the full PluginKit C++ interface.
#define OSVR_PLUGIN(PLUGIN_NAME)
This macro begins the entry point function of your plugin.
OSVR_ReturnCode operator()(OSVR_PluginRegContext ctx)
T * registerDevice(T *dev)
Registers your custom device with the server and takes ownership of the object.
std::string useDecoratedName(std::string const &name)
Decorates a device name with the plugin name and returns it, as well as records it for registration w...
OSVR_EXTERN_C_BEGIN typedef void * OSVR_PluginRegContext
A context pointer passed in to your plugin's entry point and other locations of control flow transfer...