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