Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
dan-du-car committed Jul 25, 2023
1 parent 639ad08 commit d0a5fbc
Show file tree
Hide file tree
Showing 7 changed files with 159 additions and 17 deletions.
1 change: 1 addition & 0 deletions .devcontainer/docker-compose-vscode.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ services:
- SIM_V2X_PORT=5757
- V2X_PORT=8686
- INFRASTRUCTURE_ID=1
- SENSOR_JSON_FILE_PATH=/var/www/plugins/MAP/sensors.json
- KAFKA_BROKER_ADDRESS=127.0.0.1:9092
secrets:
- mysql_password
Expand Down
5 changes: 5 additions & 0 deletions src/tmx/TmxUtils/src/simulation/SimulationEnvUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ namespace tmx::utils::sim{
* in SIMULATION MODE for connecting to CDASim.
*/
constexpr inline static const char *SIMULATION_REGISTRATION_PORT = "SIMULATION_REGISTRATION_PORT";
/**
* @brief sensors file location
*/
constexpr inline static const char *SENSOR_JSON_FILE_PATH = "SENSOR_JSON_FILE_PATH";

/**
* @brief Name of environment varaible for storing port for receiving time sync messages from CDASim. Only
* necessary in SIMULATION MODE for CDASim time sync.
Expand Down
12 changes: 12 additions & 0 deletions src/v2i-hub/CDASimAdapter/scripts/udp_socket_server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import socket

UDP_IP = "127.0.0.1"
UDP_SOCKET_PORT_SIM_REGISTRATION = 6767

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind((UDP_IP, UDP_SOCKET_PORT_SIM_REGISTRATION))
print("Server Listenning on port: %s" % UDP_SOCKET_PORT_SIM_REGISTRATION)

while True:
data, addr = sock.recvfrom(1024)
print("recevied message: %s" % data)
7 changes: 4 additions & 3 deletions src/v2i-hub/CDASimAdapter/src/CDASimAdapter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@ namespace CDASimAdapter{
uint time_sync_port = std::stoul(sim::get_sim_config(sim::TIME_SYNC_PORT));
uint v2x_port = std::stoul(sim::get_sim_config(sim::V2X_PORT));
uint sim_v2x_port = std::stoul(sim::get_sim_config(sim::SIM_V2X_PORT));
uint infrastructure_id = std::stoul(sim::get_sim_config(sim::INFRASTRUCTURE_ID));;
uint infrastructure_id = std::stoul(sim::get_sim_config(sim::INFRASTRUCTURE_ID));
std::string sensor_json_file_path = sim::get_sim_config(sim::SENSOR_JSON_FILE_PATH);

PLOG(logINFO) << "CDASim connecting " << simulation_ip <<
"\nUsing Registration Port : " << std::to_string( simulation_registration_port) <<
Expand All @@ -96,11 +97,11 @@ namespace CDASimAdapter{
}
if ( connection ) {
connection.reset(new CDASimConnection( simulation_ip, infrastructure_id, simulation_registration_port, sim_v2x_port, local_ip,
time_sync_port, v2x_port, location ));
time_sync_port, v2x_port, location, sensor_json_file_path));
}
else {
connection = std::make_unique<CDASimConnection>(simulation_ip, infrastructure_id, simulation_registration_port, sim_v2x_port, local_ip,
time_sync_port, v2x_port, location);
time_sync_port, v2x_port, location, sensor_json_file_path);
}
}
catch (const TmxException &e) {
Expand Down
82 changes: 76 additions & 6 deletions src/v2i-hub/CDASimAdapter/src/CDASimConnection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ using namespace tmx::utils;
namespace CDASimAdapter{
CDASimConnection::CDASimConnection(const std::string &simulation_ip, const uint infrastructure_id, const uint simulation_registration_port, const uint sim_v2x_port,
const std::string &local_ip, const uint time_sync_port, const uint v2x_port,
const WGS84Point &location) :
const WGS84Point &location, const std::string &sensor_json_file_path) :
_simulation_ip(simulation_ip), _infrastructure_id(infrastructure_id), _simulation_registration_port(simulation_registration_port),
_simulation_v2x_port(sim_v2x_port), _local_ip(local_ip), _time_sync_port(time_sync_port), _v2x_port(v2x_port),
_location(location) {
_location(location) ,_sensor_json_file_path(sensor_json_file_path) {
PLOG(logDEBUG) << "CARMA-Simulation connection initialized." << std::endl;
}

Expand All @@ -20,7 +20,13 @@ namespace CDASimAdapter{
}

bool CDASimConnection::connect() {
if (!carma_simulation_handshake(_simulation_ip, _infrastructure_id, _simulation_registration_port, _local_ip, _time_sync_port, _v2x_port, _location)) {
//Read local sensor file and populate the sensors JSON
populate_sensors_with_file(_sensor_json_file_path, _sensors_json_v);
if(_sensors_json_v.empty())
{
PLOG(logERROR) << "Sensors JSON is empty!" << std::endl;
}
if (!carma_simulation_handshake(_simulation_ip, _infrastructure_id, _simulation_registration_port, _local_ip, _time_sync_port, _v2x_port, _location, _sensors_json_v)) {
_connected = false;
return _connected;
}
Expand All @@ -34,7 +40,7 @@ namespace CDASimAdapter{
}

std::string CDASimConnection::get_handshake_json(const uint infrastructure_id, const std::string &local_ip, const uint time_sync_port, const uint v2x_port,
const WGS84Point &location) const
const WGS84Point &location, const Json::Value& sensors_json_v) const

{
Json::Value message;
Expand All @@ -47,19 +53,20 @@ namespace CDASimAdapter{
message["location"]["latitude"] = location.Latitude;
message["location"]["longitude"] = location.Longitude;
message["location"]["elevation"] = location.Elevation;
message["sensors"] = sensors_json_v;
Json::StyledWriter writer;
message_str = writer.write(message);
return message_str;
}

bool CDASimConnection::carma_simulation_handshake(const std::string &simulation_ip, const uint infrastructure_id, const uint simulation_registration_port,
const std::string &local_ip, const uint time_sync_port, const uint v2x_port,
const WGS84Point &location)
const WGS84Point &location, const Json::Value& sensors_json_v )
{
// Create JSON message with the content
std::string payload = "";

payload = get_handshake_json(infrastructure_id, local_ip, time_sync_port, v2x_port, location);
payload = get_handshake_json(infrastructure_id, local_ip, time_sync_port, v2x_port, location, sensors_json_v);

try
{
Expand Down Expand Up @@ -217,4 +224,67 @@ namespace CDASimAdapter{
forward_message( msg , message_receiver_publisher );
}

void CDASimConnection::populate_sensors_with_file(const std::string file_path, Json::Value& sensors_json_v){
//Read file from disk
std::ifstream in_strm;
in_strm.open(file_path, std::ifstream::binary);
if(!in_strm.is_open())
{
PLOG(logERROR) << "File cannot be opened. File path: " << file_path <<std::endl;
return;
}
std::string line;
std::stringstream ss;
while (std::getline(in_strm, line)) {
ss << line;
}
in_strm.close();

populate_json_with_string(ss.str(), sensors_json_v);
}

void CDASimConnection::populate_json_with_string(const std::string& json_str, Json::Value& json_v){
//Update JSON value with information from file
Json::CharReaderBuilder builder;
std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
JSONCPP_STRING err;
if(!reader->parse(json_str.c_str(), json_str.c_str() + json_str.length(), &json_v, &err))
{
PLOG(logERROR) << "Error parsing sensors from string: " << json_str << std::endl;
return;
}
}

Json::Value CDASimConnection::get_sensor_by_id(std::string &sensor_id)
{
Json::Value result;
if(_sensors_json_v.empty())
{
PLOG(logERROR) << "CDASimAdapter stored sensors are empty." << std::endl;
return result;
}

if(_sensors_json_v.isArray())
{
std::for_each( _sensors_json_v.begin(), _sensors_json_v.end(), [&result, &sensor_id](auto& item){
if(item["id"] == sensor_id)
{
result = item;
}
});
}
else if(_sensors_json_v.isObject())
{
if(_sensors_json_v["id"] == sensor_id)
{
result = _sensors_json_v;
}
}

if(result.empty())
{
PLOG(logERROR) << "CDASimAdapter stored sensors do not have sensor with id = " << sensor_id << std::endl;
}
return result;
}
}
31 changes: 28 additions & 3 deletions src/v2i-hub/CDASimAdapter/src/include/CDASimConnection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <jsoncpp/json/json.h>
#include <PluginLog.h>
#include <gtest/gtest.h>
#include <fstream>


namespace CDASimAdapter {
Expand Down Expand Up @@ -34,7 +35,7 @@ namespace CDASimAdapter {
*/
explicit CDASimConnection( const std::string &simulation_ip, const uint infrastructure_id, const uint simulation_registration_port,
const uint sim_v2x_port, const std::string &local_ip, const uint time_sync_port, const uint v2x_port,
const tmx::utils::WGS84Point &location);
const tmx::utils::WGS84Point &location, const std::string &sensor_json_file_path);

