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.