39 #include <boost/program_options.hpp> 
   40 #include <boost/thread/thread.hpp> 
   41 #include <boost/date_time/posix_time/posix_time.hpp> 
   42 #include <json/value.h> 
   43 #include <json/reader.h> 
   56 auto SETTLE_TIME = boost::posix_time::seconds(2);
 
   62         cout << 
"Received shutdown signal..." << endl;
 
   65         cout << 
"Received shutdown signal but server already stopped..." 
   70 void waitForEnter() { std::cin.ignore(); }
 
   72 inline Json::Value removeCalibration(std::string 
const &input) {
 
   75     if (!reader.parse(input, root)) {
 
   76         throw std::runtime_error(
"Could not parse route");
 
   79         return current.isMember(
"calibration") &&
 
   80                current[
"calibration"].isBool() &&
 
   81                current[
"calibration"].asBool();
 
   85 int main(
int argc, 
char *argv[]) {
 
   86     std::string configName;
 
   87     std::string outputName;
 
   88     namespace po = boost::program_options;
 
   90     po::options_description desc(
"Options");
 
   92         (
"help", 
"produce help message")
 
   93         (
"route", po::value<std::string>()->default_value(
"/me/head"), 
"route to calibrate")
 
   94         (
"output,O", po::value<std::string>(&outputName), 
"output file (defaults to same as config file)")
 
   96     po::options_description hidden(
"Hidden (positional-only) options");
 
   98         (
"config", po::value<std::string>(&configName)->default_value(std::string(osvr::server::getDefaultConfigFilename())))
 
  102     po::positional_options_description p;
 
  105     po::variables_map vm;
 
  106     po::store(po::command_line_parser(argc, argv)
 
  107                   .options(po::options_description().add(desc).add(hidden))
 
  117         if (vm.count(
"help")) {
 
  119         } 
else if (vm.count(
"route") != 1) {
 
  120             cout << 
"Error: --route is a required argument\n" << endl;
 
  125             cout << 
"Usage: osvr_calibrate [config file name] [options]" 
  127             cout << desc << 
"\n";
 
  132     if (outputName.empty()) {
 
  133         outputName = configName;
 
  143     cout << 
"Registering shutdown handler..." << endl;
 
  144     osvr::server::registerShutdownHandler<&handleShutdown>();
 
  146     std::string dest = vm[
"route"].as<std::string>();
 
  147     std::string route = srv->getSource(dest);
 
  149         cerr << 
"Error: No route found for provided destination: " << dest
 
  153     cout << dest << 
" -> " << route << endl;
 
  154     Json::Value pruned = removeCalibration(route);
 
  155     Json::Value prunedDirective(Json::objectValue);
 
  157         cout << pruned.toStyledString() << endl;
 
  158         cout << 
"Submitting cleaned route..." << endl;
 
  159         prunedDirective[
"destination"] = dest;
 
  160         prunedDirective[
"source"] = pruned;
 
  161         srv->addRoute(prunedDirective.toStyledString());
 
  163     cout << 
"Starting client..." << endl;
 
  168     srv->registerMainloopMethod([&client] { client.mainloop(); });
 
  175         cout << 
"Starting server and client mainloop..." << endl;
 
  177         cout << 
"Waiting a few seconds for the server to settle..." << endl;
 
  178         boost::this_thread::sleep(SETTLE_TIME);
 
  180         cout << 
"\n\nPlease place your device in its 'zero' orientation and " 
  181                 "press enter." << endl;
 
  190             ClientMainloop::lock_type lock(client.getMutex());
 
  194             cerr << 
"Sorry, no orientation state available for this route - " 
  195                     "are you sure you have a device plugged in and your path " 
  201         cout << 
"Angle: " << rotation.angle()
 
  202              << 
" Axis: " << rotation.axis().transpose() << endl;
 
  203         Json::Value newRoute;
 
  205             Json::Value newLayer(Json::objectValue);
 
  206             newLayer[
"calibration"] = 
true;
 
  207             newLayer[
"rotate"][
"radians"] = rotation.angle();
 
  209             newRoute = wrapRoute(prunedDirective, newLayer);
 
  210             bool isNew = server->addRoute(newRoute.toStyledString());
 
  213                 "Server claims this is a new, rather than a replacement, " 
  214                 "route... should not happen!");
 
  219         boost::this_thread::sleep(SETTLE_TIME);
 
  221         cout << 
"\n\nNew calibration applied: please inspect it with the " 
  222                 "Tracker Viewer." << endl;
 
  223         cout << 
"(If rotations appear incorrect, you may first need to add " 
  224                 "a basisChange transform layer to the route.)" << endl;
 
  225         if (configName == outputName) {
 
  226             cout << 
"If you are satisfied and want to OVERWRITE your existing " 
  227                     "config file with this update, press y." << endl;
 
  228             cout << 
"Otherwise, press enter or Ctrl-C to break out of this " 
  229                     "program.\n" << endl;
 
  230             cout << 
"Overwrite '" << configName << 
"'? [yN] ";
 
  232             std::cin.get(confirm);
 
  234             if (confirm != 
'y' && confirm != 
'Y') {
 
  235                 cout << 
"Calibration save cancelled." << endl;
 
  241             std::ifstream config(configName);
 
  242             if (!config.good()) {
 
  243                 cerr << 
"Could not read the original config file again!" 
  249             if (!reader.parse(config, root)) {
 
  250                 cerr << 
"Could not parse the original config file again! " 
  251                         "Should never happen!" << endl;
 
  255         auto &routes = root[
"routes"];
 
  256         for (
auto &fileRoute : routes) {
 
  257             if (fileRoute[
"destination"] == dest) {
 
  258                 fileRoute = newRoute;
 
  262             cout << 
"\n\nWriting updated config file to " << outputName << endl;
 
  263             std::ofstream outfile(outputName);
 
  264             outfile << root.toStyledString();
 
  267         cout << 
"Awaiting Ctrl-C to trigger server shutdown..." << endl;
 
  268         server->awaitShutdown();
 
  270     cout << 
"Server mainloop exited." << endl;
 
Interface handle object. Typically acquired from a ClientContext. 
Client context object: Create and keep one in your application. Handles lifetime management and provi...
Header to register a handler for cross-platform shutdown/terminate signals. WARNING: includes windows...
A structure defining a quaternion, often a unit quaternion representing 3D rotation. 
OSVR_SERVER_EXPORT ServerPtr configureServerFromFile(std::string const &configName)
This uses a file name to attempt to configure the server with that config file. Pass an empty string ...
Interface getInterface(const std::string &path)
Get the interface associated with the given path. 
OSVR_ClientInterface get()
Get the raw OSVR_ClientInterface from this wrapper. 
Simple class to handle running a client mainloop in another thread, but easily pausable. 
#define OSVR_RETURN_SUCCESS
The "success" value for an OSVR_ReturnCode. 
int main(int argc, char *argv[])
shared_ptr< Server > ServerPtr
How one should hold a Server. 
void handleShutdown()
Shutdown handler function - forcing the server pointer to be global. 
Eigen::Quaterniond fromQuat(OSVR_Quaternion const &q)
Convert an OSVR_Quaternion to an Eigen::Quaterniond. 
Header for interoperation between the Eigen math library, the internal mini math library, and VRPN's quatlib. 
OSVR_ReturnCode osvrGetOrientationState(OSVR_ClientInterface iface, struct OSVR_TimeValue *timestamp, OSVR_OrientationState *state)
Get Orientation state from an interface, returning failure if none \ * exists. 
weak_ptr< Server > ServerWeakPtr
How one might observe a Server without owning it. 
Standardized, portable parallel to struct timeval for representing both absolute times and time inter...
Json::Value toJson(Eigen::QuaternionBase< Derived > const &quat)
Converts quaternions to JSON objects.