/**
* @brief Method to forward v2x message to CARMA Simulation
Expand Down Expand Up @@ -93,11 +94,12 @@ namespace CDASimAdapter {
* @param time_sync_port port assigned to listening for time sychronization messages from CARMA-Simulation.
* @param v2x_port port assigned to listening for v2x messages from CARMA-Simulation.
* @param location simulated location of infrastructure hardware.
* @param sensors_json_v A list of sensors sent to CARLA for sensor generation.
* @return true if handshake successful and false if handshake unsuccessful.
*/
bool carma_simulation_handshake(const std::string &simulation_ip, const uint infrastructure_id, const uint simulation_registration_port,
const std::string &local_ip, const uint time_sync_port, const uint v2x_port,
const tmx::utils::WGS84Point &location);
const tmx::utils::WGS84Point &location, const Json::Value& sensors_json_v);

/**
* @brief Method to setup UDP Servers and Clients after handshake to facilate message forwarding.
Expand All @@ -121,6 +123,11 @@ namespace CDASimAdapter {
* @return Returns true if CARMA-Simulation connection is active and false if the connection is inactive.
*/
bool is_connected() const;
/**
* @brief Search the list of sensors stored by this plugin and identify the sensor based on the input id.
* @param sensor_id A unique sensor identifier
*/
Json::Value get_sensor_by_id(std::string &sensor_id);

