| // pose is a utility to query and manipulate the current pose via the pose | 
 | // service. | 
 |  | 
 | #include <cmath> | 
 | #include <cstdio> | 
 | #include <iomanip> | 
 | #include <iostream> | 
 | #include <regex> | 
 | #include <vector> | 
 |  | 
 | #include <private/dvr/types.h> | 
 | #include <dvr/pose_client.h> | 
 |  | 
 | using android::dvr::vec3; | 
 | using android::dvr::quat; | 
 |  | 
 | namespace { | 
 |  | 
 | // Prints usage information to stderr. | 
 | void PrintUsage(const char* executable_name) { | 
 |   std::cerr << "Usage: " << executable_name | 
 |             << " [--identity|--set=...|--unfreeze]\n" | 
 |             << "\n" | 
 |             << "  no arguments: display the current pose.\n" | 
 |             << "  --identity: freeze the pose to the identity pose.\n" | 
 |             << "  --set=rx,ry,rz,rw[,px,py,pz]: freeze the pose to the given " | 
 |                "state. rx,ry,rz,rw are interpreted as rotation quaternion. " | 
 |                " px, py, pz as position (0,0,0 if omitted).\n" | 
 |             << "  --mode=mode: sets mode to one of normal, head_turn:slow, " | 
 |                "head_turn:fast, rotate:slow, rotate:medium, rotate:fast, " | 
 |                "circle_strafe, float, motion_sickness.\n" | 
 |             << "  --unfreeze: sets the mode to normal.\n" | 
 |             << "  --log_controller=[true|false]: starts and stops controller" | 
 |                " logs\n" | 
 |             << std::endl; | 
 | } | 
 |  | 
 | // If return_code is negative, print out its corresponding string description | 
 | // and exit the program with a non-zero exit code. | 
 | void ExitIfNegative(int return_code) { | 
 |   if (return_code < 0) { | 
 |     std::cerr << "Error: " << strerror(-return_code) << std::endl; | 
 |     std::exit(1); | 
 |   } | 
 | } | 
 |  | 
 | // Parses the following command line flags: | 
 | // --identity | 
 | // --set=rx,ry,rz,rw[,px,py,pz] | 
 | // Returns false if parsing fails. | 
 | bool ParseState(const std::string& arg, DvrPoseState* out_state) { | 
 |   if (arg == "--identity") { | 
 |     *out_state = {.head_from_start_rotation = {0.f, 0.f, 0.f, 1.f}, | 
 |                   .head_from_start_translation = {0.f, 0.f, 0.f}, | 
 |                   .timestamp_ns = 0, | 
 |                   .sensor_from_start_rotation_velocity = {0.f, 0.f, 0.f}}; | 
 |     return true; | 
 |   } | 
 |  | 
 |   const std::string prefix("--set="); | 
 |   if (arg.size() < 6 || arg.compare(0, prefix.size(), prefix) != 0) { | 
 |     return false; | 
 |   } | 
 |  | 
 |   // Tokenize by ','. | 
 |   std::regex split_by_comma("[,]+"); | 
 |   std::sregex_token_iterator token_it(arg.begin() + prefix.size(), arg.end(), | 
 |                                       split_by_comma, | 
 |                                       -1 /* return inbetween parts */); | 
 |   std::sregex_token_iterator token_end; | 
 |  | 
 |   // Convert to float and store values. | 
 |   std::vector<float> values; | 
 |   for (; token_it != token_end; ++token_it) { | 
 |     std::string token = *(token_it); | 
 |     float value = 0.f; | 
 |     if (sscanf(token.c_str(), "%f", &value) != 1) { | 
 |       std::cerr << "Unable to parse --set value as float: " << token | 
 |                 << std::endl; | 
 |       return false; | 
 |     } else { | 
 |       values.push_back(value); | 
 |     } | 
 |   } | 
 |  | 
 |   if (values.size() != 4 && values.size() != 7) { | 
 |     std::cerr << "Unable to parse --set, expected either 4 or 7 of values." | 
 |               << std::endl; | 
 |     return false; | 
 |   } | 
 |  | 
 |   float norm2 = values[0] * values[0] + values[1] * values[1] + | 
 |                 values[2] * values[2] + values[3] * values[3]; | 
 |   if (std::abs(norm2 - 1.f) > 1e-4) { | 
 |     if (norm2 < 1e-8) { | 
 |       std::cerr << "--set quaternion norm close to zero." << std::endl; | 
 |       return false; | 
 |     } | 
 |     float norm = std::sqrt(norm2); | 
 |     values[0] /= norm; | 
 |     values[1] /= norm; | 
 |     values[2] /= norm; | 
 |     values[3] /= norm; | 
 |   } | 
 |  | 
 |   out_state->head_from_start_rotation = {values[0], values[1], values[2], | 
 |                                          values[3]}; | 
 |  | 
 |   if (values.size() == 7) { | 
 |     out_state->head_from_start_translation = {values[4], values[5], values[6]}; | 
 |   } else { | 
 |     out_state->head_from_start_translation = {0.f, 0.f, 0.f}; | 
 |   } | 
 |  | 
 |   out_state->timestamp_ns = 0; | 
 |   out_state->sensor_from_start_rotation_velocity = {0.f, 0.f, 0.f}; | 
 |  | 
 |   return true; | 
 | } | 
 |  | 
 | // Parses the command line flag --mode. | 
 | // Returns false if parsing fails. | 
 | bool ParseSetMode(const std::string& arg, DvrPoseMode* mode) { | 
 |   const std::string prefix("--mode="); | 
 |   if (arg.size() < prefix.size() || | 
 |       arg.compare(0, prefix.size(), prefix) != 0) { | 
 |     return false; | 
 |   } | 
 |  | 
 |   std::string value = arg.substr(prefix.size()); | 
 |  | 
 |   if (value == "normal") { | 
 |     *mode = DVR_POSE_MODE_6DOF; | 
 |     return true; | 
 |   } else if (value == "head_turn:slow") { | 
 |     *mode = DVR_POSE_MODE_MOCK_HEAD_TURN_SLOW; | 
 |     return true; | 
 |   } else if (value == "head_turn:fast") { | 
 |     *mode = DVR_POSE_MODE_MOCK_HEAD_TURN_FAST; | 
 |     return true; | 
 |   } else if (value == "rotate:slow") { | 
 |     *mode = DVR_POSE_MODE_MOCK_ROTATE_SLOW; | 
 |     return true; | 
 |   } else if (value == "rotate:medium") { | 
 |     *mode = DVR_POSE_MODE_MOCK_ROTATE_MEDIUM; | 
 |     return true; | 
 |   } else if (value == "rotate:fast") { | 
 |     *mode = DVR_POSE_MODE_MOCK_ROTATE_FAST; | 
 |     return true; | 
 |   } else if (value == "circle_strafe") { | 
 |     *mode = DVR_POSE_MODE_MOCK_CIRCLE_STRAFE; | 
 |     return true; | 
 |   } else if (value == "float") { | 
 |     *mode = DVR_POSE_MODE_FLOAT; | 
 |     return true; | 
 |   } else if (value == "motion_sickness") { | 
 |     *mode = DVR_POSE_MODE_MOCK_MOTION_SICKNESS; | 
 |     return true; | 
 |   } else { | 
 |     return false; | 
 |   } | 
 | } | 
 |  | 
 | // Parses the command line flag --controller_log. | 
 | // Returns false if parsing fails. | 
 | bool ParseLogController(const std::string& arg, bool* log_enabled) { | 
 |   const std::string prefix("--log_controller="); | 
 |   if (arg.size() < prefix.size() || | 
 |       arg.compare(0, prefix.size(), prefix) != 0) { | 
 |     return false; | 
 |   } | 
 |  | 
 |   std::string value = arg.substr(prefix.size()); | 
 |  | 
 |   if (value == "false") { | 
 |     *log_enabled = false; | 
 |     return true; | 
 |   } else if (value == "true") { | 
 |     *log_enabled = true; | 
 |     return true; | 
 |   } else { | 
 |     return false; | 
 |   } | 
 | } | 
 |  | 
 | // The different actions that the tool can perform. | 
 | enum class Action { | 
 |   Query,                 // Query the current pose. | 
 |   Set,                   // Set the pose and freeze. | 
 |   Unfreeze,              // Set the pose mode to normal. | 
 |   SetMode,               // Sets the pose mode. | 
 |   LogController,         // Start/stop controller logging in sensord. | 
 | }; | 
 |  | 
 | // The action to perform when no arguments are passed to the tool. | 
 | constexpr Action kDefaultAction = Action::Query; | 
 |  | 
 | }  // namespace | 
 |  | 
 | int main(int argc, char** argv) { | 
 |   Action action = kDefaultAction; | 
 |   DvrPoseState state; | 
 |   DvrPoseMode pose_mode = DVR_POSE_MODE_6DOF; | 
 |   bool log_controller = false; | 
 |  | 
 |   // Parse command-line arguments. | 
 |   for (int i = 1; i < argc; ++i) { | 
 |     const std::string arg = argv[i]; | 
 |     if (ParseState(arg, &state) && action == kDefaultAction) { | 
 |       action = Action::Set; | 
 |     } else if (arg == "--unfreeze" && action == kDefaultAction) { | 
 |       action = Action::Unfreeze; | 
 |     } else if (ParseSetMode(arg, &pose_mode) && action == kDefaultAction) { | 
 |       action = Action::SetMode; | 
 |     } else if (ParseLogController(arg, &log_controller)) { | 
 |       action = Action::LogController; | 
 |     } else { | 
 |       PrintUsage(argv[0]); | 
 |       return 1; | 
 |     } | 
 |   } | 
 |  | 
 |   auto pose_client = dvrPoseCreate(); | 
 |   if (!pose_client) { | 
 |     std::cerr << "Unable to create pose client." << std::endl; | 
 |     return 1; | 
 |   } | 
 |  | 
 |   switch (action) { | 
 |     case Action::Query: { | 
 |       ExitIfNegative(dvrPosePoll(pose_client, &state)); | 
 |       uint64_t timestamp = state.timestamp_ns; | 
 |       const auto& rotation = state.head_from_start_rotation; | 
 |       const auto& translation = state.head_from_start_translation; | 
 |       const auto& rotation_velocity = state.sensor_from_start_rotation_velocity; | 
 |       quat q(rotation.w, rotation.x, rotation.y, rotation.z); | 
 |       vec3 angles = q.matrix().eulerAngles(0, 1, 2); | 
 |       angles = angles * 180.f / M_PI; | 
 |       vec3 x = q * vec3(1.0f, 0.0f, 0.0f); | 
 |       vec3 y = q * vec3(0.0f, 1.0f, 0.0f); | 
 |       vec3 z = q * vec3(0.0f, 0.0f, 1.0f); | 
 |  | 
 |       std::cout << "timestamp_ns: " << timestamp << std::endl | 
 |                 << "rotation_quaternion: " << rotation.x << ", " << rotation.y | 
 |                 << ", " << rotation.z << ", " << rotation.w << std::endl | 
 |                 << "rotation_angles: " << angles.x() << ", " << angles.y() | 
 |                 << ", " << angles.z() << std::endl | 
 |                 << "translation: " << translation.x << ", " << translation.y | 
 |                 << ", " << translation.z << std::endl | 
 |                 << "rotation_velocity: " << rotation_velocity.x << ", " | 
 |                 << rotation_velocity.y << ", " << rotation_velocity.z | 
 |                 << std::endl | 
 |                 << "axes: " << std::setprecision(3) | 
 |                 << "x(" << x.x() << ", " << x.y() << ", " << x.z() << "), " | 
 |                 << "y(" << y.x() << ", " << y.y() << ", " << y.z() << "), " | 
 |                 << "z(" << z.x() << ", " << z.y() << ", " << z.z() << "), " | 
 |                 << std::endl; | 
 |       break; | 
 |     } | 
 |     case Action::Set: { | 
 |       ExitIfNegative(dvrPoseFreeze(pose_client, &state)); | 
 |       break; | 
 |     } | 
 |     case Action::Unfreeze: { | 
 |       ExitIfNegative(dvrPoseSetMode(pose_client, DVR_POSE_MODE_6DOF)); | 
 |       break; | 
 |     } | 
 |     case Action::SetMode: { | 
 |       ExitIfNegative(dvrPoseSetMode(pose_client, pose_mode)); | 
 |       break; | 
 |     } | 
 |     case Action::LogController: { | 
 |       ExitIfNegative( | 
 |           dvrPoseLogController(pose_client, log_controller)); | 
 |       break; | 
 |     } | 
 |   } | 
 |  | 
 |   dvrPoseDestroy(pose_client); | 
 | } |