Remove old CarlaServer
This commit is contained in:
parent
c94719156c
commit
474205b4aa
|
@ -1,316 +0,0 @@
|
|||
/* Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
* de Barcelona (UAB).
|
||||
*
|
||||
* This work is licensed under the terms of the MIT license.
|
||||
* For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
*/
|
||||
|
||||
#ifndef CARLA_CARLASERVER_H
|
||||
#define CARLA_CARLASERVER_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef CARLA_SERVER_API
|
||||
# define CARLA_SERVER_API extern
|
||||
#endif // CARLA_SERVER_API
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ======================================================================== */
|
||||
/* -- Basic types --------------------------------------------------------- */
|
||||
/* ======================================================================== */
|
||||
|
||||
struct carla_vector3d {
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
};
|
||||
|
||||
struct carla_rotation3d {
|
||||
float pitch;
|
||||
float yaw;
|
||||
float roll;
|
||||
};
|
||||
|
||||
struct carla_transform {
|
||||
/** Location in meters. */
|
||||
struct carla_vector3d location;
|
||||
/** Unit vector pointing "forward". */
|
||||
struct carla_vector3d orientation;
|
||||
/** Rotation angles in degrees. */
|
||||
struct carla_rotation3d rotation;
|
||||
};
|
||||
|
||||
struct carla_bounding_box {
|
||||
struct carla_transform transform;
|
||||
struct carla_vector3d extent;
|
||||
};
|
||||
|
||||
/* ======================================================================== */
|
||||
/* -- agents -------------------------------------------------------------- */
|
||||
/* ======================================================================== */
|
||||
|
||||
#define CARLA_SERVER_AGENT_UNKNOWN 0u
|
||||
#define CARLA_SERVER_AGENT_VEHICLE 10u
|
||||
#define CARLA_SERVER_AGENT_PEDESTRIAN 20u
|
||||
#define CARLA_SERVER_AGENT_SPEEDLIMITSIGN 30u
|
||||
#define CARLA_SERVER_AGENT_TRAFFICLIGHT 40u
|
||||
|
||||
#define CARLA_SERVER_AGENT_TRAFFICLIGHT_GREEN 41u
|
||||
#define CARLA_SERVER_AGENT_TRAFFICLIGHT_YELLOW 42u
|
||||
#define CARLA_SERVER_AGENT_TRAFFICLIGHT_RED 43u
|
||||
|
||||
/** @todo This is a bit tricky:
|
||||
* - If type is a traffic light, box extent and forward speed are ignored.
|
||||
* - If type is a speed limit sign, box extent is ignored. Forward speed is speed limit.
|
||||
* - If type is a vehicle or a pedestrian, every field is valid.
|
||||
*/
|
||||
struct carla_agent {
|
||||
uint32_t id;
|
||||
uint32_t type;
|
||||
struct carla_transform transform;
|
||||
struct carla_bounding_box bounding_box;
|
||||
float forward_speed;
|
||||
};
|
||||
|
||||
/* ======================================================================== */
|
||||
/* -- sensors ------------------------------------------------------------- */
|
||||
/* ======================================================================== */
|
||||
|
||||
#define CARLA_SERVER_SENSOR_UNKNOWN 0u
|
||||
#define CARLA_SERVER_CAMERA 101u
|
||||
#define CARLA_SERVER_LIDAR_RAY_CAST 102u
|
||||
|
||||
struct carla_sensor_definition {
|
||||
/** Id of the sensor. */
|
||||
uint32_t id;
|
||||
/** Type of the sensor (one of the above defines). */
|
||||
uint32_t type;
|
||||
/** Display name of the sensor. */
|
||||
const char *name;
|
||||
};
|
||||
|
||||
struct carla_sensor_data {
|
||||
uint32_t id;
|
||||
const void *header;
|
||||
uint32_t header_size;
|
||||
const void *data;
|
||||
uint32_t data_size;
|
||||
};
|
||||
|
||||
/* ======================================================================== */
|
||||
/* -- carla_request_new_episode ------------------------------------------- */
|
||||
/* ======================================================================== */
|
||||
|
||||
/** @warning the underlying char array is statically allocated inside
|
||||
* CarlaServer, it might be deleted on subsequent requests of new episodes,
|
||||
* therefore for a given CarlaServer carla_read_request_new_episode
|
||||
* is NOT thread-safe.
|
||||
*
|
||||
* Do NOT delete the char array.
|
||||
*/
|
||||
struct carla_request_new_episode {
|
||||
const char *ini_file;
|
||||
uint32_t ini_file_length;
|
||||
};
|
||||
|
||||
/* ======================================================================== */
|
||||
/* -- carla_scene_description --------------------------------------------- */
|
||||
/* ======================================================================== */
|
||||
|
||||
struct carla_scene_description {
|
||||
/** Display name of the current map. */
|
||||
const char *map_name;
|
||||
/** Collection of the initial player start locations. */
|
||||
const struct carla_transform *player_start_spots;
|
||||
uint32_t number_of_player_start_spots;
|
||||
/** Definitions of the sensors present in the scene. */
|
||||
const struct carla_sensor_definition *sensors;
|
||||
uint32_t number_of_sensors;
|
||||
};
|
||||
|
||||
/* ======================================================================== */
|
||||
/* -- carla_episode_start ------------------------------------------------- */
|
||||
/* ======================================================================== */
|
||||
|
||||
struct carla_episode_start {
|
||||
uint32_t player_start_spot_index;
|
||||
};
|
||||
|
||||
/* ======================================================================== */
|
||||
/* -- carla_episode_ready ------------------------------------------------- */
|
||||
/* ======================================================================== */
|
||||
|
||||
struct carla_episode_ready {
|
||||
bool ready;
|
||||
};
|
||||
|
||||
/* ======================================================================== */
|
||||
/* -- carla_control ------------------------------------------------------- */
|
||||
/* ======================================================================== */
|
||||
|
||||
struct carla_control {
|
||||
float steer;
|
||||
float throttle;
|
||||
float brake;
|
||||
bool hand_brake;
|
||||
bool reverse;
|
||||
};
|
||||
|
||||
/* ======================================================================== */
|
||||
/* -- carla_player_measurements ------------------------------------------- */
|
||||
/* ======================================================================== */
|
||||
|
||||
struct carla_player_measurements {
|
||||
/** World transform of the player. */
|
||||
struct carla_transform transform;
|
||||
/** Bounding box of the player. */
|
||||
struct carla_bounding_box bounding_box;
|
||||
/** Current acceleration of the player. */
|
||||
struct carla_vector3d acceleration;
|
||||
/** Forward speed in m/s. */
|
||||
float forward_speed;
|
||||
/** Collision intensity with other vehicles. */
|
||||
float collision_vehicles;
|
||||
/** Collision intensity with pedestrians. */
|
||||
float collision_pedestrians;
|
||||
/** General collision intensity (everything else but pedestrians and vehicles). */
|
||||
float collision_other;
|
||||
/** Percentage of the car invading other lanes. */
|
||||
float intersection_otherlane;
|
||||
/** Percentage of the car off-road. */
|
||||
float intersection_offroad;
|
||||
/** Vehicle's AI control that would apply this frame. */
|
||||
struct carla_control autopilot_control;
|
||||
};
|
||||
|
||||
/* ======================================================================== */
|
||||
/* -- carla_measurements -------------------------------------------------- */
|
||||
/* ======================================================================== */
|
||||
|
||||
struct carla_measurements {
|
||||
/** Frame counter. */
|
||||
uint32_t frame_number;
|
||||
/** Time-stamp of the current frame, in milliseconds as given by the OS. */
|
||||
uint32_t platform_timestamp;
|
||||
/** In-game time-stamp, milliseconds elapsed since the beginning of the current level. */
|
||||
uint32_t game_timestamp;
|
||||
/** Player measurements. */
|
||||
struct carla_player_measurements player_measurements;
|
||||
/** Non-player agents. */
|
||||
const struct carla_agent *non_player_agents;
|
||||
uint32_t number_of_non_player_agents;
|
||||
};
|
||||
|
||||
/* ======================================================================== */
|
||||
/* -- CARLA server -------------------------------------------------------- */
|
||||
/* ======================================================================== */
|
||||
|
||||
/** CARLA Server
|
||||
*
|
||||
* int32_t as return type indicates the error code of the operation, it
|
||||
* matches boost::asio::error::basic_errors. A value of 0 indicates success.
|
||||
*
|
||||
* Most of the functions have a time-out, typically blocking this thread
|
||||
* until the corresponding asynchronous operation is completed or the time-
|
||||
* out is met. Set a time-out of 0 to get a non-blocking call.
|
||||
*/
|
||||
|
||||
typedef void* CarlaServerPtr;
|
||||
|
||||
CARLA_SERVER_API const int32_t CARLA_SERVER_SUCCESS;
|
||||
CARLA_SERVER_API const int32_t CARLA_SERVER_TRY_AGAIN;
|
||||
CARLA_SERVER_API const int32_t CARLA_SERVER_TIMED_OUT;
|
||||
CARLA_SERVER_API const int32_t CARLA_SERVER_OPERATION_ABORTED;
|
||||
|
||||
/* -- Creation and destruction -------------------------------------------- */
|
||||
|
||||
/** Create a CARLA server instance. */
|
||||
CARLA_SERVER_API CarlaServerPtr carla_make_server();
|
||||
|
||||
/** Destroy a CARLA server instance (disconnects all running servers
|
||||
* associated with this instance).
|
||||
*/
|
||||
CARLA_SERVER_API void carla_free_server(CarlaServerPtr self);
|
||||
|
||||
/* -- Connecting and disconnecting ---------------------------------------- */
|
||||
|
||||
/** Connect the CARLA world server.
|
||||
*
|
||||
* The time-out in this functions sets the time-out used for all the
|
||||
* subsequent networking communications with the given instance.
|
||||
*
|
||||
* The non-blocking version returns immediately while the blocking version
|
||||
* waits until the connection is established successfully.
|
||||
*/
|
||||
CARLA_SERVER_API int32_t carla_server_connect(
|
||||
CarlaServerPtr self,
|
||||
uint32_t world_port,
|
||||
uint32_t server_timeout_milliseconds);
|
||||
CARLA_SERVER_API int32_t carla_server_connect_non_blocking(
|
||||
CarlaServerPtr self,
|
||||
uint32_t world_port,
|
||||
uint32_t server_timeout_milliseconds);
|
||||
|
||||
/** Signal the world server to disconnect. */
|
||||
CARLA_SERVER_API void carla_disconnect_server(CarlaServerPtr self);
|
||||
|
||||
/* -- Write and read functions -------------------------------------------- */
|
||||
|
||||
/** If the new episode request is received, blocks until the agent server is
|
||||
* terminated.
|
||||
*/
|
||||
CARLA_SERVER_API int32_t carla_read_request_new_episode(
|
||||
CarlaServerPtr self,
|
||||
carla_request_new_episode &values,
|
||||
uint32_t timeout_milliseconds);
|
||||
|
||||
CARLA_SERVER_API int32_t carla_write_scene_description(
|
||||
CarlaServerPtr self,
|
||||
const carla_scene_description &values,
|
||||
uint32_t timeout_milliseconds);
|
||||
|
||||
CARLA_SERVER_API int32_t carla_read_episode_start(
|
||||
CarlaServerPtr self,
|
||||
carla_episode_start &values,
|
||||
uint32_t timeout_milliseconds);
|
||||
|
||||
/** This launches the agent server. */
|
||||
CARLA_SERVER_API int32_t carla_write_episode_ready(
|
||||
CarlaServerPtr self,
|
||||
const carla_episode_ready &values,
|
||||
const uint32_t timeout);
|
||||
|
||||
/** Return values:
|
||||
* CARLA_SERVER_SUCCESS A value was readed.
|
||||
* CARLA_SERVER_TRY_AGAIN Nothing received yet.
|
||||
* CARLA_SERVER_OPERATION_ABORTED Agent server is missing.
|
||||
*/
|
||||
CARLA_SERVER_API int32_t carla_read_control(
|
||||
CarlaServerPtr self,
|
||||
carla_control &values,
|
||||
uint32_t timeout_milliseconds);
|
||||
|
||||
/** Return values:
|
||||
* CARLA_SERVER_SUCCESS Value was posted for sending.
|
||||
* CARLA_SERVER_OPERATION_ABORTED Agent server is missing.
|
||||
*/
|
||||
CARLA_SERVER_API int32_t carla_write_sensor_data(
|
||||
CarlaServerPtr self,
|
||||
const carla_sensor_data &data);
|
||||
|
||||
/** Return values:
|
||||
* CARLA_SERVER_SUCCESS Value was posted for sending.
|
||||
* CARLA_SERVER_OPERATION_ABORTED Agent server is missing.
|
||||
*/
|
||||
CARLA_SERVER_API int32_t carla_write_measurements(
|
||||
CarlaServerPtr self,
|
||||
const carla_measurements &values);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* CARLA_CARLASERVER_H */
|
|
@ -1,112 +0,0 @@
|
|||
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
|
||||
namespace carla {
|
||||
|
||||
namespace detail {
|
||||
|
||||
/// A view over an C-style array. Encapsulates the array and its size, but
|
||||
/// does NOT own the data.
|
||||
///
|
||||
/// Do not use ArrayView directly, use mutable_array_view or const_array_view.
|
||||
template <typename T>
|
||||
class ArrayView {
|
||||
public:
|
||||
|
||||
using value_type = T;
|
||||
using mutable_value_type = std::remove_const_t<T>;
|
||||
using const_value_type = const std::remove_const_t<T>;
|
||||
using size_type = std::size_t;
|
||||
using iterator = value_type*;
|
||||
using const_iterator = const_value_type*;
|
||||
|
||||
explicit ArrayView(T *data, size_type size)
|
||||
: _data(data),
|
||||
_size(size) {}
|
||||
|
||||
ArrayView(ArrayView<mutable_value_type> &rhs)
|
||||
: _data(rhs.data()),
|
||||
_size(rhs.size()) {}
|
||||
|
||||
ArrayView(const ArrayView<const_value_type> &rhs)
|
||||
: _data(rhs.data()),
|
||||
_size(rhs.size()) {}
|
||||
|
||||
bool empty() const {
|
||||
return _size == 0u;
|
||||
}
|
||||
|
||||
size_type size() const {
|
||||
return _size;
|
||||
}
|
||||
|
||||
iterator begin() {
|
||||
return _data;
|
||||
}
|
||||
|
||||
iterator end() {
|
||||
return _data + _size;
|
||||
}
|
||||
|
||||
const_iterator begin() const {
|
||||
return _data;
|
||||
}
|
||||
|
||||
const_iterator end() const {
|
||||
return _data + _size;
|
||||
}
|
||||
|
||||
value_type *data() {
|
||||
return _data;
|
||||
}
|
||||
|
||||
const_value_type *data() const {
|
||||
return _data;
|
||||
}
|
||||
|
||||
value_type &operator[](size_type i) {
|
||||
return _data[i];
|
||||
}
|
||||
|
||||
const_value_type &operator[](size_type i) const {
|
||||
return _data[i];
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
value_type *_data;
|
||||
|
||||
size_type _size;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename T>
|
||||
using mutable_array_view = detail::ArrayView<std::remove_const_t<T>>;
|
||||
|
||||
template <typename T>
|
||||
using const_array_view = detail::ArrayView<const std::remove_const_t<T>>;
|
||||
|
||||
namespace array_view {
|
||||
|
||||
template <typename T, typename V = mutable_array_view<T>>
|
||||
static inline auto make_mutable(T *data, typename V::size_type size) {
|
||||
return V(data, size);
|
||||
}
|
||||
|
||||
template <typename T, typename V = const_array_view<T>>
|
||||
static inline auto make_const(const T *data, typename V::size_type size) {
|
||||
return V(data, size);
|
||||
}
|
||||
|
||||
} // namespace array_view
|
||||
|
||||
} // namespace carla
|
|
@ -1,19 +0,0 @@
|
|||
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef _DEBUG
|
||||
#include <cassert>
|
||||
#endif // _DEBUG
|
||||
|
||||
#ifdef _DEBUG
|
||||
# define DEBUG_ONLY(code) code
|
||||
#else
|
||||
# define DEBUG_ONLY(code)
|
||||
#endif // _DEBUG
|
||||
|
||||
#define DEBUG_ASSERT(predicate) DEBUG_ONLY(assert(predicate))
|
|
@ -1,143 +0,0 @@
|
|||
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#define CARLA_SERVER_LOG_LEVEL_DEBUG 10
|
||||
#define CARLA_SERVER_LOG_LEVEL_INFO 20
|
||||
#define CARLA_SERVER_LOG_LEVEL_WARNING 30
|
||||
#define CARLA_SERVER_LOG_LEVEL_ERROR 40
|
||||
#define CARLA_SERVER_LOG_LEVEL_CRITICAL 50
|
||||
#define CARLA_SERVER_LOG_LEVEL_NONE 100
|
||||
|
||||
#ifndef CARLA_SERVER_LOG_LEVEL
|
||||
# ifdef NDEBUG
|
||||
# define CARLA_SERVER_LOG_LEVEL CARLA_SERVER_LOG_LEVEL_WARNING
|
||||
# else
|
||||
# define CARLA_SERVER_LOG_LEVEL CARLA_SERVER_LOG_LEVEL_INFO
|
||||
# endif // NDEBUG
|
||||
#endif // CARLA_SERVER_LOG_LEVEL
|
||||
|
||||
// The following log functions are available, they are only active if
|
||||
// CARLA_SERVER_LOG_LEVEL is greater equal the function's log level.
|
||||
//
|
||||
// * log_debug
|
||||
// * log_info
|
||||
// * log_error
|
||||
// * log_critical
|
||||
//
|
||||
// And macros
|
||||
//
|
||||
// * LOG_DEBUG_ONLY(/* code here */)
|
||||
// * LOG_INFO_ONLY(/* code here */)
|
||||
|
||||
// =============================================================================
|
||||
// -- Implementation of log functions ------------------------------------------
|
||||
// =============================================================================
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace carla {
|
||||
|
||||
namespace logging {
|
||||
|
||||
// https://stackoverflow.com/a/27375675
|
||||
template <typename Arg, typename ... Args>
|
||||
static void print(std::ostream &out, Arg &&arg, Args &&... args) {
|
||||
out << std::boolalpha << std::forward<Arg>(arg);
|
||||
using expander = int[];
|
||||
(void)expander{0, (void(out << ' ' << std::forward<Args>(args)),0)...};
|
||||
}
|
||||
|
||||
} // namespace logging
|
||||
|
||||
#if CARLA_SERVER_LOG_LEVEL <= CARLA_SERVER_LOG_LEVEL_DEBUG
|
||||
|
||||
template <typename ... Args>
|
||||
static inline void log_debug(Args &&... args) {
|
||||
logging::print(std::cout, "DEBUG:", std::forward<Args>(args)..., '\n');
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
template <typename ... Args>
|
||||
static inline void log_debug(Args &&...) {}
|
||||
|
||||
#endif
|
||||
|
||||
#if CARLA_SERVER_LOG_LEVEL <= CARLA_SERVER_LOG_LEVEL_INFO
|
||||
|
||||
template <typename ... Args>
|
||||
static inline void log_info(Args &&... args) {
|
||||
logging::print(std::cout, "INFO: ", std::forward<Args>(args)..., '\n');
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
template <typename ... Args>
|
||||
static inline void log_info(Args &&...) {}
|
||||
|
||||
#endif
|
||||
|
||||
#if CARLA_SERVER_LOG_LEVEL <= CARLA_SERVER_LOG_LEVEL_WARNING
|
||||
|
||||
template <typename ... Args>
|
||||
static inline void log_warning(Args &&... args) {
|
||||
logging::print(std::cerr, "WARNING:", std::forward<Args>(args)..., '\n');
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
template <typename ... Args>
|
||||
static inline void log_warning(Args &&...) {}
|
||||
|
||||
#endif
|
||||
|
||||
#if CARLA_SERVER_LOG_LEVEL <= CARLA_SERVER_LOG_LEVEL_ERROR
|
||||
|
||||
template <typename ... Args>
|
||||
static inline void log_error(Args &&... args) {
|
||||
logging::print(std::cerr, "ERROR:", std::forward<Args>(args)..., '\n');
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
template <typename ... Args>
|
||||
static inline void log_error(Args &&...) {}
|
||||
|
||||
#endif
|
||||
|
||||
#if CARLA_SERVER_LOG_LEVEL <= CARLA_SERVER_LOG_LEVEL_CRITICAL
|
||||
|
||||
template <typename ... Args>
|
||||
static inline void log_critical(Args &&... args) {
|
||||
logging::print(std::cerr, "CRITICAL:", std::forward<Args>(args)..., '\n');
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
template <typename ... Args>
|
||||
static inline void log_critical(Args &&...) {}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace carla
|
||||
|
||||
// =============================================================================
|
||||
// -- Implementation of macros -------------------------------------------------
|
||||
// =============================================================================
|
||||
|
||||
#if CARLA_SERVER_LOG_LEVEL <= CARLA_SERVER_LOG_LEVEL_DEBUG
|
||||
# define LOG_DEBUG_ONLY(code) code
|
||||
#else
|
||||
# define LOG_DEBUG_ONLY(code)
|
||||
#endif
|
||||
|
||||
#if CARLA_SERVER_LOG_LEVEL <= CARLA_SERVER_LOG_LEVEL_INFO
|
||||
# define LOG_INFO_ONLY(code) code
|
||||
#else
|
||||
# define LOG_INFO_ONLY(code)
|
||||
#endif
|
|
@ -1,21 +0,0 @@
|
|||
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace carla {
|
||||
|
||||
class NonCopyable {
|
||||
public:
|
||||
|
||||
NonCopyable() = default;
|
||||
|
||||
NonCopyable(const NonCopyable &) = delete;
|
||||
|
||||
void operator=(const NonCopyable &x) = delete;
|
||||
};
|
||||
|
||||
} // namespace carla
|
|
@ -1,137 +0,0 @@
|
|||
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#pragma once
|
||||
|
||||
// #define CARLA_WITH_PROFILER
|
||||
|
||||
#ifdef CARLA_WITH_PROFILER
|
||||
|
||||
#include <algorithm>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
|
||||
#include "carla/Logging.h"
|
||||
#include "carla/NonCopyable.h"
|
||||
#include "carla/StopWatch.h"
|
||||
|
||||
namespace carla {
|
||||
|
||||
template <typename ... Args>
|
||||
static inline void log_profiler(Args &&... args) {
|
||||
logging::print(std::cout, "PROFILER:", std::forward<Args>(args)..., '\n');
|
||||
}
|
||||
|
||||
class ProfilerData : private NonCopyable {
|
||||
public:
|
||||
|
||||
explicit ProfilerData(std::string name, bool show_fps = false)
|
||||
: _name(std::move(name)),
|
||||
_show_fps(show_fps) {}
|
||||
|
||||
~ProfilerData() {
|
||||
log_profiler(_name, ':', "annotated", _count, "times", std::fixed, std::setprecision(3));
|
||||
if (_count > 0u) {
|
||||
if (_show_fps) {
|
||||
log_profiler(_name, ':', "average =", fps(Average()), "FPS");
|
||||
log_profiler(_name, ':', "maximum =", fps(Minimum()), "FPS");
|
||||
log_profiler(_name, ':', "minimum =", fps(Maximum()), "FPS");
|
||||
} else {
|
||||
log_profiler(_name, ':', "average =", Average(), "ms");
|
||||
log_profiler(_name, ':', "maximum =", Maximum(), "ms");
|
||||
log_profiler(_name, ':', "minimum =", Minimum(), "ms");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Annotate(const StopWatch &stop_watch) {
|
||||
size_t elapsed_microseconds = stop_watch.GetElapsedTime<std::chrono::microseconds>();
|
||||
++_count;
|
||||
_total_microseconds += elapsed_microseconds;
|
||||
_max_elapsed = std::max(elapsed_microseconds, _max_elapsed);
|
||||
_min_elapsed = std::min(elapsed_microseconds, _min_elapsed);
|
||||
}
|
||||
|
||||
float Average() const {
|
||||
return ms(_total_microseconds) / static_cast<float>(_count);
|
||||
}
|
||||
|
||||
float Maximum() const {
|
||||
return ms(_max_elapsed);
|
||||
}
|
||||
|
||||
float Minimum() const {
|
||||
return ms(_min_elapsed);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
static inline float ms(size_t microseconds) {
|
||||
return 1e-3f * static_cast<float>(microseconds);
|
||||
}
|
||||
|
||||
static inline float fps(float milliseconds) {
|
||||
return 1e3f / milliseconds;
|
||||
}
|
||||
|
||||
const std::string _name;
|
||||
|
||||
const bool _show_fps;
|
||||
|
||||
size_t _count = 0u;
|
||||
|
||||
size_t _total_microseconds = 0u;
|
||||
|
||||
size_t _max_elapsed = 0u;
|
||||
|
||||
size_t _min_elapsed = -1;
|
||||
};
|
||||
|
||||
class ScopedProfiler {
|
||||
public:
|
||||
|
||||
explicit ScopedProfiler(ProfilerData &parent) : _profiler(parent) {}
|
||||
|
||||
~ScopedProfiler() {
|
||||
_stop_watch.Stop();
|
||||
_profiler.Annotate(_stop_watch);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
ProfilerData &_profiler;
|
||||
|
||||
StopWatch _stop_watch;
|
||||
};
|
||||
|
||||
} // namespace carla
|
||||
|
||||
#define CARLA_PROFILE_SCOPE(context, name) \
|
||||
static thread_local ::carla::ProfilerData carla_profiler_ ## context ## _ ## name ## _data( \
|
||||
#context "." #name); \
|
||||
::carla::ScopedProfiler carla_profiler_ ## context ## _ ## name ## _scoped_profiler( \
|
||||
carla_profiler_ ## context ## _ ## name ## _data);
|
||||
|
||||
#define CARLA_PROFILE_FPS(context, name) \
|
||||
{ \
|
||||
static thread_local ::carla::StopWatch stop_watch; \
|
||||
stop_watch.Stop(); \
|
||||
static thread_local bool first_time = true; \
|
||||
if (!first_time) { \
|
||||
static thread_local ::carla::ProfilerData profiler_data(#context "." #name, true); \
|
||||
profiler_data.Annotate(stop_watch); \
|
||||
} else { \
|
||||
first_time = false; \
|
||||
} \
|
||||
stop_watch.Restart(); \
|
||||
}
|
||||
|
||||
#else // CARLA_WITH_PROFILER
|
||||
|
||||
#define CARLA_PROFILE_SCOPE(context, name)
|
||||
#define CARLA_PROFILE_FPS(context, name)
|
||||
|
||||
#endif // CARLA_WITH_PROFILER
|
|
@ -1,57 +0,0 @@
|
|||
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
|
||||
namespace carla {
|
||||
|
||||
template <typename CLOCK>
|
||||
class StopWatchTmpl {
|
||||
public:
|
||||
|
||||
using clock = CLOCK;
|
||||
|
||||
StopWatchTmpl() : _start(clock::now()), _end(), _is_running(true) {}
|
||||
|
||||
void Restart() {
|
||||
_is_running = true;
|
||||
_start = clock::now();
|
||||
}
|
||||
|
||||
void Stop() {
|
||||
_end = clock::now();
|
||||
_is_running = false;
|
||||
}
|
||||
|
||||
typename clock::duration GetDuration() const {
|
||||
return _is_running ? clock::now() - _start : _end - _start;
|
||||
}
|
||||
|
||||
template <class RESOLUTION=std::chrono::milliseconds>
|
||||
typename RESOLUTION::rep GetElapsedTime() const {
|
||||
return std::chrono::duration_cast<RESOLUTION>(GetDuration()).count();
|
||||
}
|
||||
|
||||
bool IsRunning() const {
|
||||
return _is_running;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
typename clock::time_point _start;
|
||||
|
||||
typename clock::time_point _end;
|
||||
|
||||
bool _is_running;
|
||||
};
|
||||
|
||||
using StopWatch = StopWatchTmpl<std::chrono::steady_clock>;
|
||||
|
||||
static_assert(carla::StopWatch::clock::is_steady, "The StopWatch's clock must be steady");
|
||||
|
||||
} // namespace carla
|
|
@ -1,57 +0,0 @@
|
|||
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#include "carla/server/AgentServer.h"
|
||||
|
||||
namespace carla {
|
||||
namespace server {
|
||||
|
||||
AgentServer::AgentServer(
|
||||
CarlaEncoder &encoder,
|
||||
const uint32_t out_port,
|
||||
const uint32_t in_port,
|
||||
const SensorDataInbox::Sensors &sensors,
|
||||
const time_duration timeout)
|
||||
: _out(encoder),
|
||||
_in(encoder),
|
||||
_sensor_inbox(sensors),
|
||||
_measurements(timeout),
|
||||
_control(timeout) {
|
||||
_out.Connect(out_port, timeout);
|
||||
_out.Execute(_measurements);
|
||||
_in.Connect(in_port, timeout);
|
||||
_in.Execute(_control);
|
||||
}
|
||||
|
||||
error_code AgentServer::WriteSensorData(const carla_sensor_data &data) {
|
||||
_sensor_inbox.Write(data);
|
||||
return errc::success();
|
||||
}
|
||||
|
||||
error_code AgentServer::WriteMeasurements(const carla_measurements &measurements) {
|
||||
error_code ec;
|
||||
if (!_measurements.TryGetResult(ec)) {
|
||||
auto writer = _measurements.buffer()->MakeWriter();
|
||||
writer->Write(measurements, _sensor_inbox);
|
||||
ec = errc::success();
|
||||
}
|
||||
return ec;
|
||||
};
|
||||
|
||||
error_code AgentServer::ReadControl(carla_control &control, timeout_t timeout) {
|
||||
error_code ec = errc::try_again();
|
||||
if (!_control.TryGetResult(ec)) {
|
||||
auto reader = _control.buffer()->TryMakeReader(timeout);
|
||||
if (reader != nullptr) {
|
||||
control = *reader;
|
||||
ec = errc::success();
|
||||
}
|
||||
}
|
||||
return ec;
|
||||
}
|
||||
|
||||
} // namespace server
|
||||
} // namespace carla
|
|
@ -1,50 +0,0 @@
|
|||
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "carla/NonCopyable.h"
|
||||
#include "carla/server/AsyncServer.h"
|
||||
#include "carla/server/EncoderServer.h"
|
||||
#include "carla/server/SensorDataInbox.h"
|
||||
#include "carla/server/TCPServer.h"
|
||||
|
||||
namespace carla {
|
||||
namespace server {
|
||||
|
||||
class CarlaEncoder;
|
||||
|
||||
class AgentServer : private NonCopyable {
|
||||
public:
|
||||
|
||||
explicit AgentServer(
|
||||
CarlaEncoder &encoder,
|
||||
uint32_t out_port,
|
||||
uint32_t in_port,
|
||||
const SensorDataInbox::Sensors &sensors,
|
||||
time_duration timeout);
|
||||
|
||||
error_code WriteSensorData(const carla_sensor_data &data);
|
||||
|
||||
error_code WriteMeasurements(const carla_measurements &measurements);
|
||||
|
||||
error_code ReadControl(carla_control &control, timeout_t timeout);
|
||||
|
||||
private:
|
||||
|
||||
AsyncServer<EncoderServer<TCPServer>> _out;
|
||||
|
||||
AsyncServer<EncoderServer<TCPServer>> _in;
|
||||
|
||||
SensorDataInbox _sensor_inbox;
|
||||
|
||||
StreamWriteTask<MeasurementsMessage> _measurements;
|
||||
|
||||
StreamReadTask<carla_control> _control;
|
||||
};
|
||||
|
||||
} // namespace server
|
||||
} // namespace carla
|
|
@ -1,154 +0,0 @@
|
|||
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "carla/NonCopyable.h"
|
||||
#include "carla/Profiler.h"
|
||||
#include "carla/server/AsyncService.h"
|
||||
#include "carla/server/ServerTraits.h"
|
||||
#include "carla/server/Task.h"
|
||||
|
||||
namespace carla {
|
||||
namespace server {
|
||||
|
||||
// ===========================================================================
|
||||
// -- AsyncServer ------------------------------------------------------------
|
||||
// ===========================================================================
|
||||
|
||||
/// Asynchronous server. Every "Connect", "Write", and "Read" tasks are
|
||||
/// submitted to a queue of asynchronous jobs. These jobs are executed in a
|
||||
/// single separate thread in order of submission. The "Disconnect()" function
|
||||
/// of the underlying server is assumed to be thread-safe.
|
||||
template <typename SERVER>
|
||||
class AsyncServer : private NonCopyable {
|
||||
public:
|
||||
|
||||
using server_type = SERVER;
|
||||
|
||||
template<typename... Args>
|
||||
AsyncServer(Args&&... args) : _server(std::forward<Args>(args)...) {}
|
||||
|
||||
void Disconnect() {
|
||||
_server.Disconnect();
|
||||
}
|
||||
|
||||
std::future<error_code> Connect(uint32_t port, time_duration timeout);
|
||||
|
||||
void Execute(ConnectTask &task);
|
||||
|
||||
template <typename T>
|
||||
void Execute(ReadTask<T> &task);
|
||||
|
||||
template <typename T>
|
||||
void Execute(WriteTask<T> &task);
|
||||
|
||||
template <typename T>
|
||||
void Execute(StreamReadTask<T> &task);
|
||||
|
||||
template <typename T>
|
||||
void Execute(StreamWriteTask<T> &task);
|
||||
|
||||
private:
|
||||
|
||||
server_type _server;
|
||||
|
||||
AsyncService _service;
|
||||
};
|
||||
|
||||
// ===========================================================================
|
||||
// -- AsyncServer implementation ---------------------------------------------
|
||||
// ===========================================================================
|
||||
|
||||
template <typename S>
|
||||
std::future<error_code> AsyncServer<S>::Connect(
|
||||
const uint32_t port,
|
||||
const time_duration timeout) {
|
||||
return _service.Post([=](){
|
||||
return _server.Connect(port, timeout);
|
||||
});
|
||||
}
|
||||
|
||||
template <typename S>
|
||||
void AsyncServer<S>::Execute(ConnectTask &task) {
|
||||
task._result = std::move(Connect(task.port(), task.timeout()));
|
||||
}
|
||||
|
||||
template <typename S>
|
||||
template <typename T>
|
||||
void AsyncServer<S>::Execute(ReadTask<T> &task) {
|
||||
auto job = [this, timeout=task.timeout()](){
|
||||
CARLA_PROFILE_SCOPE(AsyncServer, Read);
|
||||
Reading<T> result;
|
||||
result.error_code = _server.Read(result.message, timeout);
|
||||
return result;
|
||||
};
|
||||
task._result = _service.Post(std::move(job));
|
||||
}
|
||||
|
||||
template <typename S>
|
||||
template <typename T>
|
||||
void AsyncServer<S>::Execute(WriteTask<T> &task) {
|
||||
// We could make the lambda mutable to avoid creating the shared_ptr, but it
|
||||
// doesn't compile with VC++2015. Perhaps we can change it in the future.
|
||||
auto message = std::make_shared<std::future<T>>(task.get_future_message());
|
||||
auto job = [this, message{std::move(message)}, timeout = task.timeout()]() {
|
||||
CARLA_PROFILE_SCOPE(AsyncServer, Write);
|
||||
while (!_service.done()) {
|
||||
T message_value;
|
||||
if (future::wait_and_get(*message, message_value, timeout_t::milliseconds(1))) {
|
||||
return _server.Write(message_value, timeout);
|
||||
}
|
||||
}
|
||||
return errc::operation_aborted();
|
||||
};
|
||||
task._result = _service.Post(std::move(job));
|
||||
}
|
||||
|
||||
template <typename S>
|
||||
template <typename T>
|
||||
void AsyncServer<S>::Execute(StreamReadTask<T> &task) {
|
||||
auto job = [this, buffer=task.buffer(), timeout=task.timeout()]() {
|
||||
error_code ec;
|
||||
do {
|
||||
CARLA_PROFILE_SCOPE(AsyncServer, StreamRead);
|
||||
if (_service.done()) {
|
||||
ec = errc::operation_aborted();
|
||||
break;
|
||||
}
|
||||
auto writer = buffer->MakeWriter();
|
||||
ec = _server.Read(*writer, timeout);
|
||||
} while (!ec);
|
||||
return ec;
|
||||
};
|
||||
task._result = _service.Post(std::move(job));
|
||||
}
|
||||
|
||||
template <typename S>
|
||||
template <typename T>
|
||||
void AsyncServer<S>::Execute(StreamWriteTask<T> &task) {
|
||||
auto job = [this, buffer=task.buffer(), timeout=task.timeout()]() {
|
||||
error_code ec;
|
||||
do {
|
||||
CARLA_PROFILE_SCOPE(AsyncServer, StreamWrite);
|
||||
if (_service.done()) {
|
||||
ec = errc::operation_aborted();
|
||||
break;
|
||||
}
|
||||
auto reader = buffer->TryMakeReader(timeout);
|
||||
if (reader != nullptr) {
|
||||
ec = _server.Write(*reader, timeout);
|
||||
} else if (buffer->done()) {
|
||||
ec = errc::operation_aborted();
|
||||
}
|
||||
} while (!ec);
|
||||
return ec;
|
||||
};
|
||||
task._result = _service.Post(std::move(job));
|
||||
}
|
||||
|
||||
} // namespace server
|
||||
} // namespace carla
|
|
@ -1,32 +0,0 @@
|
|||
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#include "carla/Logging.h"
|
||||
#include "carla/server/AsyncService.h"
|
||||
|
||||
namespace carla {
|
||||
namespace server {
|
||||
|
||||
AsyncService::AsyncService() {
|
||||
_thread = std::thread([this] {
|
||||
while (!_queue.done()) {
|
||||
job_type job;
|
||||
if (_queue.WaitAndPop(job)) {
|
||||
job();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
AsyncService::~AsyncService() {
|
||||
_queue.set_done();
|
||||
if (_thread.joinable()) {
|
||||
_thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace server
|
||||
} // namespace carla
|
|
@ -1,54 +0,0 @@
|
|||
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <future>
|
||||
#include <type_traits>
|
||||
|
||||
#include "carla/NonCopyable.h"
|
||||
#include "carla/server/ThreadSafeQueue.h"
|
||||
|
||||
namespace carla {
|
||||
namespace server {
|
||||
|
||||
/// Asynchronous service. Posted tasks are executed in a single separate
|
||||
/// thread in order of submission.
|
||||
class AsyncService : private NonCopyable {
|
||||
private:
|
||||
|
||||
using job_type = std::function<void()>;
|
||||
|
||||
public:
|
||||
|
||||
AsyncService();
|
||||
|
||||
~AsyncService();
|
||||
|
||||
bool done() const {
|
||||
return _queue.done();
|
||||
}
|
||||
|
||||
/// Post a task to be executed by the asynchronous process. Its return value
|
||||
/// or exception thrown is stored in a shared state which can be accessed
|
||||
/// through the returned std::future object.
|
||||
template <typename F, typename R = std::result_of_t<F()>>
|
||||
std::future<R> Post(F task) {
|
||||
auto ptask = std::make_shared<std::packaged_task<R()>>(std::move(task));
|
||||
auto future = ptask->get_future();
|
||||
_queue.Push([ptask{std::move(ptask)}]() { (*ptask)(); });
|
||||
return future;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
ThreadSafeQueue<job_type> _queue;
|
||||
|
||||
std::thread _thread;
|
||||
};
|
||||
|
||||
} // namespace server
|
||||
} // namespace carla
|
|
@ -1,232 +0,0 @@
|
|||
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#include "carla/server/CarlaEncoder.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "carla/ArrayView.h"
|
||||
#include "carla/Debug.h"
|
||||
#include "carla/Logging.h"
|
||||
#include "carla/server/CarlaSceneDescription.h"
|
||||
#include "carla/server/RequestNewEpisode.h"
|
||||
|
||||
#include "carla/server/carla_server.pb.h"
|
||||
|
||||
namespace cs = carla_server;
|
||||
|
||||
namespace carla {
|
||||
namespace server {
|
||||
|
||||
static auto start_spots(const carla_scene_description &values) {
|
||||
return array_view::make_const(values.player_start_spots, values.number_of_player_start_spots);
|
||||
}
|
||||
|
||||
static auto sensors(const carla_scene_description &values) {
|
||||
return array_view::make_const(values.sensors, values.number_of_sensors);
|
||||
}
|
||||
|
||||
static auto agents(const carla_measurements &values) {
|
||||
return array_view::make_const(values.non_player_agents, values.number_of_non_player_agents);
|
||||
}
|
||||
|
||||
static void Set(cs::Vector3D *lhs, const carla_vector3d &rhs) {
|
||||
DEBUG_ASSERT(lhs != nullptr);
|
||||
lhs->set_x(rhs.x);
|
||||
lhs->set_y(rhs.y);
|
||||
lhs->set_z(rhs.z);
|
||||
}
|
||||
|
||||
static void Set(cs::Rotation3D *lhs, const carla_rotation3d &rhs) {
|
||||
DEBUG_ASSERT(lhs != nullptr);
|
||||
lhs->set_pitch(rhs.pitch);
|
||||
lhs->set_roll(rhs.roll);
|
||||
lhs->set_yaw(rhs.yaw);
|
||||
}
|
||||
|
||||
static void Set(cs::Transform *lhs, const carla_transform &rhs) {
|
||||
DEBUG_ASSERT(lhs != nullptr);
|
||||
Set(lhs->mutable_location(), rhs.location);
|
||||
Set(lhs->mutable_orientation(), rhs.orientation);
|
||||
Set(lhs->mutable_rotation(), rhs.rotation);
|
||||
}
|
||||
|
||||
static void Set(cs::BoundingBox *lhs, const carla_bounding_box &rhs) {
|
||||
DEBUG_ASSERT(lhs != nullptr);
|
||||
Set(lhs->mutable_transform(), rhs.transform);
|
||||
Set(lhs->mutable_extent(), rhs.extent);
|
||||
}
|
||||
|
||||
static void Set(cs::Sensor *lhs, const carla_sensor_definition &rhs) {
|
||||
DEBUG_ASSERT(lhs != nullptr);
|
||||
lhs->set_id(rhs.id);
|
||||
lhs->set_name(std::string(rhs.name));
|
||||
lhs->set_type([&](){
|
||||
switch (rhs.type) {
|
||||
case CARLA_SERVER_CAMERA: return cs::Sensor::CAMERA;
|
||||
case CARLA_SERVER_LIDAR_RAY_CAST: return cs::Sensor::LIDAR_RAY_CAST;
|
||||
default: return cs::Sensor::UNKNOWN;
|
||||
}
|
||||
}());
|
||||
}
|
||||
|
||||
static void Set(cs::Control *lhs, const carla_control &rhs) {
|
||||
DEBUG_ASSERT(lhs != nullptr);
|
||||
lhs->set_steer(rhs.steer);
|
||||
lhs->set_throttle(rhs.throttle);
|
||||
lhs->set_brake(rhs.brake);
|
||||
lhs->set_hand_brake(rhs.hand_brake);
|
||||
lhs->set_reverse(rhs.reverse);
|
||||
}
|
||||
|
||||
static void SetVehicle(cs::Vehicle *lhs, const carla_agent &rhs) {
|
||||
DEBUG_ASSERT(lhs != nullptr);
|
||||
Set(lhs->mutable_transform(), rhs.transform);
|
||||
Set(lhs->mutable_bounding_box(), rhs.bounding_box);
|
||||
lhs->set_forward_speed(rhs.forward_speed);
|
||||
}
|
||||
|
||||
static void SetPedestrian(cs::Pedestrian *lhs, const carla_agent &rhs) {
|
||||
DEBUG_ASSERT(lhs != nullptr);
|
||||
Set(lhs->mutable_transform(), rhs.transform);
|
||||
Set(lhs->mutable_bounding_box(), rhs.bounding_box);
|
||||
lhs->set_forward_speed(rhs.forward_speed);
|
||||
}
|
||||
|
||||
static void SetSpeedLimitSign(cs::SpeedLimitSign *lhs, const carla_agent &rhs) {
|
||||
DEBUG_ASSERT(lhs != nullptr);
|
||||
Set(lhs->mutable_transform(), rhs.transform);
|
||||
lhs->set_speed_limit(rhs.forward_speed);
|
||||
}
|
||||
|
||||
static void SetTrafficLight(cs::TrafficLight *lhs, const carla_agent &rhs, cs::TrafficLight::State state) {
|
||||
DEBUG_ASSERT(lhs != nullptr);
|
||||
Set(lhs->mutable_transform(), rhs.transform);
|
||||
lhs->set_state(state);
|
||||
}
|
||||
|
||||
static void Set(cs::Agent *lhs, const carla_agent &rhs) {
|
||||
DEBUG_ASSERT(lhs != nullptr);
|
||||
lhs->set_id(rhs.id);
|
||||
switch (rhs.type) {
|
||||
case CARLA_SERVER_AGENT_VEHICLE:
|
||||
return SetVehicle(lhs->mutable_vehicle(), rhs);
|
||||
case CARLA_SERVER_AGENT_PEDESTRIAN:
|
||||
return SetPedestrian(lhs->mutable_pedestrian(), rhs);
|
||||
case CARLA_SERVER_AGENT_SPEEDLIMITSIGN:
|
||||
return SetSpeedLimitSign(lhs->mutable_speed_limit_sign(), rhs);
|
||||
case CARLA_SERVER_AGENT_TRAFFICLIGHT_GREEN:
|
||||
return SetTrafficLight(lhs->mutable_traffic_light(), rhs, cs::TrafficLight::GREEN);
|
||||
case CARLA_SERVER_AGENT_TRAFFICLIGHT_YELLOW:
|
||||
return SetTrafficLight(lhs->mutable_traffic_light(), rhs, cs::TrafficLight::YELLOW);
|
||||
case CARLA_SERVER_AGENT_TRAFFICLIGHT_RED:
|
||||
return SetTrafficLight(lhs->mutable_traffic_light(), rhs, cs::TrafficLight::RED);
|
||||
default:
|
||||
log_error("invalid agent type");
|
||||
}
|
||||
}
|
||||
|
||||
std::string CarlaEncoder::Encode(const carla_scene_description &values) {
|
||||
auto *message = _protobuf.CreateMessage<cs::SceneDescription>();
|
||||
DEBUG_ASSERT(message != nullptr);
|
||||
message->set_map_name(std::string(values.map_name));
|
||||
for (auto &spot : start_spots(values)) {
|
||||
Set(message->add_player_start_spots(), spot);
|
||||
}
|
||||
for (auto &sensor : sensors(values)) {
|
||||
Set(message->add_sensors(), sensor);
|
||||
}
|
||||
return Protobuf::Encode(*message);
|
||||
}
|
||||
|
||||
std::string CarlaEncoder::Encode(const CarlaSceneDescription &values) {
|
||||
return values.pop_scene();
|
||||
}
|
||||
|
||||
std::string CarlaEncoder::Encode(const carla_episode_ready &values) {
|
||||
auto *message = _protobuf.CreateMessage<cs::EpisodeReady>();
|
||||
DEBUG_ASSERT(message != nullptr);
|
||||
message->set_ready(values.ready);
|
||||
return Protobuf::Encode(*message);
|
||||
}
|
||||
|
||||
std::string CarlaEncoder::Encode(const carla_measurements &values) {
|
||||
static thread_local auto *message = _protobuf.CreateMessage<cs::Measurements>();
|
||||
DEBUG_ASSERT(message != nullptr);
|
||||
message->set_frame_number(values.frame_number);
|
||||
message->set_platform_timestamp(values.platform_timestamp);
|
||||
message->set_game_timestamp(values.game_timestamp);
|
||||
// Player measurements.
|
||||
auto *player = message->mutable_player_measurements();
|
||||
DEBUG_ASSERT(player != nullptr);
|
||||
Set(player->mutable_transform(), values.player_measurements.transform);
|
||||
Set(player->mutable_bounding_box(), values.player_measurements.bounding_box);
|
||||
Set(player->mutable_acceleration(), values.player_measurements.acceleration);
|
||||
player->set_forward_speed(values.player_measurements.forward_speed);
|
||||
player->set_collision_vehicles(values.player_measurements.collision_vehicles);
|
||||
player->set_collision_pedestrians(values.player_measurements.collision_pedestrians);
|
||||
player->set_collision_other(values.player_measurements.collision_other);
|
||||
player->set_intersection_otherlane(values.player_measurements.intersection_otherlane);
|
||||
player->set_intersection_offroad(values.player_measurements.intersection_offroad);
|
||||
Set(player->mutable_autopilot_control(), values.player_measurements.autopilot_control);
|
||||
// Non-player agents.
|
||||
message->clear_non_player_agents(); // we need to clear as we cache the message.
|
||||
for (auto &agent : agents(values)) {
|
||||
Set(message->add_non_player_agents(), agent);
|
||||
}
|
||||
return Protobuf::Encode(*message);
|
||||
}
|
||||
|
||||
bool CarlaEncoder::Decode(const std::string &str, RequestNewEpisode &values) {
|
||||
auto *message = _protobuf.CreateMessage<cs::RequestNewEpisode>();
|
||||
DEBUG_ASSERT(message != nullptr);
|
||||
message->ParseFromString(str);
|
||||
if (message->IsInitialized()) {
|
||||
const std::string &file = message->ini_file();
|
||||
auto data = std::make_unique<char[]>(file.size());
|
||||
std::memcpy(data.get(), file.c_str(), file.size());
|
||||
values.data = std::move(data);
|
||||
values.values.ini_file = values.data.get();
|
||||
values.values.ini_file_length = file.size();
|
||||
return true;
|
||||
} else {
|
||||
log_error("invalid protobuf message: request new episode");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool CarlaEncoder::Decode(const std::string &str, carla_episode_start &values) {
|
||||
auto *message = _protobuf.CreateMessage<cs::EpisodeStart>();
|
||||
DEBUG_ASSERT(message != nullptr);
|
||||
message->ParseFromString(str);
|
||||
if (message->IsInitialized()) {
|
||||
values.player_start_spot_index = message->player_start_spot_index();
|
||||
return true;
|
||||
} else {
|
||||
log_error("invalid protobuf message: episode start");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool CarlaEncoder::Decode(const std::string &str, carla_control &values) {
|
||||
static thread_local auto *message = _protobuf.CreateMessage<cs::Control>();
|
||||
DEBUG_ASSERT(message != nullptr);
|
||||
message->ParseFromString(str);
|
||||
if (message->IsInitialized()) {
|
||||
values.steer = message->steer();
|
||||
values.throttle = message->throttle();
|
||||
values.brake = message->brake();
|
||||
values.hand_brake = message->hand_brake();
|
||||
values.reverse = message->reverse();
|
||||
return true;
|
||||
} else {
|
||||
log_error("invalid protobuf message: control");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace server
|
||||
} // namespace carla
|
|
@ -1,65 +0,0 @@
|
|||
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "carla/server/CarlaServerAPI.h"
|
||||
#include "carla/server/Protobuf.h"
|
||||
|
||||
namespace carla {
|
||||
namespace server {
|
||||
|
||||
class CarlaSceneDescription;
|
||||
class RequestNewEpisode;
|
||||
|
||||
/// Converts the data between the C interface types and the Protobuf message
|
||||
/// that is going to be sent and received through the socket.
|
||||
class CarlaEncoder {
|
||||
public:
|
||||
|
||||
// =========================================================================
|
||||
/// @name string encoders (for testing only)
|
||||
// =========================================================================
|
||||
/// @{
|
||||
|
||||
std::string Encode(const std::string &values) {
|
||||
return Protobuf::Encode(values);
|
||||
}
|
||||
|
||||
bool Decode(std::string message, std::string &values) {
|
||||
values = std::move(message);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// @}
|
||||
// =========================================================================
|
||||
/// @name Protobuf encodings
|
||||
// =========================================================================
|
||||
/// @{
|
||||
|
||||
std::string Encode(const carla_scene_description &values);
|
||||
|
||||
std::string Encode(const CarlaSceneDescription &values);
|
||||
|
||||
std::string Encode(const carla_episode_ready &values);
|
||||
|
||||
std::string Encode(const carla_measurements &values);
|
||||
|
||||
bool Decode(const std::string &message, RequestNewEpisode &values);
|
||||
|
||||
bool Decode(const std::string &message, carla_episode_start &values);
|
||||
|
||||
bool Decode(const std::string &message, carla_control &values);
|
||||
|
||||
/// @}
|
||||
|
||||
private:
|
||||
|
||||
Protobuf _protobuf;
|
||||
};
|
||||
|
||||
} // namespace server
|
||||
} // namespace carla
|
|
@ -1,28 +0,0 @@
|
|||
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#include "carla/server/CarlaMeasurements.h"
|
||||
|
||||
#include "carla/Logging.h"
|
||||
|
||||
namespace carla {
|
||||
namespace server {
|
||||
|
||||
void CarlaMeasurements::Write(const carla_measurements &measurements) {
|
||||
_measurements = measurements;
|
||||
const auto size = measurements.number_of_non_player_agents * sizeof(carla_agent);
|
||||
if (_agents_buffer_size < size) {
|
||||
log_info("allocating agents buffer of", size, "bytes");
|
||||
_agents_buffer = std::make_unique<unsigned char[]>(size);
|
||||
_agents_buffer_size = size;
|
||||
}
|
||||
std::memcpy(_agents_buffer.get(), measurements.non_player_agents, size);
|
||||
_measurements.non_player_agents =
|
||||
reinterpret_cast<const carla_agent *>(_agents_buffer.get());
|
||||
}
|
||||
|
||||
} // namespace server
|
||||
} // namespace carla
|
|
@ -1,38 +0,0 @@
|
|||
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "carla/NonCopyable.h"
|
||||
#include "carla/server/CarlaServerAPI.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace carla {
|
||||
namespace server {
|
||||
|
||||
/// Holds a carla_measurements and keeps its own copy of the dynamically
|
||||
/// allocated data.
|
||||
class CarlaMeasurements : private NonCopyable {
|
||||
public:
|
||||
|
||||
void Write(const carla_measurements &measurements);
|
||||
|
||||
const carla_measurements &measurements() const {
|
||||
return _measurements;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
carla_measurements _measurements;
|
||||
|
||||
std::unique_ptr<unsigned char[]> _agents_buffer = nullptr;
|
||||
|
||||
uint32_t _agents_buffer_size = 0u;
|
||||
};
|
||||
|
||||
} // namespace server
|
||||
} // namespace carla
|
|
@ -1,48 +0,0 @@
|
|||
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "carla/NonCopyable.h"
|
||||
#include "carla/server/CarlaServerAPI.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace carla {
|
||||
namespace server {
|
||||
|
||||
/// This is the only message that for convenience it is encoded in the main
|
||||
/// thread.
|
||||
///
|
||||
/// Since the messages are only sent once, it is safe to invalidate the
|
||||
/// encoded string on the first read.
|
||||
class CarlaSceneDescription : private NonCopyable {
|
||||
public:
|
||||
|
||||
CarlaSceneDescription() = default;
|
||||
|
||||
CarlaSceneDescription(std::string &&encoded_scene)
|
||||
: _encoded_scene(std::move(encoded_scene)) {}
|
||||
|
||||
CarlaSceneDescription(CarlaSceneDescription &&rhs)
|
||||
: _encoded_scene(std::move(rhs._encoded_scene)) {}
|
||||
|
||||
CarlaSceneDescription &operator=(CarlaSceneDescription &&rhs) {
|
||||
_encoded_scene = std::move(rhs._encoded_scene);
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string pop_scene() const {
|
||||
return std::move(_encoded_scene);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
mutable std::string _encoded_scene;
|
||||
};
|
||||
|
||||
} // namespace server
|
||||
} // namespace carla
|
|
@ -1,144 +0,0 @@
|
|||
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#include "carla/Debug.h"
|
||||
#include "carla/Logging.h"
|
||||
#include "carla/server/AgentServer.h"
|
||||
#include "carla/server/CarlaServer.h"
|
||||
|
||||
using namespace carla;
|
||||
using namespace carla::server;
|
||||
|
||||
// =============================================================================
|
||||
// -- Static local functions ---------------------------------------------------
|
||||
// =============================================================================
|
||||
|
||||
static inline carla::server::CarlaServer *Cast(CarlaServerPtr self) {
|
||||
return static_cast<carla::server::CarlaServer*>(self);
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// -- Implementation of the C-interface of CarlaServer -------------------------
|
||||
// =============================================================================
|
||||
|
||||
const int32_t CARLA_SERVER_SUCCESS = errc::success().value();;
|
||||
const int32_t CARLA_SERVER_TRY_AGAIN = errc::try_again().value();
|
||||
const int32_t CARLA_SERVER_TIMED_OUT = errc::timed_out().value();
|
||||
const int32_t CARLA_SERVER_OPERATION_ABORTED = errc::operation_aborted().value();
|
||||
|
||||
CarlaServerPtr carla_make_server() {
|
||||
return new carla::server::CarlaServer;
|
||||
}
|
||||
|
||||
void carla_free_server(CarlaServerPtr self) {
|
||||
delete Cast(self);
|
||||
}
|
||||
|
||||
int32_t carla_server_connect(
|
||||
CarlaServerPtr self,
|
||||
const uint32_t world_port,
|
||||
const uint32_t timeout) {
|
||||
Cast(self)->Connect(world_port, timeout_t::milliseconds(timeout));
|
||||
return CARLA_SERVER_SUCCESS;
|
||||
}
|
||||
|
||||
int32_t carla_server_connect_blocking(
|
||||
CarlaServerPtr self,
|
||||
const uint32_t world_port,
|
||||
const uint32_t timeout) {
|
||||
auto result = Cast(self)->Connect(world_port, timeout_t::milliseconds(timeout));
|
||||
return result.get().value();
|
||||
}
|
||||
|
||||
void carla_disconnect_server(CarlaServerPtr self) {
|
||||
Cast(self)->Disconnect();
|
||||
}
|
||||
|
||||
int32_t carla_read_request_new_episode(
|
||||
CarlaServerPtr self,
|
||||
carla_request_new_episode &values,
|
||||
const uint32_t timeout) {
|
||||
CARLA_PROFILE_SCOPE(C_API, RequestNewEpisode)
|
||||
auto ec = Cast(self)->TryRead(values, timeout_t::milliseconds(timeout));
|
||||
if (!ec) {
|
||||
log_debug("received valid request new episode");
|
||||
Cast(self)->KillAgentServer();
|
||||
}
|
||||
return ec.value();
|
||||
}
|
||||
|
||||
int32_t carla_write_scene_description(
|
||||
CarlaServerPtr self,
|
||||
const carla_scene_description &values,
|
||||
const uint32_t timeout) {
|
||||
auto result = Cast(self)->Write(values);
|
||||
error_code ec = errc::timed_out();
|
||||
future::wait_and_get(result, ec, timeout_t::milliseconds(timeout));
|
||||
return ec.value();
|
||||
}
|
||||
|
||||
int32_t carla_read_episode_start(
|
||||
CarlaServerPtr self,
|
||||
carla_episode_start &values,
|
||||
const uint32_t timeout) {
|
||||
return Cast(self)->TryRead(values, timeout_t::milliseconds(timeout)).value();
|
||||
}
|
||||
|
||||
int32_t carla_write_episode_ready(
|
||||
CarlaServerPtr self,
|
||||
const carla_episode_ready &values,
|
||||
const uint32_t timeout) {
|
||||
if (values.ready) {
|
||||
Cast(self)->StartAgentServer();
|
||||
} else {
|
||||
log_error("start agent server cancelled: episode_ready = false");
|
||||
}
|
||||
error_code ec = errc::timed_out();
|
||||
auto result = Cast(self)->Write(values);
|
||||
future::wait_and_get(result, ec, timeout_t::milliseconds(timeout));
|
||||
Cast(self)->ResetProtocol();
|
||||
return ec.value();
|
||||
}
|
||||
|
||||
int32_t carla_read_control(
|
||||
CarlaServerPtr self,
|
||||
carla_control &values,
|
||||
const uint32_t timeout) {
|
||||
CARLA_PROFILE_SCOPE(C_API, ReadControl);
|
||||
auto agent = Cast(self)->GetAgentServer();
|
||||
if (agent == nullptr) {
|
||||
log_debug("trying to read control but agent server is missing");
|
||||
return CARLA_SERVER_OPERATION_ABORTED;
|
||||
}
|
||||
return agent->ReadControl(values, timeout_t::milliseconds(timeout)).value();
|
||||
}
|
||||
|
||||
int32_t carla_write_sensor_data(
|
||||
CarlaServerPtr self,
|
||||
const carla_sensor_data &sensor_data) {
|
||||
CARLA_PROFILE_SCOPE(C_API, WriteSensorData);
|
||||
auto agent = Cast(self)->GetAgentServer();
|
||||
if (agent == nullptr) {
|
||||
log_debug("trying to write sensor data but agent server is missing");
|
||||
return CARLA_SERVER_OPERATION_ABORTED;
|
||||
} else {
|
||||
return agent->WriteSensorData(sensor_data).value();
|
||||
}
|
||||
}
|
||||
|
||||
int32_t carla_write_measurements(
|
||||
CarlaServerPtr self,
|
||||
const carla_measurements &measurements) {
|
||||
CARLA_PROFILE_FPS(FPS, SendMeasurements);
|
||||
CARLA_PROFILE_SCOPE(C_API, WriteMeasurements);
|
||||
auto agent = Cast(self)->GetAgentServer();
|
||||
if (agent == nullptr) {
|
||||
log_debug("trying to write measurements but agent server is missing");
|
||||
return CARLA_SERVER_OPERATION_ABORTED;
|
||||
} else {
|
||||
return agent->WriteMeasurements(measurements).value();
|
||||
}
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "carla/server/WorldServer.h"
|
||||
|
||||
namespace carla {
|
||||
namespace server {
|
||||
|
||||
class CarlaServer : public WorldServer {};
|
||||
|
||||
} // namespace server
|
||||
} // namespace carla
|
|
@ -1,17 +0,0 @@
|
|||
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# define CARLA_SERVER_API __declspec(dllexport) extern
|
||||
#elif defined(__GNUC__) || defined(__clang__)
|
||||
# define CARLA_SERVER_API __attribute__((visibility("default"))) extern
|
||||
#else
|
||||
# error Compiler not supported!
|
||||
#endif
|
||||
|
||||
#include <carla/carla_server.h>
|
|
@ -1,101 +0,0 @@
|
|||
// This file is a modification of https://stackoverflow.com/a/23713793
|
||||
|
||||
#include "carla/server/DoubleBuffer.h"
|
||||
|
||||
// The bottom (lowest) bit of the state will be the active cell (the one for
|
||||
// writing). The active cell can only be switched if there's at most one
|
||||
// concurrent user. The next two bits of state will be the number of concurrent
|
||||
// users. The fourth bit indicates if there's a value available for reading in
|
||||
// _buffer[0u], and the fifth bit has the same meaning but for _buffer[1u].
|
||||
|
||||
namespace carla {
|
||||
namespace server {
|
||||
namespace detail {
|
||||
|
||||
DoubleBufferState::DoubleBufferState() :
|
||||
_state(0),
|
||||
_readState() {}
|
||||
|
||||
// Never returns nullptr
|
||||
DoubleBufferState::ActiveBuffer DoubleBufferState::StartWriting() {
|
||||
// Increment active users; once we do this, no one can swap the active
|
||||
// cell on us until we're done
|
||||
auto state = _state.fetch_add(0x2, std::memory_order_relaxed);
|
||||
return static_cast<ActiveBuffer>(state & 1);
|
||||
}
|
||||
|
||||
void DoubleBufferState::EndWriting() {
|
||||
// We want to swap the active cell, but only if we were the last ones
|
||||
// concurrently accessing the data (otherwise the consumer will do it
|
||||
// for us when *it's* done accessing the data).
|
||||
|
||||
auto state = _state.load(std::memory_order_relaxed);
|
||||
std::uint32_t flag = (8 << (state & 1)) ^ (state & (8 << (state & 1)));
|
||||
state = _state.fetch_add(flag - 0x2, std::memory_order_release) + flag - 0x2;
|
||||
if ((state & 0x6) == 0) {
|
||||
// The consumer wasn't in the middle of a read, we should swap
|
||||
// (unless the consumer has since started a read or already
|
||||
// swapped or read a value and is about to swap). If we swap, we
|
||||
// also want to clear the full flag on what will become the active
|
||||
// cell, otherwise the consumer could eventually read two values
|
||||
// out of order (it reads a new value, then swaps and reads the
|
||||
// old value while the producer is idle).
|
||||
_state.compare_exchange_strong(state, (state ^ 0x1) & ~(0x10 >> (state & 1)), std::memory_order_release);
|
||||
}
|
||||
}
|
||||
|
||||
// Returns nullptr if there appears to be no more data to read yet.
|
||||
DoubleBufferState::ActiveBuffer DoubleBufferState::StartReading() {
|
||||
_readState = _state.load(std::memory_order_relaxed);
|
||||
if ((_readState & (0x10 >> (_readState & 1))) == 0) {
|
||||
// Nothing to read here!
|
||||
return NUMBER_OF_BUFFERS;
|
||||
}
|
||||
|
||||
// At this point, there is guaranteed to be something to read, because
|
||||
// the full flag is never turned off by the producer thread once it's
|
||||
// on; the only thing that could happen is that the active cell
|
||||
// changes, but that can only happen after the producer wrote a value
|
||||
// into it, in which case there's still a value to read, just in a
|
||||
// different cell.
|
||||
|
||||
_readState = _state.fetch_add(0x2, std::memory_order_acquire) + 0x2;
|
||||
|
||||
// Now that we've incremented the user count, nobody can swap until we
|
||||
// decrement it.
|
||||
return static_cast<ActiveBuffer>((_readState & 1) ^ 1);
|
||||
}
|
||||
|
||||
void DoubleBufferState::EndReading() {
|
||||
if ((_readState & (0x10 >> (_readState & 1))) == 0) {
|
||||
// There was nothing to read; shame to repeat this check, but if
|
||||
// these functions are inlined it might not matter. Otherwise the
|
||||
// API could be changed. Or just don't call this method if
|
||||
// start_reading() returns nullptr -- then you could also get rid
|
||||
// of _readState.
|
||||
return;
|
||||
}
|
||||
|
||||
// Alright, at this point the active cell cannot change on us, but the
|
||||
// active cell's flag could change and the user count could change. We
|
||||
// want to release our user count and remove the flag on the value we
|
||||
// read.
|
||||
|
||||
auto state = _state.load(std::memory_order_relaxed);
|
||||
std::uint32_t sub = (0x10 >> (state & 1)) | 0x2;
|
||||
state = _state.fetch_sub(sub, std::memory_order_relaxed) - sub;
|
||||
if ((state & 0x6) == 0 && (state & (0x8 << (state & 1))) == 1) {
|
||||
// Oi, we were the last ones accessing the data when we released
|
||||
// our cell. That means we should swap, but only if the producer
|
||||
// isn't in the middle of producing something, and hasn't already
|
||||
// swapped, and hasn't already set the flag we just reset (which
|
||||
// would mean they swapped an even number of times). Note that we
|
||||
// don't bother swapping if there's nothing to read in the other
|
||||
// cell.
|
||||
_state.compare_exchange_strong(state, state ^ 0x1, std::memory_order_relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace carla
|
||||
} // namespace server
|
|
@ -1,123 +0,0 @@
|
|||
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
#include "carla/Logging.h"
|
||||
#include "carla/server/ServerTraits.h"
|
||||
|
||||
namespace carla {
|
||||
namespace server {
|
||||
|
||||
namespace detail {
|
||||
|
||||
/// Keeps the state of an atomic double-buffer.
|
||||
class DoubleBufferState {
|
||||
public:
|
||||
|
||||
enum ActiveBuffer : uint32_t {
|
||||
FIRST_BUFFER,
|
||||
SECOND_BUFFER,
|
||||
NUMBER_OF_BUFFERS
|
||||
};
|
||||
|
||||
DoubleBufferState();
|
||||
|
||||
/// Never returns None.
|
||||
ActiveBuffer StartWriting();
|
||||
|
||||
void EndWriting();
|
||||
|
||||
/// Returns None if there appears to be no more data to read yet.
|
||||
ActiveBuffer StartReading();
|
||||
|
||||
void EndReading();
|
||||
|
||||
private:
|
||||
|
||||
std::atomic<uint32_t> _state;
|
||||
|
||||
uint32_t _readState;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/// An atomic thread-safe double buffer for one producer and one consumer.
|
||||
template <typename T>
|
||||
class DoubleBuffer : private detail::DoubleBufferState {
|
||||
public:
|
||||
|
||||
DoubleBuffer() : _done(false) {}
|
||||
|
||||
~DoubleBuffer() { set_done(); }
|
||||
|
||||
bool done() const {
|
||||
return _done;
|
||||
}
|
||||
|
||||
void set_done() {
|
||||
_done = true;
|
||||
_condition.notify_all();
|
||||
}
|
||||
|
||||
/// Returns an unique_ptr to the buffer to be read. The given buffer will
|
||||
/// be locked for reading until the unique_ptr is destroyed.
|
||||
///
|
||||
/// Blocks until there is some data to read in one of the buffer, or the
|
||||
/// time-out is met.
|
||||
///
|
||||
/// Returns nullptr if the time-out was met, or the DoubleBuffer is marked
|
||||
/// as done.
|
||||
auto TryMakeReader(timeout_t timeout) {
|
||||
const auto deleter = [this](const T *ptr) { if (ptr) EndReading(); };
|
||||
ActiveBuffer active = NUMBER_OF_BUFFERS;
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(_mutex);
|
||||
_condition.wait_for(lock, timeout.to_chrono(), [&] {
|
||||
active = StartReading();
|
||||
return _done || (active != NUMBER_OF_BUFFERS);
|
||||
});
|
||||
}
|
||||
const T *pointer = (active != NUMBER_OF_BUFFERS ? &_buffer[active] : nullptr);
|
||||
return std::unique_ptr<const T, decltype(deleter)>(pointer, deleter);
|
||||
}
|
||||
|
||||
auto TryMakeReader() {
|
||||
return TryMakeReader(timeout_t::milliseconds(0u));
|
||||
}
|
||||
|
||||
/// Returns an unique_ptr to the buffer to be written. The given buffer
|
||||
/// will be locked for writing until the unique_ptr is destroyed.
|
||||
///
|
||||
/// Never returns nullptr.
|
||||
auto MakeWriter() {
|
||||
const auto deleter = [this](T *) {
|
||||
EndWriting();
|
||||
_condition.notify_one();
|
||||
};
|
||||
return std::unique_ptr<T, decltype(deleter)>(&_buffer[StartWriting()], deleter);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
std::mutex _mutex;
|
||||
|
||||
std::condition_variable _condition;
|
||||
|
||||
std::atomic_bool _done;
|
||||
|
||||
T _buffer[NUMBER_OF_BUFFERS];
|
||||
};
|
||||
|
||||
} // namespace carla
|
||||
} // namespace server
|
|
@ -1,112 +0,0 @@
|
|||
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "carla/Logging.h"
|
||||
#include "carla/NonCopyable.h"
|
||||
#include "carla/server/CarlaEncoder.h"
|
||||
#include "carla/server/MeasurementsMessage.h"
|
||||
#include "carla/server/SensorDataInbox.h"
|
||||
#include "carla/server/ServerTraits.h"
|
||||
|
||||
namespace carla {
|
||||
namespace server {
|
||||
|
||||
/// Wrapper around a server for encoding and decoding the messages with a
|
||||
/// CarlaEncoder.
|
||||
template <typename SERVER>
|
||||
class EncoderServer : private NonCopyable {
|
||||
public:
|
||||
|
||||
using server_type = SERVER;
|
||||
using encoder_type = CarlaEncoder;
|
||||
|
||||
template<typename... Args>
|
||||
explicit EncoderServer(encoder_type &encoder, Args&&... args)
|
||||
: _server(std::forward<Args>(args)...),
|
||||
_encoder(encoder) {}
|
||||
|
||||
error_code Connect(uint32_t port, time_duration timeout) {
|
||||
return _server.Connect(port, timeout);
|
||||
}
|
||||
|
||||
void Disconnect() {
|
||||
_server.Disconnect();
|
||||
}
|
||||
|
||||
/// @warning Since every received message consists of two Reads, the timeout
|
||||
/// applies to each individual Read. Effectively, it may wait twice the
|
||||
/// timeout.
|
||||
template <typename T>
|
||||
error_code Read(T &values, time_duration timeout) {
|
||||
std::string string;
|
||||
auto ec = ReadString(string, timeout);
|
||||
if (!ec && !_encoder.Decode(string, values)) {
|
||||
ec.assign(
|
||||
boost::system::errc::illegal_byte_sequence,
|
||||
boost::system::system_category());
|
||||
}
|
||||
return ec;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
error_code Write(const T &values, time_duration timeout) {
|
||||
const auto string = _encoder.Encode(values);
|
||||
return _server.Write(boost::asio::buffer(string), timeout);
|
||||
}
|
||||
|
||||
/// @warning This operation consists of several Writes, the timeout applies
|
||||
/// to each individual Write. Effectively, it may wait the timeout for each
|
||||
/// sensor.
|
||||
error_code Write(const MeasurementsMessage &values, time_duration timeout) {
|
||||
const auto string = _encoder.Encode(values.measurements());
|
||||
auto ec = _server.Write(boost::asio::buffer(string), timeout);
|
||||
if (!ec) {
|
||||
ec = Write(values.sensor_inbox(), timeout);
|
||||
}
|
||||
return ec;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
error_code Write(SensorDataInbox &inbox, time_duration timeout) {
|
||||
error_code ec;
|
||||
for (auto &sensor_buffer : inbox) {
|
||||
auto reader = sensor_buffer.TryMakeReader();
|
||||
if (reader != nullptr) {
|
||||
auto ec = _server.Write(reader->buffer(), timeout);
|
||||
if (ec)
|
||||
return ec;
|
||||
}
|
||||
}
|
||||
const uint32_t end_message = 0u;
|
||||
return _server.Write(boost::asio::buffer(&end_message, sizeof(end_message)), timeout);;
|
||||
}
|
||||
|
||||
error_code ReadString(std::string &string, time_duration timeout) {
|
||||
// Get the message's size.
|
||||
uint32_t message_size;
|
||||
auto ec = _server.Read(boost::asio::buffer(&message_size, sizeof(uint32_t)), timeout);
|
||||
if (ec) {
|
||||
return ec;
|
||||
}
|
||||
// Knowing the size now we can Read the message.
|
||||
auto buffer = std::make_unique<char[]>(message_size);
|
||||
ec = _server.Read(boost::asio::buffer(buffer.get(), message_size), timeout);
|
||||
if (!ec) {
|
||||
string.assign(buffer.get(), message_size);
|
||||
}
|
||||
return ec;
|
||||
}
|
||||
|
||||
server_type _server;
|
||||
|
||||
encoder_type &_encoder;
|
||||
};
|
||||
|
||||
} // namespace server
|
||||
} // namespace carla
|
|
@ -1,53 +0,0 @@
|
|||
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <future>
|
||||
#include <type_traits>
|
||||
|
||||
#include "carla/server/ServerTraits.h"
|
||||
|
||||
namespace carla {
|
||||
namespace server {
|
||||
/// Utils to handle std::future.
|
||||
namespace future {
|
||||
|
||||
template <typename T>
|
||||
static inline bool is_running(const std::future<T> &future) {
|
||||
return future.valid() &&
|
||||
(future.wait_for(std::chrono::seconds(0)) != std::future_status::ready);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline bool is_ready(const std::future<T> &future, timeout_t timeout) {
|
||||
return future.valid() &&
|
||||
(future.wait_for(timeout.to_chrono()) == std::future_status::ready);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline bool is_ready(const std::future<T> &future) {
|
||||
return is_ready(future, timeout_t::milliseconds(0));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline bool wait_and_get(std::future<T> &future, T &result, timeout_t timeout) {
|
||||
if (is_ready(future, timeout)) {
|
||||
result = std::move(future.get());
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline bool try_get(std::future<T> &future, T &result) {
|
||||
return wait_and_get(future, result, timeout_t::milliseconds(0));
|
||||
}
|
||||
|
||||
} // namespace future
|
||||
} // namespace server
|
||||
} // namespace carla
|
|
@ -1,46 +0,0 @@
|
|||
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "carla/Debug.h"
|
||||
#include "carla/NonCopyable.h"
|
||||
#include "carla/server/CarlaMeasurements.h"
|
||||
#include "carla/server/CarlaServerAPI.h"
|
||||
|
||||
namespace carla {
|
||||
namespace server {
|
||||
|
||||
class SensorDataInbox;
|
||||
|
||||
class MeasurementsMessage : private NonCopyable {
|
||||
public:
|
||||
|
||||
void Write(
|
||||
const carla_measurements &measurements,
|
||||
SensorDataInbox &sensor_inbox) {
|
||||
_measurements.Write(measurements);
|
||||
_sensor_inbox = &sensor_inbox;
|
||||
}
|
||||
|
||||
const carla_measurements &measurements() const {
|
||||
return _measurements.measurements();
|
||||
}
|
||||
|
||||
SensorDataInbox &sensor_inbox() const {
|
||||
DEBUG_ASSERT(_sensor_inbox != nullptr);
|
||||
return *_sensor_inbox;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
CarlaMeasurements _measurements;
|
||||
|
||||
SensorDataInbox *_sensor_inbox = nullptr;
|
||||
};
|
||||
|
||||
} // namespace server
|
||||
} // namespace carla
|
|
@ -1,36 +0,0 @@
|
|||
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#include "carla/server/Protobuf.h"
|
||||
|
||||
#include "carla/Debug.h"
|
||||
|
||||
namespace carla {
|
||||
namespace server {
|
||||
|
||||
static void PrependByteSize(std::string &string, const uint32_t size) {
|
||||
constexpr uint32_t extraSize = sizeof(uint32_t);
|
||||
string.reserve(size + extraSize);
|
||||
string.assign(reinterpret_cast<const char*>(&size), extraSize);
|
||||
}
|
||||
|
||||
std::string Protobuf::Encode(const std::string &message) {
|
||||
std::string result;
|
||||
PrependByteSize(result, message.size());
|
||||
result += message;
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string Protobuf::Encode(const google::protobuf::MessageLite &message) {
|
||||
std::string result;
|
||||
DEBUG_ASSERT(message.IsInitialized());
|
||||
PrependByteSize(result, message.ByteSize());
|
||||
message.AppendToString(&result);
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace server
|
||||
} // namespace carla
|
|
@ -1,46 +0,0 @@
|
|||
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <google/protobuf/arena.h>
|
||||
#include <google/protobuf/message_lite.h>
|
||||
|
||||
namespace carla {
|
||||
namespace server {
|
||||
|
||||
/// Wrapper around google's protobuf library. It holds a protobuf arena for a
|
||||
/// more efficient memory usage.
|
||||
///
|
||||
/// Encode functions return a string encoded as follows
|
||||
///
|
||||
/// [(uint32_t)message size, <google's protobuf encoding>...]
|
||||
///
|
||||
class Protobuf {
|
||||
public:
|
||||
|
||||
/// Prepends the size of the message to the string. Only for testing
|
||||
/// purposes, for protobuf objects use specilized version of "encode"
|
||||
/// function.
|
||||
static std::string Encode(const std::string &message);
|
||||
|
||||
/// Efficiently retrieve the string message from the protocol buffer
|
||||
/// message.
|
||||
static std::string Encode(const google::protobuf::MessageLite &message);
|
||||
|
||||
/// Creates a protobuf message using arena allocation.
|
||||
template <typename T>
|
||||
T *CreateMessage() {
|
||||
return google::protobuf::Arena::CreateMessage<T>(&_arena);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
google::protobuf::Arena _arena;
|
||||
};
|
||||
|
||||
} // namespace server
|
||||
} // namespace carla
|
|
@ -1,27 +0,0 @@
|
|||
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "carla/server/CarlaServerAPI.h"
|
||||
|
||||
namespace carla {
|
||||
namespace server {
|
||||
|
||||
/// Holds the data of a carla_request_new_episode. Since we cannot pass
|
||||
/// ownership of data throught the C interface we need to hold it internally.
|
||||
/// The data is hold in memory until the next call to
|
||||
/// carla_read_request_new_episode().
|
||||
class RequestNewEpisode {
|
||||
public:
|
||||
carla_request_new_episode values;
|
||||
std::unique_ptr<const char[]> data;
|
||||
};
|
||||
|
||||
} // namespace server
|
||||
} // namespace carla
|
|
@ -1,103 +0,0 @@
|
|||
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "carla/Debug.h"
|
||||
#include "carla/NonCopyable.h"
|
||||
#include "carla/server/DoubleBuffer.h"
|
||||
#include "carla/server/SensorDataMessage.h"
|
||||
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
struct carla_sensor_data;
|
||||
struct carla_sensor_definition;
|
||||
|
||||
namespace carla {
|
||||
namespace server {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename IT>
|
||||
class value_iterator {
|
||||
public:
|
||||
|
||||
value_iterator(IT original_iterator) : _it(original_iterator) {}
|
||||
|
||||
value_iterator &operator++() {
|
||||
++_it;
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto &operator*() {
|
||||
return _it->second;
|
||||
}
|
||||
|
||||
bool operator!=(value_iterator rhs) {
|
||||
return _it != rhs._it;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
IT _it;
|
||||
};
|
||||
|
||||
} // detail
|
||||
|
||||
/// Stores the data received from the sensors (asynchronously) to be sent next
|
||||
/// on next tick.
|
||||
///
|
||||
/// Each sensor has a double-buffer for one producer and one consumer per
|
||||
/// sensor. Several threads can simultaneously write as long as they write to
|
||||
/// different buffers, i.e. each sensor can have its own producer and consumer
|
||||
/// threads.
|
||||
class SensorDataInbox : private NonCopyable {
|
||||
|
||||
using DataBuffer = DoubleBuffer<SensorDataMessage>;
|
||||
|
||||
using Map = std::unordered_map<uint32_t, DataBuffer>;
|
||||
|
||||
public:
|
||||
|
||||
using Sensors = std::vector<carla_sensor_definition>;
|
||||
|
||||
using buffer_iterator = detail::value_iterator<Map::iterator>;
|
||||
|
||||
explicit SensorDataInbox(const Sensors &sensors) {
|
||||
// We need to initialize the map before hand so it remains constant and
|
||||
// doesn't need a lock.
|
||||
for (auto &sensor : sensors)
|
||||
_buffers[sensor.id];
|
||||
}
|
||||
|
||||
void Write(const carla_sensor_data &data) {
|
||||
auto writer = _buffers.at(data.id).MakeWriter();
|
||||
writer->Write(data);
|
||||
}
|
||||
|
||||
/// Tries to acquire a reader on the buffer of the given sensor. See
|
||||
/// DoubleBuffer.
|
||||
auto TryMakeReader(uint32_t sensor_id) {
|
||||
return _buffers.at(sensor_id).TryMakeReader();
|
||||
}
|
||||
|
||||
buffer_iterator begin() {
|
||||
return _buffers.begin();
|
||||
}
|
||||
|
||||
buffer_iterator end() {
|
||||
return _buffers.end();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Map _buffers;
|
||||
};
|
||||
|
||||
} // namespace server
|
||||
} // namespace carla
|
|
@ -1,48 +0,0 @@
|
|||
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#include "carla/server/SensorDataMessage.h"
|
||||
|
||||
#include "carla/Logging.h"
|
||||
#include "carla/server/CarlaServerAPI.h"
|
||||
|
||||
namespace carla {
|
||||
namespace server {
|
||||
|
||||
void SensorDataMessage::Write(const carla_sensor_data &data) {
|
||||
// The buffer contains id + data-header + data.
|
||||
const uint32_t buffer_size =
|
||||
sizeof(uint32_t) +
|
||||
data.header_size +
|
||||
data.data_size;
|
||||
// The message is prepended by the size of the buffer.
|
||||
Reset(sizeof(uint32_t) + buffer_size);
|
||||
|
||||
auto begin = _buffer.get();
|
||||
|
||||
std::memcpy(begin, &buffer_size, sizeof(uint32_t));
|
||||
begin += sizeof(uint32_t);
|
||||
|
||||
std::memcpy(begin, &data.id, sizeof(uint32_t));
|
||||
begin += sizeof(uint32_t);
|
||||
|
||||
std::memcpy(begin, data.header, data.header_size);
|
||||
begin += data.header_size;
|
||||
|
||||
std::memcpy(begin, data.data, data.data_size);
|
||||
}
|
||||
|
||||
void SensorDataMessage::Reset(uint32_t count) {
|
||||
if (_capacity < count) {
|
||||
log_debug("allocating sensor buffer of", count, "bytes");
|
||||
_buffer = std::make_unique<unsigned char[]>(count);
|
||||
_capacity = count;
|
||||
}
|
||||
_size = count;
|
||||
}
|
||||
|
||||
} // namespace server
|
||||
} // namespace carla
|
|
@ -1,41 +0,0 @@
|
|||
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "carla/NonCopyable.h"
|
||||
#include "carla/server/ServerTraits.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
struct carla_sensor_data;
|
||||
struct carla_sensor_definition;
|
||||
|
||||
namespace carla {
|
||||
namespace server {
|
||||
|
||||
class SensorDataMessage : private NonCopyable {
|
||||
public:
|
||||
|
||||
void Write(const carla_sensor_data &data);
|
||||
|
||||
const_buffer buffer() const {
|
||||
return boost::asio::buffer(_buffer.get(), _size);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void Reset(uint32_t count);
|
||||
|
||||
std::unique_ptr<unsigned char[]> _buffer = nullptr;
|
||||
|
||||
uint32_t _size = 0u;
|
||||
|
||||
uint32_t _capacity = 0u;
|
||||
};
|
||||
|
||||
} // namespace server
|
||||
} // namespace carla
|
|
@ -1,87 +0,0 @@
|
|||
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <boost/asio/error.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time_types.hpp>
|
||||
|
||||
namespace carla {
|
||||
namespace server {
|
||||
|
||||
using const_buffer = boost::asio::const_buffer;
|
||||
|
||||
using mutable_buffer = boost::asio::mutable_buffer;
|
||||
|
||||
using error_code = boost::system::error_code;
|
||||
|
||||
namespace errc {
|
||||
|
||||
static inline error_code success() {
|
||||
return error_code(
|
||||
boost::system::errc::success,
|
||||
boost::system::system_category());
|
||||
}
|
||||
|
||||
static inline error_code try_again() {
|
||||
return boost::asio::error::basic_errors::try_again;
|
||||
}
|
||||
|
||||
static inline error_code timed_out() {
|
||||
return boost::asio::error::basic_errors::timed_out;
|
||||
}
|
||||
|
||||
static inline error_code invalid_argument() {
|
||||
return boost::asio::error::basic_errors::invalid_argument;
|
||||
}
|
||||
|
||||
static inline error_code operation_aborted() {
|
||||
return boost::asio::error::basic_errors::operation_aborted;
|
||||
}
|
||||
|
||||
} // namespace errc
|
||||
|
||||
using time_duration = boost::posix_time::time_duration;
|
||||
|
||||
/// Positive time-out up to milliseconds resolution.
|
||||
class timeout_t {
|
||||
public:
|
||||
|
||||
static inline timeout_t milliseconds(uint32_t timeout) {
|
||||
return std::chrono::milliseconds(timeout);
|
||||
}
|
||||
|
||||
constexpr timeout_t() : _milliseconds(0u) {}
|
||||
|
||||
template <typename Rep, typename Period>
|
||||
constexpr timeout_t(std::chrono::duration<Rep, Period> duration)
|
||||
: _milliseconds(std::chrono::duration_cast<std::chrono::milliseconds>(duration).count()) {}
|
||||
|
||||
timeout_t(boost::posix_time::time_duration timeout)
|
||||
: timeout_t(std::chrono::milliseconds(timeout.total_milliseconds())) {}
|
||||
|
||||
boost::posix_time::time_duration to_posix_time() const {
|
||||
return boost::posix_time::milliseconds(_milliseconds);
|
||||
}
|
||||
|
||||
constexpr auto to_chrono() const {
|
||||
return std::chrono::milliseconds(_milliseconds);
|
||||
}
|
||||
|
||||
operator boost::posix_time::time_duration() const {
|
||||
return to_posix_time();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
uint64_t _milliseconds;
|
||||
};
|
||||
|
||||
} // namespace server
|
||||
} // namespace carla
|
|
@ -1,163 +0,0 @@
|
|||
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
//
|
||||
// This is a modification of boost example, blocking_tcp_client.cpp
|
||||
//
|
||||
// Copyright (c) 2003-2012 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include "carla/server/TCPServer.h"
|
||||
|
||||
#include <boost/asio/read.hpp>
|
||||
#include <boost/asio/write.hpp>
|
||||
#include <boost/lambda/bind.hpp>
|
||||
#include <boost/lambda/lambda.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
#include <boost/system/system_error.hpp>
|
||||
|
||||
#include "carla/Logging.h"
|
||||
|
||||
using boost::lambda::_1;
|
||||
using boost::lambda::var;
|
||||
using namespace boost::asio::ip;
|
||||
|
||||
namespace carla {
|
||||
namespace server {
|
||||
|
||||
// ===========================================================================
|
||||
// -- Static local methods ---------------------------------------------------
|
||||
// ===========================================================================
|
||||
|
||||
static inline int GetPort(const tcp::socket &socket) {
|
||||
return (socket.is_open() ? socket.local_endpoint().port() : 0);
|
||||
}
|
||||
|
||||
#define LOG_PREFIX "tcpserver", GetPort(_socket), ':'
|
||||
|
||||
static void CloseConnection(tcp::acceptor &_acceptor, tcp::socket &_socket) {
|
||||
log_info(LOG_PREFIX, "disconnecting");
|
||||
if (_acceptor.is_open()) {
|
||||
_acceptor.close();
|
||||
}
|
||||
if (_socket.is_open()) {
|
||||
_socket.close();
|
||||
}
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// -- TCPServer --------------------------------------------------------------
|
||||
// ===========================================================================
|
||||
|
||||
TCPServer::TCPServer()
|
||||
: _service(),
|
||||
_acceptor(_service),
|
||||
_socket(_service),
|
||||
_deadline(_service) {
|
||||
// No deadline is required until the first socket operation is started. We
|
||||
// set the deadline to positive infinity so that the actor takes no action
|
||||
// until a specific deadline is set.
|
||||
_deadline.expires_at(boost::posix_time::pos_infin);
|
||||
// Start the persistent actor that checks for deadline expiry.
|
||||
CheckDeadline();
|
||||
}
|
||||
|
||||
TCPServer::~TCPServer() {
|
||||
CloseConnection(_acceptor, _socket);
|
||||
}
|
||||
|
||||
void TCPServer::Disconnect() {
|
||||
log_debug(LOG_PREFIX, "request close connection");
|
||||
_service.post([this](){ CloseConnection(_acceptor, _socket); });
|
||||
}
|
||||
|
||||
error_code TCPServer::Connect(uint32_t port, time_duration timeout) {
|
||||
// Set the deadline, it will close the socket when expired.
|
||||
_deadline.expires_from_now(timeout);
|
||||
|
||||
if (_acceptor.is_open()) {
|
||||
log_error(LOG_PREFIX, "already connected");
|
||||
return boost::asio::error::already_connected;
|
||||
}
|
||||
|
||||
// Create an acceptor at the given port.
|
||||
try {
|
||||
_acceptor = tcp::acceptor(_service, tcp::endpoint(tcp::v4(), port));
|
||||
} catch (const boost::system::system_error &exception) {
|
||||
log_error(LOG_PREFIX, "unable to accept connection:", exception.what());
|
||||
return exception.code();
|
||||
}
|
||||
|
||||
// Asio guarantees that its asynchronous operations will never fail with
|
||||
// would_block, so any other value in ec indicates completion.
|
||||
error_code ec = boost::asio::error::would_block;
|
||||
|
||||
// Start the asynchronous operation.
|
||||
_acceptor.async_accept(_socket, var(ec) = _1);
|
||||
|
||||
// Block until the asynchronous operation has completed.
|
||||
do {
|
||||
_service.run_one();
|
||||
} while (ec == boost::asio::error::would_block);
|
||||
|
||||
// Determine whether a connection was successfully established.
|
||||
if (ec) {
|
||||
log_error(LOG_PREFIX, "connection failed:", ec.message());
|
||||
Disconnect(); // Will disconnect on the next run.
|
||||
} else {
|
||||
log_info(LOG_PREFIX, "connected");
|
||||
}
|
||||
return ec;
|
||||
}
|
||||
|
||||
error_code TCPServer::Read(mutable_buffer buffer, time_duration timeout) {
|
||||
log_debug(LOG_PREFIX, "receiving to buffer of length", boost::asio::buffer_size(buffer));
|
||||
_deadline.expires_from_now(timeout);
|
||||
|
||||
error_code ec = boost::asio::error::would_block;
|
||||
boost::asio::async_read(_socket, boost::asio::buffer(buffer), var(ec) = _1);
|
||||
|
||||
do {
|
||||
_service.run_one();
|
||||
} while (ec == boost::asio::error::would_block);
|
||||
|
||||
if (ec) {
|
||||
log_error(LOG_PREFIX, "error reading message:", ec.message());
|
||||
}
|
||||
return ec;
|
||||
}
|
||||
|
||||
error_code TCPServer::Write(const_buffer buffer, time_duration timeout) {
|
||||
log_debug(LOG_PREFIX, "sending from buffer of length", boost::asio::buffer_size(buffer));
|
||||
_deadline.expires_from_now(timeout);
|
||||
|
||||
error_code ec = boost::asio::error::would_block;
|
||||
boost::asio::async_write(_socket, boost::asio::buffer(buffer), var(ec) = _1);
|
||||
|
||||
do {
|
||||
_service.run_one();
|
||||
} while (ec == boost::asio::error::would_block);
|
||||
|
||||
if (ec) {
|
||||
log_error(LOG_PREFIX, "error writing message:", ec.message());
|
||||
}
|
||||
return ec;
|
||||
}
|
||||
|
||||
void TCPServer::CheckDeadline() {
|
||||
if (_deadline.expires_at() <= boost::asio::deadline_timer::traits_type::now()) {
|
||||
log_info(LOG_PREFIX, "timed out");
|
||||
CloseConnection(_acceptor, _socket);
|
||||
_deadline.expires_at(boost::posix_time::pos_infin);
|
||||
}
|
||||
_deadline.async_wait(boost::lambda::bind(&TCPServer::CheckDeadline, this));
|
||||
}
|
||||
|
||||
#undef LOG_PREFIX
|
||||
|
||||
} // namespace server
|
||||
} // namespace carla
|
|
@ -1,51 +0,0 @@
|
|||
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <boost/asio/deadline_timer.hpp>
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
|
||||
#include "carla/NonCopyable.h"
|
||||
#include "carla/server/ServerTraits.h"
|
||||
|
||||
namespace carla {
|
||||
namespace server {
|
||||
|
||||
/// Basic blocking TCP server with time-out. It is safe to call disconnect
|
||||
/// in a separate thread.
|
||||
class TCPServer : private NonCopyable {
|
||||
public:
|
||||
|
||||
TCPServer();
|
||||
|
||||
~TCPServer();
|
||||
|
||||
/// Posts a job to disconnect the server.
|
||||
void Disconnect();
|
||||
|
||||
error_code Connect(uint32_t port, time_duration timeout);
|
||||
|
||||
error_code Read(mutable_buffer buffer, time_duration timeout);
|
||||
|
||||
error_code Write(const_buffer buffer, time_duration timeout);
|
||||
|
||||
private:
|
||||
|
||||
void CheckDeadline();
|
||||
|
||||
boost::asio::io_service _service;
|
||||
|
||||
boost::asio::ip::tcp::acceptor _acceptor;
|
||||
|
||||
boost::asio::ip::tcp::socket _socket;
|
||||
|
||||
boost::asio::deadline_timer _deadline;
|
||||
};
|
||||
|
||||
} // namespace server
|
||||
} // namespace carla
|
|
@ -1,230 +0,0 @@
|
|||
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "carla/server/DoubleBuffer.h"
|
||||
#include "carla/server/Future.h"
|
||||
#include "carla/server/ServerTraits.h"
|
||||
|
||||
namespace carla {
|
||||
namespace server {
|
||||
|
||||
template<typename T>
|
||||
class AsyncServer;
|
||||
|
||||
// ===========================================================================
|
||||
// -- Reading ----------------------------------------------------------------
|
||||
// ===========================================================================
|
||||
|
||||
/// The result of a reading task.
|
||||
template <typename T>
|
||||
struct Reading {
|
||||
error_code error_code;
|
||||
T message;
|
||||
};
|
||||
|
||||
// ===========================================================================
|
||||
// -- Task -------------------------------------------------------------------
|
||||
// ===========================================================================
|
||||
|
||||
namespace detail {
|
||||
|
||||
/// Base class for a task with result and timeout.
|
||||
template <typename Result>
|
||||
class Task {
|
||||
protected:
|
||||
|
||||
Task() : _timeout(boost::posix_time::pos_infin) {}
|
||||
|
||||
explicit Task(time_duration timeout) : _timeout(timeout) {}
|
||||
|
||||
public:
|
||||
|
||||
time_duration timeout() const {
|
||||
return _timeout;
|
||||
}
|
||||
|
||||
void set_timeout(time_duration timeout) {
|
||||
_timeout = timeout;
|
||||
}
|
||||
|
||||
bool valid() const {
|
||||
return _result.valid();
|
||||
}
|
||||
|
||||
/// Blocks until the result is ready.
|
||||
auto get_result() {
|
||||
return _result.get();
|
||||
}
|
||||
|
||||
/// Gives up the result. Invalidates this Task.
|
||||
std::future<Result> ReleaseResult() {
|
||||
return std::move(_result);
|
||||
}
|
||||
|
||||
bool TryGetResult(Result &value, timeout_t timeout) {
|
||||
return future::wait_and_get(_result, value, timeout);
|
||||
}
|
||||
|
||||
bool TryGetResult(Result &value) {
|
||||
return future::try_get(_result, value);
|
||||
}
|
||||
|
||||
bool IsRunning() const {
|
||||
return future::is_running(_result);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool IsReady(T &&timeout) const {
|
||||
return future::is_ready(_result, std::forward<T>(timeout));
|
||||
}
|
||||
|
||||
bool IsReady() const {
|
||||
return future::is_ready(_result);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
template<typename T>
|
||||
friend class carla::server::AsyncServer;
|
||||
|
||||
time_duration _timeout;
|
||||
|
||||
std::future<Result> _result;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
// ===========================================================================
|
||||
// -- ConnectTask ------------------------------------------------------------
|
||||
// ===========================================================================
|
||||
|
||||
/// Connect a server to a port.
|
||||
class ConnectTask : public detail::Task<error_code> {
|
||||
public:
|
||||
|
||||
explicit ConnectTask(uint32_t port) : _port(port) {}
|
||||
|
||||
explicit ConnectTask(uint32_t port, time_duration timeout)
|
||||
: Task(timeout),
|
||||
_port(port) {}
|
||||
|
||||
uint32_t port() const {
|
||||
return _port;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
uint32_t _port;
|
||||
};
|
||||
|
||||
// ===========================================================================
|
||||
// -- ReadTask ---------------------------------------------------------------
|
||||
// ===========================================================================
|
||||
|
||||
/// Single read task.
|
||||
template <typename T>
|
||||
class ReadTask : public detail::Task<Reading<T>> {
|
||||
public:
|
||||
|
||||
ReadTask() = default;
|
||||
|
||||
explicit ReadTask(time_duration timeout)
|
||||
: detail::Task<Reading<T>>(timeout) {}
|
||||
};
|
||||
|
||||
// ===========================================================================
|
||||
// -- WriteTask --------------------------------------------------------------
|
||||
// ===========================================================================
|
||||
|
||||
/// Single write task.
|
||||
template <typename T>
|
||||
class WriteTask : public detail::Task<error_code> {
|
||||
public:
|
||||
|
||||
WriteTask() = default;
|
||||
|
||||
explicit WriteTask(time_duration timeout) : Task(timeout) {}
|
||||
|
||||
template <typename M>
|
||||
void set_message(M &&message) {
|
||||
_message.set_value(std::forward<M>(message));
|
||||
}
|
||||
|
||||
std::future<T> get_future_message() {
|
||||
return _message.get_future();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
std::promise<T> _message;
|
||||
};
|
||||
|
||||
// ===========================================================================
|
||||
// -- StreamTask -------------------------------------------------------------
|
||||
// ===========================================================================
|
||||
|
||||
namespace detail {
|
||||
|
||||
/// Base class for tasks that continuously read/write from/to a buffer.
|
||||
template <typename T>
|
||||
class StreamTask : public detail::Task<error_code> {
|
||||
public:
|
||||
|
||||
StreamTask() : _buffer(std::make_shared<DoubleBuffer<T>>()) {}
|
||||
|
||||
explicit StreamTask(time_duration timeout)
|
||||
: Task(timeout),
|
||||
_buffer(std::make_shared<DoubleBuffer<T>>()) {}
|
||||
|
||||
~StreamTask() {
|
||||
_buffer->set_done();
|
||||
}
|
||||
|
||||
std::shared_ptr<DoubleBuffer<T>> buffer() {
|
||||
return _buffer;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
const std::shared_ptr<DoubleBuffer<T>> _buffer;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
// ===========================================================================
|
||||
// -- StreamReadTask ---------------------------------------------------------
|
||||
// ===========================================================================
|
||||
|
||||
/// Continuously read from a server and write to the buffer.
|
||||
template <typename T>
|
||||
class StreamReadTask : public detail::StreamTask<T> {
|
||||
public:
|
||||
|
||||
StreamReadTask() = default;
|
||||
|
||||
explicit StreamReadTask(time_duration timeout)
|
||||
: detail::StreamTask<T>(timeout) {}
|
||||
};
|
||||
|
||||
// ===========================================================================
|
||||
// -- StreamWriteTask --------------------------------------------------------
|
||||
// ===========================================================================
|
||||
|
||||
/// Continuously read from the buffer and write to a server.
|
||||
template <typename T>
|
||||
class StreamWriteTask : public detail::StreamTask<T> {
|
||||
public:
|
||||
|
||||
StreamWriteTask() = default;
|
||||
|
||||
explicit StreamWriteTask(time_duration timeout)
|
||||
: detail::StreamTask<T>(timeout) {}
|
||||
};
|
||||
|
||||
} // namespace server
|
||||
} // namespace carla
|
|
@ -1,85 +0,0 @@
|
|||
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
|
||||
#include "carla/NonCopyable.h"
|
||||
|
||||
namespace carla {
|
||||
namespace server {
|
||||
|
||||
/// A thread-safe queue.
|
||||
///
|
||||
/// From "C++ Concurrency In Action", Anthony Williams.
|
||||
template<typename T>
|
||||
class ThreadSafeQueue : private NonCopyable {
|
||||
public:
|
||||
|
||||
ThreadSafeQueue() : _done(false) {}
|
||||
|
||||
~ThreadSafeQueue() {
|
||||
set_done(true);
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
return _queue.empty();
|
||||
}
|
||||
|
||||
bool done() const {
|
||||
return _done;
|
||||
}
|
||||
|
||||
void set_done(bool done = true) {
|
||||
_done = done;
|
||||
_condition.notify_all();
|
||||
}
|
||||
|
||||
void Push(T &&new_value) {
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
_queue.push(std::forward<T>(new_value));
|
||||
_condition.notify_one();
|
||||
}
|
||||
|
||||
bool WaitAndPop(T &value) {
|
||||
std::unique_lock<std::mutex> lock(_mutex);
|
||||
_condition.wait(lock, [this] { return _done || !_queue.empty(); });
|
||||
if (_queue.empty()) {
|
||||
return false;
|
||||
}
|
||||
value = _queue.front();
|
||||
_queue.pop();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TryPop(T &value) {
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
if (_queue.empty()) {
|
||||
return false;
|
||||
}
|
||||
value = _queue.front();
|
||||
_queue.pop();
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
mutable std::mutex _mutex;
|
||||
|
||||
std::queue<T> _queue;
|
||||
|
||||
std::atomic_bool _done;
|
||||
|
||||
std::condition_variable _condition;
|
||||
};
|
||||
|
||||
} // namespace server
|
||||
} // namespace carla
|
|
@ -1,145 +0,0 @@
|
|||
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#include "carla/server/WorldServer.h"
|
||||
|
||||
#include "carla/Debug.h"
|
||||
#include "carla/server/AgentServer.h"
|
||||
|
||||
namespace carla {
|
||||
namespace server {
|
||||
|
||||
// ===========================================================================
|
||||
// -- Static local functions -------------------------------------------------
|
||||
// ===========================================================================
|
||||
|
||||
static bool IsPortValid(const uint32_t port) {
|
||||
constexpr uint32_t MIN = 1023u;
|
||||
return (port > MIN) && (port + 1u > MIN) && (port + 2u > MIN);
|
||||
}
|
||||
|
||||
static std::future<error_code> GetInvalidPortResult(const uint32_t port) {
|
||||
log_error("invalid port", port);
|
||||
std::promise<error_code> promise;
|
||||
promise.set_value(errc::invalid_argument());
|
||||
return promise.get_future();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static error_code TryRead(ReadTask<T> &task, T &value, timeout_t timeout) {
|
||||
DEBUG_ASSERT(task.valid());
|
||||
Reading<T> reading;
|
||||
reading.error_code = errc::try_again();
|
||||
if (task.TryGetResult(reading, timeout) && !reading.error_code) {
|
||||
value = std::move(reading.message);
|
||||
}
|
||||
return reading.error_code;
|
||||
}
|
||||
|
||||
template <typename T, typename E = typename std::remove_reference<T>::type>
|
||||
static std::future<error_code> Write(WriteTask<E> &task, T &&value) {
|
||||
DEBUG_ASSERT(task.valid());
|
||||
task.set_message(std::forward<T>(value));
|
||||
return task.ReleaseResult();
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// -- -------------------------------------------------
|
||||
// ===========================================================================
|
||||
|
||||
WorldServer::Protocol::Protocol(const time_duration timeout)
|
||||
: request_new_episode(timeout),
|
||||
scene_description(timeout),
|
||||
episode_start(timeout),
|
||||
episode_ready(timeout) {}
|
||||
|
||||
// ===========================================================================
|
||||
// -- -------------------------------------------------
|
||||
// ===========================================================================
|
||||
|
||||
WorldServer::WorldServer()
|
||||
: _encoder(),
|
||||
_world_server(_encoder) {}
|
||||
|
||||
WorldServer::~WorldServer() {}
|
||||
|
||||
std::future<error_code> WorldServer::Connect(
|
||||
const uint32_t port,
|
||||
const time_duration timeout) {
|
||||
if (!IsPortValid(port)) {
|
||||
return GetInvalidPortResult(port);
|
||||
}
|
||||
_port = port;
|
||||
_timeout = timeout;
|
||||
auto result = _world_server.Connect(_port, _timeout);
|
||||
ExecuteProtocol(Protocol(_timeout));
|
||||
return result;
|
||||
}
|
||||
|
||||
error_code WorldServer::TryRead(
|
||||
carla_request_new_episode &request_new_episode,
|
||||
const timeout_t timeout) {
|
||||
auto ec = carla::server::TryRead(_protocol.request_new_episode, _new_episode_data, timeout);
|
||||
if (!ec) {
|
||||
request_new_episode = _new_episode_data.values;
|
||||
}
|
||||
return ec;
|
||||
}
|
||||
|
||||
std::future<error_code> WorldServer::Write(
|
||||
const carla_scene_description &scene_description) {
|
||||
/// @todo Here sensor names are not copied and will be invalidated.
|
||||
decltype(_sensor_definitions) defs(
|
||||
scene_description.sensors,
|
||||
scene_description.sensors + scene_description.number_of_sensors);
|
||||
_sensor_definitions = std::move(defs);
|
||||
CarlaSceneDescription scene(_encoder.Encode(scene_description));
|
||||
return carla::server::Write(_protocol.scene_description, std::move(scene));
|
||||
}
|
||||
|
||||
error_code WorldServer::TryRead(
|
||||
carla_episode_start &episode_start,
|
||||
const timeout_t timeout) {
|
||||
return carla::server::TryRead(_protocol.episode_start, episode_start, timeout);
|
||||
}
|
||||
|
||||
std::future<error_code> WorldServer::Write(
|
||||
const carla_episode_ready &episode_ready) {
|
||||
return carla::server::Write(_protocol.episode_ready, episode_ready);
|
||||
}
|
||||
|
||||
void WorldServer::StartAgentServer() {
|
||||
_agent_server = std::make_unique<AgentServer>(
|
||||
_encoder,
|
||||
_port + 1u,
|
||||
_port + 2u,
|
||||
_sensor_definitions,
|
||||
_timeout);
|
||||
}
|
||||
|
||||
void WorldServer::KillAgentServer() {
|
||||
_agent_server = nullptr;
|
||||
_sensor_definitions.clear();
|
||||
}
|
||||
|
||||
void WorldServer::ResetProtocol() {
|
||||
Protocol protocol(_timeout);
|
||||
// Here we need to wait forever for the new episode, as it will take as long
|
||||
// as the current episode lasts.
|
||||
protocol.request_new_episode.set_timeout(boost::posix_time::pos_infin);
|
||||
ExecuteProtocol(std::move(protocol));
|
||||
}
|
||||
|
||||
void WorldServer::ExecuteProtocol(Protocol &&protocol) {
|
||||
_protocol = std::move(protocol);
|
||||
_world_server.Execute(_protocol.request_new_episode);
|
||||
_world_server.Execute(_protocol.scene_description);
|
||||
_world_server.Execute(_protocol.episode_start);
|
||||
_world_server.Execute(_protocol.episode_ready);
|
||||
}
|
||||
|
||||
} // namespace server
|
||||
} // namespace carla
|
|
@ -1,88 +0,0 @@
|
|||
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "carla/NonCopyable.h"
|
||||
#include "carla/server/AsyncServer.h"
|
||||
#include "carla/server/CarlaEncoder.h"
|
||||
#include "carla/server/CarlaSceneDescription.h"
|
||||
#include "carla/server/EncoderServer.h"
|
||||
#include "carla/server/RequestNewEpisode.h"
|
||||
#include "carla/server/TCPServer.h"
|
||||
|
||||
namespace carla {
|
||||
namespace server {
|
||||
|
||||
class AgentServer;
|
||||
|
||||
class WorldServer : private NonCopyable {
|
||||
public:
|
||||
|
||||
WorldServer();
|
||||
|
||||
~WorldServer();
|
||||
|
||||
void Disconnect() {
|
||||
KillAgentServer();
|
||||
_world_server.Disconnect();
|
||||
}
|
||||
|
||||
std::future<error_code> Connect(uint32_t port, time_duration timeout);
|
||||
|
||||
error_code TryRead(carla_request_new_episode &request_new_episode, timeout_t timeout);
|
||||
|
||||
std::future<error_code> Write(const carla_scene_description &scene_description);
|
||||
|
||||
error_code TryRead(carla_episode_start &episode_start, timeout_t timeout);
|
||||
|
||||
std::future<error_code> Write(const carla_episode_ready &episode_ready);
|
||||
|
||||
/// This assumes you have entered the loop of write measurements, read
|
||||
/// control.
|
||||
void StartAgentServer();
|
||||
|
||||
AgentServer *GetAgentServer() {
|
||||
return _agent_server.get();
|
||||
}
|
||||
|
||||
void KillAgentServer();
|
||||
|
||||
void ResetProtocol();
|
||||
|
||||
private:
|
||||
|
||||
struct Protocol {
|
||||
Protocol() = default;
|
||||
explicit Protocol(time_duration timeout);
|
||||
|
||||
ReadTask<RequestNewEpisode> request_new_episode;
|
||||
WriteTask<CarlaSceneDescription> scene_description;
|
||||
ReadTask<carla_episode_start> episode_start;
|
||||
WriteTask<carla_episode_ready> episode_ready;
|
||||
};
|
||||
|
||||
void ExecuteProtocol(Protocol &&protocol);
|
||||
|
||||
uint32_t _port;
|
||||
|
||||
time_duration _timeout;
|
||||
|
||||
CarlaEncoder _encoder;
|
||||
|
||||
Protocol _protocol;
|
||||
|
||||
AsyncServer<EncoderServer<TCPServer>> _world_server;
|
||||
|
||||
std::vector<carla_sensor_definition> _sensor_definitions;
|
||||
|
||||
std::unique_ptr<AgentServer> _agent_server;
|
||||
|
||||
RequestNewEpisode _new_episode_data;
|
||||
};
|
||||
|
||||
} // namespace server
|
||||
} // namespace carla
|
|
@ -1,57 +0,0 @@
|
|||
#include "Sensor.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace test {
|
||||
|
||||
static uint32_t ID_COUNT = 0u;
|
||||
|
||||
Sensor::Sensor() : Sensor(++ID_COUNT) {}
|
||||
|
||||
Sensor::Sensor(const uint32_t id)
|
||||
: _name(std::string("Sensor") + std::to_string(id)),
|
||||
_definition({id, 0u, _name.c_str()}),
|
||||
_data({id, nullptr, 0u, nullptr, 0u}) {}
|
||||
|
||||
carla_sensor_data Sensor::MakeRandomData() {
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
|
||||
const struct {
|
||||
uint64_t FrameNumber;
|
||||
uint32_t Width;
|
||||
uint32_t Height;
|
||||
uint32_t Type;
|
||||
float FOV;
|
||||
} ImageHeader = {++_frame_number, 300u, 200u, 1u, 90.0f};
|
||||
|
||||
_data.header_size = sizeof(ImageHeader);
|
||||
auto header = std::make_unique<unsigned char[]>(_data.header_size);
|
||||
std::memcpy(
|
||||
reinterpret_cast<void *>(header.get()),
|
||||
reinterpret_cast<const void *>(&ImageHeader),
|
||||
_data.header_size);
|
||||
_header = std::move(header);
|
||||
|
||||
_data.data_size = 300u * 200u;
|
||||
_buffer = std::make_unique<const unsigned char[]>(_data.data_size);
|
||||
|
||||
_data.header = _header.get();
|
||||
_data.data = _buffer.get();
|
||||
|
||||
return _data;
|
||||
}
|
||||
|
||||
void Sensor::CheckData(boost::asio::const_buffer buffer) const {
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
const auto size = boost::asio::buffer_size(buffer);
|
||||
const auto begin = boost::asio::buffer_cast<const unsigned char *>(buffer);
|
||||
const auto header_begin = begin + 2u * sizeof(uint32_t);
|
||||
const auto data_begin = header_begin + _data.header_size;
|
||||
|
||||
const auto expected_size = 2u * sizeof(uint32_t) + _data.header_size + _data.data_size;
|
||||
ASSERT_EQ(size, expected_size);
|
||||
ASSERT_EQ(0, std::memcmp(header_begin, _header.get(), _data.header_size));
|
||||
ASSERT_EQ(0, std::memcmp(data_begin, _buffer.get(), _data.data_size));
|
||||
}
|
||||
|
||||
} // test
|
|
@ -1,52 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <carla/carla_server.h>
|
||||
|
||||
#include "carla/server/ServerTraits.h"
|
||||
|
||||
#include <boost/asio/buffer.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
|
||||
namespace test {
|
||||
|
||||
/// A class for testing usage of sensor data.
|
||||
class Sensor {
|
||||
public:
|
||||
|
||||
Sensor();
|
||||
|
||||
uint32_t id() const {
|
||||
return _definition.id;
|
||||
}
|
||||
|
||||
const carla_sensor_definition &definition() const {
|
||||
return _definition;
|
||||
}
|
||||
|
||||
carla_sensor_data MakeRandomData();
|
||||
|
||||
void CheckData(boost::asio::const_buffer buffer) const;
|
||||
|
||||
private:
|
||||
|
||||
Sensor(uint32_t id);
|
||||
|
||||
uint64_t _frame_number = 0u;
|
||||
|
||||
mutable std::mutex _mutex;
|
||||
|
||||
const std::string _name;
|
||||
|
||||
const carla_sensor_definition _definition;
|
||||
|
||||
std::unique_ptr<const unsigned char[]> _header;
|
||||
|
||||
std::unique_ptr<const unsigned char[]> _buffer;
|
||||
|
||||
carla_sensor_data _data;
|
||||
};
|
||||
|
||||
} // test
|
|
@ -1,218 +0,0 @@
|
|||
#include <iostream>
|
||||
#include <random>
|
||||
#include <string>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <carla/Logging.h>
|
||||
#include <carla/server/AsyncServer.h>
|
||||
#include <carla/server/CarlaEncoder.h>
|
||||
#include <carla/server/EncoderServer.h>
|
||||
#include <carla/server/TCPServer.h>
|
||||
|
||||
using namespace carla::server;
|
||||
using namespace boost::posix_time;
|
||||
|
||||
// These tests assume there is an echo client connected to port 4000.
|
||||
static constexpr uint32_t PORT = 4000u;
|
||||
static const auto TIMEOUT = seconds(10);
|
||||
|
||||
using AsyncTCPServer = AsyncServer<EncoderServer<TCPServer>>;
|
||||
|
||||
static std::string MakeRandomString(size_t length) {
|
||||
constexpr char charset[] =
|
||||
" 0123456789"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
|
||||
static thread_local std::mt19937 rg{std::random_device{}()};
|
||||
using distribution_t = std::uniform_int_distribution<decltype(length)>;
|
||||
static thread_local distribution_t pick(0, sizeof(charset) - 2);
|
||||
|
||||
std::string result;
|
||||
result.reserve(length);
|
||||
std::generate_n(std::back_inserter(result), length, [&]() {
|
||||
return charset[pick(rg)];
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
TEST(AsyncServer, SyncSayHello) {
|
||||
CarlaEncoder encoder;
|
||||
AsyncTCPServer server(encoder);
|
||||
|
||||
auto result = server.Connect(PORT, TIMEOUT);
|
||||
ASSERT_FALSE(result.get()) << "missing echo client!";
|
||||
|
||||
for (auto i = 0u; i < 1000u; ++i) {
|
||||
const std::string message = "Hello client!";
|
||||
|
||||
WriteTask<std::string> say_hello(TIMEOUT);
|
||||
server.Execute(say_hello);
|
||||
say_hello.set_message(message);
|
||||
ASSERT_FALSE(say_hello.get_result());
|
||||
|
||||
ReadTask<std::string> read_answer(TIMEOUT);
|
||||
server.Execute(read_answer);
|
||||
auto reading = read_answer.get_result();
|
||||
ASSERT_FALSE(reading.error_code);
|
||||
ASSERT_EQ(message, reading.message);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AsyncServer, ASyncSayHello) {
|
||||
CarlaEncoder encoder;
|
||||
AsyncTCPServer server(encoder);
|
||||
|
||||
constexpr auto numberOfIterations = 1000u;
|
||||
|
||||
struct write_and_read {
|
||||
write_and_read() : write(TIMEOUT), read(TIMEOUT) {}
|
||||
WriteTask<std::string> write;
|
||||
ReadTask<std::string> read;
|
||||
};
|
||||
|
||||
std::vector<write_and_read> tasks(numberOfIterations);
|
||||
|
||||
auto result = server.Connect(PORT, TIMEOUT);
|
||||
ASSERT_FALSE(result.get()) << "missing echo client!";
|
||||
|
||||
// Submit tasks.
|
||||
for (auto &task : tasks) {
|
||||
server.Execute(task.write);
|
||||
server.Execute(task.read);
|
||||
}
|
||||
|
||||
std::string message;
|
||||
char c = 'a';
|
||||
for (auto &task : tasks) {
|
||||
message += c++;
|
||||
task.write.set_message(message);
|
||||
ASSERT_FALSE(task.write.get_result());
|
||||
auto reading = task.read.get_result();
|
||||
ASSERT_FALSE(reading.error_code);
|
||||
ASSERT_EQ(message, reading.message);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AsyncServer, ConnectTwice) {
|
||||
CarlaEncoder encoder;
|
||||
AsyncTCPServer server(encoder);
|
||||
|
||||
auto result = server.Connect(PORT, TIMEOUT);
|
||||
ASSERT_FALSE(result.get()) << "missing echo client!";
|
||||
|
||||
ASSERT_TRUE(server.Connect(PORT, TIMEOUT).get()) << "we shouldn't be able to connect twice";
|
||||
|
||||
AsyncTCPServer server2(encoder);
|
||||
ASSERT_TRUE(server2.Connect(PORT, TIMEOUT).get()) << "we shouldn't be able to connect twice";
|
||||
}
|
||||
|
||||
TEST(AsyncServer, Disconnect) {
|
||||
CarlaEncoder encoder;
|
||||
AsyncTCPServer server(encoder);
|
||||
|
||||
auto result = server.Connect(PORT, TIMEOUT);
|
||||
ASSERT_FALSE(result.get()) << "missing echo client!";
|
||||
|
||||
ReadTask<std::string> read(TIMEOUT);
|
||||
server.Execute(read);
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::seconds(2u));
|
||||
server.Disconnect();
|
||||
|
||||
ASSERT_TRUE(read.get_result().error_code) << "we received something, and we shouldn't";
|
||||
}
|
||||
|
||||
TEST(AsyncServer, DiscardFutures) {
|
||||
CarlaEncoder encoder;
|
||||
AsyncTCPServer server(encoder);
|
||||
|
||||
constexpr auto numberOfIterations = 1000u;
|
||||
|
||||
{
|
||||
auto result = server.Connect(PORT, TIMEOUT);
|
||||
ASSERT_FALSE(result.get()) << "missing echo client!";
|
||||
}
|
||||
|
||||
std::vector<ReadTask<std::string>> reads;
|
||||
{
|
||||
std::string message;
|
||||
char c = 'a';
|
||||
for (auto i = 0u; i < numberOfIterations; ++i) {
|
||||
message += c++;
|
||||
WriteTask<std::string> write(TIMEOUT);
|
||||
write.set_message(message);
|
||||
server.Execute(write);
|
||||
reads.emplace_back(TIMEOUT);
|
||||
server.Execute(reads.back());
|
||||
}
|
||||
}
|
||||
{
|
||||
std::string message;
|
||||
char c = 'a';
|
||||
for (auto &read : reads) {
|
||||
message += c++;
|
||||
auto reading = read.get_result();
|
||||
ASSERT_FALSE(reading.error_code);
|
||||
ASSERT_EQ(message, reading.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ProfilingServer(size_t message_size) {
|
||||
CarlaEncoder encoder;
|
||||
AsyncTCPServer server(encoder);
|
||||
|
||||
auto result = server.Connect(PORT, TIMEOUT);
|
||||
ASSERT_FALSE(result.get()) << "missing echo client!";
|
||||
for (auto i = 0u; i < 10u; ++i) {
|
||||
const std::string message = MakeRandomString(message_size);
|
||||
WriteTask<std::string> say_hello;
|
||||
{
|
||||
CARLA_PROFILE_SCOPE(Test_MainThread, Send);
|
||||
say_hello = WriteTask<std::string>(seconds(3));
|
||||
say_hello.set_message(message);
|
||||
server.Execute(say_hello);
|
||||
}
|
||||
ASSERT_FALSE(say_hello.get_result());
|
||||
Reading<std::string> reading;
|
||||
ReadTask<std::string> read_answer;
|
||||
{
|
||||
CARLA_PROFILE_SCOPE(Test_MainThread, Receive);
|
||||
read_answer = ReadTask<std::string>(seconds(3));
|
||||
server.Execute(read_answer);
|
||||
if (read_answer.IsReady()) {
|
||||
CARLA_PROFILE_SCOPE(Test_MainThread, GetReading);
|
||||
reading = read_answer.get_result();
|
||||
}
|
||||
}
|
||||
if (read_answer.valid())
|
||||
reading = read_answer.get_result();
|
||||
|
||||
ASSERT_FALSE(reading.error_code);
|
||||
ASSERT_EQ(message.size(), reading.message.size());
|
||||
ASSERT_EQ(message, reading.message);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AsyncServer, Message10KB) {
|
||||
auto f = std::async(std::launch::async, [](){ ProfilingServer(10u * 1024u); });
|
||||
f.get();
|
||||
}
|
||||
|
||||
TEST(AsyncServer, Message1MB) {
|
||||
auto f = std::async(std::launch::async, [](){ ProfilingServer(1024u * 1024u); });
|
||||
f.get();
|
||||
}
|
||||
|
||||
TEST(AsyncServer, Message10MB) {
|
||||
auto f = std::async(std::launch::async, [](){ ProfilingServer(10u * 1024u * 1024u); });
|
||||
f.get();
|
||||
}
|
||||
|
||||
TEST(AsyncServer, Message20MB) {
|
||||
auto f = std::async(std::launch::async, [](){ ProfilingServer(20u * 1024u * 1024u); });
|
||||
f.get();
|
||||
}
|
|
@ -1,166 +0,0 @@
|
|||
#include <atomic>
|
||||
#include <future>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <carla/carla_server.h>
|
||||
|
||||
#include "carla/Logging.h"
|
||||
#include "carla/server/ServerTraits.h"
|
||||
|
||||
#include "Sensor.h"
|
||||
|
||||
using namespace carla::server;
|
||||
using namespace boost::posix_time;
|
||||
|
||||
// These tests assume there is a CARLA client connected to port 2000.
|
||||
static constexpr uint32_t PORT = 2000u;
|
||||
static constexpr uint32_t TIMEOUT = 6u * 1000u;
|
||||
|
||||
#define SIZE_OF_ARRAY(array) (sizeof(array) / sizeof(array[0u]))
|
||||
|
||||
// #define CARLASERVER_TEST_LOG
|
||||
#ifdef CARLASERVER_TEST_LOG
|
||||
template <typename ... Args>
|
||||
static inline void test_log(Args &&... args) {
|
||||
carla::logging::print(std::cout, "DEBUG:", std::forward<Args>(args)..., '\n');
|
||||
}
|
||||
#else
|
||||
template <typename ... Args>
|
||||
static inline void test_log(Args &&...) {}
|
||||
#endif
|
||||
|
||||
static auto make_carla_server() {
|
||||
const auto deleter = [](void *ptr) {
|
||||
test_log("destroying CarlaServer", ptr);
|
||||
carla_free_server(ptr);
|
||||
};
|
||||
auto ptr = std::unique_ptr<void, decltype(deleter)>(carla_make_server(), deleter);
|
||||
test_log("created CarlaServer", ptr.get());
|
||||
return ptr;
|
||||
}
|
||||
|
||||
TEST(CarlaServerAPI, MakeCarlaServer) {
|
||||
auto CarlaServer = make_carla_server();
|
||||
ASSERT_TRUE(CarlaServer != nullptr);
|
||||
}
|
||||
|
||||
TEST(CarlaServerAPI, SimBlocking) {
|
||||
auto CarlaServerGuard = make_carla_server();
|
||||
CarlaServerPtr CarlaServer = CarlaServerGuard.get();
|
||||
ASSERT_TRUE(CarlaServer != nullptr);
|
||||
|
||||
std::array<test::Sensor, 5u> sensors;
|
||||
|
||||
carla_sensor_definition sensor_definitions[sensors.size()];
|
||||
|
||||
for (auto i = 0u; i < sensors.size(); ++i) {
|
||||
sensor_definitions[i] = sensors[i].definition();
|
||||
}
|
||||
|
||||
const carla_transform start_locations[] = {
|
||||
{carla_vector3d{0.0f, 0.0f, 0.0f}, carla_vector3d{0.0f, 0.0f, 0.0f}, carla_rotation3d{0.0f, 0.0f, 0.0f}},
|
||||
{carla_vector3d{1.0f, 0.0f, 0.0f}, carla_vector3d{1.0f, 0.0f, 0.0f}, carla_rotation3d{0.0f, 0.0f, 0.0f}},
|
||||
{carla_vector3d{0.0f, 1.0f, 0.0f}, carla_vector3d{0.0f, 1.0f, 0.0f}, carla_rotation3d{0.0f, 0.0f, 0.0f}},
|
||||
{carla_vector3d{1.0f, 1.0f, 0.0f}, carla_vector3d{1.0f, 1.0f, 0.0f}, carla_rotation3d{0.0f, 0.0f, 0.0f}}
|
||||
};
|
||||
|
||||
const auto S = CARLA_SERVER_SUCCESS;
|
||||
ASSERT_EQ(0, S);
|
||||
|
||||
test_log("###### Begin Test ######");
|
||||
|
||||
test_log("connecting...");
|
||||
ASSERT_EQ(S, carla_server_connect(CarlaServer, PORT, TIMEOUT));
|
||||
|
||||
{
|
||||
test_log("waiting for new episode...");
|
||||
carla_request_new_episode values;
|
||||
ASSERT_EQ(S, carla_read_request_new_episode(CarlaServer, values, TIMEOUT));
|
||||
}
|
||||
|
||||
for (auto i = 0u; i < 5u; ++i) {
|
||||
test_log("###### New Episode ######");
|
||||
{
|
||||
test_log("sending scene description...");
|
||||
const carla_scene_description values{
|
||||
// cppcheck-suppress constStatement
|
||||
"TestTown01",
|
||||
start_locations,
|
||||
SIZE_OF_ARRAY(start_locations),
|
||||
sensor_definitions,
|
||||
SIZE_OF_ARRAY(sensor_definitions)};
|
||||
ASSERT_EQ(S, carla_write_scene_description(CarlaServer, values, TIMEOUT));
|
||||
}
|
||||
{
|
||||
test_log("waiting for episode start...");
|
||||
carla_episode_start values;
|
||||
ASSERT_EQ(S, carla_read_episode_start(CarlaServer, values, TIMEOUT));
|
||||
}
|
||||
{
|
||||
test_log("sending episode ready...");
|
||||
const carla_episode_ready values{true};
|
||||
ASSERT_EQ(S, carla_write_episode_ready(CarlaServer, values, TIMEOUT));
|
||||
}
|
||||
|
||||
std::array<carla_agent, 30u> agents_data;
|
||||
for (auto i = 0u; i < agents_data.size(); ++i) {
|
||||
agents_data[i].id = i;
|
||||
agents_data[i].type = CARLA_SERVER_AGENT_VEHICLE;
|
||||
agents_data[i].transform = start_locations[0u];
|
||||
agents_data[i].bounding_box = {start_locations[0u], {100.0f, 100.0f, 100.0f}};
|
||||
agents_data[i].forward_speed = 50.0f;
|
||||
}
|
||||
|
||||
std::atomic_bool done{false};
|
||||
|
||||
// Simulate game thread.
|
||||
auto game_thread_result = std::async(std::launch::async, [&](){
|
||||
while (!done) {
|
||||
{
|
||||
carla_measurements measurements;
|
||||
measurements.non_player_agents = agents_data.data();
|
||||
measurements.number_of_non_player_agents = agents_data.size();
|
||||
auto ec = carla_write_measurements(CarlaServer, measurements);
|
||||
if (ec != S)
|
||||
break;
|
||||
}
|
||||
{
|
||||
carla_control control;
|
||||
test_log("waiting for control...");
|
||||
auto ec = carla_read_control(CarlaServer, control, TIMEOUT);
|
||||
if ((ec != S) && (ec != CARLA_SERVER_TRY_AGAIN)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Simulate render thread.
|
||||
auto render_thread_result = std::async(std::launch::async, [&](){
|
||||
while (!done) {
|
||||
for (auto &sensor : sensors) {
|
||||
carla_write_sensor_data(CarlaServer, sensor.MakeRandomData());
|
||||
std::this_thread::sleep_for(std::chrono::microseconds(150));
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
for (;;) {
|
||||
carla_request_new_episode new_episode;
|
||||
auto ec = carla_read_request_new_episode(CarlaServer, new_episode, 0);
|
||||
ASSERT_TRUE((ec == S) || (ec == CARLA_SERVER_TRY_AGAIN));
|
||||
if (ec != CARLA_SERVER_TRY_AGAIN) {
|
||||
test_log("received new episode request");
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(16));
|
||||
}
|
||||
|
||||
test_log("waiting for async's future");
|
||||
game_thread_result.get();
|
||||
render_thread_result.get();
|
||||
}
|
||||
test_log("###### End Test ######");
|
||||
}
|
|
@ -1,146 +0,0 @@
|
|||
#include <iostream>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <carla/Logging.h>
|
||||
#include <carla/server/DoubleBuffer.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <cstring>
|
||||
#include <future>
|
||||
#include <string>
|
||||
|
||||
// #define CARLA_DOUBLEBUFFER_TEST_LOG
|
||||
#ifdef CARLA_DOUBLEBUFFER_TEST_LOG
|
||||
template <typename ... Args>
|
||||
static inline void test_log(Args &&... args) {
|
||||
carla::detail::print_args(std::cout, "DEBUG:", std::forward<Args>(args)..., '\n');
|
||||
}
|
||||
#else
|
||||
template <typename ... Args>
|
||||
static inline void test_log(Args &&...) {}
|
||||
#endif
|
||||
|
||||
TEST(DoubleBuffer, WriteAndRead) {
|
||||
using namespace carla::server;
|
||||
|
||||
DoubleBuffer<size_t> buffer;
|
||||
|
||||
constexpr auto numberOfWrites = 50u;
|
||||
|
||||
std::atomic_bool done{false};
|
||||
|
||||
auto result_writer = std::async(std::launch::async, [&](){
|
||||
for (size_t i = 0u; i < numberOfWrites; ++i) {
|
||||
{
|
||||
auto writer = buffer.MakeWriter();
|
||||
ASSERT_TRUE(writer != nullptr);
|
||||
*writer = i;
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(20u));
|
||||
};
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(200u));
|
||||
done = true;
|
||||
});
|
||||
|
||||
const time_duration timeout = boost::posix_time::milliseconds(10u);
|
||||
|
||||
auto result_reader = std::async(std::launch::async, [&](){
|
||||
auto readings = 0u;
|
||||
while (!done && (readings < numberOfWrites)) {
|
||||
size_t i;
|
||||
bool readed = false;
|
||||
const void* ptr = nullptr;
|
||||
{
|
||||
auto reader = buffer.TryMakeReader(timeout);
|
||||
if (reader != nullptr) {
|
||||
readed = true;
|
||||
i = *reader;
|
||||
ASSERT_EQ(readings, i);
|
||||
++readings;
|
||||
ptr = reader.get();
|
||||
}
|
||||
}
|
||||
if (readed) {
|
||||
test_log("buffer", ptr, '=', i);
|
||||
} else {
|
||||
std::this_thread::yield();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
result_reader.get();
|
||||
result_writer.get();
|
||||
}
|
||||
|
||||
TEST(DoubleBuffer, LongMessage) {
|
||||
using namespace carla::server;
|
||||
|
||||
const std::string message =
|
||||
"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod"
|
||||
"tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim"
|
||||
"veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea"
|
||||
"commodo consequat. Duis aute irure dolor in reprehenderit in voluptate"
|
||||
"velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint"
|
||||
"occaecat cupidatat non proident, sunt in culpa qui officia deserunt"
|
||||
"mollit anim id est laborum."
|
||||
"Doloremque consequuntur quo perferendis ea aut neque ab. Corrupti"
|
||||
"tempora iusto voluptatem eum neque qui reiciendis iusto. Ut ipsa iste"
|
||||
"perspiciatis illum et cupiditate possimus. Vel omnis et sint. Voluptas"
|
||||
"nihil corrupti quasi et facilis. Autem doloribus autem accusantium"
|
||||
"quibusdam natus ut. Odit voluptatem similique dolor omnis aut."
|
||||
"Doloremque maxime et excepturi. Ullam in distinctio eligendi consequatur"
|
||||
"facilis assumenda. Vel dolores id similique blanditiis libero aut qui"
|
||||
"ea. Quod quam eligendi possimus quae et sed est. Neque ut nemo"
|
||||
"necessitatibus. Exercitationem molestiae minima sunt voluptate adipisci"
|
||||
"recusandae. Doloribus tenetur quas nostrum esse. Error at voluptas et"
|
||||
"pariatur accusantium nulla. Voluptatem repellat sit suscipit. Reiciendis"
|
||||
"sed officiis doloribus tempora quia. Tempora quam quasi cumque unde"
|
||||
"consequatur consequuntur. Nihil consequatur mollitia voluptas aspernatur"
|
||||
"voluptates expedita et enim. Est doloremque veritatis placeat ut. In at"
|
||||
"qui nemo consequatur omnis quasi. Dignissimos ullam et ut et dolores"
|
||||
"distinctio nisi. Aut quia et harum. Quam aspernatur illum cupiditate"
|
||||
"unde. Inventore est ut est ducimus libero.";
|
||||
|
||||
DoubleBuffer<std::string> buffer;
|
||||
|
||||
constexpr auto numberOfWrites = 50u;
|
||||
|
||||
std::atomic_bool done{false};
|
||||
|
||||
auto result_writer = std::async(std::launch::async, [&](){
|
||||
for (size_t i = 0u; i < numberOfWrites; ++i) {
|
||||
{
|
||||
auto writer = buffer.MakeWriter();
|
||||
ASSERT_TRUE(writer != nullptr);
|
||||
*writer = message;
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1u));
|
||||
};
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(200u));
|
||||
done = true;
|
||||
});
|
||||
|
||||
const time_duration timeout = boost::posix_time::milliseconds(10u);
|
||||
|
||||
auto result_reader = std::async(std::launch::async, [&](){
|
||||
auto readings = 0u;
|
||||
while (!done && (readings < numberOfWrites)) {
|
||||
auto reader = buffer.TryMakeReader(timeout);
|
||||
if (reader != nullptr) {
|
||||
const std::string received = *reader;
|
||||
const void* ptr = reader.get();
|
||||
reader = nullptr; // release reader.
|
||||
|
||||
ASSERT_EQ(received, message);
|
||||
test_log(readings, "buffer", ptr, '=', std::string(received.begin(), received.begin() + 11u), "...");
|
||||
++readings;
|
||||
} else {
|
||||
std::this_thread::yield();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
result_reader.get();
|
||||
result_writer.get();
|
||||
}
|
|
@ -1,90 +0,0 @@
|
|||
#include <iostream>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <carla/carla_server.h>
|
||||
|
||||
#include "carla/server/SensorDataInbox.h"
|
||||
|
||||
#include "Sensor.h"
|
||||
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <future>
|
||||
|
||||
TEST(SensorDataInbox, SyncSingleSensor) {
|
||||
using namespace carla::server;
|
||||
test::Sensor sensor0;
|
||||
SensorDataInbox::Sensors defs;
|
||||
defs.push_back(sensor0.definition());
|
||||
SensorDataInbox inbox(defs);
|
||||
for (auto j = 0u; j < 1000u; ++j) {
|
||||
auto data = sensor0.MakeRandomData();
|
||||
inbox.Write(data);
|
||||
auto buffer = (*inbox.begin()).TryMakeReader();
|
||||
ASSERT_TRUE(buffer != nullptr);
|
||||
sensor0.CheckData(buffer->buffer());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(SensorDataInbox, SyncMultipleSensors) {
|
||||
using namespace carla::server;
|
||||
std::array<test::Sensor, 50u> sensors;
|
||||
SensorDataInbox::Sensors defs;
|
||||
defs.reserve(sensors.size());
|
||||
std::for_each(sensors.begin(), sensors.end(), [&](auto &s){
|
||||
defs.push_back(s.definition());
|
||||
});
|
||||
SensorDataInbox inbox(defs);
|
||||
for (auto j = 0u; j < 1000u; ++j) {
|
||||
for (auto &sensor : sensors) {
|
||||
inbox.Write(sensor.MakeRandomData());
|
||||
auto buffer = inbox.TryMakeReader(sensor.id());
|
||||
ASSERT_TRUE(buffer != nullptr);
|
||||
sensor.CheckData(buffer->buffer());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(SensorDataInbox, Async) {
|
||||
using namespace carla::server;
|
||||
std::array<test::Sensor, 50u> sensors;
|
||||
SensorDataInbox::Sensors defs;
|
||||
defs.reserve(sensors.size());
|
||||
std::for_each(sensors.begin(), sensors.end(), [&](auto &s){
|
||||
defs.push_back(s.definition());
|
||||
});
|
||||
SensorDataInbox inbox(defs);
|
||||
|
||||
constexpr auto numberOfWrites = 200u;
|
||||
|
||||
std::atomic_bool done{false};
|
||||
|
||||
auto result_writer = std::async(std::launch::async, [&](){
|
||||
for (size_t i = 0u; i < numberOfWrites; ++i) {
|
||||
for (auto &sensor : sensors) {
|
||||
inbox.Write(sensor.MakeRandomData());
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10u));
|
||||
};
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(200u));
|
||||
done = true;
|
||||
});
|
||||
|
||||
auto result_reader = std::async(std::launch::async, [&](){
|
||||
auto readings = 0u;
|
||||
while (!done && (readings < numberOfWrites * sensors.size())) {
|
||||
for (auto &sensor : sensors) {
|
||||
auto buffer = inbox.TryMakeReader(sensor.id());
|
||||
if (buffer != nullptr) {
|
||||
sensor.CheckData(buffer->buffer());
|
||||
++readings;
|
||||
}
|
||||
}
|
||||
}
|
||||
ASSERT_EQ(numberOfWrites * sensors.size(), readings);
|
||||
});
|
||||
|
||||
result_reader.get();
|
||||
result_writer.get();
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
#include <future>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <carla/Logging.h>
|
||||
#include <carla/server/Protobuf.h>
|
||||
#include <carla/server/TCPServer.h>
|
||||
|
||||
using namespace carla::server;
|
||||
using namespace boost::posix_time;
|
||||
|
||||
// These tests assume there is an echo client connected to port 4000.
|
||||
static constexpr uint32_t PORT = 4000u;
|
||||
static const auto TIMEOUT = seconds(10);
|
||||
|
||||
TEST(TCPServer, SayHello) {
|
||||
TCPServer server;
|
||||
ASSERT_FALSE(server.Connect(PORT, TIMEOUT)) << "missing echo client!";
|
||||
|
||||
const std::string message = Protobuf::Encode("Hello client!");
|
||||
const auto length = message.size();
|
||||
|
||||
for (auto i = 0u; i < 20u; ++i) {
|
||||
ASSERT_FALSE(server.Write(boost::asio::buffer(message), TIMEOUT));
|
||||
|
||||
auto buffer = std::make_unique<char[]>(length);
|
||||
ASSERT_FALSE(server.Read(boost::asio::buffer(buffer.get(), length), TIMEOUT));
|
||||
ASSERT_EQ(message, std::string(buffer.get(), length));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(TCPServer, ConnectTwice) {
|
||||
TCPServer server;
|
||||
ASSERT_FALSE(server.Connect(PORT, TIMEOUT)) << "missing echo client!";
|
||||
ASSERT_TRUE(server.Connect(PORT, TIMEOUT)) << "we shouldn't be able to connect twice";
|
||||
TCPServer server2;
|
||||
ASSERT_TRUE(server2.Connect(PORT, TIMEOUT)) << "we shouldn't be able to connect twice";
|
||||
}
|
||||
|
||||
TEST(TCPServer, ReadTimedOut) {
|
||||
TCPServer server;
|
||||
ASSERT_FALSE(server.Connect(PORT, TIMEOUT)) << "missing echo client!";
|
||||
|
||||
constexpr size_t size = 50u;
|
||||
char received[size];
|
||||
ASSERT_TRUE(server.Read(boost::asio::buffer(received, size), seconds(1))) << "we received something, and we shouldn't";
|
||||
}
|
||||
|
||||
TEST(TCPServer, ConnectionTimedOut) {
|
||||
TCPServer server;
|
||||
ASSERT_TRUE(server.Connect(4567, seconds(2))) << "woah! it seems we connected";
|
||||
}
|
||||
|
||||
TEST(TCPServer, AsyncDisconnect) {
|
||||
TCPServer server;
|
||||
ASSERT_FALSE(server.Connect(PORT, TIMEOUT)) << "missing echo client!";
|
||||
|
||||
auto result = std::async(std::launch::async, [&](){
|
||||
std::this_thread::sleep_for(std::chrono::seconds(2u));
|
||||
server.Disconnect();
|
||||
});
|
||||
|
||||
constexpr size_t size = 50u;
|
||||
char received[size];
|
||||
ASSERT_TRUE(server.Read(boost::asio::buffer(received, size), TIMEOUT)) << "we received something, and we shouldn't";
|
||||
|
||||
result.get();
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
|
@ -1,159 +0,0 @@
|
|||
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package carla_server;
|
||||
|
||||
option cc_enable_arenas = true;
|
||||
|
||||
// =============================================================================
|
||||
// -- Basic types --------------------------------------------------------------
|
||||
// =============================================================================
|
||||
|
||||
message Vector3D {
|
||||
float x = 1;
|
||||
float y = 2;
|
||||
float z = 3;
|
||||
}
|
||||
|
||||
message Rotation3D {
|
||||
float pitch = 1;
|
||||
float yaw = 2;
|
||||
float roll = 3;
|
||||
}
|
||||
|
||||
message Transform {
|
||||
Vector3D location = 1;
|
||||
Vector3D orientation = 2 [deprecated=true];
|
||||
Rotation3D rotation = 3;
|
||||
}
|
||||
|
||||
message BoundingBox {
|
||||
Transform transform = 1;
|
||||
Vector3D extent = 2;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// -- Sensors ------------------------------------------------------------------
|
||||
// =============================================================================
|
||||
|
||||
message Sensor {
|
||||
enum Type {
|
||||
UNKNOWN = 0;
|
||||
CAMERA = 1;
|
||||
LIDAR_RAY_CAST = 2;
|
||||
}
|
||||
|
||||
fixed32 id = 1;
|
||||
Type type = 2;
|
||||
string name = 3;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// -- Agents -------------------------------------------------------------------
|
||||
// =============================================================================
|
||||
|
||||
message Vehicle {
|
||||
Transform transform = 1;
|
||||
BoundingBox bounding_box = 4;
|
||||
float forward_speed = 3;
|
||||
}
|
||||
|
||||
message Pedestrian {
|
||||
Transform transform = 1;
|
||||
BoundingBox bounding_box = 4;
|
||||
float forward_speed = 3;
|
||||
}
|
||||
|
||||
message TrafficLight {
|
||||
enum State {
|
||||
GREEN = 0;
|
||||
YELLOW = 1;
|
||||
RED = 2;
|
||||
}
|
||||
Transform transform = 1;
|
||||
State state = 2;
|
||||
}
|
||||
|
||||
message SpeedLimitSign {
|
||||
Transform transform = 1;
|
||||
float speed_limit = 2;
|
||||
}
|
||||
|
||||
message Agent {
|
||||
fixed32 id = 1;
|
||||
oneof agent {
|
||||
Vehicle vehicle = 2;
|
||||
Pedestrian pedestrian = 3;
|
||||
TrafficLight traffic_light = 4;
|
||||
SpeedLimitSign speed_limit_sign = 5;
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// -- World Server Messages ----------------------------------------------------
|
||||
// =============================================================================
|
||||
|
||||
message RequestNewEpisode {
|
||||
string ini_file = 1;
|
||||
}
|
||||
|
||||
message SceneDescription {
|
||||
string map_name = 3;
|
||||
repeated Transform player_start_spots = 1;
|
||||
repeated Sensor sensors = 2;
|
||||
}
|
||||
|
||||
message EpisodeStart {
|
||||
uint32 player_start_spot_index = 1;
|
||||
}
|
||||
|
||||
message EpisodeReady {
|
||||
bool ready = 1;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// -- Agent Server Messages ----------------------------------------------------
|
||||
// =============================================================================
|
||||
|
||||
message Control {
|
||||
float steer = 1;
|
||||
float throttle = 2;
|
||||
float brake = 3;
|
||||
bool hand_brake = 4;
|
||||
bool reverse = 5;
|
||||
}
|
||||
|
||||
message Measurements {
|
||||
message PlayerMeasurements {
|
||||
Transform transform = 1;
|
||||
|
||||
BoundingBox bounding_box = 12;
|
||||
|
||||
Vector3D acceleration = 3;
|
||||
float forward_speed = 4;
|
||||
|
||||
float collision_vehicles = 5;
|
||||
float collision_pedestrians = 6;
|
||||
float collision_other = 7;
|
||||
|
||||
float intersection_otherlane = 8;
|
||||
float intersection_offroad = 9;
|
||||
|
||||
Control autopilot_control = 10;
|
||||
}
|
||||
|
||||
uint64 frame_number = 5;
|
||||
|
||||
uint32 platform_timestamp = 1;
|
||||
|
||||
uint32 game_timestamp = 2;
|
||||
|
||||
PlayerMeasurements player_measurements = 3;
|
||||
|
||||
repeated Agent non_player_agents = 4;
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
@echo off
|
||||
|
||||
set PROTOBUF_SRC_DIR=Proto
|
||||
set PROTOBUF_CPP_OUT_DIR=CarlaServer/source/carla/server
|
||||
set PROTOBUF_PY_OUT_DIR=../Deprecated/PythonClient/carla
|
||||
set PROTO_BASENAME=carla_server
|
||||
|
||||
if "%1" == "--clean" (
|
||||
rem Delete existing ones.
|
||||
@rd /s /q "%PROTOBUF_CPP_OUT_DIR%\carla_server.pb.h" 2>nul
|
||||
@rd /s /q "%PROTOBUF_CPP_OUT_DIR%\carla_server.pb.cc" 2>nul
|
||||
@rd /s /q "%PROTOBUF_PY_OUT_DIR%\carla_server_pb2.py" 2>nul
|
||||
goto end
|
||||
)
|
||||
|
||||
set PROTOC=Build\protobuf-install\bin\protoc.exe
|
||||
|
||||
if exist %PROTOC% (
|
||||
|
||||
echo Compiling %PROTO_BASENAME%.proto...
|
||||
|
||||
%PROTOC% ^
|
||||
-I=%PROTOBUF_SRC_DIR% ^
|
||||
--cpp_out=%PROTOBUF_CPP_OUT_DIR% ^
|
||||
--python_out=%PROTOBUF_PY_OUT_DIR% ^
|
||||
%PROTOBUF_SRC_DIR%/%PROTO_BASENAME%.proto
|
||||
|
||||
echo done.
|
||||
|
||||
) else (
|
||||
|
||||
echo ERROR: Missing protobuf compiler: %PROTOC%
|
||||
exit /b
|
||||
|
||||
)
|
||||
|
||||
:end
|
|
@ -1,38 +0,0 @@
|
|||
#! /bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
pushd "$SCRIPT_DIR" >/dev/null
|
||||
|
||||
PROTOBUF_SRC_DIR=Proto
|
||||
PROTOBUF_CPP_OUT_DIR=CarlaServer/source/carla/server
|
||||
PROTOBUF_PY_OUT_DIR=../Deprecated/PythonClient/carla
|
||||
PROTO_BASENAME=carla_server
|
||||
|
||||
if [ "$1" == "--clean" ]; then
|
||||
# Delete existing ones.
|
||||
rm -f ${PROTOBUF_CPP_OUT_DIR}/*.pb.h ${PROTOBUF_CPP_OUT_DIR}/*.pb.cc
|
||||
rm -f ${PROTOBUF_PY_OUT_DIR}/*_pb2.py
|
||||
exit 0
|
||||
fi
|
||||
|
||||
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./Build/llvm-install/lib
|
||||
PROTOC=./Build/protobuf-install/bin/protoc
|
||||
|
||||
if [[ ! -f $PROTOC ]]; then
|
||||
echo >&2 "ERROR: Missing protobuf compiler."
|
||||
echo >&2 "Did you forget to run Setup.sh?"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Compiling ${PROTO_BASENAME}.proto..."
|
||||
|
||||
${PROTOC} \
|
||||
-I=${PROTOBUF_SRC_DIR} \
|
||||
--cpp_out=${PROTOBUF_CPP_OUT_DIR} \
|
||||
--python_out=${PROTOBUF_PY_OUT_DIR} \
|
||||
${PROTOBUF_SRC_DIR}/${PROTO_BASENAME}.proto
|
||||
|
||||
popd >/dev/null
|
||||
echo "done."
|
|
@ -1,34 +0,0 @@
|
|||
cmake_minimum_required(VERSION 3.5.0)
|
||||
project(CARLA)
|
||||
|
||||
set(CARLA_UTIL_PATH "${PROJECT_SOURCE_DIR}/..")
|
||||
|
||||
set(CARLA_LIBCXX_INSTALL_PATH "${CARLA_UTIL_PATH}/Build/llvm-install")
|
||||
set(CARLA_BOOST_INSTALL_PATH "${CARLA_UTIL_PATH}/Build/boost-install")
|
||||
set(CARLA_PROTOBUF_INSTALL_PATH "${CARLA_UTIL_PATH}/Build/protobuf-install")
|
||||
set(CARLA_GOOGLETEST_INSTALL_PATH "${CARLA_UTIL_PATH}/Build/googletest-install")
|
||||
|
||||
# Suppress windows warning, http://stackoverflow.com/a/40217291
|
||||
if (WIN32)
|
||||
macro(get_WIN32_WINNT version)
|
||||
if (CMAKE_SYSTEM_VERSION)
|
||||
set(ver ${CMAKE_SYSTEM_VERSION})
|
||||
string(REGEX MATCH "^([0-9]+).([0-9])" ver ${ver})
|
||||
string(REGEX MATCH "^([0-9]+)" verMajor ${ver})
|
||||
# Check for Windows 10, b/c we'll need to convert to hex 'A'.
|
||||
if ("${verMajor}" MATCHES "10")
|
||||
set(verMajor "A")
|
||||
string(REGEX REPLACE "^([0-9]+)" ${verMajor} ver ${ver})
|
||||
endif ("${verMajor}" MATCHES "10")
|
||||
# Remove all remaining '.' characters.
|
||||
string(REPLACE "." "" ver ${ver})
|
||||
# Prepend each digit with a zero.
|
||||
string(REGEX REPLACE "([0-9A-Z])" "0\\1" ver ${ver})
|
||||
set(${version} "0x${ver}")
|
||||
endif(CMAKE_SYSTEM_VERSION)
|
||||
endmacro(get_WIN32_WINNT)
|
||||
get_WIN32_WINNT(ver)
|
||||
add_definitions(-D_WIN32_WINNT=${ver})
|
||||
endif(WIN32)
|
||||
|
||||
add_subdirectory("CarlaServer")
|
|
@ -1,129 +0,0 @@
|
|||
cmake_minimum_required (VERSION 3.5.0)
|
||||
project (CarlaServer)
|
||||
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
set(CarlaServer_Lib_Target carlaserverd)
|
||||
set(CarlaServer_Test_Target test_carlaserverd)
|
||||
elseif (CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||
set(CarlaServer_Lib_Target carlaserver)
|
||||
set(CarlaServer_Test_Target test_carlaserver)
|
||||
endif (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
|
||||
# ==============================================================================
|
||||
# -- Compiler and dependencies -------------------------------------------------
|
||||
# ==============================================================================
|
||||
|
||||
if (UNIX)
|
||||
|
||||
find_package(Threads)
|
||||
|
||||
set(CMAKE_CXX_COMPILER /usr/bin/clang++-3.9)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -std=c++14 -pthread")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -Wextra -Wno-unused-parameter")
|
||||
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -D_DEBUG -O0")
|
||||
elseif (CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DNDEBUG -O3")
|
||||
endif (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
|
||||
# Setup libc++.
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
|
||||
include_directories("${CARLA_LIBCXX_INSTALL_PATH}/include/c++/v1")
|
||||
link_directories("${CARLA_LIBCXX_INSTALL_PATH}/lib")
|
||||
file(GLOB LibCXX_Shared_Libraries "${CARLA_LIBCXX_INSTALL_PATH}/lib/libc++*.so*")
|
||||
file(GLOB LibCXX_Static_Libraries "${CARLA_LIBCXX_INSTALL_PATH}/lib/libc++*.a")
|
||||
|
||||
# Setup boost.
|
||||
include_directories("${CARLA_BOOST_INSTALL_PATH}/include")
|
||||
set(Boost_Static_Libraries "${CARLA_BOOST_INSTALL_PATH}/lib/libboost_system.a")
|
||||
|
||||
# Setup protobuf.
|
||||
include_directories("${CARLA_PROTOBUF_INSTALL_PATH}/include")
|
||||
set(Protobuf_Static_Libraries "${CARLA_PROTOBUF_INSTALL_PATH}/lib/libprotobuf.a")
|
||||
|
||||
# Setup googletest.
|
||||
include_directories("${CARLA_GOOGLETEST_INSTALL_PATH}/include")
|
||||
set(GTest_Static_Libraries "${CARLA_GOOGLETEST_INSTALL_PATH}/lib/libgtest.a")
|
||||
|
||||
install(FILES
|
||||
${LibCXX_Shared_Libraries}
|
||||
DESTINATION shared)
|
||||
|
||||
install(FILES
|
||||
${LibCXX_Static_Libraries}
|
||||
${Boost_Static_Libraries}
|
||||
${Protobuf_Static_Libraries}
|
||||
DESTINATION lib)
|
||||
|
||||
elseif (WIN32)
|
||||
|
||||
# Setup boost.
|
||||
include_directories("${CARLA_BOOST_INSTALL_PATH}/boost-1_64")
|
||||
file(GLOB Boost_System_Static_Libraries "${CARLA_BOOST_INSTALL_PATH}/lib/libboost_system*.lib")
|
||||
file(GLOB Boost_DateTime_Static_Libraries "${CARLA_BOOST_INSTALL_PATH}/lib/libboost_date_time*.lib")
|
||||
set(Boost_Static_Libraries
|
||||
"${Boost_System_Static_Libraries}"
|
||||
"${Boost_DateTime_Static_Libraries}")
|
||||
|
||||
# Setup protobuf.
|
||||
include_directories("${CARLA_PROTOBUF_INSTALL_PATH}/include")
|
||||
set(Protobuf_Static_Libraries "${CARLA_PROTOBUF_INSTALL_PATH}/lib/libprotobuf.lib")
|
||||
|
||||
# Setup googletest.
|
||||
include_directories("${CARLA_GOOGLETEST_INSTALL_PATH}/include")
|
||||
set(GTest_Static_Libraries "${CARLA_GOOGLETEST_INSTALL_PATH}/lib/gtest.lib")
|
||||
|
||||
install(FILES
|
||||
${Boost_Static_Libraries}
|
||||
${Protobuf_Static_Libraries}
|
||||
DESTINATION lib)
|
||||
|
||||
else (UNIX)
|
||||
message(FATAL_ERROR "Build configuration not yet available for this platform")
|
||||
endif (UNIX)
|
||||
|
||||
# ==============================================================================
|
||||
# -- Project config ------------------------------------------------------------
|
||||
# ==============================================================================
|
||||
|
||||
set(CarlaServer_Path "${CARLA_UTIL_PATH}/CarlaServer")
|
||||
|
||||
include_directories("${CarlaServer_Path}/source")
|
||||
include_directories("${CarlaServer_Path}/include")
|
||||
|
||||
# libcarlaserver
|
||||
|
||||
file(GLOB carlaserver_SRC
|
||||
"${CarlaServer_Path}/include/carla/carla_server.h"
|
||||
"${CarlaServer_Path}/source/carla/*.h"
|
||||
"${CarlaServer_Path}/source/carla/*.cpp"
|
||||
"${CarlaServer_Path}/source/carla/server/*.h"
|
||||
"${CarlaServer_Path}/source/carla/server/*.cpp"
|
||||
"${CarlaServer_Path}/source/carla/server/*.pb.h"
|
||||
"${CarlaServer_Path}/source/carla/server/*.pb.cc")
|
||||
|
||||
add_library(${CarlaServer_Lib_Target} STATIC ${carlaserver_SRC})
|
||||
install(DIRECTORY "${CarlaServer_Path}/include/carla" DESTINATION include)
|
||||
install(TARGETS ${CarlaServer_Lib_Target} DESTINATION lib)
|
||||
|
||||
# unit tests
|
||||
|
||||
file(GLOB test_carlaserver_SRC
|
||||
"${CarlaServer_Path}/source/test/*.h"
|
||||
"${CarlaServer_Path}/source/test/*.cpp")
|
||||
|
||||
set(CarlaServer_Static_LIBRARIES
|
||||
${CarlaServer_Lib_Target}
|
||||
${GTest_Static_Libraries}
|
||||
${Protobuf_Static_Libraries}
|
||||
${Boost_Static_Libraries}
|
||||
${CMAKE_THREAD_LIBS_INIT})
|
||||
|
||||
if (UNIX)
|
||||
add_executable(${CarlaServer_Test_Target} ${test_carlaserver_SRC})
|
||||
target_link_libraries(${CarlaServer_Test_Target} ${CarlaServer_Static_LIBRARIES})
|
||||
install(TARGETS ${CarlaServer_Test_Target} DESTINATION bin)
|
||||
endif (UNIX)
|
Loading…
Reference in New Issue