private:
/**
Expand All @@ -129,11 +136,25 @@ namespace CDASimAdapter {
* @param time_sync_port port assigned to listening for time sychronization messages from CARMA-Simulation.
* @param v2x_port port assigned to listening for v2x messages from CARMA-Simulation.
* @param location simulated location of infrastructure hardware.
* @param sensors_json_v A list of sensors sent to CARLA for sensor generation.
* @return true if handshake successful and false if handshake unsuccessful.
*/
std::string get_handshake_json(const uint infrastructure_id, const std::string &local_ip, const uint time_sync_port,
const uint v2x_port, const tmx::utils::WGS84Point &location) const;
const uint v2x_port, const tmx::utils::WGS84Point &location, const Json::Value& sensors_json_v) const;

/**
* @brief Read local file that has the sensor information in JSON format from disk. Populate global sensor json variable with the information.
* @param file_path A string of file location in the host machine.
* @param sensors_json_v A reference to the location where the sensors inforation is updated and stored.
*/
void populate_sensors_with_file(const std::string file_path, Json::Value& sensors_json_v);
/**
* @brief Read local file that has the sensor information in JSON format from disk. Populate global sensor json variable with the information.
* @param json_str A JSON string.
* @param json_v A reference to JSON value.
*/
void populate_json_with_string(const std::string &json_str, Json::Value& json_v);

