diff --git a/src/v2i-hub/CDASimAdapter/README.md b/src/v2i-hub/CDASimAdapter/README.md new file mode 100755 index 000000000..2267f3dba --- /dev/null +++ b/src/v2i-hub/CDASimAdapter/README.md @@ -0,0 +1,82 @@ +# CDASim Adapter Plugin Plugin Documentation + +## Introduction + +This Plugin is an adapter for integration with the **CDASim Co-simulation** enviroment. + +## Related Plugins + +A list of plugins related to the CDASim Adapter Plugin. + +### Immediate Forward Plugin + +For RSU Immediate Message Forwarding (IMF) functionality forward J2735 messages to CDASim. + +### Message Receiver Plugin + +The Message Receiver Plugin for receiving incoming J2735 message from CDASim. + +## Configuration/Deployment + +### System Configuration + +This plugin uses several system configuration parameters set as enviroment variables described below. + +**SIMULATION_MODE** – Environment variable for enabling simulation components for V2X-Hub. If set to "true" or "TRUE" simulation components will be enable. Otherwise, simulation components will not be enabled. + +**SIMULATION_IP** – Environment variable for storing IP address of CDASim application. + +**SIMULATION_REGISTRATION_PORT** – Environment variable for storing port on CDASim that handles registration attempts. + +**TIME_SYNC_PORT** – Environment varaible for storing port for receiving time sync messages from CDASim. + +**V2X_PORT** – Environment variable for storing port for receiving v2x messages from CDASim + +**SIM_V2X_PORT** – Environment variable for storing port for sending v2x messages to CDASim + +**V2XHUB_IP** – Environment variable for storing IP address of V2X Hub. + +**INFRASTRUCTURE_ID** – Environment variable for storing infrastructure id of V2X Hub. + +**SENSOR_JSON_FILE_PATH** – Environment variable for storing path to sensor configuration file. This is an optional simulation environment variable that allows for setting up simulated sensor for a V2X-Hub instance. Example file can be found in the **CDASimAdapterPlugin** tests [here](../src/v2i-hub/CDASimAdapter/test/sensors.json). + +### Plugin Configuration + +In addition to the system configuration, the CDASim Adapter also has plugin configuration parameters that can be set via the admin portal. + +**LogLevel**:The log level for this plugin" + +**X**:Cartesian X coordinate in simulated map (in meters). + +**Y**:Cartesian Y coordinate in simulated map (in meters). + +**Z**:Cartesian Z coordinate in simulated map (in meters). + +**MaxConnectionAttempts**:Number of connection attempts CDASimAdapter plugin will execute before failing. Valid values are any integers greater than or equal to 1. Any value less than 1 will result in unlimited connection attemtps. + +**ConnectionSleepTime**:Number of seconds to wait after a failed CDASim connection attempt, before retrying to establish connection. Valid values are equal or greater than 1. Any value less than 1 will be treated as 1. + +## Design + +### Communication + +![Alt text](docs/communication_diagram.png) +The integration with the **CDASim Co-simulation** enviorment consists of 4 major parts: + +**Registration Adapter**: The CDASimAdapter will establish a unique connection with CDASim and provide configuration information about harware like RSUs or Sensors associated with V2X-Hub. + +**Time Adapter**: The CDASimAdapter will consume and broadcast simulation time from the CDASim enviromment to ensure all plugins are using simulation time in place of machine time. + +**Message Adapter**: The CDASimAdapter will forward V2X messages to CDASim for simulated radio broadcast. It will also listen for incoming simulated V2X message recptions for the RSUs it registered with CDASim. + +**Simulation Adapter**: This final part captures any simulated events V2X-Hub needs to listen for. An example is Sensor Detections. When registering a sensor with CDASim, the sensor is created and detections from that sensor need to be forwarded to V2X-Hub. The simulation adapter will listen for these events from CDASim and broadcast them on the TMX message bus for other plugin. + +### Messages + +**Time Sync Message**: A V2X-Hub message that all PluginClientClockAware plugins subscribe to when running V2X-Hub in the simulation environment. This updates the base class clock object to allow for seamless integration of plugins into the simulation environment. + +**Sensor Detected Object**: V2X-Hub's generic message for detection data. This message is generated when the CDASim adapter receives a detection interaction for one of the sensors it registers. + +## Functionality Testing + +Included in this directory is a `scripts` directory that includes scripts to mock a CDASim Server listening for simulation registration events (`udp_socket_server.py`), time steps sent from CDASim (`send_timestep_udp.py`), and simulated detection events sent from CDASim (`send_sim_detected_object_udp.py`). These can be used to test functiontionality associated with the **CDASimAdapter Plugin** diff --git a/src/v2i-hub/CDASimAdapter/docs/communication_diagram.png b/src/v2i-hub/CDASimAdapter/docs/communication_diagram.png new file mode 100644 index 000000000..14c1c92c4 Binary files /dev/null and b/src/v2i-hub/CDASimAdapter/docs/communication_diagram.png differ diff --git a/src/v2i-hub/CDASimAdapter/src/CDASimConnection.cpp b/src/v2i-hub/CDASimAdapter/src/CDASimConnection.cpp index 4ab7cabd7..1fe032cf3 100644 --- a/src/v2i-hub/CDASimAdapter/src/CDASimConnection.cpp +++ b/src/v2i-hub/CDASimAdapter/src/CDASimConnection.cpp @@ -54,12 +54,14 @@ namespace CDASimAdapter{ //Sample sensors.json: https://raw.githubusercontent.com/usdot-fhwa-OPS/V2X-Hub/develop/src/v2i-hub/CDASimAdapter/test/sensors.json // Sensor configuration is an optional part of registration message. if ( !_sensor_json_file_path.empty() ) { - auto sensors_json_v = read_json_file(_sensor_json_file_path); - if(sensors_json_v.empty()) - { - PLOG(logWARNING) << "Sensors JSON is empty!" << std::endl; - } - message["sensors"] = sensors_json_v; + try { + auto sensors_json_v = read_sensor_configuration_file(_sensor_json_file_path); + message["sensors"] = sensors_json_v; + } + catch(const std::invalid_argument &e) { + PLOG(tmx::utils::logWARNING) << "Error occured reading sensor configuration file: " << e.what() + << std::endl << "Not sending any Sensor Registration information with CDASim Infrastructure Registration!"; + } } else { PLOG(logWARNING) << "No sensors where configured for this V2X-Hub instance."; @@ -234,14 +236,12 @@ namespace CDASimAdapter{ } Json::Value CDASimConnection::read_json_file(const std::string& file_path) const{ - 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 <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; + throw std::invalid_argument("Error parsing JSON from string: " + json_str); } return json_v; } + + Json::Value CDASimConnection::read_sensor_configuration_file(const std::string &file_path) const { + // Sensor Configuration File JSON format + /* { + "sensorId": "sensor_1", + "type": "SemanticLidar", + "ref": { + "type": "CARTESIAN", + "location": { + "x": 1.0, + "y": 2.0, + "z": -3.2 + }, + "orientation": { + "yaw": 0.0, + "pitch": 0.0, + "roll": 0.0 + } + } + } + ] */ + auto sensor_configuration = read_json_file(file_path); + Json::Value sensors_registration; + for ( int index = 0; index < sensor_configuration.size(); ++index ) { + Json::Value sensor; + if ( sensor_configuration[index]["ref"]["type"] != "CARTESIAN" ){ + PLOG(logWARNING) << "Skipping sensor configuration for " + sensor["sensorId"].asString() + ". Invalid ref type! Only CARTESIAN ref type currently supported for CDASim!" ; + continue; + } + sensor["sensorId"] = sensor_configuration[index]["sensorId"]; + sensor["type"] = sensor_configuration[index]["type"]; + sensor["location"] = sensor_configuration[index]["ref"]["location"]; + sensor["orientation"] =sensor_configuration[index]["ref"]["orientation"]; + sensors_registration.append(sensor); + } + /** Sensor Registration JSON Format + [ + { + "sensorId": "SomeID", + "type": "SemanticLidar", + "location": { + "x": 1.0, + "y": 2.0, + "z": -3.2 + }, + "orientation": { + "yaw": 0.0, + "pitch": 0.0, + "roll": 0.0 + } + } + ] + */ + return sensors_registration; + } } diff --git a/src/v2i-hub/CDASimAdapter/src/include/CDASimConnection.hpp b/src/v2i-hub/CDASimAdapter/src/include/CDASimConnection.hpp index 3a9bdf1a4..7899af4f7 100644 --- a/src/v2i-hub/CDASimAdapter/src/include/CDASimConnection.hpp +++ b/src/v2i-hub/CDASimAdapter/src/include/CDASimConnection.hpp @@ -135,17 +135,26 @@ namespace CDASimAdapter { const tmx::utils::Point &location) const; /** - * @brief Read Json file specified by the file path from disk, and convert the json into Json::Value object. - * @param file_path A string of file path in the host machine. + * @brief Helper method to read JSON file and return resulting Json::Value. + * @param file_path A string of file path in the host machine to the JSON file. * @return A Json::Value object. + * @throw std::invalid_argument exception if no file is found or file is not readable for provided path. */ Json::Value read_json_file(const std::string& file_path) const; - /** - * @brief Convert the Json string into Json::Value object. - * @param json_str A JSON string. - * @return A Json::Value object. - */ + /** + * @brief Helper method to convert string JSON content to JSON::Value. + * @param json_str A JSON string content of Sensor Configuration JSON file + * @return A Json::Value object parsed from string. + * @throw std::invalid_argument exception if provided string is not valid JSON + */ Json::Value string_to_json(const std::string &json_str) const; + /** + * @brief Method to read Sensor Configuration JSON file and return Sensor Registration information + * required for Infrastructure Registration to CDASim. + * @param file_path Path to Sensor Configuration file. + * @return Json::Value correspoding to Sensor Registration information for Infrastructure Registration to CDASim. + */ + Json::Value read_sensor_configuration_file(const std::string &file_path) const; std::string _simulation_ip; uint _simulation_registration_port; @@ -171,6 +180,8 @@ namespace CDASimAdapter { FRIEND_TEST(TestCDASimConnection, get_handshake_json_no_sensor_config); FRIEND_TEST(TestCDASimConnection, read_json_file); FRIEND_TEST(TestCDASimConnection, string_to_json); + FRIEND_TEST(TestCDASimConnection, read_sensor_configuration_file); + }; diff --git a/src/v2i-hub/CDASimAdapter/test/TestCDASimConnection.cpp b/src/v2i-hub/CDASimAdapter/test/TestCDASimConnection.cpp index 710dc49d8..80a47cc2f 100644 --- a/src/v2i-hub/CDASimAdapter/test/TestCDASimConnection.cpp +++ b/src/v2i-hub/CDASimAdapter/test/TestCDASimConnection.cpp @@ -101,20 +101,26 @@ namespace CDASimAdapter { TEST_F(TestCDASimConnection, read_json_file) { - auto sensorJsonV = connection->read_json_file("Invalid_file_path" ); - ASSERT_TRUE(sensorJsonV.empty()); + EXPECT_THROW(connection->read_json_file("Invalid_file_path" ), std::invalid_argument); std::ifstream in_strm; in_strm.open(sensors_file_path, std::ifstream::binary); if(in_strm.is_open()) { - sensorJsonV = connection->read_json_file(sensors_file_path ); + auto sensorJsonV = connection->read_json_file(sensors_file_path ); ASSERT_FALSE(sensorJsonV.empty()); } } TEST_F(TestCDASimConnection, string_to_json) { - auto sensorJsonV = connection->string_to_json("Invalid Json"); - ASSERT_TRUE(sensorJsonV.empty()); + EXPECT_THROW(connection->string_to_json("Invalid Json"), std::invalid_argument); + } + + TEST_F(TestCDASimConnection, read_sensor_configuration_file) { + auto sensor_registration = connection->read_sensor_configuration_file("../../CDASimAdapter/test/sensors_including_invalid_entries.json"); + EXPECT_EQ(2, sensor_registration.size()); + EXPECT_EQ("SomeID", sensor_registration[0]["sensorId"].asString()); + EXPECT_EQ("SomeID2", sensor_registration[1]["sensorId"].asString()); + } } \ No newline at end of file diff --git a/src/v2i-hub/CDASimAdapter/test/sensors.json b/src/v2i-hub/CDASimAdapter/test/sensors.json index 985496f8d..3f7cb1094 100755 --- a/src/v2i-hub/CDASimAdapter/test/sensors.json +++ b/src/v2i-hub/CDASimAdapter/test/sensors.json @@ -2,29 +2,35 @@ { "sensorId": "SomeID", "type": "SemanticLidar", - "location": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - }, - "orientation": { - "yaw": 0.0, - "pitch": 0.0, - "roll": 0.0 - } + "ref": { + "type": "CARTESIAN", + "location": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "orientation": { + "yaw": 0.0, + "pitch": 0.0, + "roll": 0.0 + } + } }, { "sensorId": "SomeID2", "type": "SemanticLidar", - "location": { - "x": 1.0, - "y": 2.0, - "z": 0.0 - }, - "orientation": { - "yaw": 23.0, - "pitch": 0.0, - "roll": 0.0 - } + "ref": { + "type": "CARTESIAN", + "location": { + "x": 1.0, + "y": 2.0, + "z": 0.0 + }, + "orientation": { + "yaw": 23.0, + "pitch": 0.0, + "roll": 0.0 + } + } } ] \ No newline at end of file diff --git a/src/v2i-hub/CDASimAdapter/test/sensors_including_invalid_entries.json b/src/v2i-hub/CDASimAdapter/test/sensors_including_invalid_entries.json new file mode 100755 index 000000000..edf290686 --- /dev/null +++ b/src/v2i-hub/CDASimAdapter/test/sensors_including_invalid_entries.json @@ -0,0 +1,48 @@ +[ + { + "sensorId": "SomeID", + "type": "SemanticLidar", + "ref": { + "type": "CARTESIAN", + "location": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "orientation": { + "yaw": 0.0, + "pitch": 0.0, + "roll": 0.0 + } + } + }, + { + "sensorId": "sensor_1", + "type": "SemanticLidar", + "ref": { + "type": "WGS84", + "location": { + "latitude": 38.9549716548523, + "longitude": -77.14935313519123, + "altitude": 5.5 + } + } + }, + { + "sensorId": "SomeID2", + "type": "SemanticLidar", + "ref": { + "type": "CARTESIAN", + "location": { + "x": 1.0, + "y": 2.0, + "z": 0.0 + }, + "orientation": { + "yaw": 23.0, + "pitch": 0.0, + "roll": 0.0 + } + } + } +] \ No newline at end of file