Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4f079d0e authored by Alex Vakulenko's avatar Alex Vakulenko
Browse files

frameworks/native: Add VR command-line tools

Bug: None
Test: `m -j32` succeeds
Change-Id: Ia83c71875eb0f207f63a168c88a138daeea42d5d
parent 87162c12
Loading
Loading
Loading
Loading

cmds/vr/.clang-format

0 → 100644
+5 −0
Original line number Diff line number Diff line
BasedOnStyle: Google
DerivePointerAlignment: false
PointerAlignment: Left
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
+41 −0
Original line number Diff line number Diff line
# Copyright (C) 2008 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

LOCAL_PATH := $(call my-dir)

sourceFiles := \
  pose.cpp

staticLibraries := \
  libdvrcommon \
  libsensor \
  libpdx_default_transport \

sharedLibraries := \
  libcutils \
  liblog

include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(sourceFiles)
LOCAL_STATIC_LIBRARIES := $(staticLibraries)
LOCAL_SHARED_LIBRARIES := $(sharedLibraries)
LOCAL_MODULE := pose
LOCAL_MODULE_TAGS := optional
include $(BUILD_EXECUTABLE)

ifeq ($(TARGET_BUILD_VARIANT),eng)
ALL_DEFAULT_INSTALLED_MODULES += pose
all_modules: pose
endif

cmds/vr/pose/pose.cpp

0 → 100644
+274 −0
Original line number Diff line number Diff line
// 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.\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 {
    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);
}
+28 −0
Original line number Diff line number Diff line
LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)

LOCAL_SRC_FILES := \
	vrscreencap.cpp

LOCAL_STATIC_LIBRARIES := \
	libdisplay \
	libimageio \
	libpdx_default_transport \

LOCAL_SHARED_LIBRARIES := \
	libcutils \
	liblog \
	libpng \
	libsync

LOCAL_MODULE := vrscreencap

LOCAL_MODULE_TAGS := optional

include $(BUILD_EXECUTABLE)

ifeq ($(TARGET_BUILD_VARIANT),eng)
ALL_DEFAULT_INSTALLED_MODULES += vrscreencap
all_modules: vrscreencap
endif
+74 −0
Original line number Diff line number Diff line
// screencap is a tool for taking screenshots using the screenshot service.

#include <fstream>
#include <iostream>
#include <string>
#include <vector>

#include <private/dvr/image_io.h>
#include <private/dvr/screenshot_client.h>

namespace {

// Attempt to take a screenshot and save it to |filename|.
// Returns zero on success, or a non-zero exit code otherwise.
int TakeScreenshot(const std::string& app_name, const std::string& filename,
                   int index) {
  auto error_out = [app_name]() -> std::ostream& {
    return std::cerr << app_name << ": ";
  };

  auto info_out = [app_name]() -> std::ostream& {
    return std::cout << app_name << ": ";
  };

  auto client = android::dvr::ScreenshotClient::Create();

  if (client->format() != HAL_PIXEL_FORMAT_RGB_888) {
    error_out() << "The screenshot format for this device is not supported."
                << std::endl;
    return 1;
  }

  std::vector<uint8_t> image;
  int width = 0;
  int height = 0;
  if (client->Take(&image, index, &width, &height) != 0) {
    error_out() << "Failed to take screenshot." << std::endl;
    return 1;
  }

  info_out() << "Got " << width << "x" << height << " screenshot." << std::endl;

  if (!image_io_write_rgb888(filename.c_str(), width, height, image.data())) {
    error_out() << "Failed to write image to output file " << filename
                << std::endl;
    return 1;
  }

  return 0;
}

}  // namespace

int main(int argc, char** argv) {
  // Parse arguments
  if (argc != 2 && argc != 3) {
    std::cerr
        << "Usage: " << argv[0]
        << " filename.[" DVR_IMAGE_IO_SUPPORTED_WRITE
           "] [INDEX]\n"
           "INDEX: specify 1..n to grab hw_composer layers by index.\n"
           "       specify -n to grab pre-warp layers (-1 is base layer).\n"
           "       the default is 1 (the base hw_composer layer).\n"
           "       an invalid index will result in an error.\n";
    return 1;
  }
  const std::string filename(argv[1]);
  int index = 1;
  if (argc > 2)
    index = atoi(argv[2]);

  // Perform the actual screenshot.
  return TakeScreenshot(argv[0], filename, index);
}