Skip to content

Commit

Permalink
Feature/carma messenger ambassador (#228)
Browse files Browse the repository at this point in the history
<!-- Thanks for the contribution, this is awesome. -->

# PR Details
## Description

<!--- Describe your changes in detail -->
Implement carma messenger ambassador
## Related GitHub Issue

<!--- This project only accepts pull requests related to open GitHub
issues or Jira Keys -->
<!--- If suggesting a new feature or change, please discuss it in an
issue first -->
<!--- If fixing a bug, there should be an issue describing it with steps
to reproduce -->
<!--- Please DO NOT name partially fixed issues, instead open an issue
specific to this fix -->
<!--- Please link to the issue here: -->

## Related Jira Key
CXC-88
<!-- e.g. CAR-123 -->

## Motivation and Context

<!--- Why is this change required? What problem does it solve? -->

## How Has This Been Tested?

<!--- Please describe in detail how you tested your changes. -->
<!--- Include details of your testing environment, and the tests you ran
to -->
<!--- see how your change affects other areas of the code, etc. -->

## Types of changes

<!--- What types of changes does your code introduce? Put an `x` in all
the boxes that apply: -->

- [ ] Defect fix (non-breaking change that fixes an issue)
- [x] New feature (non-breaking change that adds functionality)
- [ ] Breaking change (fix or feature that cause existing functionality
to change)

## Checklist:

<!--- Go over all the following points, and put an `x` in all the boxes
that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're
here to help! -->

- [ ] I have added any new packages to the sonar-scanner.properties file
- [ ] My change requires a change to the documentation.
- [ ] I have updated the documentation accordingly.
- [ ] I have read the
[**CONTRIBUTING**](https://github.com/usdot-fhwa-stol/carma-platform/blob/develop/Contributing.md)
document.
- [ ] I have added tests to cover my changes.
- [ ] All new and existing tests passed.
  • Loading branch information
EricChen-Lei authored Oct 23, 2024
2 parents 1132597 + 267911c commit a8d7ad4
Show file tree
Hide file tree
Showing 41 changed files with 2,535 additions and 832 deletions.
6 changes: 6 additions & 0 deletions co-simulation/fed/mosaic-application/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@
<version>${mosaic.version}</version>
<type>test-jar</type>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.eclipse.mosaic</groupId>
<artifactId>mosaic-application</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>

Expand Down
138 changes: 138 additions & 0 deletions co-simulation/fed/mosaic-carma-messenger/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.eclipse.mosaic</groupId>
<artifactId>mosaic-parent</artifactId>
<version>22.1-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

<artifactId>mosaic-carma-messenger</artifactId>
<name>CARMA Messenger Ambassador</name>

<dependencies>
<dependency>
<groupId>org.eclipse.mosaic</groupId>
<artifactId>mosaic-rti-api</artifactId>
<version>${mosaic.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.mosaic</groupId>
<artifactId>mosaic-objects</artifactId>
<version>${mosaic.version}</version>
</dependency>
<dependency>
<groupId>gov.dot.fhwa.saxton</groupId>
<artifactId>mosaic-carma-utils</artifactId>
<version>${mosaic.version}</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.9</version>
</dependency>
<dependency>
<groupId>org.eclipse.mosaic</groupId>
<artifactId>mosaic-interactions</artifactId>
<version>${mosaic.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.mosaic</groupId>
<artifactId>mosaic-utils</artifactId>
<version>${mosaic.version}</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.mosaic</groupId>
<artifactId>mosaic-geomath</artifactId>
<version>${mosaic.version}</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.mosaic</groupId>
<artifactId>mosaic-objects</artifactId>
<version>${mosaic.version}</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.mosaic</groupId>
<artifactId>mosaic-application</artifactId>
<version>22.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.15</version>
</dependency>
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>2.3.2</version>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.2</version>
</dependency>
<dependency>
<groupId>org.eclipse.mosaic</groupId>
<artifactId>mosaic-utils</artifactId>
<version>${mosaic.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.eclipse.mosaic</groupId>
<artifactId>mosaic-carma</artifactId>
<version>22.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.eclipse.mosaic</groupId>
<artifactId>mosaic-common-utils</artifactId>
<version>22.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>

<profiles>
<profile>
<id>skip-carma-messenger-tests</id>

<build>
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</profile>
</profiles>
</project>
Original file line number Diff line number Diff line change
@@ -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.fed.carmamessenger.ambassador;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;

import org.eclipse.mosaic.lib.CommonUtil.ambassador.CommonInstance;


public class CarmaMessengerInstance extends CommonInstance{

private String messengerEmergencyState;
private int rxBridgeMessagePort;

public CarmaMessengerInstance(String carmaMessengerVehicleId, String sumoRoleName, InetAddress targetAddress, int v2xPort, int timeSyncPort, String messengerEmergencyState, int rxBridgeMessagePort) {
super(carmaMessengerVehicleId, sumoRoleName, targetAddress, v2xPort, timeSyncPort);
this.messengerEmergencyState = messengerEmergencyState;
this.rxBridgeMessagePort = rxBridgeMessagePort;
}
/**
* Carma Messenger Emergency state
*/

public String getMessengerEmergencyState() {
return messengerEmergencyState;
}

public void setMessengerEmergencyState(String messengerEmergencyState) {
this.messengerEmergencyState = messengerEmergencyState;
}

public int getRxBridgeMessagePort() {
return rxBridgeMessagePort;
}

public void setRxBridgeMessagePort(int rxBridgeMessagePort) {
this.rxBridgeMessagePort = rxBridgeMessagePort;
}

public void sendVehStatusMsgs(byte[] data) throws IOException {
if (super.rxMsgsSocket == null) {
throw new IllegalStateException("Attempted to send data before opening socket");
}

DatagramPacket packet = new DatagramPacket(data, data.length, super.getTargetAddress(), rxBridgeMessagePort);
super.rxMsgsSocket.send(packet);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
* 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.carmamessenger.ambassador;

import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;

import org.eclipse.mosaic.lib.CommonUtil.ambassador.CommonInstanceManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.gson.Gson;

import gov.dot.fhwa.saxton.TimeSyncMessage;

public class CarmaMessengerInstanceManager extends CommonInstanceManager<CarmaMessengerInstance, CarmaMessengerRegistrationMessage>{

private static final int BRIDGE_TARGET_PORT = 5500;
private final Logger log = LoggerFactory.getLogger(this.getClass());

/**
* Callback to invoked when a new CARMA Platform instance registers with the mosaic-carma ambassador for the first time
* @param registration The new instance's registration data
*/
public void onNewRegistration(CarmaMessengerRegistrationMessage registration) {
super.setTargetPort(5600);
if (!managedInstances.containsKey(registration.getVehicleRole())) {
try {
newCarmaMessengerInstance(
registration.getVehicleId(),
registration.getVehicleRole(),
InetAddress.getByName(registration.getRxMessageIpAddress()),
registration.getRxMessagePort(),
registration.getRxTimeSyncPort(),
registration.getMessengerEmergencyState(),
registration.getRxBridgeMessagePort()
);
} catch (UnknownHostException e) {
throw new RuntimeException(e);
}
} else {
// log warning
log.warn("Received duplicate registration for vehicle " + registration.getVehicleRole());
}
}

/**
* 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
*/
@Override
public void onTimeStepUpdate(TimeSyncMessage message) throws IOException {
if (managedInstances.size() == 0) {
log.debug("There are no registered instances");
}
else {
Gson gson = new Gson();
byte[] bytes = gson.toJson(message).getBytes();
for (CarmaMessengerInstance currentInstance : managedInstances.values()) {
log.debug("Sending CARMA Messenger instance {} at {}:{} time sync message for time {}!" ,
currentInstance.getVehicleId(),
currentInstance.getTargetAddress(),
currentInstance.getTimeSyncPort(),
currentInstance.getMessengerEmergencyState(),
message.getTimestep());
currentInstance.sendTimeSyncMsg(bytes);
}
}
}


/**
* Helper function to configure a new CARMA Platform instance object upon registration
* @param carmaMessengerVehId The CARMA Platform vehicle ID (e.g. it's license plate number)
* @param sumoRoleName The Role Name associated with the CARMA Platform's ego vehicle in CARLA
* @param targetAddress The IP address to which received simulated V2X messages should be sent
* @param v2xPort The port to which received simulated V2X messages should be sent
* @param timeSyncPort The port to which to send time sync messages.
*/
private void newCarmaMessengerInstance(String carmaMessengerVehId, String sumoRoleName, InetAddress targetAddress, int v2xPort, int timeSyncPort, String messengerEmergencyState, int rxBridgeMessagePort) {
CarmaMessengerInstance tmp = new CarmaMessengerInstance(carmaMessengerVehId, sumoRoleName, targetAddress, v2xPort, timeSyncPort, messengerEmergencyState, rxBridgeMessagePort);
try {
tmp.bind();
log.info("New CARMA Messenger instance '{}' registered with CARMA Instance Manager.", sumoRoleName);
} catch (IOException e) {
log.error("Failed to bind CARMA Messenger instance with ID '{}' to its RX message socket: {}",
sumoRoleName, e.getMessage());
log.error("Stack trace:", e);
throw new RuntimeException(e);
}
managedInstances.put(sumoRoleName, tmp);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* 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.carmamessenger.ambassador;

import org.eclipse.mosaic.lib.CommonUtil.ambassador.CommonMessageAmbassador;
import org.eclipse.mosaic.lib.CommonUtil.configuration.CommonConfiguration;
import org.eclipse.mosaic.lib.util.objects.ObjectInstantiation;
import org.eclipse.mosaic.rti.api.parameters.AmbassadorParameter;

public class CarmaMessengerMessageAmbassador extends CommonMessageAmbassador<CarmaMessengerInstanceManager, CarmaMessengerRegistrationReceiver, CarmaMessengerRegistrationMessage, CommonConfiguration>{


/**
* Create a new {@link CarmaMessengerMessageAmbassador} object.
*
* @param ambassadorParameter includes parameters for the
* CarmaMessageAmbassador.
*/
public CarmaMessengerMessageAmbassador(AmbassadorParameter ambassadorParameter) {
super(ambassadorParameter, CarmaMessengerRegistrationMessage.class, CommonConfiguration.class);

try {
// Read the CARMA message ambassador configuration file
commonConfiguration = new ObjectInstantiation<>(CommonConfiguration.class, log)
.readFile(ambassadorParameter.configuration);
} catch (InstantiationException e) {
log.error("Configuration object could not be instantiated: ", e);
}

log.info("The update interval of CARMA message ambassador is " + commonConfiguration.updateInterval + " .");

// Check the CARMA update interval
if (commonConfiguration.updateInterval <= 0) {
throw new RuntimeException("Invalid update interval for CARMA message ambassador, should be >0.");
}
log.info("CARMA message ambassador is generated.");
}

}
Loading

0 comments on commit a8d7ad4

Please sign in to comment.