diff --git a/co-simulation/fed/mosaic-infrastructure/pom.xml b/co-simulation/fed/mosaic-infrastructure/pom.xml
index 15a1bd00..b7466bcd 100644
--- a/co-simulation/fed/mosaic-infrastructure/pom.xml
+++ b/co-simulation/fed/mosaic-infrastructure/pom.xml
@@ -25,6 +25,13 @@
mosaic-objects
${mosaic.version}
+
+ org.eclipse.mosaic
+ mosaic-objects
+ ${mosaic.version}
+ test-jar
+ test
+
gov.dot.fhwa.saxton
mosaic-carma-utils
diff --git a/co-simulation/fed/mosaic-infrastructure/src/main/java/org/eclipse/mosaic/fed/infrastructure/ambassador/InfrastructureInstance.java b/co-simulation/fed/mosaic-infrastructure/src/main/java/org/eclipse/mosaic/fed/infrastructure/ambassador/InfrastructureInstance.java
index 87e602d4..3b3415ad 100644
--- a/co-simulation/fed/mosaic-infrastructure/src/main/java/org/eclipse/mosaic/fed/infrastructure/ambassador/InfrastructureInstance.java
+++ b/co-simulation/fed/mosaic-infrastructure/src/main/java/org/eclipse/mosaic/fed/infrastructure/ambassador/InfrastructureInstance.java
@@ -16,17 +16,23 @@
package org.eclipse.mosaic.fed.infrastructure.ambassador;
-import org.eclipse.mosaic.lib.geo.CartesianPoint;
-
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
+import java.util.List;
+
+import org.eclipse.mosaic.lib.geo.CartesianPoint;
+import org.eclipse.mosaic.lib.objects.detector.DetectedObject;
+import org.eclipse.mosaic.lib.objects.detector.Detector;
+import org.eclipse.mosaic.rti.api.Interaction;
+
+import com.google.gson.Gson;
/**
* InfrastructureInstance class represents a physical instance of an
- * infrastructure node in the simulated environment.
- * It contains information about the infrastructure node such as its ID,
+ * infrastructure instance in the simulated environment.
+ * It contains information about the infrastructure instance such as its ID,
* location, target address, and ports.
*/
public class InfrastructureInstance {
@@ -35,40 +41,48 @@ public class InfrastructureInstance {
private InetAddress targetAddress;
private int rxMessagePort;
private int timeSyncPort;
+ private int simulatedInteractionPort;
private CartesianPoint location = null;
- private DatagramSocket rxMsgsSocket = null;
+ private DatagramSocket socket = null;
+ private List sensors;
/**
* Constructor for InfrastructureInstance
*
- * @param infrastructureId the ID of the infrastructure node
- * @param targetAddress the target IP address of the infrastructure node
- * @param rxMessagePort the receive message port of the infrastructure node
- * @param timeSyncPort the time synchronization port of the infrastructure
- * node
- * @param location the location of the infrastructure node in the
- * simulated environment
- */
- public InfrastructureInstance(String infrastructureId, InetAddress targetAddress,
- int rxMessagePort, int timeSyncPort, CartesianPoint location) {
+ * @param infrastructureId the ID of the infrastructure instance.
+ * @param targetAddress the target IP address of the infrastructure instance.
+ * @param rxMessagePort the receive V2X message port of the infrastructure instance.
+ * @param timeSyncPort the receive time synchronization message port of the infrastructure.
+ *
+ * @param simulatedInteractionPort the receive simulated interaction message port of the infrastructure
+ * instance.
+ * @param location the location of the infrastructure instance in the
+ * simulated environment
+ */
+ public InfrastructureInstance(String infrastructureId, InetAddress targetAddress, int rxMessagePort,
+ int timeSyncPort, int simulatedInteractionPort, CartesianPoint location, List sensors) {
this.infrastructureId = infrastructureId;
this.targetAddress = targetAddress;
this.rxMessagePort = rxMessagePort;
this.timeSyncPort = timeSyncPort;
+ this.simulatedInteractionPort = simulatedInteractionPort;
this.location = location;
+ this.sensors = sensors;
}
+
+
/**
- * Returns the target IP address of the infrastructure node
+ * Returns the target IP address of the infrastructure instance
*
- * @return InetAddress the target IP address of the infrastructure node
+ * @return InetAddress the target IP address of the infrastructure instance
*/
public InetAddress getTargetAddress() {
return targetAddress;
}
/**
- * Sets the target IP address of the infrastructure node
+ * Sets the target IP address of the infrastructure instance
*
* @param targetAddress the target IP address to set
*/
@@ -77,16 +91,16 @@ public void setTargetAddress(InetAddress targetAddress) {
}
/**
- * Returns the location of the infrastructure node in the simulated environment
+ * Returns the location of the infrastructure instance in the simulated environment
*
- * @return CartesianPoint the location of the infrastructure node
+ * @return CartesianPoint the location of the infrastructure instance
*/
public CartesianPoint getLocation() {
return this.location;
}
/**
- * Sets the location of the infrastructure node in the simulated environment
+ * Sets the location of the infrastructure instance in the simulated environment
*
* @param location the location to set
*/
@@ -95,16 +109,16 @@ public void setLocation(CartesianPoint location) {
}
/**
- * Returns the ID of the infrastructure node
+ * Returns the ID of the infrastructure instance
*
- * @return String the ID of the infrastructure node
+ * @return String the ID of the infrastructure instance
*/
public String getInfrastructureId() {
return infrastructureId;
}
/**
- * Sets the ID of the infrastructure node
+ * Sets the ID of the infrastructure instance
*
* @param infrastructureId the ID to set
*/
@@ -113,16 +127,16 @@ public void setInfrastructureId(String infrastructureId) {
}
/**
- * Returns the receive message port of the infrastructure node
+ * Returns the receive message port of the infrastructure instance
*
- * @return int the receive message port of the infrastructure node
+ * @return int the receive message port of the infrastructure instance
*/
public int getRxMessagePort() {
return rxMessagePort;
}
/**
- * Sets the receive message port of the infrastructure node
+ * Sets the receive message port of the infrastructure instance
*
* @param rxMessagePort the port to set
*/
@@ -131,32 +145,87 @@ public void setRxMessagePort(int rxMessagePort) {
}
/**
- * Returns the time synchronization port of the infrastructure node
+ * Returns the time synchronization port of the infrastructure instance
*
- * @return int the time synchronization port of the infrastructure node
+ * @return int the time synchronization port of the infrastructure instance
*/
public int getTimeSyncPort() {
return timeSyncPort;
}
/**
- * Sets the time synchronization port of the infrastructure node
+ * Sets the time synchronization port of the infrastructure instance
*
* @param timeSyncPort the port to set
*/
public void setTimeSyncPort(int timeSyncPort) {
this.timeSyncPort = timeSyncPort;
}
+
+ /**
+ * Returns the simulated interaction port of the infrastructure instance.
+ *
+ * @return int simulated interaction port of the infrastructure instance.
+ */
+ public int getSimulatedInteractionPort() {
+ return simulatedInteractionPort;
+ }
+
/**
- * Creates a DatagramSocket object and binds it to this infrastructure
- * instance's receive message port
+ * Sets the simulated interaction port of the infrastructure instance.
*
- * @throws IOException if there is an issue with the underlying socket object or
- * methods
+ * @param simulatedInteractionPort int simulated interaction port of the infrastructure
+ * instance.
+ */
+ public void setSimulatedInteractionPort(int simulatedInteractionPort) {
+ this.simulatedInteractionPort = simulatedInteractionPort;
+ }
+
+
+ /**
+ * Returns list of Sensor/Detectors registered to this infrastructure instance.
+ *
+ * @return list of detectors registered to infrastructure instance.
+ */
+ public List getSensors() {
+ return sensors;
+ }
+
+
+ /**
+ * Sets list of Sensors/Detectors registered to infrastructure instance.
+ *
+ * @param sensors list of detectors registered to infrastructure instance.
+ */
+ public void setSensors(List sensors) {
+ this.sensors = sensors;
+ }
+
+
+ /**
+ * Method that returns boolean value based on whether any registered Sensor/Detector
+ * in the sensor list has a sensorId equivalent to the passed parameter.
+ *
+ * @param sensorId sensor ID to search for
+ * @return true if sensor with sensor ID exists in sensor list. False otherwise.
*/
- public void bind() throws IOException {
- rxMsgsSocket = new DatagramSocket();
+ public boolean containsSensor(String sensorId) {
+ for (Detector sensor : sensors) {
+ if (sensor.getSensorId().equals(sensorId) ) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Creates a DatagramSocket object
+ *
+ * @throws IOException if there is an issue with the underlying socket object
+ */
+ public void connect() throws IOException {
+ socket = new DatagramSocket();
}
/**
@@ -167,27 +236,52 @@ public void bind() throws IOException {
* @throws IOException If there is an issue with the underlying socket object or
* methods
*/
- public void sendMsgs(byte[] data) throws IOException {
- if (rxMsgsSocket == null) {
- throw new IllegalStateException("Attempted to send data before opening socket");
- }
- DatagramPacket packet = new DatagramPacket(data, data.length, targetAddress, rxMessagePort);
- rxMsgsSocket.send(packet);
+ public void sendV2xMsg(byte[] data) throws IOException {
+ sendPacket(data, rxMessagePort);
+ }
+ /**
+ * Sends time sync data to the Infrastrucutre Instance Time Sync port.
+ *
+ * @param data The binary data to transmit
+ * @throws IOException If there is an issue with the underlying socket object or methods
+ */
+ public void sendTimeSyncMsg(InfrastructureTimeMessage message) throws IOException {
+ sendPacket(toJsonBytes(message), timeSyncPort);
+ }
+
+ /**
+ * Helper method to serialize message into JSON and encode as bytes.
+ *
+ * @param message java object containing message information
+ * @return bytes encoded from JSON string representation of object.
+ */
+ private byte[] toJsonBytes(Object message) {
+ Gson gson = new Gson();
+ return gson.toJson(message).getBytes();
}
/**
- * Sends time sync data to the Infrastructure Device communications interface configured at construction time.
+ * Sends time sync data to the Infrastrucutre Instance Simulated Interaction port.
+ *
* @param data The binary data to transmit
* @throws IOException If there is an issue with the underlying socket object or methods
*/
- public void sendTimeSyncMsgs(byte[] data) throws IOException {
- if (rxMsgsSocket == null) {
+ public void sendDetection(DetectedObject detectedObject) throws IOException {
+ sendPacket(toJsonBytes(detectedObject), simulatedInteractionPort);
+ }
+ /**
+ * Method to send byte data to specified port using the infrastructure instance Datagramsocket.
+ *
+ * @param data byte data to send using Datagramsocket.
+ * @param port in integer format to send Datagram to.
+ * @throws IOException
+ */
+ private void sendPacket(byte[] data, int port) throws IOException {
+ if (socket == null) {
throw new IllegalStateException("Attempted to send data before opening socket");
}
-
- DatagramPacket packet = new DatagramPacket(data, data.length, targetAddress, timeSyncPort);
- rxMsgsSocket.send(packet);
-
+ DatagramPacket packet = new DatagramPacket(data, data.length, targetAddress, port);
+ socket.send(packet);
}
}
diff --git a/co-simulation/fed/mosaic-infrastructure/src/main/java/org/eclipse/mosaic/fed/infrastructure/ambassador/InfrastructureInstanceManager.java b/co-simulation/fed/mosaic-infrastructure/src/main/java/org/eclipse/mosaic/fed/infrastructure/ambassador/InfrastructureInstanceManager.java
index f711fc16..79659553 100644
--- a/co-simulation/fed/mosaic-infrastructure/src/main/java/org/eclipse/mosaic/fed/infrastructure/ambassador/InfrastructureInstanceManager.java
+++ b/co-simulation/fed/mosaic-infrastructure/src/main/java/org/eclipse/mosaic/fed/infrastructure/ambassador/InfrastructureInstanceManager.java
@@ -16,23 +16,29 @@
package org.eclipse.mosaic.fed.infrastructure.ambassador;
-import gov.dot.fhwa.saxton.CarmaV2xMessage;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
import org.eclipse.mosaic.interactions.communication.V2xMessageTransmission;
import org.eclipse.mosaic.lib.enums.AdHocChannel;
-import org.eclipse.mosaic.lib.geo.GeoCircle;
import org.eclipse.mosaic.lib.geo.CartesianPoint;
+import org.eclipse.mosaic.lib.geo.GeoCircle;
import org.eclipse.mosaic.lib.objects.addressing.AdHocMessageRoutingBuilder;
+import org.eclipse.mosaic.lib.objects.detector.DetectedObject;
+import org.eclipse.mosaic.lib.objects.detector.Detector;
import org.eclipse.mosaic.lib.objects.v2x.ExternalV2xContent;
import org.eclipse.mosaic.lib.objects.v2x.ExternalV2xMessage;
import org.eclipse.mosaic.lib.objects.v2x.MessageRouting;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.HashMap;
-import java.util.Map;
+import com.google.gson.Gson;
+
+import gov.dot.fhwa.saxton.CarmaV2xMessage;
/**
* Session management class for Infrastructure instances communicating with
@@ -47,6 +53,7 @@ public class InfrastructureInstanceManager {
private Map managedInstances = new HashMap<>();
private final Logger log = LoggerFactory.getLogger(this.getClass());
+
/**
* Register a new infrastructure instance with the MOSAIC system.
*
@@ -65,7 +72,10 @@ public void onNewRegistration(InfrastructureRegistrationMessage registration) {
InetAddress.getByName(registration.getRxMessageIpAddress()),
registration.getRxMessagePort(),
registration.getTimeSyncPort(),
- registration.getLocation());
+ registration.getSimulatedInteractionPort(),
+ registration.getLocation(),
+ registration.getSensors());
+
} catch (UnknownHostException e) {
log.error("Failed to create infrastructure instance with ID '{}' due to an unknown host exception: {}",
registration.getInfrastructureId(), e.getMessage());
@@ -91,25 +101,30 @@ public void onNewRegistration(InfrastructureRegistrationMessage registration) {
*
*/
private void newInfrastructureInstance(String infrastructureId, InetAddress rxMessageIpAddress, int rxMessagePort,
- int timeSyncPort, CartesianPoint location) {
+ int timeSyncPort, int simulatedInteractionPort, CartesianPoint location, List sensors) {
InfrastructureInstance tmp = new InfrastructureInstance(infrastructureId, rxMessageIpAddress, rxMessagePort,
- timeSyncPort, location);
+ timeSyncPort, simulatedInteractionPort, location, sensors);
try {
- tmp.bind();
- log.info("New Infrastructure instance '{}' registered with Infrastructure Instance Manager.", infrastructureId);
+ tmp.connect();
+ log.info("New Infrastructure instance '{}' registered with Infrastructure Instance Manager.",
+ infrastructureId);
} catch (IOException e) {
log.error("Failed to bind infrastructure instance with ID '{}' to its RX message socket: {}",
infrastructureId, e.getMessage());
log.error("Stack trace:", e);
}
+
managedInstances.put(infrastructureId, tmp);
}
/**
- * Callback to be invoked when CARMA Platform receives a V2X Message from the NS-3 simulation
+ * Callback to be invoked when CARMA Platform receives a V2X Message from the
+ * NS-3 simulation
+ *
* @param sourceAddr The V2X Message received
- * @param txMsg The Host ID of the vehicle receiving the data
- * @throws RuntimeException If the socket used to communicate with the platform experiences failure
+ * @param txMsg The Host ID of the vehicle receiving the data
+ * @throws RuntimeException If the socket used to communicate with the platform
+ * experiences failure
*/
public V2xMessageTransmission onV2XMessageTx(InetAddress sourceAddr, CarmaV2xMessage txMsg, long time) {
InfrastructureInstance sender = null;
@@ -121,7 +136,8 @@ public V2xMessageTransmission onV2XMessageTx(InetAddress sourceAddr, CarmaV2xMes
if (sender == null) {
// Unregistered instance attempting to send messages
- throw new IllegalStateException("Unregistered CARMA Streets/V2XHub instance attempting to send messages via MOSAIC");
+ throw new IllegalStateException(
+ "Unregistered CARMA Streets/V2XHub instance attempting to send messages via MOSAIC");
}
AdHocMessageRoutingBuilder messageRoutingBuilder = new AdHocMessageRoutingBuilder(
@@ -135,24 +151,69 @@ public V2xMessageTransmission onV2XMessageTx(InetAddress sourceAddr, CarmaV2xMes
}
/**
- * Callback to be invoked when CARMA Platform receives a V2X Message from the NS-3 simulation
- * @param rxMsg The V2X Message received
+ * Callback to be invoked when an RSU receives a V2X Message from the NS-3
+ * simulation
+ *
+ * @param rxMsg The V2X Message received
* @param rxRsuId The Host ID of the vehicle receiving the data
- * @throws RuntimeException If the socket used to communicate with the platform experiences failure
+ * @throws RuntimeException If the socket used to communicate with the platform
+ * experiences failure
*/
public void onV2XMessageRx(byte[] rxMsg, String rxRsuId) {
- if (!managedInstances.containsKey(rxRsuId)) {
+ if (!managedInstances.containsKey(rxRsuId)) {
return;
}
InfrastructureInstance rsu = managedInstances.get(rxRsuId);
try {
- rsu.sendMsgs(rxMsg);
+ rsu.sendV2xMsg(rxMsg);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
+ /**
+ * Callback to be invoked when a infrastructure instance receives a simulated
+ * object detection from a registered simulated sensors. Only send object detection
+ * to the infrastructure instance that contains the sensor that reported it.
+ *
+ * @param detection Detected Object.
+ */
+ public void onDetectedObject(DetectedObject detection) {
+ for (InfrastructureInstance instance : managedInstances.values()) {
+ if (instance.containsSensor(detection.getSensorId())) {
+ try {
+ instance.sendDetection(detection);
+ // Assuming each sensor would only ever be registered to a single infrastructure
+ // instance
+ break;
+ } catch (IOException e) {
+ log.error("Error occured: {}", e.getMessage());
+ }
+ }
+ }
+ }
+
+
+
+ /**
+ * This function is used to send out encoded timestep update to all registered
+ * instances the manager has on the managed instances map
+ *
+ * @param message This time message is used to store current seq and timestep
+ * from the ambassador side
+ * @throws IOException
+ */
+ public void onTimeStepUpdate(InfrastructureTimeMessage message) throws IOException {
+ if (managedInstances.size() == 0) {
+ log.debug("There are no registered instances");
+ }
+
+ for (InfrastructureInstance currentInstance : managedInstances.values()) {
+ currentInstance.sendTimeSyncMsg(message);
+ }
+ }
+
/**
* External helper function to allow the ambassador to check if a given vehicle
* ID is a registered CARMA Platform instance
@@ -164,6 +225,12 @@ public void onV2XMessageRx(byte[] rxMsg, String rxRsuId) {
public boolean checkIfRegistered(String infrastructureId) {
return managedInstances.keySet().contains(infrastructureId);
}
+ /**
+ * Returns Map of managed infrastructure instances with infrastructure ID as the
+ * String Key.
+ *
+ * @return map of managed infrastructure instances.
+ */
public Map getManagedInstances() {
return managedInstances;
}
diff --git a/co-simulation/fed/mosaic-infrastructure/src/main/java/org/eclipse/mosaic/fed/infrastructure/ambassador/InfrastructureMessageAmbassador.java b/co-simulation/fed/mosaic-infrastructure/src/main/java/org/eclipse/mosaic/fed/infrastructure/ambassador/InfrastructureMessageAmbassador.java
index a5dedc1c..7db5cfd1 100644
--- a/co-simulation/fed/mosaic-infrastructure/src/main/java/org/eclipse/mosaic/fed/infrastructure/ambassador/InfrastructureMessageAmbassador.java
+++ b/co-simulation/fed/mosaic-infrastructure/src/main/java/org/eclipse/mosaic/fed/infrastructure/ambassador/InfrastructureMessageAmbassador.java
@@ -16,14 +16,23 @@
package org.eclipse.mosaic.fed.infrastructure.ambassador;
-import gov.dot.fhwa.saxton.CarmaV2xMessage;
-import gov.dot.fhwa.saxton.CarmaV2xMessageReceiver;
+import java.io.IOException;
+import java.net.Inet4Address;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Collections;
+import java.util.List;
+
+import javax.xml.bind.DatatypeConverter;
+
import org.eclipse.mosaic.fed.application.ambassador.SimulationKernel;
import org.eclipse.mosaic.fed.infrastructure.configuration.InfrastructureConfiguration;
import org.eclipse.mosaic.interactions.application.InfrastructureV2xMessageReception;
import org.eclipse.mosaic.interactions.communication.AdHocCommunicationConfiguration;
import org.eclipse.mosaic.interactions.communication.V2xMessageReception;
import org.eclipse.mosaic.interactions.communication.V2xMessageTransmission;
+import org.eclipse.mosaic.interactions.detector.DetectedObjectInteraction;
+import org.eclipse.mosaic.interactions.detector.DetectorRegistration;
import org.eclipse.mosaic.interactions.mapping.RsuRegistration;
import org.eclipse.mosaic.lib.enums.AdHocChannel;
import org.eclipse.mosaic.lib.geo.GeoPoint;
@@ -31,6 +40,7 @@
import org.eclipse.mosaic.lib.objects.addressing.IpResolver;
import org.eclipse.mosaic.lib.objects.communication.AdHocConfiguration;
import org.eclipse.mosaic.lib.objects.communication.InterfaceConfiguration;
+import org.eclipse.mosaic.lib.objects.detector.Detector;
import org.eclipse.mosaic.lib.objects.v2x.ExternalV2xMessage;
import org.eclipse.mosaic.lib.objects.v2x.V2xMessage;
import org.eclipse.mosaic.lib.util.objects.ObjectInstantiation;
@@ -41,13 +51,8 @@
import org.eclipse.mosaic.rti.api.InternalFederateException;
import org.eclipse.mosaic.rti.api.parameters.AmbassadorParameter;
-import javax.xml.bind.DatatypeConverter;
-import java.io.IOException;
-import java.net.Inet4Address;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.Collections;
-import java.util.List;
+import gov.dot.fhwa.saxton.CarmaV2xMessage;
+import gov.dot.fhwa.saxton.CarmaV2xMessageReceiver;
/**
* Implementation of a {@link AbstractFederateAmbassador} for Infrastructure
@@ -72,8 +77,6 @@ public class InfrastructureMessageAmbassador extends AbstractFederateAmbassador
private Thread v2xMessageBackgroundThread;
private InfrastructureInstanceManager infrastructureInstanceManager = new InfrastructureInstanceManager();
- private InfrastructureTimeInterface infrastructureTimeInterface = new InfrastructureTimeInterface(
- infrastructureInstanceManager);
private int timeSyncSeq = 0;
@@ -154,15 +157,26 @@ public void processInteraction(Interaction interaction) throws InternalFederateE
if (interaction.getTypeId().equals(InfrastructureV2xMessageReception.TYPE_ID)) {
this.receiveInteraction((InfrastructureV2xMessageReception) interaction);
}
+ if (interaction.getTypeId().equals(DetectedObjectInteraction.TYPE_ID)) {
+ this.receiveDetectedObjectInteraction((DetectedObjectInteraction) interaction);
+ }
}
+ /**
+ * Provide infrastructure instance manager with detected objects from processed detected
+ * object interactions.
+ *
+ * @param interaction processed detected objected interaction.
+ */
+ private synchronized void receiveDetectedObjectInteraction( DetectedObjectInteraction interaction) {
+ log.trace("Process Detected Object Interaction {}", interaction);
+ infrastructureInstanceManager.onDetectedObject(interaction.getDetectedObject());
+ }
/**
* Extract external message from received
* {@link InfrastructureV2xMessageReception} interaction.
*
- * @param interaction Interaction indicates that the
- * external message is received by a
- * rsu.
+ * @param interaction Interaction indicates that the external message is received by a rsu.
*/
private synchronized void receiveV2xReceptionInteraction(V2xMessageReception interaction) {
String rsuId = interaction.getReceiverName();
@@ -191,6 +205,7 @@ private synchronized void receiveV2xReceptionInteraction(V2xMessageReception int
}
}
+
/**
*
* Creates an Ad-Hoc configuration object to represent the configuration of the
@@ -273,7 +288,7 @@ public synchronized void processTimeAdvanceGrant(long time) throws InternalFeder
if (time < currentSimulationTime) {
return;
}
- log.info("Infrastructure message ambassador processing timestep to " + time);
+ log.info("Infrastructure message ambassador processing timestep to {}.", time);
try {
// Handle any new infrastructure registration requests
@@ -287,6 +302,14 @@ public synchronized void processTimeAdvanceGrant(long time) throws InternalFeder
onRsuRegistrationRequest(reg.getInfrastructureId(), reg.getLocation().toGeo());
log.info("RSU Registration for "+ reg.getInfrastructureId() + " @ x, y, z: (" + reg.getLocation().getX() + ", " + reg.getLocation().getY() + ", " + reg.getLocation().getZ() + ")");
onDsrcRegistrationRequest(reg.getInfrastructureId());
+ // Check for empty list of sensors which is valid
+ if (reg.getSensors() != null ) {
+ log.debug("Sending SensorRegistration interactions for sensor : {}", reg.getSensors());
+ }
+ for (Detector sensor : reg.getSensors()) {
+ // Trigger Sensor registrations for all listed sensors.
+ this.rti.triggerInteraction(new DetectorRegistration(time,sensor));
+ }
}
if (currentSimulationTime == 0) {
@@ -295,7 +318,7 @@ public synchronized void processTimeAdvanceGrant(long time) throws InternalFeder
} else {
List> newMessages = v2xMessageReceiver.getReceivedMessages();
for (Tuple msg : newMessages) {
- log.info("Processing new V2X transmit event of type " + msg.getB().getType());
+ log.info("Processing new V2X transmit event of type {}.", msg.getB().getType());
V2xMessageTransmission msgInt = infrastructureInstanceManager.onV2XMessageTx(msg.getA(), msg.getB(), currentSimulationTime);
SimulationKernel.SimulationKernel.getV2xMessageCache().putItem(currentSimulationTime, msgInt.getMessage());
log.info("Inserted message ID {} into v2xmessage cache.", msgInt.getMessageId());
@@ -308,7 +331,7 @@ public synchronized void processTimeAdvanceGrant(long time) throws InternalFeder
timeSyncMessage.setSeq(timeSyncSeq);
// nanoseconds to milliseconds for InfrastructureTimeMessage
timeSyncMessage.setTimestep(currentSimulationTime/1000000);
- infrastructureTimeInterface.onTimeStepUpdate(timeSyncMessage);
+ infrastructureInstanceManager.onTimeStepUpdate(timeSyncMessage);
// TODO: Handle any queued V2X message receiver's received messages
@@ -316,13 +339,12 @@ public synchronized void processTimeAdvanceGrant(long time) throws InternalFeder
currentSimulationTime += infrastructureConfiguration.updateInterval * TIME.MILLI_SECOND;
// Request the next time advance from the RTI
- log.info("Requesting timestep updated to " + currentSimulationTime);
+ log.info("Requesting timestep updated to {}.", currentSimulationTime);
rti.requestAdvanceTime(currentSimulationTime, 0, (byte) 2);
} catch (IllegalValueException e) {
- log.error("Error during advanceTime(" + time + ")", e);
throw new InternalFederateException(e);
} catch (IOException e1) {
- log.error("Error during updating timestep :" + e1.getMessage());
+ log.error("Error during updating timestep :", e1);
}
}
diff --git a/co-simulation/fed/mosaic-infrastructure/src/main/java/org/eclipse/mosaic/fed/infrastructure/ambassador/InfrastructureRegistrationMessage.java b/co-simulation/fed/mosaic-infrastructure/src/main/java/org/eclipse/mosaic/fed/infrastructure/ambassador/InfrastructureRegistrationMessage.java
index b81bde84..e1dabf83 100644
--- a/co-simulation/fed/mosaic-infrastructure/src/main/java/org/eclipse/mosaic/fed/infrastructure/ambassador/InfrastructureRegistrationMessage.java
+++ b/co-simulation/fed/mosaic-infrastructure/src/main/java/org/eclipse/mosaic/fed/infrastructure/ambassador/InfrastructureRegistrationMessage.java
@@ -13,61 +13,79 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
-
package org.eclipse.mosaic.fed.infrastructure.ambassador;
+import java.util.List;
+
import org.eclipse.mosaic.lib.geo.CartesianPoint;
+import org.eclipse.mosaic.lib.objects.detector.Detector;
/**
- * A message to be sent by Infrastructure Device when it registers with the
+ * A message to be sent by Infrastructure instance when it registers with the
* carma-mosaic ambassador
*/
public class InfrastructureRegistrationMessage {
- // IP address where the Infrastructure Device will be listening for inbound
+ // IP address where the Infrastructure instance will be listening for inbound
// messages
private String rxMessageIpAddress;
- // Unique identifier for the Infrastructure Device
+ // Unique identifier for the Infrastructure instance
private String infrastructureId;
- // Port number where the Infrastructure Device will be listening for inbound
+ // Port number where the Infrastructure instance will be listening for inbound
// messages
- private int rxMessagePort = 1536;
+ private int rxMessagePort;
- // Port number where the Infrastructure Device will be listening for time
+ // Port number where the Infrastructure instance will be listening for time
// synchronization messages
- private int timeSyncPort = 1517;
+ private int timeSyncPort;
+
+ // Port number where infrastructure instance will be listening for interaction
+ // messages
+ private int simulatedInteractionPort;
- // Geo-coordinate of the Infrastructure Device location
+ // Geo-coordinate of the Infrastructure instance location
private CartesianPoint location = null;
+ // List of Sensor/Detectors associated with infrastructure instance.
+ private List sensors;
+
+
/**
* Constructor for an `InfrastructureRegistrationMessage` instance
*
- * @param rxMessageIpAddress IP address where the Infrastructure Device will be
- * listening for inbound messages
- * @param infrastructureId Unique identifier for the Infrastructure Device
- * @param rxMessagePort Port number where the Infrastructure Device will be
- * listening for inbound messages
- * @param timeSyncPort Port number where the Infrastructure Device will be
- * listening for time synchronization messages
- * @param location Geo-coordinate of the Infrastructure Device
- * location
+ * @param rxMessageIpAddress IP address where the Infrastructure instance will be
+ * listening for inbound messages
+ * @param infrastructureId Unique identifier for the Infrastructure instance
+ * @param rxMessagePort Port number where the Infrastructure instance will be
+ * listening for inbound messages
+ * @param simulatedInteractionPort Port number where Infrastructure instance will be listening
+ * for simulated interactions.
+ * @param timeSyncPort Port number where the Infrastructure instance will be
+ * listening for time synchronization messages
+ * @param location Geo-coordinate of the Infrastructure instance
+ * location
+ * @param sensors ArrayList of sensors to register for a given infrastructure
+ * instance
*/
- public InfrastructureRegistrationMessage(String rxMessageIpAddress, String infrastructureId,
- int rxMessagePort, int timeSyncPort, CartesianPoint location) {
+ public InfrastructureRegistrationMessage(String rxMessageIpAddress, String infrastructureId, int rxMessagePort,
+ int timeSyncPort, int simulatedInteractionPort, CartesianPoint location, List sensors) {
this.rxMessageIpAddress = rxMessageIpAddress;
this.infrastructureId = infrastructureId;
this.rxMessagePort = rxMessagePort;
this.timeSyncPort = timeSyncPort;
+ this.simulatedInteractionPort = simulatedInteractionPort;
this.location = location;
+ this.sensors = sensors;
}
+
+
/**
- * Returns the IP address where the Infrastructure Device will be listening for
+ * Returns the IP address where the Infrastructure instance will be listening for
* inbound messages
*
- * @return The IP address where the Infrastructure Device will be listening for
+ * @return The IP address where the Infrastructure instance will be listening for
* inbound messages
*/
public String getRxMessageIpAddress() {
@@ -75,19 +93,19 @@ public String getRxMessageIpAddress() {
}
/**
- * Returns the unique identifier for the Infrastructure Device
+ * Returns the unique identifier for the Infrastructure instance
*
- * @return The unique identifier for the Infrastructure Device
+ * @return The unique identifier for the Infrastructure instance
*/
public String getInfrastructureId() {
return this.infrastructureId;
}
/**
- * Returns the port number where the Infrastructure Device will be listening for
+ * Returns the port number where the Infrastructure instance will be listening for
* inbound messages
*
- * @return The port number where the Infrastructure Device will be listening for
+ * @return The port number where the Infrastructure instance will be listening for
* inbound messages
*/
public int getRxMessagePort() {
@@ -95,10 +113,10 @@ public int getRxMessagePort() {
}
/**
- * Returns the port number where the Infrastructure Device will be listening for
+ * Returns the port number where the Infrastructure instance will be listening for
* time synchronization messages
*
- * @return The port number where the Infrastructure Device will be listening for
+ * @return The port number where the Infrastructure instance will be listening for
* time synchronization messages
*/
public int getTimeSyncPort() {
@@ -106,76 +124,39 @@ public int getTimeSyncPort() {
}
/**
- * Returns the Geo-coordinate of the Infrastructure Device location
+ * Returns the Geo-coordinate of the Infrastructure instance location
*
- * @return The Geo-coordinate of the Infrastructure Device location
+ * @return The Geo-coordinate of the Infrastructure instance location
*/
public CartesianPoint getLocation() {
return this.location;
}
/**
- * Sets the IP address where the Infrastructure Device will be listening for
- * inbound messages
+ * Returns list of associated sensors/detectors.
*
- * @param rxMessageIpAddress The IP address where the Infrastructure Device will
- * be listening for inbound messages
+ * @return list of sensors/detectors registered to infrastructure instances.
*/
- public void setRxMessageIpAddress(String rxMessageIpAddress) {
- this.rxMessageIpAddress = rxMessageIpAddress;
+ public List getSensors() {
+ return sensors;
}
-
+
/**
- * Sets the unique identifier for the Infrastructure Device
- * It currently is the same with RSU ID
+ * Returns port where infrastructure instance will be listening for interaction messages
+ * from CDASim.
*
- * @param infrastructureId The unique identifier for the Infrastructure Device
+ * @return int simulated interaction port
*/
- public void setInfrastructureId(String infrastructureId) {
- this.infrastructureId = infrastructureId;
+ public int getSimulatedInteractionPort() {
+ return simulatedInteractionPort;
}
- /**
- * Sets the port number where the Infrastructure Device will be listening for
- * inbound messages
- *
- * @param rxMessagePort The port number where the Infrastructure Device will be
- * listening for inbound messages
- */
- public void setRxMessagePort(int rxMessagePort) {
- this.rxMessagePort = rxMessagePort;
- }
-
- /**
- * Set the time sync port for the InfrastructureRegistrationMessage
- *
- * @param timeSyncPort the new time sync port to be set
- */
- public void setTimeSyncPort(int timeSyncPort) {
- this.timeSyncPort = timeSyncPort;
- }
-
- /**
- * Set the location for the InfrastructureRegistrationMessage
- *
- * @param location the new GeoPoint object representing the location of the
- * Infrastructure Device
- */
- public void setLocation(CartesianPoint location) {
- this.location = location;
- }
-
- /**
- * Returns a string representation of the InfrastructureRegistrationMessage
- * object
- *
- * @return a string representation of the object
- */
@Override
public String toString() {
- return "InfrastructureRegistrationMessage [rxMessageIpAddress=" + rxMessageIpAddress
- + ", infrastructureId=" + infrastructureId + ", rxMessagePort=" + rxMessagePort
- + ", timeSyncPort=" + timeSyncPort + ", location=" + location + "]";
+ return "InfrastructureRegistrationMessage [rxMessageIpAddress=" + rxMessageIpAddress + ", infrastructureId="
+ + infrastructureId + ", rxMessagePort=" + rxMessagePort + ", timeSyncPort=" + timeSyncPort
+ + ", simulatedInteractionPort=" + simulatedInteractionPort + ", location=" + location + ", sensors="
+ + sensors + "]";
}
}
diff --git a/co-simulation/fed/mosaic-infrastructure/src/main/java/org/eclipse/mosaic/fed/infrastructure/ambassador/InfrastructureRegistrationReceiver.java b/co-simulation/fed/mosaic-infrastructure/src/main/java/org/eclipse/mosaic/fed/infrastructure/ambassador/InfrastructureRegistrationReceiver.java
index 246d8d38..d1b90069 100644
--- a/co-simulation/fed/mosaic-infrastructure/src/main/java/org/eclipse/mosaic/fed/infrastructure/ambassador/InfrastructureRegistrationReceiver.java
+++ b/co-simulation/fed/mosaic-infrastructure/src/main/java/org/eclipse/mosaic/fed/infrastructure/ambassador/InfrastructureRegistrationReceiver.java
@@ -24,7 +24,7 @@
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
-
+import java.util.concurrent.atomic.AtomicBoolean;
import com.google.gson.Gson;
@@ -44,7 +44,7 @@ public class InfrastructureRegistrationReceiver implements Runnable {
private Queue rxQueue = new LinkedList<>();
private DatagramSocket listenSocket = null;
private static final int listenPort = 1615;
- private boolean running = false;
+ private AtomicBoolean running = new AtomicBoolean(false);
private static final int UDP_MTU = 1635;
private final Logger log = LoggerFactory.getLogger(this.getClass());
@@ -70,13 +70,14 @@ public void init() {
@Override
public void run() {
byte[] buf = new byte[UDP_MTU];
- running = true;
- while (running) {
+ running.set(true);
+ while (running.get()) {
DatagramPacket msg = new DatagramPacket(buf, buf.length);
try {
listenSocket.receive(msg);
} catch (IOException e) {
- throw new RuntimeException(e);
+ log.error("Error occurred", e);
+ continue;
}
// parse message
@@ -98,10 +99,10 @@ public void run() {
* Stop the runnable instance and close the listen socket.
*/
public void stop() {
+ running.set(false);
if (listenSocket != null) {
listenSocket.close();
}
- running = false;
}
/**
diff --git a/co-simulation/fed/mosaic-infrastructure/src/main/java/org/eclipse/mosaic/fed/infrastructure/ambassador/InfrastructureTimeInterface.java b/co-simulation/fed/mosaic-infrastructure/src/main/java/org/eclipse/mosaic/fed/infrastructure/ambassador/InfrastructureTimeInterface.java
deleted file mode 100644
index e9b7df99..00000000
--- a/co-simulation/fed/mosaic-infrastructure/src/main/java/org/eclipse/mosaic/fed/infrastructure/ambassador/InfrastructureTimeInterface.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2023 LEIDOS.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package org.eclipse.mosaic.fed.infrastructure.ambassador;
-
-import java.io.IOException;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.gson.Gson;
-
-public class InfrastructureTimeInterface {
- private InfrastructureInstanceManager manager;
- // set to false on init release
- private boolean await_infrastructure_advance_request = false;
-
- private final Logger log = LoggerFactory.getLogger(this.getClass());
-
- public InfrastructureTimeInterface(InfrastructureInstanceManager manager) {
- this.manager = manager;
- }
-
- /**
- * This function implements the encoding of a json string consist of timestep
- * and seq
- *
- * @param message This is the class that gets encoded, which include the data of
- * timestep and seq
- * @return return_json: encoded json string
- */
- public byte[] encodeTimeMessage(InfrastructureTimeMessage message) {
- Gson gson = new Gson();
- String json = gson.toJson(message);
- byte[] returnJson = json.getBytes();
- return returnJson;
- }
-
- /**
- * This function is used to send out encoded timestep update to all registered
- * instances the manager has on the managed instances map
- *
- * @param message This time message is used to store current seq and timestep
- * from the ambassador side
- * @throws IOException
- */
- public void onTimeStepUpdate(InfrastructureTimeMessage message) throws IOException {
- if (this.manager.getManagedInstances().size() == 0) {
- log.debug("There are no registered instances");
- }
-
- for (InfrastructureInstance currentInstance : manager.getManagedInstances().values()) {
- currentInstance.sendTimeSyncMsgs(encodeTimeMessage(message));
- }
- }
-}
\ No newline at end of file
diff --git a/co-simulation/fed/mosaic-infrastructure/src/main/java/org/eclipse/mosaic/fed/infrastructure/ambassador/InfrastructureTimeMessage.java b/co-simulation/fed/mosaic-infrastructure/src/main/java/org/eclipse/mosaic/fed/infrastructure/ambassador/InfrastructureTimeMessage.java
index 85eff91b..d0fe56b9 100644
--- a/co-simulation/fed/mosaic-infrastructure/src/main/java/org/eclipse/mosaic/fed/infrastructure/ambassador/InfrastructureTimeMessage.java
+++ b/co-simulation/fed/mosaic-infrastructure/src/main/java/org/eclipse/mosaic/fed/infrastructure/ambassador/InfrastructureTimeMessage.java
@@ -16,9 +16,6 @@
package org.eclipse.mosaic.fed.infrastructure.ambassador;
-import java.net.InetAddress;
-import java.nio.charset.StandardCharsets;
-
/**
* Message to be sent or received by the Infrastructure Device Adapter interface
* NOTE: TODO See .ambassador for reference
diff --git a/co-simulation/fed/mosaic-infrastructure/src/test/java/org/eclipse/mosaic/fed/infrastructure/ambassador/InfrastructureInstanceManagerTest.java b/co-simulation/fed/mosaic-infrastructure/src/test/java/org/eclipse/mosaic/fed/infrastructure/ambassador/InfrastructureInstanceManagerTest.java
index c49d4dfc..91d805c5 100644
--- a/co-simulation/fed/mosaic-infrastructure/src/test/java/org/eclipse/mosaic/fed/infrastructure/ambassador/InfrastructureInstanceManagerTest.java
+++ b/co-simulation/fed/mosaic-infrastructure/src/test/java/org/eclipse/mosaic/fed/infrastructure/ambassador/InfrastructureInstanceManagerTest.java
@@ -16,29 +16,56 @@
package org.eclipse.mosaic.fed.infrastructure.ambassador;
-import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
-import java.net.InetAddress;
+import java.io.IOException;
+import java.util.ArrayList;
import org.eclipse.mosaic.lib.geo.CartesianPoint;
+import org.eclipse.mosaic.lib.math.Vector3d;
+import org.eclipse.mosaic.lib.objects.detector.DetectedObject;
+import org.eclipse.mosaic.lib.objects.detector.DetectionType;
+import org.eclipse.mosaic.lib.objects.detector.Detector;
+import org.eclipse.mosaic.lib.objects.detector.DetectorType;
+import org.eclipse.mosaic.lib.objects.detector.Orientation;
+import org.eclipse.mosaic.lib.objects.detector.Size;
import org.junit.Before;
import org.junit.Test;
-import org.mockito.Mockito;
+
public class InfrastructureInstanceManagerTest {
private InfrastructureInstanceManager manager;
- private InfrastructureRegistrationMessage registration;
- private InetAddress ipAddress;
- private CartesianPoint location;
+ private InfrastructureInstance instance1;
+ private InfrastructureInstance instance2;
+ private InfrastructureInstance instance3;
@Before
public void setUp() throws Exception {
manager = new InfrastructureInstanceManager();
- registration = mock(InfrastructureRegistrationMessage.class);
- ipAddress = mock(InetAddress.class);
- location = mock(CartesianPoint.class);
+ instance1 = mock(InfrastructureInstance.class);
+ instance2 = mock(InfrastructureInstance.class);
+ instance3 = mock(InfrastructureInstance.class);
+ // Add mocks to managed instances
+ manager.getManagedInstances().put("instance1", instance1);
+ manager.getManagedInstances().put("instance2", instance2);
+ manager.getManagedInstances().put("instance3", instance3);
+ // Mocks will account for detected objects with the given sensor IDs.
+ when(instance1.containsSensor("sensor1")).thenReturn(true);
+ when(instance1.containsSensor("sensor2")).thenReturn(true);
+ when(instance2.containsSensor("sensor3")).thenReturn(true);
+ when(instance2.containsSensor("sensor4")).thenReturn(true);
+ when(instance3.containsSensor("sensor5")).thenReturn(true);
+ when(instance3.containsSensor("sensor6")).thenReturn(true);
+
}
@Test
@@ -47,27 +74,92 @@ public void testOnNewRegistration() {
String infrastructureId = "infrastructure-123";
int rxMessagePort = 1234;
int timeSyncPort = 5678;
+ int simulatedInteractionPort = 2355;
String ipAddressString = "127.0.0.1";
CartesianPoint pt = CartesianPoint.xyz(37.3382, -121.8863, 1.0);
+ ArrayList sensors = new ArrayList<>();
+ sensors.add(
+ new Detector(
+ "String sensorId",
+ DetectorType.SEMANTIC_LIDAR,
+ new Orientation( 0.0,0.0,0.0),
+ CartesianPoint.ORIGO));
// Mock the behavior of the registration object
- mockRegistrationObject(infrastructureId, rxMessagePort, timeSyncPort, ipAddressString, pt);
+ InfrastructureRegistrationMessage registration = new InfrastructureRegistrationMessage(
+ ipAddressString,
+ infrastructureId,
+ rxMessagePort,
+ timeSyncPort,
+ simulatedInteractionPort ,
+ pt,
+ sensors);
+ // Ensure checkIfRegistered returns false for infrastructure ID before registering
+ assertFalse( manager.checkIfRegistered(infrastructureId) );
// Call the onNewRegistration method with the mocked registration object
manager.onNewRegistration(registration);
// Verify that the infrastructure instance was added to the manager
- assertEquals(true, manager.checkIfRegistered(infrastructureId));
+ assertTrue( manager.checkIfRegistered(infrastructureId) );
+ // Ensure checkIfRegistered returns false for other Ids
+ assertFalse( manager.checkIfRegistered(infrastructureId + "something") );
}
- private void mockRegistrationObject(String infrastructureId, int rxMessagePort, int timeSyncPort,
- String ipAddressString, CartesianPoint pt) {
- // Mock the behavior of the registration object
- Mockito.when(registration.getInfrastructureId()).thenReturn(infrastructureId);
- Mockito.when(registration.getRxMessagePort()).thenReturn(rxMessagePort);
- Mockito.when(registration.getTimeSyncPort()).thenReturn(timeSyncPort);
- Mockito.when(registration.getRxMessageIpAddress()).thenReturn(ipAddressString);
- Mockito.when(registration.getLocation()).thenReturn(pt);
- Mockito.when(ipAddress.getHostAddress()).thenReturn(ipAddressString);
+ @Test
+ public void testOnTimeStepUpdate() throws IOException {
+ InfrastructureTimeMessage message = new InfrastructureTimeMessage();
+
+ message.setSeq(3);
+ message.setTimestep(300);
+ manager.onTimeStepUpdate(message);
+ // Verify that all instances sendTimeSyncMsgs was called.
+ verify(instance1).sendTimeSyncMsg(message);
+ verify(instance2).sendTimeSyncMsg(message);
+ verify(instance2).sendTimeSyncMsg(message);
+
}
+
+ @Test
+ public void testOnDetectedObject() throws IOException{
+ // Create detected object
+ DetectedObject detectedObject1 = new DetectedObject(
+ DetectionType.VAN,
+ 0.5,
+ "sensor1",
+ "projection String",
+ "Object1",
+ CartesianPoint.xyz(1.1, 2, 3.2),
+ new Vector3d(2, 3, 4),
+ new Vector3d(-4.4,-5.5,-6.6),
+ new Size(3, 4, 5));
+ Double[] covarianceMatrix = new Double[] { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
+ detectedObject1.setPositionCovariance(covarianceMatrix);
+ detectedObject1.setVelocityCovariance(covarianceMatrix);
+ detectedObject1.setAngularVelocityCovariance(covarianceMatrix);
+ // Attempt to send detected object to infrastructure instance
+ manager.onDetectedObject(detectedObject1);
+ // Verify Infrastructure Manager attempted to sent Detected Object
+ // to instance1
+ verify(instance1, times(1)).sendDetection(detectedObject1);
+ // Create second detected object
+ DetectedObject detectedObject2 = new DetectedObject(
+ DetectionType.VAN,
+ 0.5,
+ "sensor6",
+ "projection String",
+ "Object1",
+ CartesianPoint.xyz(1.1, 2, 3.2),
+ new Vector3d(2, 3, 4),
+ new Vector3d(-4.4,-5.5,-6.6),
+ new Size(3, 4, 5));
+ detectedObject2.setPositionCovariance(covarianceMatrix);
+ detectedObject2.setVelocityCovariance(covarianceMatrix);
+ detectedObject2.setAngularVelocityCovariance(covarianceMatrix);
+ manager.onDetectedObject(detectedObject2);
+ doThrow(new IOException("Something went wrong")).when(instance3).sendDetection(detectedObject2);
+ verify(instance3, times(1)).sendDetection(detectedObject2);
+ verify(instance2, never()).sendDetection(any(DetectedObject.class));
+ }
+
}
diff --git a/co-simulation/fed/mosaic-infrastructure/src/test/java/org/eclipse/mosaic/fed/infrastructure/ambassador/InfrastructureInstanceTest.java b/co-simulation/fed/mosaic-infrastructure/src/test/java/org/eclipse/mosaic/fed/infrastructure/ambassador/InfrastructureInstanceTest.java
new file mode 100644
index 00000000..7a99a95e
--- /dev/null
+++ b/co-simulation/fed/mosaic-infrastructure/src/test/java/org/eclipse/mosaic/fed/infrastructure/ambassador/InfrastructureInstanceTest.java
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2023 LEIDOS.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.eclipse.mosaic.fed.infrastructure.ambassador;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import java.io.IOException;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.util.ArrayList;
+
+import org.eclipse.mosaic.lib.geo.CartesianPoint;
+import org.eclipse.mosaic.lib.math.Vector3d;
+import org.eclipse.mosaic.lib.objects.detector.DetectedObject;
+import org.eclipse.mosaic.lib.objects.detector.DetectionType;
+import org.eclipse.mosaic.lib.objects.detector.Detector;
+import org.eclipse.mosaic.lib.objects.detector.DetectorType;
+import org.eclipse.mosaic.lib.objects.detector.Orientation;
+import org.eclipse.mosaic.lib.objects.detector.Size;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.internal.util.reflection.FieldSetter;
+
+import com.google.gson.Gson;
+
+public class InfrastructureInstanceTest {
+ /**
+ * Mock Datagram socket
+ */
+ private DatagramSocket socket;
+
+ private InfrastructureInstance instance;
+ /**
+ * Mock InetAddress
+ */
+ private InetAddress address;
+
+ @Before
+ public void setup() throws NoSuchFieldException {
+ // Initialize Mocks
+ address = mock(InetAddress.class);
+ socket = mock(DatagramSocket.class);
+ // Initialize Infrastructure Instance
+ ArrayList sensors = new ArrayList<>();
+ sensors.add(
+ new Detector(
+ "sensor1",
+ DetectorType.SEMANTIC_LIDAR,
+ new Orientation(0.0, 0.0, 0.0),
+ CartesianPoint.ORIGO));
+ sensors.add(
+ new Detector(
+ "NewSensor",
+ DetectorType.SEMANTIC_LIDAR,
+ new Orientation(20.0, 20.0, 0.0),
+ CartesianPoint.ORIGO));
+ instance = new InfrastructureInstance(
+ "SomeID",
+ address,
+ 3456,
+ 5667,
+ 8888,
+ CartesianPoint.ORIGO,
+ sensors);
+ // Set private instance field to mock using reflection
+ FieldSetter.setField(instance, instance.getClass().getDeclaredField("socket"), socket);
+
+ }
+
+ @Test
+ public void testContainsSensor() {
+ // Test contains sensor method
+ assertTrue(instance.containsSensor("NewSensor"));
+ assertTrue(instance.containsSensor("sensor1"));
+ assertFalse(instance.containsSensor("otherSensor"));
+ }
+
+ @Test
+ public void testGetterSetterConstructor() {
+ // Test getters and constructor for setting and retrieving class members
+ assertEquals("SomeID", instance.getInfrastructureId());
+ assertEquals(CartesianPoint.ORIGO, instance.getLocation());
+ assertEquals(3456, instance.getRxMessagePort());
+ assertEquals(5667, instance.getTimeSyncPort());
+ // Test Setter
+ instance.setInfrastructureId("DifferentID");
+ assertEquals("DifferentID", instance.getInfrastructureId());
+ instance.setLocation(CartesianPoint.xy(40, 50));
+ assertEquals(CartesianPoint.xy(40, 50), instance.getLocation());
+ instance.setTimeSyncPort(4321);
+ assertEquals(4321, instance.getTimeSyncPort());
+ instance.setRxMessagePort(5678);
+ assertEquals(5678, instance.getRxMessagePort());
+ instance.setSimulatedInteractionPort(9999);
+ assertEquals(9999, instance.getSimulatedInteractionPort());
+ ArrayList sensors = new ArrayList<>();
+ sensors.add(
+ new Detector(
+ "sensor1",
+ DetectorType.SEMANTIC_LIDAR,
+ new Orientation(1.0, 2.0, 3.0),
+ CartesianPoint.ORIGO));
+ sensors.add(
+ new Detector(
+ "NewSensor",
+ DetectorType.SEMANTIC_LIDAR,
+ new Orientation(24.0, 25.0, 6.0),
+ CartesianPoint.ORIGO));
+ instance.setSensors(sensors);
+ assertEquals(sensors, instance.getSensors());
+ instance.setTargetAddress(address);
+ assertEquals(address, instance.getTargetAddress());
+
+ }
+
+ @Test
+ public void testSendV2xMsg() throws IOException {
+ // Test SendV2xMsg method
+ String test_msg = "test message";
+ instance.sendV2xMsg(test_msg.getBytes());
+ // ArgumentCaptor to capture parameters passed to mock on method calls
+ ArgumentCaptor packet = ArgumentCaptor.forClass(DatagramPacket.class);
+ // Verify socket.send(DatagramPacket packet) is called and capture packet
+ // parameter
+ verify(socket, times(1)).send(packet.capture());
+
+ // Verify parameter members
+ assertArrayEquals(test_msg.getBytes(), packet.getValue().getData());
+ assertEquals(instance.getRxMessagePort(), packet.getValue().getPort());
+ assertEquals(address, packet.getValue().getAddress());
+ }
+
+ @Test
+ public void testSendTimeSyncMsg() throws IOException {
+ // Test SendTimeSyncMsg method
+ InfrastructureTimeMessage test_msg = new InfrastructureTimeMessage();
+ test_msg.setSeq(1);
+ test_msg.setTimestep(100);
+ instance.sendTimeSyncMsg(test_msg);
+
+
+ // ArgumentCaptor to capture parameters passed to mock on method calls
+ ArgumentCaptor packet = ArgumentCaptor.forClass(DatagramPacket.class);
+ // Verify socket.send(DatagramPacket packet) is called and capture packet
+ // parameter
+ verify(socket, times(1)).send(packet.capture());
+ // Convert message to bytes
+ Gson gson = new Gson();
+ byte[] message_bytes = gson.toJson(test_msg).getBytes();
+ // Verify parameter members
+ assertArrayEquals(message_bytes, packet.getValue().getData());
+ assertEquals(instance.getTimeSyncPort(), packet.getValue().getPort());
+ assertEquals(address, packet.getValue().getAddress());
+ }
+
+ @Test
+ public void testSendInteraction() throws IOException {
+ // Test SendInteraction method
+ DetectedObject test_msg = new DetectedObject(
+ DetectionType.BUS,
+ 0.5,
+ "sensor1",
+ "projection String",
+ "Object1",
+ CartesianPoint.xyz(1.1, 2, 3.2),
+ new Vector3d(0, 0, 0),
+ new Vector3d(),
+ new Size(0, 0, 0));
+ Double[] covarianceMatrix = new Double[] { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
+ test_msg.setPositionCovariance(covarianceMatrix);
+ test_msg.setVelocityCovariance(covarianceMatrix);
+ test_msg.setAngularVelocityCovariance(covarianceMatrix);
+ instance.sendDetection(test_msg);
+ // ArgumentCaptor to capture parameters passed to mock on method calls
+ ArgumentCaptor packet = ArgumentCaptor.forClass(DatagramPacket.class);
+ // Verify socket.send(DatagramPacket packet) is called and capture packet
+ // parameter
+ verify(socket, times(1)).send(packet.capture());
+ // Convert message to bytes
+ Gson gson = new Gson();
+ byte[] message_bytes = gson.toJson(test_msg).getBytes();
+ // Verify parameter members
+ assertArrayEquals(message_bytes, packet.getValue().getData());
+ assertEquals(instance.getSimulatedInteractionPort(), packet.getValue().getPort());
+ assertEquals(address, packet.getValue().getAddress());
+ }
+
+}
diff --git a/co-simulation/fed/mosaic-infrastructure/src/test/java/org/eclipse/mosaic/fed/infrastructure/ambassador/InfrastructureMessageAmbassadorTest.java b/co-simulation/fed/mosaic-infrastructure/src/test/java/org/eclipse/mosaic/fed/infrastructure/ambassador/InfrastructureMessageAmbassadorTest.java
index 07014bb7..a0103dcf 100644
--- a/co-simulation/fed/mosaic-infrastructure/src/test/java/org/eclipse/mosaic/fed/infrastructure/ambassador/InfrastructureMessageAmbassadorTest.java
+++ b/co-simulation/fed/mosaic-infrastructure/src/test/java/org/eclipse/mosaic/fed/infrastructure/ambassador/InfrastructureMessageAmbassadorTest.java
@@ -16,8 +16,45 @@
package org.eclipse.mosaic.fed.infrastructure.ambassador;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.DatagramPacket;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.mosaic.interactions.communication.AdHocCommunicationConfiguration;
+import org.eclipse.mosaic.interactions.communication.V2xMessageReception;
+import org.eclipse.mosaic.interactions.detector.DetectedObjectInteraction;
+import org.eclipse.mosaic.interactions.detector.DetectorRegistration;
+import org.eclipse.mosaic.interactions.mapping.RsuRegistration;
+import org.eclipse.mosaic.lib.enums.AdHocChannel;
+import org.eclipse.mosaic.lib.geo.CartesianPoint;
+import org.eclipse.mosaic.lib.geo.GeoPoint;
+import org.eclipse.mosaic.lib.junit.GeoProjectionRule;
+import org.eclipse.mosaic.lib.junit.IpResolverRule;
+import org.eclipse.mosaic.lib.math.Vector3d;
+import org.eclipse.mosaic.lib.objects.addressing.IpResolver;
+import org.eclipse.mosaic.lib.objects.detector.DetectedObject;
+import org.eclipse.mosaic.lib.objects.detector.DetectionType;
+import org.eclipse.mosaic.lib.objects.detector.Detector;
+import org.eclipse.mosaic.lib.objects.detector.DetectorType;
+import org.eclipse.mosaic.lib.objects.detector.Orientation;
+import org.eclipse.mosaic.lib.objects.detector.Size;
+import org.eclipse.mosaic.lib.transform.GeoProjection;
import org.eclipse.mosaic.lib.util.junit.TestFileRule;
import org.eclipse.mosaic.rti.TIME;
+import org.eclipse.mosaic.rti.api.IllegalValueException;
+import org.eclipse.mosaic.rti.api.Interaction;
+import org.eclipse.mosaic.rti.api.InternalFederateException;
import org.eclipse.mosaic.rti.api.RtiAmbassador;
import org.eclipse.mosaic.rti.api.parameters.AmbassadorParameter;
import org.eclipse.mosaic.rti.api.parameters.FederateDescriptor;
@@ -28,12 +65,10 @@
import org.junit.Test;
import org.junit.rules.RuleChain;
import org.junit.rules.TemporaryFolder;
+import org.mockito.ArgumentCaptor;
+import org.mockito.internal.util.reflection.FieldSetter;
-import java.io.File;
-import java.io.IOException;
-
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.*;
+import gov.dot.fhwa.saxton.CarmaV2xMessageReceiver;
/**
* Tests for {@link InfrastructureMessageAmbassador}.
@@ -47,47 +82,191 @@ public class InfrastructureMessageAmbassadorTest {
@Rule
public RuleChain chain = RuleChain.outerRule(temporaryFolder).around(testFileRule);
+ private static GeoPoint BERLIN = GeoPoint.latLon(52.5, 13.4);
+ /**
+ * Rule to initialize {@link GeoProjection} Singleton.
+ */
+ @Rule
+ public GeoProjectionRule geoProjectionRule = new GeoProjectionRule(BERLIN);
+ /**
+ * Rule to initialize {@link IpResolver} Singleton.
+ */
+ @Rule
+ public IpResolverRule ipResolverRule = new IpResolverRule();
+
+ /**
+ * {@link RtiAmbassador} mock.
+ */
private RtiAmbassador rtiMock;
private InfrastructureMessageAmbassador ambassador;
+ /**
+ * {@link InfrastructureInstanceManager} mock.
+ */
+ private InfrastructureInstanceManager instanceManagerMock;
+ /**
+ * {@link InfrastructureRegistrationReceiver} mock.
+ */
+ private InfrastructureRegistrationReceiver receiverMock;
+ /**
+ * {@link CarmaV2xMessageReceiver} mock,
+ */
+ private CarmaV2xMessageReceiver v2xMessageReceiverMock;
- @Before
- public void setup() throws IOException {
+ private ArrayList registrationMessages;
+ @Before
+ public void setup() throws IOException, NoSuchFieldException, InternalFederateException, IllegalValueException {
+ // Initialize Mocks
rtiMock = mock(RtiAmbassador.class);
-
FederateDescriptor handleMock = mock(FederateDescriptor.class);
-
+ instanceManagerMock = mock(InfrastructureInstanceManager.class);
+ receiverMock = mock(InfrastructureRegistrationReceiver.class);
+ v2xMessageReceiverMock = mock(CarmaV2xMessageReceiver.class);
File workingDir = temporaryFolder.getRoot();
-
CLocalHost testHostConfig = new CLocalHost();
-
testHostConfig.workingDirectory = workingDir.getAbsolutePath();
+ // Mock methods
when(handleMock.getHost()).thenReturn(testHostConfig);
-
when(handleMock.getId()).thenReturn("infrastructure");
+ // Create Infrastructure registration
+ ArrayList rsu_1_sensors = new ArrayList<>();
+ rsu_1_sensors.add(
+ new Detector(
+ "sensor1",
+ DetectorType.SEMANTIC_LIDAR,
+ new Orientation( 0.0,0.0,0.0),
+ CartesianPoint.ORIGO));
+ rsu_1_sensors.add(
+ new Detector(
+ "sensor2",
+ DetectorType.SEMANTIC_LIDAR,
+ new Orientation( 20.0,0.0,0.0),
+ CartesianPoint.xy(1,1)));
+ rsu_1_sensors.add(
+ new Detector(
+ "sensor3",
+ DetectorType.SEMANTIC_LIDAR,
+ new Orientation( 180.0,0.0,0.0),
+ CartesianPoint.xy(-1,1)));
+ InfrastructureRegistrationMessage message = new InfrastructureRegistrationMessage(
+ "127.0.0.1",
+ "rsu_1",
+ 4567 ,
+ 5678,
+ 8642,
+ CartesianPoint.xy(1, 2),
+ rsu_1_sensors);
+ registrationMessages = new ArrayList<>();
+ registrationMessages.add(message);
+ when(receiverMock.getReceivedMessages()).thenReturn(registrationMessages);
+ // Set mocks as ambassador members through reflection or setters
ambassador = new InfrastructureMessageAmbassador(new AmbassadorParameter("infrastructure",
- temporaryFolder.newFile("infrastructure/infrastructure_config.json")));
-
+ temporaryFolder.newFile("infrastructure/infrastructure_config.json")));
ambassador.setRtiAmbassador(rtiMock);
-
ambassador.setFederateDescriptor(handleMock);
+ FieldSetter.setField(ambassador, ambassador.getClass().getDeclaredField("infrastructureRegistrationReceiver"), receiverMock);
+ FieldSetter.setField(ambassador, ambassador.getClass().getDeclaredField("v2xMessageReceiver"), v2xMessageReceiverMock);
+ FieldSetter.setField(ambassador, ambassador.getClass().getDeclaredField("infrastructureInstanceManager"), instanceManagerMock);
+
+
}
- @After
- public void teardown() throws IOException {
+ @Test
+ public void testInitialize() throws InternalFederateException, IllegalValueException{
+ // Test initialize method
+ ambassador.initialize(0, 100 * TIME.SECOND);
+ verify(rtiMock, times(1)).requestAdvanceTime(eq(0L), eq(0L), eq((byte) 1));
+ // cleanup threads and UDP Sockets
ambassador.close();
+
+ }
+ @Test
+ public void testProcessInteraction() throws InternalFederateException{
+ // Test process interaction for detected objects interactions
+ DetectedObject detectedObject = new DetectedObject(
+ DetectionType.VAN,
+ 0.5,
+ "sensor1",
+ "projection String",
+ "Object1",
+ CartesianPoint.xyz(1.1, 2, 3.2),
+ new Vector3d(2, 3, 4),
+ new Vector3d(-4.4,-5.5,-6.6),
+ new Size(3, 4, 5));
+ Double[] covarianceMatrix = new Double[] { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
+ detectedObject.setPositionCovariance(covarianceMatrix);
+ detectedObject.setVelocityCovariance(covarianceMatrix);
+ detectedObject.setAngularVelocityCovariance(covarianceMatrix);
+ DetectedObjectInteraction interaction = new DetectedObjectInteraction(100,detectedObject);
+
+ ambassador.processInteraction(interaction);
+ verify(instanceManagerMock).onDetectedObject(detectedObject);
+
}
@Test
- public void initialize() throws Throwable {
+ public void testProcessTimeAdvanceGrant() throws InternalFederateException, IllegalValueException, NoSuchFieldException, SecurityException {
+ //Test processTimeAdvanceGrant for Infrastructure Registration
+ ambassador.processTimeAdvanceGrant(100);
+ // Verify received messages were attempted to be pulled from Infrastructure Registration Receiver mock
+ verify(receiverMock, times(1)).getReceivedMessages();
+ // Capture interaction triggered with trigger interaction call
+ ArgumentCaptor interactions = ArgumentCaptor.forClass(Interaction.class);
+ // Verify that trigger interaction was call 5 times on rti mock
+ verify(rtiMock, times(5)).triggerInteraction(interactions.capture());
+ // Separate triggered interactions by interaction type
+ List captured_interactions = interactions.getAllValues();
+ List capturedDetectorRegistrations = new ArrayList<>();
+ List capturedRsuRegistrations = new ArrayList<>();
+ List capturedAdHocCommunicationConfiguration = new ArrayList<>();
+ List otherInteractions = new ArrayList<>();
+ for (Interaction interaction : captured_interactions) {
+ if ( interaction.getClass().equals(DetectorRegistration.class)) {
+ capturedDetectorRegistrations.add((DetectorRegistration) interaction);
+ }
+ else if (interaction.getClass().equals(RsuRegistration.class) ) {
+ capturedRsuRegistrations.add((RsuRegistration)interaction);
+ }
+ else if (interaction.getClass().equals(AdHocCommunicationConfiguration.class)) {
+ capturedAdHocCommunicationConfiguration.add((AdHocCommunicationConfiguration) interaction);
+ }
+ else {
+ otherInteractions.add(interaction);
+ }
+ }
+
+ int rsu_registration_index = 0;
+ int sensor_registration_index = 0;
+ // Loop through registration messages given message ambassador
+ for (InfrastructureRegistrationMessage registrationMessage : registrationMessages) {
+ // For each registration message, confirm that all the sensors in the regisration message
+ // trigger sensor registration calls.
+ for (Detector detector: registrationMessage.getSensors()) {
+ assertEquals(detector, capturedDetectorRegistrations.get(sensor_registration_index).getDetector());
+ sensor_registration_index++;
+ }
+ // For each registration message, ensure that RsuRegistration interactions and AdHocCommunicationConfiguration
+ // interactions are trigger
+ RsuRegistration registration = capturedRsuRegistrations.get( rsu_registration_index);
+ AdHocCommunicationConfiguration adhocConfig = capturedAdHocCommunicationConfiguration.get(rsu_registration_index);
+ assertEquals(registrationMessage.getInfrastructureId(), registration.getMapping().getName());
+ assertTrue(
+ registrationMessage.getLocation().toVector3d().isFuzzyEqual(
+ registration.getMapping().getPosition().toCartesian().toVector3d()
+ )
+ );
+ assertEquals(300.0, adhocConfig.getConfiguration().getConf0().getRadius(), 0.01);
+ assertEquals(50.0, adhocConfig.getConfiguration().getConf0().getNewPower(), 0.01);
+ assertEquals(AdHocChannel.CCH, adhocConfig.getConfiguration().getConf0().getChannel0());
+ rsu_registration_index++;
+ }
+
+ // Assert that no other interactions were triggered
+ assertEquals(0, otherInteractions.size());
- // RUN
- ambassador.initialize(0, 100 * TIME.SECOND);
- // ASSERT
- verify(rtiMock, times(1)).requestAdvanceTime(eq(0L), eq(0L), eq((byte) 1));
}
}
diff --git a/co-simulation/fed/mosaic-infrastructure/src/test/java/org/eclipse/mosaic/fed/infrastructure/ambassador/InfrastructureRegistrationMessageTest.java b/co-simulation/fed/mosaic-infrastructure/src/test/java/org/eclipse/mosaic/fed/infrastructure/ambassador/InfrastructureRegistrationMessageTest.java
new file mode 100644
index 00000000..4fcec579
--- /dev/null
+++ b/co-simulation/fed/mosaic-infrastructure/src/test/java/org/eclipse/mosaic/fed/infrastructure/ambassador/InfrastructureRegistrationMessageTest.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2023 LEIDOS.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.eclipse.mosaic.fed.infrastructure.ambassador;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.ArrayList;
+
+import org.eclipse.mosaic.lib.geo.CartesianPoint;
+import org.eclipse.mosaic.lib.objects.detector.Detector;
+import org.eclipse.mosaic.lib.objects.detector.DetectorType;
+import org.eclipse.mosaic.lib.objects.detector.Orientation;
+import org.junit.Test;
+
+public class InfrastructureRegistrationMessageTest {
+ @Test
+ public void testGetterSettersConstructor() {
+ // Test Constructor
+ ArrayList sensors = new ArrayList<>();
+ sensors.add(
+ new Detector(
+ "String sensorId",
+ DetectorType.SEMANTIC_LIDAR,
+ new Orientation( 0.0,0.0,0.0),
+ CartesianPoint.ORIGO));
+ InfrastructureRegistrationMessage message = new InfrastructureRegistrationMessage(
+ "127.0.0.1",
+ "rsu_1",
+ 4567 ,
+ 5678,
+ 8642,
+ CartesianPoint.xy(1, 2),
+ sensors);
+ // Test Getter
+ assertEquals("rsu_1",message.getInfrastructureId());
+ assertEquals("127.0.0.1", message.getRxMessageIpAddress() );
+ assertEquals(4567, message.getRxMessagePort());
+ assertEquals(5678, message.getTimeSyncPort());
+ assertEquals(8642, message.getSimulatedInteractionPort());
+ assertEquals(CartesianPoint.xy(1,2), message.getLocation());
+ assertEquals(sensors, message.getSensors());
+
+ }
+
+}
diff --git a/co-simulation/fed/mosaic-infrastructure/src/test/java/org/eclipse/mosaic/fed/infrastructure/ambassador/InfrastructureRegistrationReceiverTest.java b/co-simulation/fed/mosaic-infrastructure/src/test/java/org/eclipse/mosaic/fed/infrastructure/ambassador/InfrastructureRegistrationReceiverTest.java
index a93a24b5..0f1ad685 100644
--- a/co-simulation/fed/mosaic-infrastructure/src/test/java/org/eclipse/mosaic/fed/infrastructure/ambassador/InfrastructureRegistrationReceiverTest.java
+++ b/co-simulation/fed/mosaic-infrastructure/src/test/java/org/eclipse/mosaic/fed/infrastructure/ambassador/InfrastructureRegistrationReceiverTest.java
@@ -82,6 +82,8 @@ public void testMessageReceive() throws Exception {
assertEquals(121.8863, msg.getLocation().getY(), delta);
assertEquals(1.0, msg.getLocation().getZ(), delta);
}
+
+
}
\ No newline at end of file
diff --git a/co-simulation/fed/mosaic-infrastructure/src/test/java/org/eclipse/mosaic/fed/infrastructure/ambassador/InfrastructureTimeInterfaceTest.java b/co-simulation/fed/mosaic-infrastructure/src/test/java/org/eclipse/mosaic/fed/infrastructure/ambassador/InfrastructureTimeInterfaceTest.java
deleted file mode 100644
index d679aed8..00000000
--- a/co-simulation/fed/mosaic-infrastructure/src/test/java/org/eclipse/mosaic/fed/infrastructure/ambassador/InfrastructureTimeInterfaceTest.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2023 LEIDOS.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package org.eclipse.mosaic.fed.infrastructure.ambassador;
-
-import org.junit.Test;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import org.junit.Before;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
-
-import com.google.gson.Gson;
-
-public class InfrastructureTimeInterfaceTest {
- @Mock
- private InfrastructureInstanceManager manager;
- @Mock
- private InfrastructureInstance infrastructureInstanceMock1;
- @Mock
- private InfrastructureInstance infrastructureInstanceMock2;
- private InfrastructureTimeInterface infrastructureTimeInterface;
-
- @Before
- public void setup() {
- MockitoAnnotations.initMocks(this);
- infrastructureTimeInterface = new InfrastructureTimeInterface(manager);
- }
-
- @Test
- public void testTimesyncUpdate() throws IOException {
- InfrastructureTimeMessage infrastructureTimeMessage = new InfrastructureTimeMessage();
- infrastructureTimeMessage.setSeq(1);
- infrastructureTimeMessage.setTimestep((long) 20230406);
-
- Map managed_instance_map = new HashMap<>();
- managed_instance_map.put("instance1", infrastructureInstanceMock1);
- managed_instance_map.put("instance2", infrastructureInstanceMock2);
-
- when(manager.getManagedInstances()).thenReturn(managed_instance_map);
-
- infrastructureTimeInterface.onTimeStepUpdate(infrastructureTimeMessage);
-
- infrastructureTimeMessage.setSeq(2);
- infrastructureTimeMessage.setTimestep((long) 20230407);
-
- infrastructureTimeInterface.onTimeStepUpdate(infrastructureTimeMessage);
-
- Gson gson = new Gson();
- String temp = gson.toJson(infrastructureTimeMessage);
- byte[] t_byte = temp.getBytes();
-
- verify(infrastructureInstanceMock1, times(1)).sendTimeSyncMsgs(eq((byte[]) t_byte));
- verify(infrastructureInstanceMock2, times(1)).sendTimeSyncMsgs(eq((byte[]) t_byte));
-
- verify(infrastructureInstanceMock1, times(2)).sendTimeSyncMsgs(any());
- verify(infrastructureInstanceMock2, times(2)).sendTimeSyncMsgs(any());
-
- }
-}
diff --git a/co-simulation/lib/mosaic-carma-utils/src/main/java/gov/dot/fhwa/saxton/CarmaV2xMessageReceiver.java b/co-simulation/lib/mosaic-carma-utils/src/main/java/gov/dot/fhwa/saxton/CarmaV2xMessageReceiver.java
index dc2d369d..dd009085 100644
--- a/co-simulation/lib/mosaic-carma-utils/src/main/java/gov/dot/fhwa/saxton/CarmaV2xMessageReceiver.java
+++ b/co-simulation/lib/mosaic-carma-utils/src/main/java/gov/dot/fhwa/saxton/CarmaV2xMessageReceiver.java
@@ -29,6 +29,7 @@
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
+import java.util.concurrent.atomic.AtomicBoolean;
/**
* Worker thread Runnable for operating a listen socket to receive outbound V2X Messages from CARMA Platform instances
@@ -41,7 +42,7 @@ public class CarmaV2xMessageReceiver implements Runnable {
private Queue> rxQueue = new LinkedList<>();
private DatagramSocket listenSocket = null;
private int listenPort;
- private boolean running = true;
+ private AtomicBoolean running = new AtomicBoolean(false);
private static final int UDP_MTU = 1536;
private final Logger log = LoggerFactory.getLogger(this.getClass());
@@ -74,7 +75,7 @@ public CarmaV2xMessageReceiver(int listenPort) {
public void init() {
try {
listenSocket = new DatagramSocket(listenPort);
- log.info("CarmaV2xMessageReceiver started listening on UDP port: " + listenPort);
+ log.info("CarmaV2xMessageReceiver started listening on UDP port: {}.", listenPort);
} catch (SocketException e) {
throw new RuntimeException(e);
}
@@ -83,14 +84,16 @@ public void init() {
@Override
public void run() {
byte[] buf = new byte[UDP_MTU];
- while (running) {
+ running.set(true);
+ while (running.get()) {
DatagramPacket msg = new DatagramPacket(buf, buf.length);
try {
- listenSocket.receive(msg);
- log.info("CarmaV2xMessageReceiver received message of size: " + msg.getLength() + " from client " + msg.getAddress().toString() + ".");
+ listenSocket.receive(msg);
+ log.debug("CarmaV2xMessageReceiver received message of size {} from client {}.",msg.getLength(), msg.getAddress());
} catch (IOException e) {
- throw new RuntimeException(e);
+ log.error("Error occured :", e);
+ continue;
}
// parse message
@@ -100,23 +103,22 @@ public void run() {
// Enqueue message for processing on main thread
synchronized (rxQueue) {
rxQueue.add(new Tuple<>(msg.getAddress(), parsedMessage));
- log.info("CarmaV2xMessageReceiver enqueued message of size: " + msg.getLength() + " from client " + msg.getAddress().toString() + ".");
+ log.debug("CarmaV2xMessageReceiver enqueued message of size {} from client {}." , msg.getLength(), msg.getAddress());
}
} catch (IllegalArgumentException parseError) {
- log.warn("CarmaV2xMessageReceiver received malformed message with length: " + msg.getLength() + " from client " + msg.getAddress().toString() + "! Reason: " + parseError.getMessage() +". Discarding...");
+ log.warn("CarmaV2xMessageReceiver received malformed message with size {} from client {} !\nReason: {} .\nDiscarding ...",msg.getLength(), msg.getAddress(), parseError.getMessage());
}
- }
+ }
}
/**
* Stop the runnable instance
*/
public void stop() {
+ running.set(false);
if (listenSocket != null) {
listenSocket.close();
}
-
- running = false;
}
/**
diff --git a/co-simulation/lib/mosaic-interactions/src/main/java/org/eclipse/mosaic/interactions/detector/DetectedObjectInteraction.java b/co-simulation/lib/mosaic-interactions/src/main/java/org/eclipse/mosaic/interactions/detector/DetectedObjectInteraction.java
new file mode 100644
index 00000000..551bb781
--- /dev/null
+++ b/co-simulation/lib/mosaic-interactions/src/main/java/org/eclipse/mosaic/interactions/detector/DetectedObjectInteraction.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2023 LEIDOS.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.eclipse.mosaic.interactions.detector;
+
+import org.eclipse.mosaic.lib.objects.detector.DetectedObject;
+import org.eclipse.mosaic.rti.api.Interaction;
+
+public class DetectedObjectInteraction extends Interaction {
+
+ public static final String TYPE_ID = createTypeIdentifier(DetectedObjectInteraction.class);
+
+ private DetectedObject detectedObject;
+
+ /**
+ * Constructor for DetectedObjectInteraction.
+ * @param time time for interaction.
+ * @param detectedObject detected object data for interaction.
+ */
+ public DetectedObjectInteraction(long time, DetectedObject detectedObject) {
+ super(time);
+ this.detectedObject = detectedObject;
+ }
+
+ /**
+ * Getter returns detected object.
+ * @return Detected Object
+ */
+ public DetectedObject getDetectedObject() {
+ return detectedObject;
+ }
+
+ /**
+ * Set detected object.
+ * @param detectedObject
+ */
+ public void setDetectedObject(DetectedObject detectedObject) {
+ this.detectedObject = detectedObject;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = super.hashCode();
+ result = prime * result + ((detectedObject == null) ? 0 : detectedObject.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!super.equals(obj))
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ DetectedObjectInteraction other = (DetectedObjectInteraction) obj;
+ if (detectedObject == null) {
+ if (other.detectedObject != null)
+ return false;
+ } else if (!detectedObject.equals(other.detectedObject))
+ return false;
+ return true;
+ }
+
+
+
+
+}
diff --git a/co-simulation/lib/mosaic-interactions/src/main/java/org/eclipse/mosaic/interactions/detector/DetectorRegistration.java b/co-simulation/lib/mosaic-interactions/src/main/java/org/eclipse/mosaic/interactions/detector/DetectorRegistration.java
new file mode 100644
index 00000000..034f17b4
--- /dev/null
+++ b/co-simulation/lib/mosaic-interactions/src/main/java/org/eclipse/mosaic/interactions/detector/DetectorRegistration.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2023 LEIDOS.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.eclipse.mosaic.interactions.detector;
+
+import org.eclipse.mosaic.lib.objects.detector.Detector;
+import org.eclipse.mosaic.rti.api.Interaction;
+
+public class DetectorRegistration extends Interaction {
+ public static final String TYPE_ID = createTypeIdentifier(DetectorRegistration.class);
+
+ private Detector detector;
+ /**
+ * Constructor
+ * @param time for interaction.
+ * @param sensor to register.
+ */
+ public DetectorRegistration(long time, Detector sensor) {
+ super(time);
+ this.detector = sensor;
+ }
+ /**
+ * Getter for sensor/detector information.
+ * @return
+ */
+ public Detector getDetector() {
+ return detector;
+ }
+ /**
+ * Setter for sensor/detection information.
+ * @param sensor
+ */
+ public void setDetector(Detector sensor) {
+ this.detector = sensor;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = super.hashCode();
+ result = prime * result + ((detector == null) ? 0 : detector.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!super.equals(obj))
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ DetectorRegistration other = (DetectorRegistration) obj;
+ if (detector == null) {
+ if (other.detector != null)
+ return false;
+ } else if (!detector.equals(other.detector))
+ return false;
+ return true;
+ }
+
+
+}
diff --git a/co-simulation/lib/mosaic-interactions/src/test/java/org/eclipse/mosaic/interactions/detector/DetectedObjectInteractionTest.java b/co-simulation/lib/mosaic-interactions/src/test/java/org/eclipse/mosaic/interactions/detector/DetectedObjectInteractionTest.java
new file mode 100644
index 00000000..bb0772ef
--- /dev/null
+++ b/co-simulation/lib/mosaic-interactions/src/test/java/org/eclipse/mosaic/interactions/detector/DetectedObjectInteractionTest.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2023 LEIDOS.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.eclipse.mosaic.interactions.detector;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import org.eclipse.mosaic.lib.geo.CartesianPoint;
+import org.eclipse.mosaic.lib.math.Vector3d;
+import org.eclipse.mosaic.lib.objects.detector.DetectedObject;
+import org.eclipse.mosaic.lib.objects.detector.DetectionType;
+import org.eclipse.mosaic.lib.objects.detector.Size;
+import org.junit.Before;
+import org.junit.Test;
+
+public class DetectedObjectInteractionTest {
+
+ private DetectedObjectInteraction interaction;
+ @Before
+ public void setUp() throws Exception {
+ interaction = new DetectedObjectInteraction(0, null);
+ }
+
+ @Test
+ public void testGetterSetterConstructor() {
+ DetectedObject detectedObject = new DetectedObject(
+ DetectionType.CAR,
+ 0.7,
+ "sensor2",
+ "projection String2",
+ "Object7",
+ CartesianPoint.xyz(-1.1, -2, -3.2),
+ new Vector3d(1, 1, 1),
+ new Vector3d(.1, .2, .3),
+ new Size(2, 1, .5));
+ Double[] covarianceMatrix = new Double[] { 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0 };
+ detectedObject.setPositionCovariance(covarianceMatrix);
+ detectedObject.setVelocityCovariance(covarianceMatrix);
+ detectedObject.setAngularVelocityCovariance(covarianceMatrix);
+
+ interaction.setDetectedObject(detectedObject);
+
+ assertEquals(detectedObject, interaction.getDetectedObject());
+
+ DetectedObjectInteraction interaction2 = new DetectedObjectInteraction(0, detectedObject);
+ DetectedObjectInteraction interaction3 = interaction2;
+ assertNotEquals(interaction, interaction2);
+ assertEquals(interaction2, interaction3);
+ assertEquals(interaction2.hashCode(), interaction3.hashCode());
+ }
+}
diff --git a/co-simulation/lib/mosaic-interactions/src/test/java/org/eclipse/mosaic/interactions/detector/DetectorRegistrationTest.java b/co-simulation/lib/mosaic-interactions/src/test/java/org/eclipse/mosaic/interactions/detector/DetectorRegistrationTest.java
new file mode 100644
index 00000000..eff0fd8c
--- /dev/null
+++ b/co-simulation/lib/mosaic-interactions/src/test/java/org/eclipse/mosaic/interactions/detector/DetectorRegistrationTest.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2023 LEIDOS.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.eclipse.mosaic.interactions.detector;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import org.eclipse.mosaic.lib.geo.CartesianPoint;
+import org.eclipse.mosaic.lib.objects.detector.Detector;
+import org.eclipse.mosaic.lib.objects.detector.DetectorType;
+import org.eclipse.mosaic.lib.objects.detector.Orientation;
+import org.junit.Before;
+import org.junit.Test;
+
+public class DetectorRegistrationTest {
+ DetectorRegistration detectorRegistration;
+ @Before
+ public void setUp() throws Exception {
+ detectorRegistration = new DetectorRegistration(0, null);
+ }
+
+ @Test
+ public void testGetterSetterConstructor() {
+ Detector detector = new Detector("something", DetectorType.SEMANTIC_LIDAR, new Orientation(23.0, 0, 0),
+ CartesianPoint.xyz(1, 2, 3));
+ detectorRegistration.setDetector(detector);
+ assertEquals(detector, detectorRegistration.getDetector());
+
+ DetectorRegistration detectorRegistration1 = new DetectorRegistration(0, detector);
+
+ assertNotEquals(detectorRegistration, detectorRegistration1);
+ DetectorRegistration detectorRegistration2 = detectorRegistration1;
+ assertEquals(detectorRegistration1, detectorRegistration2);
+ assertEquals(detectorRegistration1.hashCode(), detectorRegistration2.hashCode());
+
+ }
+}
diff --git a/co-simulation/lib/mosaic-objects/src/main/java/org/eclipse/mosaic/lib/objects/detector/DetectedObject.java b/co-simulation/lib/mosaic-objects/src/main/java/org/eclipse/mosaic/lib/objects/detector/DetectedObject.java
new file mode 100644
index 00000000..59f22cdb
--- /dev/null
+++ b/co-simulation/lib/mosaic-objects/src/main/java/org/eclipse/mosaic/lib/objects/detector/DetectedObject.java
@@ -0,0 +1,358 @@
+/*
+ * Copyright (C) 2023 LEIDOS.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.eclipse.mosaic.lib.objects.detector;
+
+import java.io.Serializable;
+import java.util.Arrays;
+
+import org.eclipse.mosaic.lib.geo.CartesianPoint;
+import org.eclipse.mosaic.lib.math.Vector3d;
+
+public final class DetectedObject implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private DetectionType type;
+
+ private double confidence;
+
+ private String sensorId;
+
+ private String projString;
+
+ private String objectId;
+
+ private CartesianPoint position;
+
+ private Double[] positionCovariance = new Double[9];
+
+ private Vector3d velocity;
+
+ private Double[] velocityCovariance = new Double[9];
+
+ private Vector3d angularVelocity;
+
+ private Double[] angularVelocityCovariance = new Double[9];
+
+ private Size size;
+ /**
+ * Constructor for Detected Object information.
+ *
+ * @param type {@link DetectionType}.
+ * @param confidence in detection type classification.
+ * @param sensorId of sensor/detector reporting object detection
+ * @param projString containing information about reference frame in
+ * which kinematic information is reported.
+ * @param objectId unique string ID of detected object (only guaranteed
+ * unique among other detected objects reported by the
+ * same sensor).
+ * @param position position of detected object relative to sensor/detector
+ * frame.
+ * @param velocity velocity of detected object in sensor/detector frame.
+ * @param angularVelocity angular velocity of detected object in sensor/detector frame.
+ * @param size size of object including height,width and length.
+ */
+ public DetectedObject(DetectionType type, double confidence, String sensorId, String projString, String objectId,
+ CartesianPoint position, Vector3d velocity, Vector3d angularVelocity, Size size) {
+ this.type = type;
+ this.confidence = confidence;
+ this.sensorId = sensorId;
+ this.projString = projString;
+ this.objectId = objectId;
+ this.position = position;
+ this.velocity = velocity;
+ this.angularVelocity = angularVelocity;
+ this.size = size;
+ }
+
+ /**
+ * Getter for {@link DetectionType}
+ * @return
+ */
+ public DetectionType getType() {
+ return type;
+ }
+
+ /**
+ * Getter for projection string which describes how to translate
+ * Detected Object position,velocity, and angular velocity from a
+ * sensor/detector relative map reference frame to other reference frames.
+ * @return
+ */
+ public String getProjString() {
+ return projString;
+ }
+
+ /**
+ * Getter for 3x3 covariance associated with position represented as
+ * a 9 element vector for JSON serialization/deserialization.
+ * @return
+ */
+ public Double[] getPositionCovariance() {
+ return positionCovariance;
+ }
+
+ /**
+ * Setter for 3x3 covariance associated with position represented as
+ * a 9 element vector for JSON serialization/deserialization.
+ * @param positionCovariance
+ */
+ public void setPositionCovariance(Double[] positionCovariance) {
+ this.positionCovariance = positionCovariance;
+ }
+
+ /**
+ * Getter for 3x3 covariance associated with velocity represented as
+ * a 9 element vector for JSON serialization/deserialization.
+ * @return
+ */
+ public Double[] getVelocityCovariance() {
+ return velocityCovariance;
+ }
+
+ /**
+ * Setter for 3x3 covariance associated with velocity represented as
+ * a 9 element vector for JSON serialization/deserialization.
+ * @param positionCovariance
+ */
+ public void setVelocityCovariance(Double[] velocityCovariance) {
+ this.velocityCovariance = velocityCovariance;
+ }
+ /**
+ * Getter for 3x3 covariance associated with angular velocity represented
+ * as a 9 element vector for JSON serialization/deserialization.
+ * @return
+ */
+ public Double[] getAngularVelocityCovariance() {
+ return angularVelocityCovariance;
+ }
+
+ /**
+ * Setter for 3x3 covariance associated with angular velocity represented
+ * as a 9 element vector for JSON serialization/deserialization.
+ * @param positionCovariance
+ */
+ public void setAngularVelocityCovariance(Double[] angularVelocityCovariance) {
+ this.angularVelocityCovariance = angularVelocityCovariance;
+ }
+
+ /**
+ * Getter for confidence value in DetectionType classification.
+ * @return
+ */
+ public double getConfidence() {
+ return confidence;
+ }
+
+ /**
+ * Getter for sensor ID reporting detected object.
+ * @return
+ */
+ public String getSensorId() {
+ return sensorId;
+ }
+
+ /**
+ * Getter for String object ID.
+ * @return
+ */
+ public String getObjectId() {
+ return objectId;
+ }
+
+ /**
+ * Getter for object location.
+ * @return
+ */
+ public CartesianPoint getPosition() {
+ return position;
+ }
+
+ /**
+ * Getter for object velocity.
+ * @return
+ */
+ public Vector3d getVelocity() {
+ return velocity;
+ }
+
+ /**
+ * Getter for object angular velocity
+ * @return
+ */
+ public Vector3d getAngularVelocity() {
+ return angularVelocity;
+ }
+
+ /**
+ * Getter for object size
+ * @return
+ */
+ public Size getSize() {
+ return size;
+ }
+
+ /**
+ * Setter for object {@link DetectionType}
+ * @param type
+ */
+ public void setType(DetectionType type) {
+ this.type = type;
+ }
+
+ /**
+ * Setter for confidence in detected object {@link DetectionType} classification.
+ * @param confidence
+ */
+ public void setConfidence(double confidence) {
+ this.confidence = confidence;
+ }
+
+ /**
+ * Setter for String sensor ID reporting DetectedObject.
+ * @param sensorId
+ */
+ public void setSensorId(String sensorId) {
+ this.sensorId = sensorId;
+ }
+
+ /**
+ * Setter for projection string to translate object kinematic information from
+ * reference frame to geodetic cordinates.
+ * @param projString
+ */
+ public void setProjString(String projString) {
+ this.projString = projString;
+ }
+
+ /**
+ * Setter for detected object unique string ID.
+ * @param objectId
+ */
+ public void setObjectId(String objectId) {
+ this.objectId = objectId;
+ }
+
+ /**
+ * Setter for detected object position.
+ * @param position
+ */
+ public void setPosition(CartesianPoint position) {
+ this.position = position;
+ }
+
+ /**
+ * Setter for detected object velocity.
+ * @param velocity {@link Vector3d}
+ */
+ public void setVelocity(Vector3d velocity) {
+ this.velocity = velocity;
+ }
+ /**
+ * Setter for detected object angular velocity.
+ * @param angularVelocity {@link Vector3d}
+ */
+ public void setAngularVelocity(Vector3d angularVelocity) {
+ this.angularVelocity = angularVelocity;
+ }
+
+ /**
+ * Setter for object size.
+ * @param size {@link Size}
+ */
+ public void setSize(Size size) {
+ this.size = size;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((type == null) ? 0 : type.hashCode());
+ long temp;
+ temp = Double.doubleToLongBits(confidence);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ result = prime * result + ((sensorId == null) ? 0 : sensorId.hashCode());
+ result = prime * result + ((projString == null) ? 0 : projString.hashCode());
+ result = prime * result + ((objectId == null) ? 0 : objectId.hashCode());
+ result = prime * result + ((position == null) ? 0 : position.hashCode());
+ result = prime * result + Arrays.hashCode(positionCovariance);
+ result = prime * result + ((velocity == null) ? 0 : velocity.hashCode());
+ result = prime * result + Arrays.hashCode(velocityCovariance);
+ result = prime * result + ((angularVelocity == null) ? 0 : angularVelocity.hashCode());
+ result = prime * result + Arrays.hashCode(angularVelocityCovariance);
+ result = prime * result + ((size == null) ? 0 : size.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ DetectedObject other = (DetectedObject) obj;
+ if (type != other.type)
+ return false;
+ if (Double.doubleToLongBits(confidence) != Double.doubleToLongBits(other.confidence))
+ return false;
+ if (sensorId == null) {
+ if (other.sensorId != null)
+ return false;
+ } else if (!sensorId.equals(other.sensorId))
+ return false;
+ if (projString == null) {
+ if (other.projString != null)
+ return false;
+ } else if (!projString.equals(other.projString))
+ return false;
+ if (objectId == null) {
+ if (other.objectId != null)
+ return false;
+ } else if (!objectId.equals(other.objectId))
+ return false;
+ if (position == null) {
+ if (other.position != null)
+ return false;
+ } else if (!position.equals(other.position))
+ return false;
+ if (!Arrays.equals(positionCovariance, other.positionCovariance))
+ return false;
+ if (velocity == null) {
+ if (other.velocity != null)
+ return false;
+ } else if (!velocity.equals(other.velocity))
+ return false;
+ if (!Arrays.equals(velocityCovariance, other.velocityCovariance))
+ return false;
+ if (angularVelocity == null) {
+ if (other.angularVelocity != null)
+ return false;
+ } else if (!angularVelocity.equals(other.angularVelocity))
+ return false;
+ if (!Arrays.equals(angularVelocityCovariance, other.angularVelocityCovariance))
+ return false;
+ if (size == null) {
+ if (other.size != null)
+ return false;
+ } else if (!size.equals(other.size))
+ return false;
+ return true;
+ }
+
+}
diff --git a/co-simulation/lib/mosaic-objects/src/main/java/org/eclipse/mosaic/lib/objects/detector/DetectionType.java b/co-simulation/lib/mosaic-objects/src/main/java/org/eclipse/mosaic/lib/objects/detector/DetectionType.java
new file mode 100644
index 00000000..fb375357
--- /dev/null
+++ b/co-simulation/lib/mosaic-objects/src/main/java/org/eclipse/mosaic/lib/objects/detector/DetectionType.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2023 LEIDOS.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.eclipse.mosaic.lib.objects.detector;
+
+
+public enum DetectionType {
+ CAR("CAR"),
+ VAN("VAN"),
+ TRUCK("TRUCK"),
+ BUS("BUS"),
+ MOTORCYCLE("MOTORCYCLE"),
+ CYCLIST("CYCLIST"),
+ PEDESTRIAN("PEDESTRIAN");
+
+
+ public final String label;
+
+ /**
+ * Default constructor.
+ *
+ * @param label String
+ */
+ DetectionType(String label) {
+ this.label = label;
+ }
+
+ /**
+ * Returns the enum mapped from an String label.
+ *
+ * @param label string.
+ * @return the enum mapped from String label.
+ */
+ public static DetectionType fromLabel(String label) {
+ for (DetectionType type: DetectionType.values()) {
+ if (type.label.equalsIgnoreCase(label)) {
+ return type;
+ }
+ }
+ throw new IllegalArgumentException("Unknown DetectionType name " + label);
+ }
+
+ /**
+ * Returns string label associated with enum.
+ * @return
+ */
+ public String getLabel(){
+ return label;
+ }
+}
diff --git a/co-simulation/lib/mosaic-objects/src/main/java/org/eclipse/mosaic/lib/objects/detector/Detector.java b/co-simulation/lib/mosaic-objects/src/main/java/org/eclipse/mosaic/lib/objects/detector/Detector.java
new file mode 100644
index 00000000..d82ef91d
--- /dev/null
+++ b/co-simulation/lib/mosaic-objects/src/main/java/org/eclipse/mosaic/lib/objects/detector/Detector.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2023 LEIDOS.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.eclipse.mosaic.lib.objects.detector;
+
+import java.io.Serializable;
+
+import org.eclipse.mosaic.lib.geo.CartesianPoint;
+
+public class Detector implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ private String sensorId;
+ private DetectorType type;
+ private Orientation orientation;
+ private CartesianPoint location;
+
+ /**
+ * Sensor/Detector constructor
+ *
+ * @param sensorId unique string ID of sensor/detector.
+ * @param type of the sensor/detector.
+ * @param orientation of the sensor/detector.
+ * @param location of the sensor/detector.
+ */
+ public Detector(String sensorId, DetectorType type, Orientation orientation, CartesianPoint location) {
+ this.sensorId = sensorId;
+ this.type = type;
+ this.orientation = orientation;
+ this.location = location;
+ }
+
+ /**
+ * Get unique String sensor ID.
+ * @return
+ */
+ public String getSensorId() {
+ return sensorId;
+ }
+
+ /**
+ * Set unique String sensor ID.
+ * @param sensorId
+ */
+ public void setSensorId(String sensorId) {
+ this.sensorId = sensorId;
+ }
+
+ /**
+ * Get sensor/detector {@link DetectorType}.
+ * @return
+ */
+ public DetectorType getType() {
+ return type;
+ }
+
+ /**
+ * Set the sensor/detector {@link DetectorType}.
+ * @param type
+ */
+ public void setType(DetectorType type) {
+ this.type = type;
+ }
+
+ /**
+ * Get sensor/detector {@link Orientation}.
+ * @return
+ */
+ public Orientation getOrientation() {
+ return orientation;
+ }
+
+ /**
+ * Set sensor/detector {@link Orientation}.
+ * @param orientation
+ */
+ public void setOrientation(Orientation orientation) {
+ this.orientation = orientation;
+ }
+
+ /**
+ * Get sensor/detector location.
+ * @return {@link CartesianPoint}.
+ */
+ public CartesianPoint getLocation() {
+ return location;
+ }
+ /**
+ * Set sensor/detector location
+ * @param point {@link CartesianPoint}.
+ */
+ public void setLocation(CartesianPoint point) {
+ this.location = point;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((sensorId == null) ? 0 : sensorId.hashCode());
+ result = prime * result + ((type == null) ? 0 : type.hashCode());
+ result = prime * result + ((orientation == null) ? 0 : orientation.hashCode());
+ result = prime * result + ((location == null) ? 0 : location.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ Detector other = (Detector) obj;
+ if (sensorId == null) {
+ if (other.sensorId != null)
+ return false;
+ } else if (!sensorId.equals(other.sensorId))
+ return false;
+ if (type != other.type)
+ return false;
+ if (orientation == null) {
+ if (other.orientation != null)
+ return false;
+ } else if (!orientation.equals(other.orientation))
+ return false;
+ if (location == null) {
+ if (other.location != null)
+ return false;
+ } else if (!location.equals(other.location))
+ return false;
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "Detector [sensorId=" + sensorId + ", type=" + type + ", orientation=" + orientation + ", location="
+ + location + "]";
+ }
+
+
+
+
+}
diff --git a/co-simulation/lib/mosaic-objects/src/main/java/org/eclipse/mosaic/lib/objects/detector/DetectorType.java b/co-simulation/lib/mosaic-objects/src/main/java/org/eclipse/mosaic/lib/objects/detector/DetectorType.java
new file mode 100644
index 00000000..de39e6ef
--- /dev/null
+++ b/co-simulation/lib/mosaic-objects/src/main/java/org/eclipse/mosaic/lib/objects/detector/DetectorType.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2023 LEIDOS.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.eclipse.mosaic.lib.objects.detector;
+
+
+
+import org.eclipse.mosaic.lib.objects.detector.gson.DetectorTypeAdapter;
+
+import com.google.gson.annotations.JsonAdapter;
+
+@JsonAdapter(DetectorTypeAdapter.class)
+public enum DetectorType {
+ SEMANTIC_LIDAR("SemanticLidar"),
+ RADAR("Radar"),
+ LIDAR("Lidar"),
+ SEMANTIC_SEGMENTATION_CAMERA("SemanticSegnmentationCamera"),
+ INSTANCE_SEGMENTATION_CAMERA("InstanceSegmentationCamera");
+
+
+
+ public final String label;
+
+ /**
+ * Default constructor.
+ *
+ * @param label String
+ */
+ DetectorType(String label) {
+ this.label = label;
+ }
+
+ /**
+ * Returns the enum mapped from an String name.
+ *
+ * @param label string.
+ * @return the enum mapped from String name.
+ */
+ public static DetectorType fromLabel(String label) {
+ for (DetectorType type: DetectorType.values()) {
+ if (type.label.equalsIgnoreCase(label)) {
+ return type;
+ }
+ }
+ throw new IllegalArgumentException("Unknown DetectorType label " + label);
+ }
+
+ public String getLabel(){
+ return label;
+ }
+}
diff --git a/co-simulation/lib/mosaic-objects/src/main/java/org/eclipse/mosaic/lib/objects/detector/Orientation.java b/co-simulation/lib/mosaic-objects/src/main/java/org/eclipse/mosaic/lib/objects/detector/Orientation.java
new file mode 100644
index 00000000..5ed1ddbc
--- /dev/null
+++ b/co-simulation/lib/mosaic-objects/src/main/java/org/eclipse/mosaic/lib/objects/detector/Orientation.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2023 LEIDOS.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.eclipse.mosaic.lib.objects.detector;
+
+import java.io.Serializable;
+
+public class Orientation implements Serializable{
+ private static final long serialVersionUID = 1L;
+
+ private double yaw;
+
+ private double pitch;
+
+ private double roll;
+ /**
+ * Constructor for orientation
+ * @param yaw in degrees
+ * @param pitch in degrees
+ * @param roll in degrees
+ */
+ public Orientation( double yaw, double pitch, double roll) {
+ this.yaw = yaw;
+ this.pitch = pitch;
+ this.roll = roll;
+ }
+
+ /**
+ * Get yaw in degrees.
+ * @return
+ */
+ public double getYaw() {
+ return yaw;
+ }
+
+ /**
+ * Get pitch in degrees.
+ * @return
+ */
+ public double getPitch() {
+ return pitch;
+ }
+
+ /**
+ * Get roll in degrees.
+ * @return
+ */
+ public double getRoll() {
+ return roll;
+ }
+
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ long temp;
+ temp = Double.doubleToLongBits(pitch);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(yaw);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(roll);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ Orientation other = (Orientation) obj;
+ if (Double.doubleToLongBits(pitch) != Double.doubleToLongBits(other.pitch))
+ return false;
+ if (Double.doubleToLongBits(yaw) != Double.doubleToLongBits(other.yaw))
+ return false;
+ if (Double.doubleToLongBits(roll) != Double.doubleToLongBits(other.roll))
+ return false;
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "Orientation [yaw=" + yaw + ", pitch=" + pitch + ", roll=" + roll + "]";
+ }
+
+
+
+
+
+}
diff --git a/co-simulation/lib/mosaic-objects/src/main/java/org/eclipse/mosaic/lib/objects/detector/Size.java b/co-simulation/lib/mosaic-objects/src/main/java/org/eclipse/mosaic/lib/objects/detector/Size.java
new file mode 100644
index 00000000..97716728
--- /dev/null
+++ b/co-simulation/lib/mosaic-objects/src/main/java/org/eclipse/mosaic/lib/objects/detector/Size.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2023 LEIDOS.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.eclipse.mosaic.lib.objects.detector;
+
+import java.io.Serializable;
+
+public class Size implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ private double length;
+
+ private double height;
+
+ private double width;
+ /**
+ * Constructor for size
+ * @param length in meters
+ * @param height in meters
+ * @param width in meters
+ */
+ public Size(double length, double height, double width) {
+ this.length = length;
+ this.height = height;
+ this.width = width;
+ }
+
+ /**
+ * Get length in meters.
+ * @return
+ */
+ public double getLength() {
+ return length;
+ }
+
+ /**
+ * Get height in meters.
+ * @return
+ */
+ public double getHeight() {
+ return height;
+ }
+
+ /**
+ * Get width in meters.
+ * @return
+ */
+ public double getWidth() {
+ return width;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ long temp;
+ temp = Double.doubleToLongBits(length);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(height);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(width);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ Size other = (Size) obj;
+ if (Double.doubleToLongBits(length) != Double.doubleToLongBits(other.length))
+ return false;
+ if (Double.doubleToLongBits(height) != Double.doubleToLongBits(other.height))
+ return false;
+ if (Double.doubleToLongBits(width) != Double.doubleToLongBits(other.width))
+ return false;
+ return true;
+ }
+
+}
diff --git a/co-simulation/lib/mosaic-objects/src/main/java/org/eclipse/mosaic/lib/objects/detector/gson/DetectorTypeAdapter.java b/co-simulation/lib/mosaic-objects/src/main/java/org/eclipse/mosaic/lib/objects/detector/gson/DetectorTypeAdapter.java
new file mode 100644
index 00000000..3488a0f1
--- /dev/null
+++ b/co-simulation/lib/mosaic-objects/src/main/java/org/eclipse/mosaic/lib/objects/detector/gson/DetectorTypeAdapter.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2023 LEIDOS.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.eclipse.mosaic.lib.objects.detector.gson;
+
+import java.lang.reflect.Type;
+
+import org.eclipse.mosaic.lib.objects.detector.DetectorType;
+
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonDeserializer;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParseException;
+import com.google.gson.JsonSerializationContext;
+import com.google.gson.JsonSerializer;
+
+public class DetectorTypeAdapter implements JsonSerializer, JsonDeserializer {
+
+ @Override
+ public DetectorType deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
+ throws JsonParseException {
+ return DetectorType.fromLabel(json.getAsString());
+ }
+
+ @Override
+ public JsonElement serialize(DetectorType src, Type typeOfSrc, JsonSerializationContext context) {
+ return context.serialize(src.getLabel());
+ }
+
+}
diff --git a/co-simulation/lib/mosaic-objects/src/test/java/org/eclipse/mosaic/lib/objects/detector/DetectedObjectTest.java b/co-simulation/lib/mosaic-objects/src/test/java/org/eclipse/mosaic/lib/objects/detector/DetectedObjectTest.java
new file mode 100644
index 00000000..616e2ea7
--- /dev/null
+++ b/co-simulation/lib/mosaic-objects/src/test/java/org/eclipse/mosaic/lib/objects/detector/DetectedObjectTest.java
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) 2023 LEIDOS.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.eclipse.mosaic.lib.objects.detector;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import org.eclipse.mosaic.lib.geo.CartesianPoint;
+import org.eclipse.mosaic.lib.math.Vector3d;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.gson.Gson;
+
+public class DetectedObjectTest {
+ @Before
+ public void setUp() throws Exception {
+
+ }
+
+ @Test
+ public void testDetectObjectJsonSerialization() {
+ // Set up the registration object
+ DetectedObject detectedObject = new DetectedObject(
+ DetectionType.BUS,
+ 0.5,
+ "sensor1",
+ "projection String",
+ "Object1",
+ CartesianPoint.xyz(1.1, 2, 3.2),
+ new Vector3d(0, 0, 0),
+ new Vector3d(),
+ new Size(0, 0, 0));
+ Double[] covarianceMatrix = new Double[] { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
+ detectedObject.setPositionCovariance(covarianceMatrix);
+ detectedObject.setVelocityCovariance(covarianceMatrix);
+ detectedObject.setAngularVelocityCovariance(covarianceMatrix);
+ Gson gson = new Gson();
+ String json = gson.toJson(detectedObject);
+ String json_prediction = "{"
+ + "\"type\":\"BUS\","
+ + "\"confidence\":0.5,"
+ + "\"sensorId\":\"sensor1\","
+ + "\"projString\":\"projection String\","
+ + "\"objectId\":\"Object1\","
+ + "\"position\":"
+ + "{"
+ + "\"x\":1.1,"
+ + "\"y\":2.0,"
+ + "\"z\":3.2"
+ + "},"
+ + "\"positionCovariance\":[0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0],"
+ + "\"velocity\":"
+ + "{"
+ + "\"x\":0.0,"
+ + "\"y\":0.0,"
+ + "\"z\":0.0"
+ + "},"
+ + "\"velocityCovariance\":[0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0],"
+ + "\"angularVelocity\":"
+ + "{"
+ + "\"x\":0.0,"
+ + "\"y\":0.0,"
+ + "\"z\":0.0"
+ + "},"
+ + "\"angularVelocityCovariance\":[0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0],"
+ + "\"size\":"
+ + "{"
+ + "\"length\":0.0,"
+ + "\"height\":0.0,"
+ + "\"width\":0.0"
+ + "}"
+ + "}";
+ assertEquals(json,
+ json_prediction);
+
+ }
+
+ @Test
+ public void testDetectObjectJsonDeserialization() {
+ Gson gson = new Gson();
+ String json = "{"
+ + "\"type\":\"CAR\","
+ + "\"confidence\":0.7,"
+ + "\"sensorId\":\"sensor2\","
+ + "\"projString\":\"projection String2\","
+ + "\"objectId\":\"Object7\","
+ + "\"position\":"
+ + "{"
+ + "\"x\":-1.1,"
+ + "\"y\":-2.0,"
+ + "\"z\":-3.2"
+ + "},"
+ + "\"positionCovariance\":[1.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,1.0],"
+ + "\"velocity\":"
+ + "{"
+ + "\"x\":1,"
+ + "\"y\":1,"
+ + "\"z\":1"
+ + "},"
+ + "\"velocityCovariance\":[1.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,1.0],"
+ + "\"angularVelocity\":"
+ + "{"
+ + "\"x\":0.1,"
+ + "\"y\":0.2,"
+ + "\"z\":0.3"
+ + "},"
+ + "\"angularVelocityCovariance\":[1.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,1.0],"
+ + "\"size\":"
+ + "{"
+ + "\"length\":2.0,"
+ + "\"height\":1.0,"
+ + "\"width\":0.5"
+ + "}"
+ + "}";
+
+ DetectedObject detectedObject = gson.fromJson(json, DetectedObject.class);
+ DetectedObject predictedDetectedObject = new DetectedObject(
+ DetectionType.CAR,
+ 0.7,
+ "sensor2",
+ "projection String2",
+ "Object7",
+ CartesianPoint.xyz(-1.1, -2, -3.2),
+ new Vector3d(1, 1, 1),
+ new Vector3d(.1, .2, .3),
+ new Size(2, 1, .5));
+ Double[] covarianceMatrix = new Double[] { 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0 };
+ predictedDetectedObject.setPositionCovariance(covarianceMatrix);
+ predictedDetectedObject.setVelocityCovariance(covarianceMatrix);
+ predictedDetectedObject.setAngularVelocityCovariance(covarianceMatrix);
+ assertEquals(detectedObject, predictedDetectedObject);
+ assertEquals(detectedObject.hashCode(), predictedDetectedObject.hashCode());
+ }
+
+ @Test
+ public void testGetterSetterConstructor() {
+ //Test constructor
+ DetectedObject detectedObject = new DetectedObject(
+ DetectionType.VAN,
+ 0.5,
+ "sensor1",
+ "projection String",
+ "Object1",
+ CartesianPoint.xyz(1.1, 2, 3.2),
+ new Vector3d(2, 3, 4),
+ new Vector3d(-4.4,-5.5,-6.6),
+ new Size(3, 4, 5));
+ Double[] covarianceMatrix = new Double[] { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
+ detectedObject.setPositionCovariance(covarianceMatrix);
+ detectedObject.setVelocityCovariance(covarianceMatrix);
+ detectedObject.setAngularVelocityCovariance(covarianceMatrix);
+ // Test Getters
+ assertEquals(DetectionType.VAN, detectedObject.getType());
+ assertEquals(0.5, detectedObject.getConfidence(), .01);
+ assertEquals("sensor1", detectedObject.getSensorId());
+ assertEquals("projection String", detectedObject.getProjString());
+ assertEquals("Object1", detectedObject.getObjectId());
+ assertEquals(CartesianPoint.xyz(1.1, 2, 3.2), detectedObject.getPosition());
+ assertEquals(new Vector3d(2, 3, 4), detectedObject.getVelocity());
+ assertEquals(new Vector3d(-4.4, -5.5, -6.6), detectedObject.getAngularVelocity());
+ assertEquals( new Size(3,4,5), detectedObject.getSize());
+ assertArrayEquals(covarianceMatrix, detectedObject.getPositionCovariance());
+ assertArrayEquals(covarianceMatrix, detectedObject.getVelocityCovariance());
+ assertArrayEquals(covarianceMatrix, detectedObject.getAngularVelocityCovariance());
+
+
+ }
+
+ @Test
+ public void testEquals() {
+ DetectedObject detectedObject = new DetectedObject(
+ DetectionType.VAN,
+ 0.5,
+ "sensor1",
+ "projection String",
+ "Object1",
+ CartesianPoint.xyz(1.1, 2, 3.2),
+ new Vector3d(2, 3, 4),
+ new Vector3d(-4.4,-5.5,-6.6),
+ new Size(3, 4, 5));
+ Double[] covarianceMatrix = new Double[] { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
+ detectedObject.setPositionCovariance(covarianceMatrix);
+ detectedObject.setVelocityCovariance(covarianceMatrix);
+ detectedObject.setAngularVelocityCovariance(covarianceMatrix);
+
+ DetectedObject detectedObject1 = new DetectedObject(
+ null,
+ 0.6,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null);
+ DetectedObject detectedObject2 = new DetectedObject(
+ null,
+ 0.6,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null);
+
+ assertNotEquals(detectedObject1, detectedObject);
+ assertEquals(detectedObject2, detectedObject1);
+
+
+ //Correct Type
+ detectedObject1.setType(detectedObject.getType());
+ assertNotEquals(detectedObject1, detectedObject);
+ //Correct Confidence
+ detectedObject1.setConfidence(detectedObject.getConfidence());
+ assertNotEquals(detectedObject1, detectedObject);
+ //Correct Sensor ID
+ detectedObject1.setSensorId(detectedObject.getSensorId());
+ assertNotEquals(detectedObject1, detectedObject);
+ //Correct Projection String
+ detectedObject1.setProjString(detectedObject.getProjString());
+ assertNotEquals(detectedObject1, detectedObject);
+ //Correct Object ID
+ detectedObject1.setObjectId(detectedObject.getObjectId());
+ assertNotEquals(detectedObject1, detectedObject);
+ //Correct Size
+ detectedObject1.setSize(detectedObject.getSize());
+ assertNotEquals(detectedObject1, detectedObject);
+ //Correct Position
+ detectedObject1.setPosition(detectedObject.getPosition());
+ assertNotEquals(detectedObject1, detectedObject);
+ //Correct Position Covariance
+ detectedObject1.setPositionCovariance(detectedObject.getPositionCovariance());
+ assertNotEquals(detectedObject1, detectedObject);
+ //Correct Velocity
+ detectedObject1.setVelocity(detectedObject.getVelocity());
+ assertNotEquals(detectedObject1, detectedObject);
+ //Correct Velocity Covariance
+ detectedObject1.setVelocityCovariance(detectedObject.getVelocityCovariance());
+ assertNotEquals(detectedObject1, detectedObject);
+ //Correct Angular Velocity
+ detectedObject1.setAngularVelocity(detectedObject.getAngularVelocity());
+ assertNotEquals(detectedObject1, detectedObject);
+ //Correct Angular Velocity Covariance
+ detectedObject1.setAngularVelocityCovariance(detectedObject.getAngularVelocityCovariance());
+ assertEquals(detectedObject1, detectedObject);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+
+}
diff --git a/co-simulation/lib/mosaic-objects/src/test/java/org/eclipse/mosaic/lib/objects/detector/DetectorTest.java b/co-simulation/lib/mosaic-objects/src/test/java/org/eclipse/mosaic/lib/objects/detector/DetectorTest.java
new file mode 100644
index 00000000..ad1482e6
--- /dev/null
+++ b/co-simulation/lib/mosaic-objects/src/test/java/org/eclipse/mosaic/lib/objects/detector/DetectorTest.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2023 LEIDOS.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.eclipse.mosaic.lib.objects.detector;
+
+import static org.junit.Assert.assertEquals;
+
+import org.eclipse.mosaic.lib.geo.CartesianPoint;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.gson.Gson;
+
+public class DetectorTest {
+ @Before
+ public void setUp() throws Exception {
+
+ }
+
+ @Test
+ public void testDetectorJsonSerialization() {
+ Detector sensor = new Detector("something", DetectorType.SEMANTIC_LIDAR, new Orientation(23.0, 0, 0),
+ CartesianPoint.xyz(1, 2, 3));
+ Gson gson = new Gson();
+ String sensorJson = gson.toJson(sensor);
+ String predictedSensorJson = "{"
+ + "\"sensorId\":\"something\","
+ + "\"type\":\"SemanticLidar\","
+ + "\"orientation\":"
+ + "{"
+ + "\"yaw\":23.0,"
+ + "\"pitch\":0.0,"
+ + "\"roll\":0.0"
+ + "},"
+ + "\"location\":"
+ + "{"
+ + "\"x\":1.0,"
+ + "\"y\":2.0,"
+ + "\"z\":3.0"
+ + "}"
+ +"}";
+ assertEquals(sensorJson, predictedSensorJson);
+ }
+
+ @Test
+ public void testDetectorJsonDeserialization() {
+ String predictedSensorJson = "{"
+ + "\"sensorId\":\"something\","
+ + "\"type\":\"SemanticLidar\","
+ + "\"orientation\":"
+ + "{"
+ + "\"yaw\":23.0,"
+ + "\"pitch\":0.0,"
+ + "\"roll\":0.0"
+ + "},"
+ + "\"location\":"
+ + "{"
+ + "\"x\":1.0,"
+ + "\"y\":2.0,"
+ + "\"z\":3.0"
+ + "}"
+ +"}";
+ Gson gson = new Gson();
+ Detector predictedSensor = new Detector("something", DetectorType.SEMANTIC_LIDAR, new Orientation(23.0, 0, 0),
+ CartesianPoint.xyz(1, 2, 3));
+ Detector sensor = gson.fromJson(predictedSensorJson, Detector.class);
+ assertEquals(sensor, predictedSensor);
+ assertEquals(sensor.hashCode(), predictedSensor.hashCode());
+ }
+
+ @Test
+ public void testGetterSetterConstructor() {
+ Detector sensor = new Detector("something", DetectorType.SEMANTIC_LIDAR, new Orientation(23.0, 0, 0),
+ CartesianPoint.xyz(1, 2, 3));
+ assertEquals("something", sensor.getSensorId());
+ assertEquals(DetectorType.SEMANTIC_LIDAR, sensor.getType());
+ assertEquals(new Orientation(23.0, 0, 0), sensor.getOrientation());
+ assertEquals(CartesianPoint.xyz(1,2,3), sensor.getLocation());
+ // Test Setters
+ sensor.setSensorId("NewSensor");
+ sensor.setLocation(CartesianPoint.xy(45,67));
+ sensor.setOrientation(new Orientation(22, 33, 44));
+ sensor.setType(DetectorType.INSTANCE_SEGMENTATION_CAMERA);
+ assertEquals("NewSensor", sensor.getSensorId());
+ assertEquals(DetectorType.INSTANCE_SEGMENTATION_CAMERA, sensor.getType());
+ assertEquals(new Orientation(22, 33, 44), sensor.getOrientation());
+ assertEquals(CartesianPoint.xy(45,67), sensor.getLocation());
+ }
+ @Test
+ public void testToString() {
+ Detector sensor = new Detector("something", DetectorType.SEMANTIC_LIDAR, new Orientation(23.0, 0, 0),
+ CartesianPoint.xyz(1, 2, 3));
+ String sensoString = "Detector [sensorId=something, type=SEMANTIC_LIDAR, "
+ + "orientation=Orientation [yaw=23.0, pitch=0.0, roll=0.0], "
+ + "location=CartesianPoint{x=1.00,y=2.00,z=3.00}]";
+ assertEquals(sensoString, sensor.toString());
+ }
+}
+
+
diff --git a/co-simulation/lib/mosaic-objects/src/test/java/org/eclipse/mosaic/lib/objects/detector/DetectorTypeTest.java b/co-simulation/lib/mosaic-objects/src/test/java/org/eclipse/mosaic/lib/objects/detector/DetectorTypeTest.java
new file mode 100644
index 00000000..1e6d285e
--- /dev/null
+++ b/co-simulation/lib/mosaic-objects/src/test/java/org/eclipse/mosaic/lib/objects/detector/DetectorTypeTest.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2023 LEIDOS.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.eclipse.mosaic.lib.objects.detector;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+public class DetectorTypeTest {
+ @Test
+ public void testFromLabel() {
+ DetectorType type = DetectorType.fromLabel("SemanticLidar");
+ assertEquals( DetectorType.SEMANTIC_LIDAR, type);
+ Exception exception = assertThrows(IllegalArgumentException.class, () -> {
+ DetectorType.fromLabel("NotSupportedDetected");
+ });
+ assertTrue(exception.getMessage().contains("Unknown DetectorType label"));
+ }
+}
diff --git a/co-simulation/lib/mosaic-objects/src/test/java/org/eclipse/mosaic/lib/objects/detector/OrientationTest.java b/co-simulation/lib/mosaic-objects/src/test/java/org/eclipse/mosaic/lib/objects/detector/OrientationTest.java
new file mode 100644
index 00000000..65d6078e
--- /dev/null
+++ b/co-simulation/lib/mosaic-objects/src/test/java/org/eclipse/mosaic/lib/objects/detector/OrientationTest.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2023 LEIDOS.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.eclipse.mosaic.lib.objects.detector;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+public class OrientationTest {
+ @Test
+ public void testEquals() {
+ Orientation orientation = new Orientation(23, 55.3, 5);
+ assertEquals(23, orientation.getYaw(), 0.01);
+ assertEquals(55.3, orientation.getPitch(), 0.01);
+ assertEquals(5, orientation.getRoll(), 0.01);
+ }
+
+ @Test
+ public void testGetPitch() {
+ Orientation orientation = new Orientation(23, 55.3, 5);
+ Orientation orientation1 = new Orientation(23, 55.3, 5);
+ assertEquals(orientation, orientation1);
+ assertEquals(orientation.hashCode(), orientation1.hashCode());
+ }
+}
diff --git a/co-simulation/lib/mosaic-objects/src/test/java/org/eclipse/mosaic/lib/objects/detector/SizeTest.java b/co-simulation/lib/mosaic-objects/src/test/java/org/eclipse/mosaic/lib/objects/detector/SizeTest.java
new file mode 100644
index 00000000..f73faa3e
--- /dev/null
+++ b/co-simulation/lib/mosaic-objects/src/test/java/org/eclipse/mosaic/lib/objects/detector/SizeTest.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2023 LEIDOS.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.eclipse.mosaic.lib.objects.detector;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+public class SizeTest {
+ @Test
+ public void testGetterSetterConstructor() {
+ Size size = new Size(23, 55.3, 5);
+ assertEquals(23, size.getLength(), 0.01);
+ assertEquals(55.3, size.getHeight(), 0.01);
+ assertEquals(5, size.getWidth(), 0.01);
+ }
+ @Test
+ public void testEquals(){
+ Size size = new Size(23, 55.3, 5);
+ Size size1 = new Size(23, 55.3, 5);
+ assertEquals(size, size1);
+ assertEquals(size.hashCode(), size1.hashCode());
+ }
+}