Aufgrund einer Wartung wird GitLab am 18.01. zwischen 8:00 und 9:00 Uhr kurzzeitig nicht zur Verfügung stehen. / Due to maintenance, GitLab will be temporarily unavailable on 18.01. between 8:00 and 9:00 am.

Commit 1144e736 authored by Evgeny Kusmenko's avatar Evgeny Kusmenko
Browse files

Merge branch 'ee-infrastructre' into 'master'

ee infrastructure

See merge request !28
parents b7dab289 8a6315c1
Pipeline #188374 failed with stage
in 34 seconds
......@@ -5,8 +5,6 @@
# can be found under https://github.com/MontiCore/monticore.
#
# (c) https://github.com/MontiCore/monticore
#
stages:
- windows
......
# (c) https://github.com/MontiCore/monticore
script:
- git checkout ${TRAVIS_BRANCH}
- mvn -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn -B clean install cobertura:cobertura org.eluder.coveralls:coveralls-maven-plugin:report --settings "settings.xml"
......
<!-- (c) https://github.com/MontiCore/monticore -->
# Simulation
![pipeline](https://git.rwth-aachen.de/monticore/EmbeddedMontiArc/simulators/simulation/badges/master/build.svg)
![coverage](https://git.rwth-aachen.de/monticore/EmbeddedMontiArc/simulators/simulation/badges/master/coverage.svg)
......
# Bus
This part of the project includes the classes for the simulation of diffrent buses.
# An exaple of a bussystem
This picture ![picture](/docs/busexample.jpg) [here](https://git.rwth-aachen.de/monticore/EmbeddedMontiArc/simulators/simulation/blob/ee-infrastructre/bus/docs/BusExample.jpg) shows an example bus system with the buses A,B,C , the actuator 1-6 and the bridges ab and bc. The times, shown in red, describes the delay by using the specific component, the arrows describe which actuator sends or want to recieve the message Mes1 (green), send by actuator one, and Mess2 (blue), send by actuator five.
# How does the bus is used
This sequence diagram ![diagram](/docs/sequencediagram.jpg) [here](https://git.rwth-aachen.de/monticore/EmbeddedMontiArc/simulators/simulation/blob/ee-infrastructre/bus/docs/SequenceDiagram.jpg) describes the function calls to transmit Mes2 from actuator five to actuator two. Actuator act5 creates an event of type busMessage and register it at the simulator by using the function `addEvent()` of the simulator. In regular time steps, the simulator got the function call `simualteFor(time)`. The simulator will start to process all registered events with an event time lower than the argument `time`. For processing, the simulator uses the function `processEvent()` of the target component saved in the busMessage. This function will process the event individually, depending on the target component type.
Bridges create new events with a new target bus.
Actuators use the information send in the busMessage.
Buses create new keepAlive events for themselves with the event time when the incoming busMessage will be transmitted completely. KeepAlive events will be processed by the bus by sending the original busMessage to all next receivers.
# How does the event queue of the simulator works
This diagram ![diagram](/docs/eventqueue.jpg) [here](https://git.rwth-aachen.de/monticore/EmbeddedMontiArc/simulators/simulation/blob/ee-infrastructre/bus/docs/EventQueue.jpg) describes how the event queue of the simulator develops over a time period after the actuators one and five have added their messages and the simulator have gotten the `simulateFor()` call. The arrows show which event is created based on the actual event. The red dashed lines mark the events that are not processed this time, depending on the time of the events.
For example, at the beginning, the fist entry of the event queue ist the message 1 with target bus A at the time 0. The simulator will use the function `processEvent(Mes1)` of the bus A. In the following bus A will create a KeepAlive event with target bus A and time 2. The time of this keepAlive event is the time when the bus would have transmitted the whole message Mes1 to the next components. In the next step, the simulator will choose the first event again. It will call `processEvent(KeepAlive)` of the bus and the bus will create two new busMessages to each component, wich want to receive the message 1.
(c) https://github.com/MontiCore/monticore
The license generally applicable for this project
can be found under https://github.com/MontiCore/monticore.
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<!--
(c) https://github.com/MontiCore/monticore
The license generally applicable for this project
can be found under https://github.com/MontiCore/monticore.
-->
<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 PROJECT -->
<parent>
<artifactId>simulation</artifactId>
<groupId>montisim</groupId>
<version>${revision}</version>
</parent>
<!-- OUR OWN PROJECT -->
<artifactId>bus</artifactId>
<groupId>montisim-simulation</groupId>
<version>${revision}</version>
<!-- PROJECT DEPENDENCIES -->
<dependencies>
<!-- https://mvnrepository.com/artifact/junit/junit -->
<!-- All modules have dependency to util -->
<dependency>
<groupId>montisim-simulation</groupId>
<artifactId>util</artifactId>
<version>${revision}</version>
</dependency>
<!-- Bus has dependency to environment -->
<dependency>
<groupId>montisim-simulation</groupId>
<artifactId>environment</artifactId>
<version>${revision}</version>
</dependency>
<!-- Bus has dependency to navigation -->
<dependency>
<groupId>montisim-controller</groupId>
<artifactId>navigation</artifactId>
<version>${controller.version}</version>
</dependency>
<!-- Bus has dependency to commons -->
<dependency>
<groupId>montisim</groupId>
<artifactId>commons</artifactId>
<version>${commons.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.1</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>11.0.2</version>
</dependency>
<dependency>
<groupId>montisim</groupId>
<artifactId>hardware_emulator</artifactId>
<version>${hardwareemulator.version}</version>
</dependency>
</dependencies>
<!-- PROJECT PLUGINS AND PROPERTIES -->
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
<configuration>
<useSystemClassLoader>false</useSystemClassLoader>
<!-- Set root directory to ensure same execution context in subprojects
(e.g. for Log in test mode) -->
<workingDirectory>${project.parent.basedir}</workingDirectory>
</configuration>
</plugin>
</plugins>
</build>
<properties>
<!-- Set root directory to ensure same execution context in subprojects
(e.g. for Log in test mode) -->
<main.basedir>${project.parent.basedir}</main.basedir>
<!-- Specify Java 8 as version to avoid compile warnings -->
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
</project>
\ No newline at end of file
/**
* (c) https://github.com/MontiCore/monticore
*
* The license generally applicable for this project
* can be found under https://github.com/MontiCore/monticore.
*/
package simulation.EESimulator;
import java.time.Instant;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import de.rwth.monticore.EmbeddedMontiArc.simulators.commons.controller.commons.BusEntry;
import org.apache.commons.math3.exception.NullArgumentException;
import simulation.bus.BusMessage;
/**
* Abstract class that implements all common functionality of EEComponents.
*/
abstract class AbstractEEComponent implements EEComponent{
private final EESimulator simulator;
private final EEComponentType componentType;
private final UUID Id;
public AbstractEEComponent(EESimulator simulator, EEComponentType type) {
if (simulator == null || type == null) {
throw new NullArgumentException();
}
this.simulator = simulator;
this.componentType = type;
this.Id = UUID.randomUUID();
}
@Override
public EEComponentType getComponentType() {
return componentType;
}
@Override
public EESimulator getSimulator() {
return simulator;
}
@Override
public UUID getId() {
return Id;
}
/**
* Send message to all targets that are registered for this message in targetsByMessageId
* @param message message to be send
* @param messageLen length of message in bytes
* @param messageId message id of the message
* @param eventTime time when the message is sent
*/
@Override
public void sendMessage(Object message, int messageLen , BusEntry messageId, Instant eventTime) {
List<EEComponent> targets = this.getTargetsByMessageId().getOrDefault(messageId, Collections.emptyList());
for(EEComponent target : targets) {
BusMessage msg = new BusMessage(message, 6, messageId,
eventTime, this.getId(), target);
this.getSimulator().addEvent(msg);
}
}
}
/**
* (c) https://github.com/MontiCore/monticore
*
* The license generally applicable for this project
* can be found under https://github.com/MontiCore/monticore.
*/
package simulation.EESimulator;
import de.rwth.monticore.EmbeddedMontiArc.simulators.commons.controller.commons.BusEntry;
import simulation.bus.Bus;
import simulation.bus.BusMessage;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.time.Duration;
import org.apache.commons.lang3.tuple.Pair;
/**
* Used to connect to buses.
*/
public class Bridge extends MutableEEComponent{
/**
* The two buses that should be connected
*/
protected Pair<Bus, Bus> connected;
/**
* The delay that is added to each event if it is transmitted over this bride.
*/
private final Duration delay;
public Bridge (Pair<Bus, Bus> connected, Duration delay){
super(connected.getLeft().getSimulator(), EEComponentType.BRIDGE);
if(connected.getLeft().getSimulator() != connected.getRight().getSimulator()) {
throw new IllegalArgumentException("Bus with different simulators can not be connected");
}
this.connected = connected;
this.delay = delay;
//initialize subscribed messages and targetsByMessageId
Set<BusEntry> subscribedMessages = new HashSet<BusEntry>(connected.getKey().getSubscribedMessages());
subscribedMessages.addAll(connected.getValue().getSubscribedMessages());
this.subscribedMessages.addAll(subscribedMessages);
for(BusEntry messageId : subscribedMessages) {
List<EEComponent> targets = new ArrayList<EEComponent>();
if(connected.getKey().getSubscribedMessages().contains(messageId)) {
targets.add(connected.getKey());
}
if(connected.getValue().getSubscribedMessages().contains(messageId)) {
targets.add(connected.getValue());
}
this.targetsByMessageId.put(messageId, targets);
}
connected.getKey().registerComponent(this);
connected.getValue().registerComponent(this);
}
@Override
public void processEvent(EEDiscreteEvent event){
if(event.getEventType() == EEDiscreteEventTypeEnum.BUSMESSAGE){
BusMessage msg = (BusMessage) event;
msg.setFinishTime(msg.getEventTime().plus(delay));
msg.transmitBytes(msg.getMessageLen(), 0);
if(msg.getControllerID() == connected.getLeft().getId()) {
this.getSimulator().addEvent(msg.forwardTo(connected.getRight()));
}
else if(msg.getControllerID() == connected.getRight().getId()) {
this.getSimulator().addEvent(msg.forwardTo(connected.getLeft()));
}
else {
throw new IllegalArgumentException("Message from invalid controller" + msg.getControllerID() + "received at: " + this.toString());
}
}
else{
throw new IllegalArgumentException("Only BusMessages events expected at " + this.toString() + " but was: " + event.getEventType());
}
}
/**
* Updates the subscribed messages of this and the other connected buses.
* Add bus as target for messages ids.
* @param bus Bus which needs the messages with messageIds
* @param messageIds Ids of messages that bus wants to receive.
*/
public void update(Bus bus, List<BusEntry> messageIds){
for(BusEntry messageId : messageIds) {
List<EEComponent> targets = this.targetsByMessageId.getOrDefault(messageId, new ArrayList<EEComponent>());
targets.add(bus);
this.targetsByMessageId.put(messageId, targets);
if(!subscribedMessages.contains(messageId)) {
this.subscribedMessages.add(messageId);
}
}
if(bus.equals(connected.getKey())){
connected.getValue().addSubscribedMessages(this, messageIds);
}
else{
if(bus.equals(connected.getValue())){
connected.getKey().addSubscribedMessages(this, messageIds);
}
else{
throw new IllegalArgumentException("Message send by unknown Bus.");
}
}
}
public Pair<Bus, Bus> getConnectedBuses() {
return this.connected;
}
public Duration getDelay() {
return delay;
}
}
/**
* (c) https://github.com/MontiCore/monticore
*
* The license generally applicable for this project
* can be found under https://github.com/MontiCore/monticore.
*/
package simulation.EESimulator;
import com.google.common.collect.Sets;
import de.rwth.monticore.EmbeddedMontiArc.simulators.commons.controller.commons.BusEntry;
import de.rwth.monticore.EmbeddedMontiArc.simulators.commons.controller.interfaces.FunctionBlockInterface;
import simulation.bus.Bus;
import java.util.*;
/**
* Wrapper for a function block that always sends the messages.
*/
public class ConstantFunctionBlockAsEEComponent extends ImmutableEEComponent{
/**
* BusEntries that are send by this component by their name.
*/
private Map<String, BusEntry> busEntryByName = new HashMap<>();
/**
* Size of the message by BusEntry
*/
private final HashMap<BusEntry, Integer> sizeByMessageId;
/**
* Create a constant function block as EEComponent with default settings.
* @param buses Buses that the EEComponent should be connected
* @param sizeByMessageId Size of the messages that are transmitted
* @param functionBlock The function block that is wrapped.
* @return ConstantFunctionBlockAsEEComponent
*/
public static ConstantFunctionBlockAsEEComponent createConstantFunctionBlockAsEEComponent(List<Bus> buses, HashMap<BusEntry, Integer> sizeByMessageId, FunctionBlockInterface functionBlock){
if(buses == null || buses.isEmpty()){
throw new IllegalArgumentException("Buses can not be null or empty");
}
Set<String> outputMessageNames = functionBlock.getOutputs().keySet();
List<EEComponent> targets = new ArrayList<>(buses);
HashMap<BusEntry, List<EEComponent>> targetsByMessageId = new HashMap<>();
for(BusEntry entry : BusEntry.values()){
if(outputMessageNames.contains(entry.toString())){
targetsByMessageId.put(entry, targets);
}
}
return new ConstantFunctionBlockAsEEComponent(buses.get(0).getSimulator(), targetsByMessageId, sizeByMessageId, functionBlock);
}
/**
* Create a constant function block as EEComponent with default settings.
* @param bus Bus that the EEComponent should be connected
* @param sizeByMessageId Size of the messages that are transmitted
* @param functionBlock The function block that is wrapped.
* @return ConstantFunctionBlockAsEEComponent
*/
public static ConstantFunctionBlockAsEEComponent createConstantFunctionBlockAsEEComponent(Bus bus, HashMap<BusEntry, Integer> sizeByMessageId, FunctionBlockInterface functionBlock){
return createConstantFunctionBlockAsEEComponent(Collections.singletonList(bus), sizeByMessageId, functionBlock);
}
public ConstantFunctionBlockAsEEComponent(EESimulator simulator, HashMap<BusEntry, List<EEComponent>> targetsByMessageId, HashMap<BusEntry, Integer> sizeByMessageId, FunctionBlockInterface functionBlock) {
super(simulator, EEComponentType.FUNCTION_BLOCK, Collections.emptyList(), targetsByMessageId);
if(Sets.symmetricDifference(targetsByMessageId.keySet(), sizeByMessageId.keySet()).size() != 0){
throw new IllegalArgumentException("targetsByMessageId and sizeByMessageId have to have the same keys.");
}
for(BusEntry entry : targetsByMessageId.keySet()){
busEntryByName.put(entry.toString(), entry);
}
this.sizeByMessageId = sizeByMessageId;
this.setConstantOutput(functionBlock.getOutputs());
}
/**
* Send the constant messages by the wrapped function block
* @param outputs Messages that should be send. Indexed by the names of the message Ids.
*/
private void setConstantOutput(Map<String, Object> outputs) {
for(Map.Entry<String, Object> entry : outputs.entrySet()){
BusEntry messageId = busEntryByName.get(entry.getKey());
this.sendMessage(entry.getValue(), sizeByMessageId.get(messageId), messageId, getSimulator().getSimulationTime());
}
}
@Override
public void processEvent(EEDiscreteEvent event) {
throw new UnsupportedOperationException("Constant function block does not expect any event. Event was: " + event);
}
}
/**
* (c) https://github.com/MontiCore/monticore
*
* The license generally applicable for this project
* can be found under https://github.com/MontiCore/monticore.
*/
package simulation.EESimulator;
import java.time.Instant;
public class ControllerExecuteEvent extends EEDiscreteEvent {
public ControllerExecuteEvent(Instant eventTime, EEComponent target) {
super(EEDiscreteEventTypeEnum.CONTROLLER_EXECUTE_EVENT, eventTime, target);
}
}
/**
* (c) https://github.com/MontiCore/monticore
*
* The license generally applicable for this project
* can be found under https://github.com/MontiCore/monticore.
*/
package simulation.EESimulator;
import de.rwth.monticore.EmbeddedMontiArc.simulators.commons.controller.commons.BusEntry;
import de.rwth.monticore.EmbeddedMontiArc.simulators.hardware_emulator.HardwareEmulatorInterface;
import org.apache.commons.math3.linear.RealVector;
import simulation.bus.Bus;
import simulation.bus.BusMessage;
import java.io.Serializable;
import java.time.Duration;
import java.time.Instant;
import java.util.*;
import static com.vividsolutions.jts.util.Memory.free;
/**
* Autopilot that communicate directly with the HardwareEmulatorServer.
* Controls the velocity and path of the vehicle.
* Calculates actuator values for brakes, engine, steering.
*/
public class DirectModelAsEEComponent extends ImmutableEEComponent {
private static final int MAX_TRAJECTORY_LENGTH = 100;
/**
* Last values that were send indexed by the bus entry
*/
private Map<Object, BusEntry> lastValueByMessageId = new HashMap<>();
/**
* Necessary messages that the controller needs
*/
private static final ArrayList<BusEntry> STANDARD_SUBSCRIBED_MESSAGES = new ArrayList<BusEntry>() {{
add(BusEntry.SENSOR_VELOCITY);
add(BusEntry.SENSOR_GPS_COORDINATES);
add(BusEntry.SENSOR_COMPASS);
add(BusEntry.ACTUATOR_ENGINE_CURRENT);
add(BusEntry.ACTUATOR_BRAKE_CURRENT);
add(BusEntry.ACTUATOR_STEERING_CURRENT);
add(BusEntry.PLANNED_TRAJECTORY_X);
add(BusEntry.PLANNED_TRAJECTORY_Y);
}};
/**
* Outputs when created for a MassPointVehicle
*/
public static final ArrayList<BusEntry> MASSPOINT_OUTPUT_MESSAGES = new ArrayList<BusEntry>() {{
add(BusEntry.ACTUATOR_STEERING);
add(BusEntry.ACTUATOR_BRAKE);
add(BusEntry.ACTUATOR_ENGINE);
}};
/**
* Determines if the controller has received new inputs
*/
boolean newInputs = false;
/**
* Determines if the controller needs to start the calculation again afer receiving the next message.
*/
boolean wakeUpNeeded = false;
/**
* The duration of the an update cycle of this controller
*/
Duration cycleTime;
/**
* Direct reference to the hardware emulator
*/
HardwareEmulatorInterface modelServer;
int modelId;
HashMap<String, Serializable> inputs = new HashMap<String, Serializable>();
HashMap<String, Serializable> outputs = new HashMap<String, Serializable>();
Optional<Object> trajectoryX = Optional.empty();
Optional<Object> trajectoryY = Optional.empty();
/**
* Time when the controller was executed last
*/
Instant lastFinishTime = Instant.EPOCH;
/**
* Create a DirectModelAsEEComponent that is connected to bus.
* @param bus Bus that the DirectModelAsEEComponent is connected to
* @return DirectModelAsEEComponent with default configuration
*/
public static DirectModelAsEEComponent createDirectModelAsEEComponent(Bus bus) {
return createDirectModelAsEEComponent(Collections.singletonList(bus));
}
/**
* Create a DirectModelAsEEComponent that is connected to bus.
* @param buses Buses that the DirectModelAsEEComponent is connected to
* @return DirectModelAsEEComponent with default configuration
*/
public static DirectModelAsEEComponent createDirectModelAsEEComponent(List<Bus> buses){
HashMap<BusEntry, List<EEComponent>> targetsByMessageId = new HashMap<>();
targetsByMessageId.put(BusEntry.ACTUATOR_BRAKE, new LinkedList<>());
targetsByMessageId.put(BusEntry.ACTUATOR_STEERING, new LinkedList<>());
targetsByMessageId.put(BusEntry.ACTUATOR_ENGINE, new LinkedList<>());
for (Bus bus : buses) {
if (bus.subscribedMessages.contains(BusEntry.ACTUATOR_ENGINE)) {
targetsByMessageId.get(BusEntry.ACTUATOR_ENGINE).add(bus);
}
if (bus.subscribedMessages.contains(BusEntry.ACTUATOR_STEERING)) {
targetsByMessageId.get(BusEntry.ACTUATOR_STEERING).add(bus);
}
if (bus.subscribedMessages.contains(BusEntry.ACTUATOR_BRAKE)) {
targetsByMessageId.get(BusEntry.ACTUATOR_BRAKE).add(bus);
}
}