Skip to content

File service.cpp

File List > fauxpose > service.cpp

Go to the documentation of this file

/*****************************************************************************/
/* fauxpose/plugin.cpp                                                       */
/*                                                                           */
/* Created: 03/03/2022                                                       */
/* Last Edited: 07/27/2023                                                   */
/*                                                                           */
/* An ILLIXR plugin that publishes position tracking data ("pose")           */
/*     from a mathematical operation just to quickly produce some known      */
/*     tracking path for the purpose of debugging other portions of ILLIXR.  */
/*                                                                           */
/* USAGE:                                                                    */
/*   * Add "- path: fauxpose/" as a plugin (and not other trackers)          */
/*   * Use "FAUXPOSE_PERIOD" environment variable to control orbit period    */
/*   * Use "FAUXPOSE_AMPLITUDE" environment variable to control orbit size   */
/*   * Use "FAUXPOSE_CENTER" env-var to control the center point of orbit    */
/*                                                                           */
/* TODO:                                                                     */
/*   * DONE: Need to implement as a "pose_prediction" "impl" (service?)      */
/*   * DONE: Fix so that "gldemo" (etc.) face forward.                       */
/*   * DONE: Implement environment variables to control parameters           */
/*   * Add control of the view direction as a control parameter              */
/*   * Add control of orbital plane as a control parameter                   */
/*                                                                           */
/* NOTES:                                                                    */
/*   * get_fast_pose() method returns a "fast_head_pose_type"                */
/*   * "fast_head_pose_type" is a "head_pose_type" plus computed & target    */
/*   * timestamps correct_pose() method returns a "head_pose_type"           */
/*   * (This version uploaded to ILLIXR GitHub)                              */
/*                                                                           */

#include "service.hpp"

#include 
#include 
#ifdef __ANDROID__
#    include 
#    include 
#else
#    include 
#    include 
#endif
#include 
#include 

using namespace ILLIXR;
using namespace ILLIXR::data_format;

#if defined(_WIN32) || defined(_WIN64)

char* strchrnul(char* str, int c) {
    char* pos = strchr(str, c);
    return (pos != nullptr) ? pos : str + strlen(str);
}

const char* strchrnul(const char* str, int c) {
    const char* pos = strchr(str, c);
    return (pos != nullptr) ? pos : str + strlen(str);
}

#endif
fauxpose_impl::fauxpose_impl(const phonebook* pb)
    : switchboard_{pb->lookup_impl<switchboard>()}
    , clock_{pb->lookup_impl<relative_clock>()}
    , vsync_estimate_{switchboard_->get_reader<switchboard::event_wrapper<time_point>>("vsync_estimate")} {
    const char* env_input; /* pointer to environment variable input */
#ifndef NDEBUG
    spdlog::get("illixr")->debug("[fauxpose] Starting Service");
#endif

    // Store the initial time
    if (clock_->is_started()) {
        sim_start_time_ = clock_->now();
#ifndef NDEBUG
        spdlog::get("illixr")->debug("[fauxpose] Starting Service");
#endif
    } else {
#ifndef NDEBUG
        spdlog::get("illixr")->debug("[fauxpose] Warning: the clock isn't started yet");
#endif
    }

    // Set default faux-pose parameters
    center_location_ = Eigen::Vector3f{0.0, 1.5, 0.0};
    period_          = 0.5;
    amplitude_       = 2.0;

    // Adjust parameters based on environment variables
    if ((env_input = switchboard_->get_env_char("FAUXPOSE_PERIOD"))) {
        period_ = std::strtof(env_input, nullptr);
    }
    if ((env_input = switchboard_->get_env_char("FAUXPOSE_AMPLITUDE"))) {
        amplitude_ = std::strtof(env_input, nullptr);
    }
    if ((env_input = switchboard_->get_env_char("FAUXPOSE_CENTER"))) {
        center_location_[0] = std::strtof(env_input, nullptr);
        center_location_[1] = std::strtof(strchrnul(env_input, ',') + 1, nullptr);
        center_location_[2] = std::strtof(strchrnul(strchrnul(env_input, ',') + 1, ',') + 1, nullptr);
    }
#ifndef NDEBUG
    spdlog::get("illixr")->debug("[fauxpose] Period is {}", period_);
    spdlog::get("illixr")->debug("[fauxpose] Amplitude is {}", amplitude_);
    spdlog::get("illixr")->debug("[fauxpose] Center is {}, {}, {}", center_location_[0], center_location_[1],
                                 center_location_[2]);
#endif
}

