Commit e5066da9 authored by Jean Meurice's avatar Jean Meurice
Browse files

Intermediate Commit

parent f722eb73
Pipeline #275791 failed with stage
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -31,9 +31,9 @@ public class ComponentManager {
private final Vector<Integer> componentPriority = new Vector<>();
private final HashMap<String, EEEventProcessor> componentsByName = new HashMap<>();
// Non-Bridge and Non-Bus components
private final List<EEComponent> components = new ArrayList<>();
private final List<Bridge> bridges = new ArrayList<>();
private final List<Bus> buses = new ArrayList<>();
public final List<EEComponent> components = new ArrayList<>();
public final List<Bridge> bridges = new ArrayList<>();
public final List<Bus> buses = new ArrayList<>();
private final EESetupErrors errors;
public ComponentManager(EESetupErrors errors){
......@@ -108,7 +108,7 @@ public class ComponentManager {
}
}
// Currently: minimizes traffic
// Currently: minimizes traffic -> Assumes the components & bridges are configured to send/transmit only messages where they are required
public void finalizeSetup() {
if (componentTable.size() == 0) return;
// Create EE system graph.
......@@ -154,27 +154,37 @@ public class ComponentManager {
}
}
// Propagate outputs:
final class InputInfo {
boolean covered = false;
boolean multiple = false;
List<String> senders = null;
}
// Propagate outputs:
// - For all INPUTS: boolean tables: flag if message is sent by someone
Vector<HashMap<String, Boolean>> inputsCovered = graph.<HashMap<String, Boolean>>newColor(null);
Vector<HashMap<String, InputInfo>> inputsCovered = graph.<HashMap<String, InputInfo>>newColor(null);
for (EEComponent ec : components){
List<PortInformation> ports = ec.getInputPorts();
if (ports.size() > 0){
HashMap<String, Boolean> map = new HashMap<>();
HashMap<String, InputInfo> map = new HashMap<>();
inputsCovered.set(ec.id, map);
for (PortInformation p : ports){
map.put(p.msg.name, false);
map.put(p.msg.name, new InputInfo());
}
}
}
// 2nd usage of inputsCovered: for buses & bridges: mark messages that are already routed
// Used when an output is already sent and routed by another component -> When the routing encounters
// a bus or bridge which already transmits the message -> stop the search there and mark as "using"
Vector<Boolean> usesOutput = graph.newColor(false);
// - Per output port:
for (EEComponent ec : components){
List<PortInformation> ports = ec.getOutputPorts();
for (PortInformation p : ports){
boolean multiple = false;
List<String> senders = null;
// - Propagate reachable:
// - Error if same output
// - Mark input table
......@@ -198,17 +208,31 @@ public class ComponentManager {
parent.set(a, next);
if (type.get(a) == 2){
List<PortInformation> outputs = ((EEComponent) componentTable.get(a)).getOutputPorts();
EEComponent ec2 = ((EEComponent) componentTable.get(a));
List<PortInformation> outputs = ec2.getOutputPorts();
for (PortInformation o : outputs)
if (o.msg.name.equals(p.msg.name))
errors.addOutputOverlap(p.msg.name, new EEOutputOverlapException(ec.name));
HashMap<String, Boolean> map = inputsCovered.get(a);
if (o.msg.name.equals(p.msg.name)){
if (senders == null){
senders = new ArrayList<>();
senders.add(ec.name);
}
senders.add(ec2.name);
multiple = true; // Detect if multiple components send the same message
}
// Check if the component has the message as input
HashMap<String, InputInfo> map = inputsCovered.get(a);
if (map != null && map.containsKey(p.msg.name)){
map.put(p.msg.name, true);
map.get(p.msg.name).covered = true;
usesOutput.set(a, true);
}
} else {
stack.push(a); // Only propagate through Buses and Bridges
HashMap<String, InputInfo> map = inputsCovered.get(a);
if (map != null && map.containsKey(p.msg.name)){
usesOutput.set(a, true); // Routing for this message is already covered from here on
} else {
stack.push(a); // Simply propagate through Buses and Bridges
}
}
}
}
......@@ -221,6 +245,16 @@ public class ComponentManager {
if (usesOutput.get(j)){
stack.push(j);
visited.set(j, true);
// Set "multiple" flag
if (multiple && type.get(j) == 2){
HashMap<String, InputInfo> map = inputsCovered.get(j);
if (map != null && map.containsKey(p.msg.name)){
InputInfo info = map.get(p.msg.name);
info.multiple = true;
info.senders = senders;
}
}
}
}
// - Warning if not used
......@@ -246,6 +280,18 @@ public class ComponentManager {
for (int j = 0; j < componentTable.size(); ++j){
if (usesOutput.get(j)){
int t = type.get(j);
if (t == 0 || t == 1){
HashMap<String, InputInfo> map = inputsCovered.get(j);
if (map != null && map.containsKey(p.msg.name)){
continue; // Routing for this message is already covered
}
// Mark the bus or bridge as routing the message
if (map == null){
map = new HashMap<>();
inputsCovered.set(j, map);
}
map.put(p.msg.name, null);
}
if (ec.id == j || t == 1){
List<Bus> targets = new ArrayList<>();
for (int n : graph.adjacencies.get(j)){
......@@ -276,15 +322,21 @@ public class ComponentManager {
}
// Check input tables: error if non-optional not covered.
int i = -1;
for (HashMap<String,Boolean> map : inputsCovered){
++i;
for (EEComponent c : components){
HashMap<String,InputInfo> map = inputsCovered.get(c.id);
if (map == null) continue;
EEComponent c = ((EEComponent) componentTable.get(i));
for (PortInformation p : c.getInputPorts()){
if (!map.get(p.msg.name) && !p.optional){
errors.missingOutputExceptions.add(new EEMissingOutputException(p.msg.name, c.name));
InputInfo info = map.get(p.msg.name);
if (info == null){
// Check optional
if (!p.optional)
errors.missingOutputExceptions.add(new EEMissingOutputException(p.msg.name, c.name));
} else {
// Check if the "multipleInputs" flag is respected
if (!p.multipleInputsAllowed && info.multiple)
errors.multipleInputsExceptions.add(new EEMultipleInputsException(c.name, p.msg.name, info.senders));
}
}
}
}
......
......@@ -48,33 +48,29 @@ public abstract class EEComponent extends BusComponent {
return outputPorts;
}
public MessageInformation addInput(String name, DataType type, boolean optional) {
public MessageInformation addInput(String name, DataType type, boolean multipleInputsAllowed, boolean optional) {
MessageInformation m = new MessageInformation(name, type, simulator.messageTypeManager, this);
inputPorts.add(new PortInformation(m, PortDirection.INPUT, optional));
inputPorts.add(new PortInformation(m, PortDirection.INPUT, multipleInputsAllowed, optional));
return m;
}
public MessageInformation addInput(String name, DataType type, boolean multipleInputsAllowed) {
return addInput(name, type, multipleInputsAllowed, false);
}
public MessageInformation addInput(String name, DataType type) {
return addInput(name, type, false);
return addInput(name, type, false, false);
}
public MessageInformation addOptionalInput(String name, DataType type) {
return addInput(name, type, true);
public MessageInformation addOptionalInput(String name, DataType type, boolean multipleInputsAllowed) {
return addInput(name, type, multipleInputsAllowed, true);
}
public MessageInformation addOutput(String name, DataType type, boolean optional) {
public MessageInformation addOutput(String name, DataType type) {
MessageInformation m = new MessageInformation(name, type, simulator.messageTypeManager, this);
outputPorts.add(new PortInformation(m, PortDirection.OUTPUT, optional));
outputPorts.add(new PortInformation(m, PortDirection.OUTPUT, false, true));
return m;
}
public MessageInformation addOutput(String name, DataType type) {
return addOutput(name, type, false);
}
public MessageInformation addOptionalOutput(String name, DataType type) {
return addOutput(name, type, true);
}
@Override
public void process(EEDiscreteEvent event) {
......@@ -90,7 +86,7 @@ public abstract class EEComponent extends BusComponent {
}
}
protected void send(Instant time, Message msg) {
public void send(Instant time, Message msg) {
this.simulator.addEvent(new MessageSendEvent(time, this, msg));
}
......
/**
* (c) https://github.com/MontiCore/monticore
*
* The license generally applicable for this project
* can be found under https://github.com/MontiCore/monticore.
*/
package de.rwth.montisim.simulation.eesimulator.actuator;
import java.time.Duration;
import java.util.logging.Logger;
import de.rwth.montisim.commons.dynamicinterface.DataType;
import de.rwth.montisim.commons.simulation.PhysicalValue;
import de.rwth.montisim.commons.simulation.TimeUpdate;
import de.rwth.montisim.commons.simulation.Updatable;
import de.rwth.montisim.commons.simulation.Updater;
import de.rwth.montisim.simulation.eesimulator.EEComponent;
import de.rwth.montisim.simulation.eesimulator.EEComponentType;
import de.rwth.montisim.simulation.eesimulator.EESimulator;
import de.rwth.montisim.simulation.eesimulator.events.MessageReceiveEvent;
import de.rwth.montisim.simulation.eesimulator.message.Message;
import de.rwth.montisim.simulation.eesimulator.message.MessageInformation;
import de.rwth.montisim.simulation.eesimulator.sensor.SensorLogic;
public class Actuator extends EEComponent implements Updatable {
final SensorLogic sensor;
double targetValue;
final PhysicalValue currentValue;
final double minValue;
final double maxValue;
double changeRate; // Max "value per second" this actuator can actuate.
final boolean sendFeedback; // Whether the actuator senses itself and sends its current value on the bus. ~> "Sensor enabled"
final MessageInformation msgInfo;
public Actuator(
EESimulator simulator, String name, int priority,
PhysicalValue actuatedValue, double minValue, double maxValue, double changeRate,
boolean sendFeedback, Duration updateInterval, Duration readTime, boolean sendOnlyChanged,
Updater updater
){
super(simulator, name, priority);
sensor = new SensorLogic(actuatedValue, updateInterval, readTime, sendOnlyChanged, this);
this.currentValue = actuatedValue;
this.minValue = minValue;
this.maxValue = maxValue;
this.targetValue = actuatedValue.get();
this.changeRate = changeRate;
this.sendFeedback = sendFeedback;
this.msgInfo = addInput("set_"+actuatedValue.name, DataType.newDoubleType());
updater.addUpdatable(this);
}
/** Returns an actuator which doesn't send its value back. */
public static Actuator newSimpleActuator(
EESimulator simulator, String name, int priority,
PhysicalValue actuatedValue, double minValue, double maxValue, double changeRate,
Updater updater
){
return new Actuator(simulator, name, priority, actuatedValue, minValue, maxValue, changeRate, false, Duration.ZERO, Duration.ZERO, true, updater);
}
@Override
public void update(TimeUpdate newTime) {
actuate(newTime);
if (sendFeedback)
sensor.update(newTime);
}
// Can be overwritten for more complex actuation behavior
protected void actuate(TimeUpdate newTime){
double val = currentValue.get();
double maxChange = changeRate*newTime.deltaSeconds;
double delta = targetValue - val;
if (Math.abs(delta) > maxChange){
delta = Math.signum(delta) * maxChange;
}
val += delta;
if (val > maxValue)
val = maxValue;
if (val < minValue)
val = minValue;
currentValue.set(val);
}
@Override
protected void receive(MessageReceiveEvent msgRecvEvent) {
Message msg = msgRecvEvent.getMessage();
if (msg.msgId == msgInfo.messageId){
targetValue = (Double)msg.message;
} else {
Logger.getLogger("Warnings").warning("Actuator \""+name+"\" received unexpected message: " + simulator.getMessageTypeManager().getMsgInfo(msg.msgId).name);
}
}
@Override
public EEComponentType getComponentType() {
return EEComponentType.ACTUATOR;
}
}
\ No newline at end of file
......@@ -12,6 +12,7 @@ import java.util.Optional;
import java.util.PriorityQueue;
import java.util.Random;
import de.rwth.montisim.commons.utils.Time;
import de.rwth.montisim.simulation.eesimulator.EESimulator;
import de.rwth.montisim.simulation.eesimulator.bus.Bus;
import de.rwth.montisim.simulation.eesimulator.bus.BusType;
......@@ -29,7 +30,6 @@ public class CAN extends Bus {
// https://en.wikipedia.org/wiki/CAN_bus
// NOTE: Not accounted right now: Bit stuffing, Errors, Error frames
public static final long NANOSECS_IN_SEC = 1000000000;
/**
* Number of bits at the start of a frame, before the data payload. Header =
* Start-of-frame + Identifier A + SRR + IDE + Identifier B + RTR + Reserved
......@@ -167,11 +167,10 @@ public class CAN extends Bus {
}
private Instant instantFromBitTime(long time){
return startTime.plus(Duration.ofNanos((time*NANOSECS_IN_SEC)/bitRate));
return startTime.plus(Duration.ofNanos((time*Time.SECOND_TO_NANOSEC)/bitRate));
}
private long bitTimeFromInstant(Instant time){
Duration delta = Duration.between(startTime, time);
long nanos = (delta.getNano() + delta.getSeconds()*NANOSECS_IN_SEC);
return (nanos*bitRate)/NANOSECS_IN_SEC;
long nanos = Time.nanosecondsFromDuration(Duration.between(startTime, time));
return (nanos*bitRate)/Time.SECOND_TO_NANOSEC;
}
}
......@@ -8,6 +8,7 @@ package de.rwth.montisim.simulation.eesimulator.bus.constant;
import java.time.Duration;
import de.rwth.montisim.commons.utils.Time;
import de.rwth.montisim.simulation.eesimulator.*;
import de.rwth.montisim.simulation.eesimulator.bus.*;
import de.rwth.montisim.simulation.eesimulator.events.*;
......@@ -85,7 +86,7 @@ public class ConstantBus extends Bus {
break;
case CONSTANT_RATE:
double time = event.getMessage().msgLen / rate;
Duration d = Duration.ofNanos((long)(time*1000000000L));
Duration d = Time.durationFromSeconds(time);
simulator.addEvent(new MessageReceiveEvent(event.getEventTime().plus(d), this, event.getMessage()));
break;
case CONSTANT_TIME:
......
......@@ -6,17 +6,17 @@
*/
package de.rwth.montisim.simulation.eesimulator.bus.flexray;
import de.rwth.montisim.commons.utils.Pair;
import de.rwth.montisim.simulation.eesimulator.bus.*;
import de.rwth.montisim.simulation.eesimulator.events.MessageSendEvent;
import de.rwth.montisim.simulation.eesimulator.message.*;
import java.time.Duration;
import java.time.Instant;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.PriorityQueue;
import java.util.UUID;
// import de.rwth.montisim.commons.utils.Pair;
// import de.rwth.montisim.simulation.eesimulator.bus.*;
// import de.rwth.montisim.simulation.eesimulator.events.MessageSendEvent;
// import de.rwth.montisim.simulation.eesimulator.message.*;
// import java.time.Duration;
// import java.time.Instant;
// import java.util.LinkedHashMap;
// import java.util.Map;
// import java.util.PriorityQueue;
// import java.util.UUID;
/**
* Models the transmission of BusMessageEvent over a FlexRay. Calculates delay
......@@ -113,8 +113,8 @@ import java.util.UUID;
// * @return The duration of a slot
// */
// Duration getSlotDuration() {
// long mikroBits = ((long) (HEADER_SIZE + TRAILER_SIZE + MAX_SLOT_PAYLOAD)) * 8l * 1000000l;
// double nanoseconds = mikroBits / ((double) mode.getDataRate());
// long microBits = ((long) (HEADER_SIZE + TRAILER_SIZE + MAX_SLOT_PAYLOAD)) * 8l * 1000000l;
// double nanoseconds = microBits / ((double) mode.getDataRate());
// return Duration.ofNanos((long) Math.ceil(nanoseconds));
// }
......@@ -248,10 +248,10 @@ import java.util.UUID;
// }
// // determine highest priority message
// BusMessageEvent highestPrio = null;
// BusMessageEvent highestPriority = null;
// for (BusMessageEvent msg : firstMsgByControllerId.values()) {
// if (msg != null && (highestPrio == null || COMP_ID_DESC.compare(highestPrio, msg) > 0)) {
// highestPrio = msg;
// if (msg != null && (highestPriority == null || COMP_ID_DESC.compare(highestPriority, msg) > 0)) {
// highestPriority = msg;
// }
// }
......@@ -268,19 +268,19 @@ import java.util.UUID;
// + " transmittedBytes");
// } else {
// int transmittedBytes = pair.getKey();
// int fullSlots = highestPrio.getRemainingBytes() / FlexRay.MAX_SLOT_PAYLOAD;
// int remainingBytes = highestPrio.getRemainingBytes() % FlexRay.MAX_SLOT_PAYLOAD;
// int fullSlots = highestPriority.getRemainingBytes() / FlexRay.MAX_SLOT_PAYLOAD;
// int remainingBytes = highestPriority.getRemainingBytes() % FlexRay.MAX_SLOT_PAYLOAD;
// if (fullSlots < FlexRay.DYNAMIC_SLOTS) {
// transmittedBytes += (fullSlots * FlexRay.MAX_SLOT_SIZE);
// if (remainingBytes > 0) {
// transmittedBytes += FlexRay.HEADER_SIZE + remainingBytes;
// }
// earliestFinishTime = time.plusNanos(calculateTransmissionTime(transmittedBytes));
// Log.info("New earliest finished msg + " + highestPrio
// Log.info("New earliest finished msg + " + highestPriority
// + " finished in dynamic segment of incomplete cycle with: " + pair.getKey()
// + " transmittedBytes");
// } else {
// highestPrio.transmitBytes(FlexRay.TOTAL_DYNAMIC_PAYLOAD, 0);
// highestPriority.transmitBytes(FlexRay.TOTAL_DYNAMIC_PAYLOAD, 0);
// transmittedBytes += FlexRay.DYNAMIC_SEGMENT_SIZE;
// Log.info("Transmitted bytes in incomplete segment: " + transmittedBytes);
// time = time.plusNanos(calculateTransmissionTime(transmittedBytes));
......@@ -289,10 +289,10 @@ import java.util.UUID;
// } else if (lastPartialStaticSegmentBytes > 0 && lastPartialDynamicSegmentBytes < FlexRay.DYNAMIC_SEGMENT_SIZE
// && lastPartialDynamicSegmentBytes >= 0) {
// Log.info("Start from incomplete dynamic segment with " + lastPartialDynamicSegmentBytes + " bytes");
// Pair<Integer, Instant> pair = mockFillIncompleteDynamicSegment(highestPrio);
// Pair<Integer, Instant> pair = mockFillIncompleteDynamicSegment(highestPriority);
// if (pair.getValue().isBefore(earliestFinishTime)) {
// earliestFinishTime = pair.getValue();
// Log.info("New earliest finished msg: " + highestPrio + " finished in incomplete dynamic segment with: "
// Log.info("New earliest finished msg: " + highestPriority + " finished in incomplete dynamic segment with: "
// + pair.getKey() + " transmittedBytes");
// } else {
// Log.info("Transmitted bytes in incomplete segment: " + pair.getKey());
......@@ -308,7 +308,7 @@ import java.util.UUID;
// int completeCycles = 0;
// int completeSlots = 0;
// long partialSlotNs = 0;
// if (msg.getId() == highestPrio.getId()) {
// if (msg.getId() == highestPriority.getId()) {
// // transmitted during static and dynamic segments
// completeCycles = remainingBytes
// / (FlexRay.CONTROLLER_STATIC_PAYLOAD + FlexRay.TOTAL_DYNAMIC_PAYLOAD);
......@@ -323,7 +323,7 @@ import java.util.UUID;
// // controller
// if (remainingBytes == 0) {
// completeCycles = Math.max(completeCycles - 1, 0);
// if (msg.getMessageID() != highestPrio.getMessageID()) {
// if (msg.getMessageID() != highestPriority.getMessageID()) {
// completeSlots = FlexRay.STATIC_SLOTS;
// } else {
// completeSlots = FlexRay.STATIC_SLOTS + FlexRay.DYNAMIC_SLOTS;
......
......@@ -16,6 +16,8 @@ import de.rwth.montisim.simulation.eesimulator.message.Message;
*/
public class MessageSendEvent extends EEDiscreteEvent {
private Message msg;
public MessageSendEvent(Instant eventTime, EEEventProcessor target, Message msg) {
super(eventTime, target);
this.msg = msg;
......@@ -26,8 +28,6 @@ public class MessageSendEvent extends EEDiscreteEvent {
return EEEventType.MESSAGE_SEND;
}
private Message msg;
public Message getMessage(){
return msg;
}
......
......@@ -6,13 +6,27 @@
*/
package de.rwth.montisim.simulation.eesimulator.exceptions;
public class EEOutputOverlapException extends Exception {
import java.util.List;
public class EEMultipleInputsException extends Exception {
private static final long serialVersionUID = 8089530988637131344L;
public final String componentName;
public final String messageName;
public final List<String> sendingComponents;
public EEOutputOverlapException(String componentName) {
super(componentName);
public EEMultipleInputsException(String componentName, String messageName, List<String> sendingComponents) {
this.componentName = componentName;
this.messageName = messageName;
this.sendingComponents = sendingComponents;
}
@Override
public String getMessage(){
String res = "Component \"" + componentName + "\" expects the input \"" + messageName + "\" from only one sender but receives it from:";
for (String s : sendingComponents){
res += "\n - " + s;
}
return res;
}
}
\ No newline at end of file
......@@ -24,7 +24,7 @@ public class EESetupErrors {
public List<EEMissingComponentException> missingComponentExceptions = new ArrayList<>();
public List<EEComponentTypeException> componentTypeExceptions = new ArrayList<>();
public List<EEInvalidComponentIdException> invalidIdExceptions = new ArrayList<>();
public HashMap<String, HashSet<EEOutputOverlapException>> outputOverlapExceptions = new HashMap<>();
public List<EEMultipleInputsException> multipleInputsExceptions = new ArrayList<>();
public List<EEMissingOutputException> missingOutputExceptions = new ArrayList<>();
public void throwExceptions() throws EESetupException {
......@@ -35,7 +35,7 @@ public class EESetupErrors {
!missingComponentExceptions.isEmpty() ||
!componentTypeExceptions.isEmpty() ||
!invalidIdExceptions.isEmpty() ||
!outputOverlapExceptions.isEmpty() ||
!multipleInputsExceptions.isEmpty() ||
!missingOutputExceptions.isEmpty()
)
throw new EESetupException(this);
......@@ -48,11 +48,11 @@ public class EESetupErrors {
res += "## EECyclicSetupException: " +cyclicError.get().getMessage() + '\n';
}
res += printExceptions("EEComponentNameException", namesErrors);
res += printExceptions("EEMessageTypeException","is sent by multiple components", messageTypeErrors);
res += printExceptions("EEMessageTypeException","sent with different types", messageTypeErrors);
res += printExceptions("EEMissingComponentException", missingComponentExceptions);
res += printExceptions("EEComponentTypeException", componentTypeExceptions);