You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

316 lines
10 KiB

// License: Apache 2.0. See LICENSE file in root directory.
// Copyright(c) 2015 Intel Corporation. All Rights Reserved.
#pragma once
#include "approx.h"
#include <librealsense2/rs.hpp>
#include <librealsense2/hpp/rs_context.hpp>
#include <librealsense2/hpp/rs_internal.hpp>
#include <limits> // For std::numeric_limits
#include <cmath> // For std::sqrt
#include <cassert> // For assert
#include <thread> // For std::this_thread::sleep_for
#include <map>
#include <mutex>
#include <condition_variable>
#include <atomic>
#include <vector>
#include <fstream>
#include <array>
#include <set>
#include <src/types.h>
// noexcept is not accepted by Visual Studio 2013 yet, but noexcept(false) is require on throwing destructors on gcc and clang
// It is normally advisable not to throw in a destructor, however, this usage is safe for require_error/require_no_error because
// they will only ever be created as temporaries immediately before being passed to a C ABI function. All parameters and return
// types are vanilla C types, and thus nothrow-copyable, and the function itself cannot throw because it is a C ABI function.
// Therefore, when a temporary require_error/require_no_error is destructed immediately following one of these C ABI function
// calls, we should not have any exceptions in flight, and can freely throw (perhaps indirectly by calling Catch's REQUIRE()
// macro) to indicate postcondition violations.
#ifdef WIN32
#define NOEXCEPT_FALSE
#else
#define NOEXCEPT_FALSE noexcept(false)
#endif
struct stream_request
{
rs2_stream stream;
rs2_format format;
int width;
int height;
int fps;
int index;
bool operator==(const rs2::video_stream_profile& other) const
{
return stream == other.stream_type() &&
format == other.format() &&
width == other.width() &&
height == other.height() &&
index == other.stream_index();
}
};
struct profile
{
rs2_stream stream;
rs2_format format;
int width;
int height;
int index;
int fps;
bool operator==(const profile& other) const
{
return stream == other.stream &&
(format == 0 || other.format == 0 || format == other.format) &&
(width == 0 || other.width == 0 || width == other.width) &&
(height == 0 || other.height == 0 || height == other.height) &&
(index == 0 || other.index == 0 || index == other.index);
}
bool operator!=(const profile& other) const
{
return !(*this == other);
}
bool operator<(const profile& other) const
{
return stream < other.stream;
}
};
inline std::ostream& operator <<(std::ostream& stream, const profile& cap)
{
stream << cap.stream << " " << cap.stream << " " << cap.format << " "
<< cap.width << " " << cap.height << " " << cap.index << " " << cap.fps;
return stream;
}
struct device_profiles
{
std::vector<profile> streams;
int fps;
bool sync;
};
std::vector< profile >
configure_all_supported_streams( rs2::sensor & sensor, int width = 640, int height = 480, int fps = 60 );
std::pair< std::vector< rs2::sensor >, std::vector< profile > >
configure_all_supported_streams( rs2::device & dev, int width = 640, int height = 480, int fps = 30 );
std::string space_to_underscore( const std::string & text );
#define SECTION_FROM_TEST_NAME space_to_underscore(Catch::getCurrentContext().getResultCapture()->getCurrentTestName()).c_str()
//inline long long current_time();
//// disable in one place options that are sensitive to frame content
//// this is done to make sure unit-tests are deterministic
void disable_sensitive_options_for( rs2::sensor & sen );
void disable_sensitive_options_for( rs2::device & dev );
bool wait_for_reset( std::function< bool( void ) > func, std::shared_ptr< rs2::device > dev );
bool is_usb3( const rs2::device & dev );
// Provides for Device PID , USB3/2 (true/false)
typedef std::pair<std::string, bool > dev_type;
dev_type get_PID( rs2::device & dev );
struct command_line_params
{
static void init( int argc, char const * const * argv );
};
bool found_any_section();
inline bool file_exists(const std::string& filename)
{
std::ifstream f(filename);
return f.good();
}
rs2::context make_context( const char * id );
// Can be passed to rs2_error ** parameters, requires that an error is indicated with the specific provided message
class require_error
{
std::string message;
bool validate_error_message; // Messages content may vary , subject to backend selection
rs2_error * err;
public:
require_error(std::string message, bool message_validation = true) : message(std::move(message)), validate_error_message(message_validation), err() {}
require_error(const require_error &) = delete;
~require_error() NOEXCEPT_FALSE
{
assert(!std::uncaught_exception());
REQUIRE(err != nullptr);
if (validate_error_message)
{
REQUIRE(rs2_get_error_message(err) == std::string(message));
}
}
require_error & operator = (const require_error &) = delete;
operator rs2_error ** () { return &err; }
};
// Can be passed to rs2_error ** parameters, requires that no error is indicated
class require_no_error
{
rs2_error * err;
public:
require_no_error() : err() {}
require_no_error(const require_error &) = delete;
~require_no_error() NOEXCEPT_FALSE
{
assert(!std::uncaught_exception());
REQUIRE(rs2_get_error_message(err) == rs2_get_error_message(nullptr)); // Perform this check first. If an error WAS indicated, Catch will display it, making our debugging easier.
REQUIRE(err == nullptr);
}
require_no_error & operator = (const require_no_error &) = delete;
operator rs2_error ** () { return &err; }
};
// Compute dot product of a and b
inline float dot_product(const float(&a)[3], const float(&b)[3])
{
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
}
// Compute length of v
inline float vector_length(const float(&v)[3])
{
return std::sqrt(dot_product(v, v));
}
// Require that r = cross(a, b)
inline void require_cross_product(const float(&r)[3], const float(&a)[3], const float(&b)[3])
{
REQUIRE(r[0] == approx(a[1] * b[2] - a[2] * b[1]));
REQUIRE(r[1] == approx(a[2] * b[0] - a[0] * b[2]));
REQUIRE(r[2] == approx(a[0] * b[1] - a[1] * b[0]));
}
// Require that vector is exactly the zero vector
inline void require_zero_vector(const float(&vector)[3])
{
for (int i = 1; i < 3; ++i) REQUIRE(vector[i] == 0.0f);
}
// Require that a == transpose(b)
inline void require_transposed(const float(&a)[9], const float(&b)[9])
{
REQUIRE(a[0] == approx(b[0]));
REQUIRE(a[1] == approx(b[3]));
REQUIRE(a[2] == approx(b[6]));
REQUIRE(a[3] == approx(b[1]));
REQUIRE(a[4] == approx(b[4]));
REQUIRE(a[5] == approx(b[7]));
REQUIRE(a[6] == approx(b[2]));
REQUIRE(a[7] == approx(b[5]));
REQUIRE(a[8] == approx(b[8]));
}
// Require that matrix is an orthonormal 3x3 matrix
void require_rotation_matrix( const float ( &matrix )[9] );
// Require that matrix is exactly the identity matrix
void require_identity_matrix( const float ( &matrix )[9] );
struct test_duration {
bool is_start_time_initialized;
bool is_end_time_initialized;
std::chrono::high_resolution_clock::time_point start_time, end_time;
uint32_t actual_frames_to_receive;
uint32_t first_frame_to_capture;
uint32_t frames_to_capture;
};
struct frame_metadata
{
std::array<std::pair<bool, rs2_metadata_type>, RS2_FRAME_METADATA_COUNT> md_attributes{};
};
struct internal_frame_additional_data
{
double timestamp;
unsigned long long frame_number;
rs2_timestamp_domain timestamp_domain;
rs2_stream stream;
rs2_format format;
frame_metadata frame_md; // Metadata attributes
internal_frame_additional_data(const double &ts, const unsigned long long frame_num, const rs2_timestamp_domain& ts_domain, const rs2_stream& strm, const rs2_format& fmt) :
timestamp(ts),
frame_number(frame_num),
timestamp_domain(ts_domain),
stream(strm),
format(fmt) {}
};
inline void check_fps(double actual_fps, double configured_fps)
{
REQUIRE(actual_fps >= configured_fps * 0.9); // allow threshold of 10 percent
}
// All streaming tests are bounded by time or number of frames, which comes first
const int max_capture_time_sec = 3; // Each streaming test configuration shall not exceed this threshold
const uint32_t max_frames_to_receive = 50; // Max frames to capture per streaming tests
//void test_wait_for_frames(rs2_device * device, std::initializer_list<stream_mode>& modes, std::map<rs2_stream, test_duration>& duration_per_stream);
struct user_data {
std::map<rs2_stream, test_duration> duration_per_stream;
std::map<rs2_stream, unsigned> number_of_frames_per_stream;
};
void frame_callback( rs2::device & dev, rs2::frame frame, void * user );
//void test_frame_callback(device &device, std::initializer_list<stream_profile>& modes, std::map<rs2_stream, test_duration>& duration_per_stream);
//void motion_callback(rs2_device * , rs2_motion_data, void *);
void test_option( rs2::sensor & device,
rs2_option option,
std::initializer_list< int > good_values,
std::initializer_list< int > bad_values );
rs2::stream_profile get_profile_by_resolution_type( rs2::sensor & s, res_type res );
std::shared_ptr< rs2::device > do_with_waiting_for_camera_connection( rs2::context ctx,
std::shared_ptr< rs2::device > dev,
std::string serial,
std::function< void() > operation );
rs2::depth_sensor restart_first_device_and_return_depth_sensor( const rs2::context & ctx,
const rs2::device_list & devices_list );
enum special_folder
{
user_desktop,
user_documents,
user_pictures,
user_videos,
temp_folder
};
#ifdef _WIN32
std::string get_folder_path( special_folder f );
#endif //_WIN32
#if defined __linux__ || defined __APPLE__
std::string get_folder_path( special_folder f );
#endif // defined __linux__ || defined __APPLE__