std::string _simulation_ip;
uint _simulation_registration_port;
uint _infrastructure_id;
Expand All @@ -143,6 +164,9 @@ namespace CDASimAdapter {
uint _v2x_port;
tmx::utils::WGS84Point _location;
bool _connected = false;
std::string _sensor_json_file_path;
//Global variable to store the sensors information
Json::Value _sensors_json_v;

std::shared_ptr<tmx::utils::UdpServer> carma_simulation_listener;
std::shared_ptr<tmx::utils::UdpClient> carma_simulation_publisher;
Expand All @@ -152,6 +176,7 @@ namespace CDASimAdapter {
std::shared_ptr<tmx::utils::UdpServer> time_sync_listener;

FRIEND_TEST(TestCARMASimulationConnection, get_handshake_json);
FRIEND_TEST(TestCARMASimulationConnection, populate_sensors_with_file);
};

}
38 changes: 33 additions & 5 deletions src/v2i-hub/CDASimAdapter/test/TestCARMASimulationConnection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <kafka/mock_kafka_producer_worker.h>
#include <MockUdpClient.h>
#include <MockUdpServer.h>
#include <filesystem>


using testing::_;
Expand All @@ -24,14 +25,15 @@ namespace CDASimAdapter {
void SetUp() override {
// Initialize CARMA Simulation connection with (0,0,0) location and mock kafka producer.
WGS84Point location;
connection = std::make_shared<CDASimConnection>("127.0.0.1", 1212, 4567, 4678, "127.0.0.1", 1213, 1214, location);
connection = std::make_shared<CDASimConnection>("127.0.0.1", 1212, 4567, 4678, "127.0.0.1", 1213, 1214, location, sensors_file_path);

}
void TearDown() override {

}
public:
std::shared_ptr<CDASimConnection> connection;
std::string sensors_file_path = "/var/www/plugins/MAP/sensors.json";


};
Expand Down Expand Up @@ -87,19 +89,45 @@ namespace CDASimAdapter {
location.Elevation = 1000;
location.Latitude = 38.955;
location.Longitude = -77.149;

ASSERT_EQ(connection->get_handshake_json(4566, "127.0.0.1", 4567, 4568, location),
"{\n \"infrastructureId\" : 4566,\n \"location\" : {\n \"elevation\" : 1000.0,\n \"latitude\" : 38.954999999999998,\n \"longitude\" : -77.149000000000001\n },\n \"rxMessageIpAddress\" : \"127.0.0.1\",\n \"rxMessagePort\" : 4568,\n \"timeSyncPort\" : 4567\n}\n");
Json::Value sensorsJsonV;
ASSERT_EQ(connection->get_handshake_json(4566, "127.0.0.1", 4567, 4568, location, sensorsJsonV),
"{\n \"infrastructureId\" : 4566,\n \"location\" : {\n \"elevation\" : 1000.0,\n \"latitude\" : 38.954999999999998,\n \"longitude\" : -77.149000000000001\n },\n \"rxMessageIpAddress\" : \"127.0.0.1\",\n \"rxMessagePort\" : 4568,\n \"sensors\" : null,\n \"timeSyncPort\" : 4567\n}\n");
}

TEST_F( TestCARMASimulationConnection, carma_simulation_handshake) {
WGS84Point location;
Json::Value sensorsJsonV;
// UDP creation error
ASSERT_FALSE(connection->carma_simulation_handshake("", 45, NULL,
"", 45, 45, location));
"", 45, 45, location, sensorsJsonV));
}

TEST_F(TestCARMASimulationConnection, connect) {
ASSERT_TRUE(connection->connect());
}

TEST_F(TestCARMASimulationConnection, populate_sensors_with_file)
{
Json::Value sensorJsonV;
ASSERT_TRUE(sensorJsonV.empty());
//Assuming the sensor file exist.
connection->populate_sensors_with_file(sensors_file_path, sensorJsonV );
ASSERT_FALSE(sensorJsonV.empty());
}

TEST_F(TestCARMASimulationConnection, get_sensor_by_id)
{
//Populate connection with sensors upon connect call.
//Assuming the sensor file exist.
connection->connect();
std::string sensor_id = "SomeID";
auto sensor = connection->get_sensor_by_id(sensor_id);
ASSERT_FALSE(sensor.empty());
ASSERT_EQ("SematicLidar", sensor["type"].asString());

sensor_id = "not_found";
sensor = connection->get_sensor_by_id(sensor_id);
ASSERT_TRUE(sensor.empty());
}

}

0 comments on commit d0a5fbc

Please sign in to comment.