/*----------------------------------------------------------------------------------------------------------------
* CupCarbon: A Smart City & IoT Wireless Sensor Network Simulator
* www.cupcarbon.com
* ----------------------------------------------------------------------------------------------------------------
* Copyright (C) 2013-2016 CupCarbon
* ----------------------------------------------------------------------------------------------------------------
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*----------------------------------------------------------------------------------------------------------------
* CupCarbon U-One is part of the research project PERSEPTEUR supported by the
* French Agence Nationale de la Recherche ANR
* under the reference ANR-14-CE24-0017-01.
* ----------------------------------------------------------------------------------------------------------------
**/
/**
* @author Ahcene Bounceur
* @author Lounis Massinissa
*/
package wisen_simulation;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import cupcarbon.CupCarbon;
import device.Channels;
import device.Device;
import device.DeviceList;
import device.MultiChannels;
import device.SensorNode;
import javafx.application.Platform;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.paint.Color;
import map.MapLayer;
import markers.Routes;
import project.Project;
public class WisenSimulation implements Runnable {
public static double time = 0.0;
public static double sTime = 0.0;
public static boolean isSimulating = false;
public static double resultsWritingTime = 0.0; // The time in seconds, of writing the battery level in the results csv file
private boolean mobilityAndEvents = false;
// Change to true if you want do display some simulation info on the console
public static boolean showInConsole = true;
private boolean generateResults = true ;
public WisenSimulation() {
}
// ------------------------------------------------------------
// Run simulation
// ------------------------------------------------------------
public void simulate() {
if(ready()) {
start_simulation();
}
else {
Platform.runLater(new Runnable() {
@Override
public void run() {
Alert alert = new Alert(AlertType.WARNING);
alert.setTitle("Warning");
alert.setHeaderText(null);
alert.setContentText("Not Ready to simulate!");
alert.showAndWait();
}
});
}
}
public void start_simulation() {
DeviceList.initAll();
Routes.loadRoutes();
resultsWritingTime = 0.0;
SimLog.init();
mobilityAndEvents = SimulationInputs.mobilityAndEvents;
System.out.println("mobility "+mobilityAndEvents);
generateResults = SimulationInputs.displayResults ;
System.out.println(generateResults);
showInConsole = SimulationInputs.showInConsole ;
System.out.println("Initialization ... ");
SimLog.add("===========================");
SimLog.add("Initialization");
MultiChannels.init();
Channels.numberOfSentMessages = 0;
Channels.numberOfReceivedMessages = 0;
Channels.numberOfAckMessages = 0;
Channels.numberOfLostMessages = 0;
for (Device device : DeviceList.devices) {
device.initForSimulation();
if (mobilityAndEvents) {
if (!device.getGPSFileName().equals(""))
device.setEvent2(device.getNextTime());
else
device.setEvent2(Double.MAX_VALUE);
if (!device.getNatEventFileName().equals(""))
device.setEvent3(device.getNextValueTime());
else
device.setEvent3(Double.MAX_VALUE);
}
}
for (SensorNode sensor : DeviceList.sensors) {
sensor.initForSimulation();
if(SimulationInputs.clockDrift) sensor.drift();
if (mobilityAndEvents) {
if (!sensor.getGPSFileName().equals(""))
sensor.setEvent2(sensor.getNextTime());
else
sensor.setEvent2(Double.MAX_VALUE);
}
}
System.out.println("End of Initialization.");
long startTime = System.currentTimeMillis();
System.out.println("Start Simulation (WISEN : D-Event) ... ");
MapLayer.repaint();
try {
PrintStream ps = new PrintStream(new FileOutputStream(Project.getProjectResultPath() + File.separator + "wisen_simulation" + ".csv"));
if (generateResults) {
ps.print("Time (Sec);");
for (SensorNode sensor : DeviceList.sensors) {
ps.print("S"+sensor.getId() + ";");
}
ps.println();
}
boolean moving = false ;
String fMessage = "";
SimLog.add("======================================================");
SimLog.add("START SIMULATION");
SimLog.add("======================================================");
// ------------------------------------------------------
// ------------------------------------------------------
// ------------------------------------------------------
//
// From here the simulation will start
//
// ------------------------------------------------------
// ------------------------------------------------------
// ------------------------------------------------------
stopCondition = false;
double min = 0;
boolean allDeadSensors = false;
double timeEvt = 1.0;
time = 0.0;
double previousTime = time;
Platform.runLater(new Runnable() {
@Override
public void run() {
CupCarbon.cupCarbonController.simulationTimeLabel.setText("RT");
}
});
//--------> Loop - Simulation starts here
while (time <= SimulationInputs.simulationTime) {
isSimulating = true;
if (min == Double.MAX_VALUE) {
System.out.println("Infinite WAITs!");
Platform.runLater(new Runnable() {
@Override
public void run() {
updateButtons();
isSimulating = false;
Alert alert = new Alert(AlertType.INFORMATION);
alert.setTitle("Simulation");
alert.setHeaderText(null);
alert.setContentText("Infinite WAITs! [time = "+String.format("%4.4f", sTime)+"]");
alert.showAndWait();
}
});
CupCarbon.cupCarbonController.monitor.setFill(Color.GREENYELLOW);
break;
}
if(stopCondition) {
System.out.println("Simulation stopped!");
CupCarbon.cupCarbonController.monitor.setFill(Color.GREENYELLOW);
break;
}
if(allDeadSensors) {
System.out.println("Dead Sensors!");
Platform.runLater(new Runnable() {
@Override
public void run() {
updateButtons();
isSimulating = false;
Alert alert = new Alert(AlertType.INFORMATION);
alert.setTitle("Simulation");
alert.setHeaderText(null);
alert.setContentText("Dead Sensors! [time = "+String.format("%4.4f", sTime)+"]");
alert.showAndWait();
}
});
CupCarbon.cupCarbonController.monitor.setFill(Color.GREENYELLOW);
break;
}
consolPrint(time + " : ");
SimLog.add("");
SimLog.add("----------------------------------------------------------------------------");
SimLog.add("Time : "+time);
SimLog.add("Min (milliseconds) : "+min);
consolPrintln("--------------------------------------");
consolPrint(""+time);
if(!fMessage.replace("\n", "").equals(""))
SimLog.add(fMessage);
fMessage = "";
consolPrintln(" + "+min+" = "+time);
MultiChannels.goToTheNextTime(min);
MultiChannels.receivedMessages();
min = Double.MAX_VALUE;
for (SensorNode sensor : DeviceList.sensors) {
if(!sensor.isDead()) {
consolPrint(sensor + " [" +sensor.getScript().getCurrent().toString()+"] - ");
sensor.execute();
if ((min > sensor.getEvent()))
min = sensor.getEvent();
if ((min > sensor.getLocEventTime()))
min = sensor.getLocEventTime();
}
}
consolPrintln("");
double minmv = Double.MAX_VALUE;
if (mobilityAndEvents) {
for (SensorNode sensor : DeviceList.sensors) {
if(!sensor.isDead()) {
if (sensor.getEvent2() == 0) {
SimLog.add(sensor.getIdFL()+sensor.getId()+" SENSOR MOVING");
if (!sensor.getGPSFileName().equals("")) {
sensor.moveToNext(true, 0);
sensor.setEvent2(sensor.getNextTime());
}
}
if ((minmv > sensor.getEvent2()))
minmv = sensor.getEvent2();
}
}
for (Device device : DeviceList.devices) {
if(!device.isDead()) {
if (device.getEvent2() == 0) {
SimLog.add(device.getIdFL()+device.getId()+" DEVICE MOVING");
if (!device.getGPSFileName().equals("")) {
device.moveToNext(true, 0);
device.setEvent2(device.getNextTime());
}
}
if (device.getEvent3() == 0) {
SimLog.add(device.getIdFL()+device.getId()+" VALUE GENERATION");
if (!device.getNatEventFileName().equals("")) {
device.generateNextValue();
device.setEvent3(device.getNextValueTime());
}
}
if ((minmv > device.getEvent2()))
minmv = device.getEvent2();
if ((minmv > device.getEvent3()))
minmv = device.getEvent3();
}
}
}
consolPrintln("");
boolean waitArrow = false;
if (min > MultiChannels.getMin()) {
min = MultiChannels.getMin();
waitArrow = true;
}
if (mobilityAndEvents) {
moving = false;
if (minmv < min) {
min = minmv;
moving = true;
}
}
// min ready
consolPrintln("");
if((min > 0) || (moving)) {
if (generateResults && resultsWritingTime<=time) {
ps.print(time + ";");
for (SensorNode sensor : DeviceList.sensors) {
ps.print(sensor.getBatteryLevel() + ";");
consolPrint(sensor.getBatteryLevel()+" | ");
}
ps.println();
if(resultsWritingTime<=time) {
resultsWritingTime += SimulationInputs.resultsWritingPeriod;
}
}
consolPrintln("");
}
if(SimulationInputs.clockDrift) {
if ((timeEvt <= time)) {
timeEvt += 3600; // Drift each 1 hour
for (SensorNode sensor : DeviceList.sensors) {
if(!sensor.isDead()) {
for(int i=0; i<min; i++) {
sensor.drift();
}
}
}
}
}
allDeadSensors = true;
for (SensorNode sensor : DeviceList.sensors) {
if(!sensor.isDead()) {
consolPrint(sensor.getEvent()+" : ");
sensor.gotoTheNextEvent(min);
sensor.goToNextLocEvent(min);
sensor.executeLocEvent();
if(sensor.getEvent() == 0) {
fMessage += sensor.getScript().getCurrent().finishMessage() + "\n";
sensor.gotoTheNextInstruction() ;
}
consolPrint(sensor.getEvent()+" | ");
if (!sensor.isDead())
allDeadSensors = false;
}
}
for (SensorNode sensor : DeviceList.sensors) {
if (mobilityAndEvents) {
sensor.setEvent2(sensor.getEvent2()-min);
}
}
for (Device device : DeviceList.devices) {
if (mobilityAndEvents) {
device.setEvent2(device.getEvent2()-min);
device.setEvent3(device.getEvent3()-min);
}
}
time += min;
if(time<SimulationInputs.simulationTime)
sTime = time;
consolPrintln("");
consolPrintln("------------------------------------------");
try {
CupCarbon.cupCarbonController.progress.setProgress(time *1.0/ SimulationInputs.simulationTime);
} catch(Exception e) {
isSimulating = false;
System.err.println("[CUPCARBO:WisenSimulation] Simulation Progress: "+(time *1.0/ SimulationInputs.simulationTime));
}
MapLayer.repaint();
if (waitArrow && SimulationInputs.arrowsDelay > 0) {
Thread.sleep((int)(SimulationInputs.arrowsDelay));
}
else {
int d = (int)(SimulationInputs.visualDelay*(time - previousTime));
if(time < SimulationInputs.simulationTime) {
Thread.sleep(d);
}
else {
isSimulating = false;
System.out.println("Infinite Times!");
}
}
previousTime = time;
ps.flush();
}
try {
CupCarbon.cupCarbonController.progress.setProgress(0.0);
} catch(Exception e) {
isSimulating = false;
System.err.println("[CUPCARBO:WisenSimulation] Simulation Progress: 0");
}
SimLog.close();
ps.close();
MultiChannels.init();
isSimulating = false;
updateButtons();
}
catch (FileNotFoundException e) {e.printStackTrace();}
catch (InterruptedException e) {e.printStackTrace();}
MapLayer.repaint();
long endTime = System.currentTimeMillis();
System.out.println();
System.out.println("End of Simulation (WISEN : D-Event).");
System.out.println(((endTime - startTime) / 1000.) + " sec");
isSimulating = false;
Platform.runLater(new Runnable() {
@Override
public void run() {
CupCarbon.cupCarbonController.simulationTimeLabel.setText(String.format("RT = %4.4f s", ((endTime - startTime) / 1000.)));
}
});
for (SensorNode sensorNode : DeviceList.sensors) {
sensorNode.toOri();
sensorNode.stopAgentSimulation();
}
for (Device device : DeviceList.devices) {
device.toOri();
device.stopAgentSimulation();
}
if(DeviceList.propagationsCalculated)
DeviceList.calculatePropagations();
MapLayer.repaint();
System.out.println(String.format("Simulation Time: %4.4f s", WisenSimulation.sTime));
System.out.println("Number of SENT messages:"+Channels.numberOfSentMessages );
System.out.println("Number of RECEIVED messages:"+Channels.numberOfReceivedMessages);
System.out.println("Number of SENT & RECEIVED messages:"+(Channels.numberOfReceivedMessages+Channels.numberOfSentMessages));
System.out.println("Number of ACK messages:"+Channels.numberOfAckMessages);
System.out.println("Number of LOST messages:"+Channels.numberOfLostMessages);
}
// ------------------------------------------------------------
// Run simulation (call the simulate() method)
// ------------------------------------------------------------
@Override
public void run() {
simulate();
}
public static void consolPrint(String txt) {
if(showInConsole)
System.out.print(txt);
}
public static void consolPrintln(String txt) {
if(showInConsole)
System.out.println(txt);
}
private boolean stopCondition = false;
public void stopSimulation() {
updateButtons();
MultiChannels.init();
isSimulating = false;
stopCondition = true;
MapLayer.repaint();
}
// ------------------------------------------------------------------------
// Check if everything it's OK for simulation
// -> Check if each sensor has its own script
// ------------------------------------------------------------------------
/**
* Check if each sensor has its own script
*/
public static void check() {
for(SensorNode sensor : DeviceList.sensors) {
if(sensor.getScriptFileName().equals("")) {
//JOptionPane.showMessageDialog(null, "Not Ready to simulate!", "Warning", JOptionPane.WARNING_MESSAGE);
Platform.runLater(new Runnable() {
@Override
public void run() {
updateButtons();
Alert alert = new Alert(AlertType.WARNING);
alert.setTitle("Warning");
alert.setHeaderText(null);
alert.setContentText("Not Ready to simulate!");
alert.showAndWait();
}
});
return;
}
}
Platform.runLater(new Runnable() {
@Override
public void run() {
updateButtons();
Alert alert = new Alert(AlertType.INFORMATION);
alert.setTitle("Valid");
alert.setHeaderText(null);
alert.setContentText("Ready to simulate!");
alert.showAndWait();
}
});
}
public boolean ready() {
for(SensorNode sensor : DeviceList.sensors) {
if(sensor.getScriptFileName().equals("")) {
return false;
}
}
return true;
}
public static void updateButtons() {
Platform.runLater(new Runnable() {
@Override
public void run() {
CupCarbon.cupCarbonController.runSimulationButton.setDisable(false);
CupCarbon.cupCarbonController.qRunSimulationButton.setDisable(false);
CupCarbon.cupCarbonController.qRunSimulationButton.setDefaultButton(true);
CupCarbon.cupCarbonController.qStopSimulationButton.setDefaultButton(false);
CupCarbon.cupCarbonController.monitor.setFill(Color.YELLOWGREEN);
CupCarbon.cupCarbonController.stateLabel.setText("Ready");
}
});
}
}