fauxpose_impl::~fauxpose_impl() {
#ifndef NDEBUG
    spdlog::get("illixr")->debug("[fauxpose] Ending Service");
#endif
}

pose::head_pose_type fauxpose_impl::correct_pose([[maybe_unused]] const pose::head_pose_type& pose) const {
#ifndef NDEBUG
    spdlog::get("illixr")->debug("[fauxpose] Returning (passthru) pose");
#endif
    return pose;
}

Eigen::Quaternionf fauxpose_impl::get_offset() {
    return offset_;
}

void fauxpose_impl::set_offset(const Eigen::Quaternionf& raw_o_times_offset) {
    std::unique_lock   lock{offset_mutex_};
    Eigen::Quaternionf raw_o = raw_o_times_offset * offset_.inverse();
    offset_                  = raw_o.inverse();
}

pose::fast_head_pose_type fauxpose_impl::get_fast_pose() const {
    // In actual pose prediction, the semantics are that we return
    //   the pose for next vsync, not now.
    switchboard::ptr<const switchboard::event_wrapper<time_point>> vsync_estimate = vsync_estimate_.get_ro_nullable();
    if (vsync_estimate == nullptr) {
        return get_fast_pose(clock_->now());
    } else {
        return get_fast_pose(vsync_estimate.get()->operator time_point());
    }
}

pose::fast_head_pose_type fauxpose_impl::get_fast_pose(time_point time) const {
    pose::head_pose_type simulated_pose; /* The algorithmically calculated 6-DOF pose */
    double               sim_time;       /* sim_time is used to regulate a consistent movement */

    RAC_ERRNO_MSG("[fauxpose] at start of _p_one_iteration");

    // Calculate simulation time from start of execution
    std::chrono::nanoseconds elapsed_time;
    elapsed_time = time - sim_start_time_;
    sim_time     = static_cast<double>(elapsed_time.count()) * 0.000000001;

    // Calculate new pose values
    //   Pose values are calculated from the passage of time to maintain consistency */
    simulated_pose.position[0] = static_cast<float>(center_location_[0] + amplitude_ * sin(sim_time * period_)); // X
    simulated_pose.position[1] = static_cast<float>(center_location_[1]);                                        // Y
    simulated_pose.position[2] = static_cast<float>(center_location_[2] + amplitude_ * cos(sim_time * period_)); // Z
    simulated_pose.orientation = Eigen::Quaternionf(0.707, 0.0, 0.707, 0.0); // (W,X,Y,Z) Facing forward (90deg about Y)

    // Return the new pose
#ifndef NDEBUG
    spdlog::get("illixr")->debug("[fauxpose] Returning pose");
#endif
    return pose::fast_head_pose_type{simulated_pose, clock_->now(), time};
}

[[maybe_unused]] fauxpose::fauxpose(const std::string& name, phonebook* pb)
    : plugin{name, pb} {
    // "pose_prediction" is a class inheriting from "phonebook::service"
    //   It is described in "pose_prediction.hpp"
    pb->register_impl<pose_prediction>(std::static_pointer_cast<pose_prediction>(std::make_shared<fauxpose_impl>(pb)));
#ifndef NDEBUG
    spdlog::get("illixr")->debug("[fauxpose] Starting Plugin");
#endif
}

fauxpose::~fauxpose() {
#ifndef NDEBUG
    spdlog::get("illixr")->debug("[fauxpose] Ending Plugin");
#endif
}

// This line makes the plugin importable by Spindle
PLUGIN_MAIN(fauxpose)