Remove old CarlaServer

This commit is contained in:
nsubiron 2019-04-08 14:00:03 +02:00
parent c94719156c
commit 474205b4aa
51 changed files with 0 additions and 4526 deletions

View File

@ -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 */

View File

@ -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

View File

@ -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))

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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();
}
}

View File

@ -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

View File

@ -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>

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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();
}

View File

@ -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 ######");
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -1,6 +0,0 @@
#include <gtest/gtest.h>
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@ -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;
}

View File

@ -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

View File

@ -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."

View File

@ -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")

View File

@ -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)