package vnsim.network.scft; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.io.Serializable; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import vnsim.applications.trafficview.SimulatedCarInfo; import vnsim.core.CarInfo; import vnsim.core.Communicator; import vnsim.core.Engine; import vnsim.map.object.Globals; import vnsim.map.object.Point; import vnsim.map.object.Road; import vnsim.map.utils.GPSutil; import vnsim.network.dsrc.Application; import vnsim.network.dsrc.CarRunningDSRC; import vnsim.vehicular.scenarios.Route; import vnsim.vehicular.simulator.CarInstance; import vnsim.vehicular.simulator.RouteSegment; /** * Implements the functionality of a car that uses the SCFT algorithm to route messages (store-and-forward and based on the car's trajectory), * as well as DSRC as transporting protocol. * @author Serban George-Cristian */ public class CarRunningSCFT extends CarRunningDSRC { public Map msgQueue = new HashMap(); /** * Number of nodes the message can traverse until it discarding - used to avoid continuous loops */ public int ttl = 5; /** * Numarul de mesaje transmise */ public static int nrPleaca = 0; /** * Numarul de mesaje receptionate (livrate destinatarului) */ public static int nrLivrate = 0; public static Object lock = new Object(); public static PrintWriter out = null; /** * rezultatele se depun intr-un fisier text */ static { try { out= new PrintWriter(new File("outputSCFT.txt")); } catch (Exception e) { } } /** * Atribute coada de mesaje * @param insertKey - cheia de insertie * @param removeKey - cheia de stergere numarul * @param maxNrOfMessages- numarul maxim de mesaje ce pot fi stocate * @param nrMsgToRemove - numarul de mesaje ce vor fi sterse in caz de coada plina * @param secBeforeDeleteMsg - timpul de store al mesajelor */ /** Insertion key */ public int insertKey = 1; /** Removal key (number) */ public int removeKey = 1; /** * numarul maxim de mesaje ce va fi pastrat in coada */ public int maxNrOfMessages = 20; /** * numarul de mesaje ce vor fi sterse in cazul in care coada de mesaje este plina */ public int nrMsgToRemove = 3; /** * timpul dupa care un mesaj aflat in coada de mesaje va fi sters */ public int timeBeforeDeleteMsg = 30000; /** * tipul de mesaj ce va fi stocat */ public MesageSCFT mesage; /** * constructorul clasei * @param vehicleId * @param lane * @param speed * @param roadIdx * @param pointIdx * @param direction * @param offset */ public CarRunningSCFT(int vehicleId, byte lane, double speed, short roadIdx, short pointIdx, byte direction, double offset) { super(vehicleId, lane, speed, roadIdx, pointIdx, direction, offset); System.out.println("CarRunningSCFT"); } /** * calculeaza distanta intre vehicule aflate pe aceeasi strada * @return */ public double getDistance() { return this.getRealPos().getDistanceToCarInFront(); } /** * calculeaza distanta reala intre doua puncte * @param x1 - sursa * @param y1 - sursa * @param x2 - destinatie * @param y2 - destinatie * @return */ public double getRealDistance(double x1, double y1,double x2,double y2){ return Math.sqrt( Math.pow((x1-x2) ,2 ) + Math.pow((y1-y2) ,2 )); } /** * functia de fitness a traiectoriei * Fitnesul se calculeaza pe baza segmentelor comune si daca vehiculele * se vor afla pe acel segment la un acelasi moment de timp sau * la un moment de timp apropiat * Ca si un sistem real de GPS se estimeaza timpul in care vehiculul sursa si vehiculul destinatie vor ajunge * si pe baza acestor parametrii se calculeaza fitness-ul * @return */ public double getTrajectoryFitness(int vId){ int nrSegComune =0; SimulatedCarInfo sciTr = (SimulatedCarInfo)Globals.engine.getCarIdx(vId); if (sciTr != null ) { CarInstance destCar = sciTr.getRealPos(); /** * preluam coordonatele punctului destinatie * */ Road currentRoadsDestI = (Road) Globals.map.roads.get(sciTr.getRoadIdx()); short ptd = sciTr.getPointIdx(); Point pd = (Point) currentRoadsDestI.points.get(ptd); float yd = (float) GPSutil.getMetersLatitude(Globals.minPoint, pd); float xd = (float) GPSutil.getMetersLongitude(Globals.minPoint, pd); /** * preluam datele initiale de la sursa */ Road currentRoadSourceI = (Road) Globals.map.roads.get(getRoadIdx()); short pts = getPointIdx(); Point ps = (Point) currentRoadSourceI.points.get(pts); float ys = (float) GPSutil.getMetersLatitude(Globals.minPoint, ps); float xs = (float) GPSutil.getMetersLongitude(Globals.minPoint, ps); CarInstance sourceCar = getRealPos(); if (destCar.routeIndex == destCar.route.length - 1) { return 0.1; } if (sourceCar.routeIndex == sourceCar.route.length - 1) { return 0.1; } /** * cautam segmentele comune */ for (int i=destCar.routeIndex; i 40) return 0.1; else return -0.1; } /** * functia de fitness - ia in calcul distanta,viteza si traiectoria * vehicului si in urma acestor factori calculeaza o valoare * @return - valoarea care duce la memorarea mesajului sau la transmiterea acestuia direct */ public double getFitness(int vId) { return Math.log(this.getDistance())/10 + this.getSpeed(vId) + this.getTrajectoryFitness(vId); } /** * functia care intoarce probabilitatea ca mesajul sa ajunga la destinatie * @return 1 - se poate transmite direct * -1 - se face store-carry */ public int getDecision(int vId) { if (getFitness(vId) < 0.45) return 1; else return -1; } /** * functia de receptie a unui mesaj */ public void onReceive(byte[] bytesReceived,Serializable m, Communicator sender) { int vehicleIdSource; int vehicleIdDest; long carIdSourceH; long carIdSourceV; long carlIdDestH; long carlIdDestV; long timeStamp; int ttl; MesageSCFT msg; if (!isEquipped || bytesReceived == null) return; //System.out.println("on receive:"+bytesReceived[0]); int tip; byte[] message = null; ByteBuffer bb = ByteBuffer.wrap(bytesReceived); bb.rewind(); final int header =bb.getInt(); switch(header) { case 1: //preiau informatiile si creez mesajul /** * se preiau informatiile transmise */ vehicleIdSource = bb.getInt(); vehicleIdDest = bb.getInt(); carIdSourceH = bb.getLong(); carIdSourceV = bb.getLong(); carlIdDestH = bb.getLong(); carlIdDestV = bb.getLong(); timeStamp = bb.getLong(); ttl = bb.getInt() - 1;//decrementam la primire ttl-ul /** * daca id-ul destinatie este chiar cel al masinii curente * inseamna livrarea unui mesaj */ if(vehicleId == vehicleIdDest){ synchronized (lock) { nrLivrate++; if ((float)nrLivrate/ nrPleaca <=1) { out.println((long)((float)Globals.engine.crtTime / Globals.SECOND * 1000L)+" "+(float)nrLivrate/nrPleaca * 100+" "+Math.abs(nrPleaca-nrLivrate)); out.flush(); } else { out.println((long)((float)Globals.engine.crtTime / Globals.SECOND * 1000L)+" "+ 100+" "+Math.abs(nrPleaca-nrLivrate)); out.flush(); } } return; } /** * daca id-ul curent nu este acelasi cu id-ul destinatie * si daca ttl >0 se introduce in coada de mesaje */ if (ttl > 0) { msg = new MesageSCFT(vehicleIdSource,vehicleIdDest,carIdSourceH,carIdSourceV,carlIdDestH,carlIdDestV, timeStamp,ttl); insertKey++; msgQueue.put(insertKey, msg); } break; default:super.onReceive(bytesReceived,m,sender); } } /** * funtia de transmitere a mesajelor */ public byte[] prepareMessage(int messageType) { ByteBuffer bb = ByteBuffer.allocate(56); byte[] bytesToSend=null; System.out.println("CarRunningSCFT - prepareMessage called"); if (!isEquipped) return null; if(messageType==1) { byte[] localinfo = null; System.out.println("CarRunningSCFT - storeCarryForward called"); /** * stergem primele nrMsgToRemove mesaje in caz de coada plina */ if (insertKey - removeKey + 1 > maxNrOfMessages) for (int i = 0; i < nrMsgToRemove; i++) { removeKey++; msgQueue.remove(removeKey); } /** * daca mesajul a expirat - a stat iPn coada mai mult de timeBeforeDeleteMsg secunde * aici sunt eliminate in ordine daca mesajele sunt ordonate */ for(int i=removeKey;i< insertKey;i++) if(msgQueue.containsKey(i)) { long timeMsg = msgQueue.get(i).getTimeStamp() ; long timeGlobal = Globals.engine.getCrtTime() ; if ( timeGlobal - timeMsg > timeBeforeDeleteMsg ){ msgQueue.remove(i); } } /** * store, carry sau forward * incercam sa scoatem mesajele si sa le transmitem daca nu se reuseste * si timpul de store nu a fost depasit pastram mesajul daca nu se * reuseste dupa un timpul de stocare mesajele se sterg din coada */ /** * daca exista mesaje in coada de mesaje * acestea se transmit */ for (int i=removeKey;i 0) { bb.clear(); bb.putInt(1); bb.putInt(msgQueue.get(i).vehicleIdSource); bb.putInt(msgQueue.get(i).vehicleIdDest); bb.putLong(msgQueue.get(i).carIdSourceH); bb.putLong(msgQueue.get(i).carIdSourceV); bb.putLong(msgQueue.get(i).carIdDestH); bb.putLong(msgQueue.get(i).carIdDestV); bb.putLong(msgQueue.get(i).timeStamp); bb.putInt(msgQueue.get(i).ttl); } /** * cautam un posibil vehicul destinatie * se alege un index random si se cauta daca a fost creat un vehicul cu acel index * daca nu exista un astfel de vehicul, cautarea continua dupa pasii prezentati mai sus * daca este gasit, cautarea inceteaza */ int nextCar = 0; SimulatedCarInfo sci = null; while (true) { nextCar =(int)(Math.random()*Engine.lastCarID); sci = (SimulatedCarInfo)Globals.engine.getCarIdx(nextCar); if (sci != null) break; } /** * preiau coordonatele vehiculului sursa, date necesare in vederea stabilirii distantei reale * intre vehiculul sursa si vehiculul destinatie * datele preluate - coordonatele vehiculului */ Road currentRoads = (Road) Globals.map.roads.get(getRoadIdx()); short pts = getPointIdx(); Point ps = (Point) currentRoads.points.get(pts); float ys = (float) GPSutil.getMetersLatitude(Globals.minPoint, ps); float xs = (float) GPSutil.getMetersLongitude(Globals.minPoint, ps); /** * preiau coordonatele vehiculului destinatie, date necesare in vederea stabilirii distantei reale * intre vehiculul sursa si vehiculul destinatie * datele preluate - coordonatele vehiculului */ Road currentRoad = (Road) Globals.map.roads.get(sci.getRoadIdx()); short pt = sci.getPointIdx(); Point pd = (Point) currentRoad.points.get(pt); float y = (float) GPSutil.getMetersLatitude(Globals.minPoint, pd); float x = (float) GPSutil.getMetersLongitude(Globals.minPoint, pd); /** * daca mesajul nu poate fi transmis se va stoca in coada * si se va incerca transmiterea lui de fiecare data cand vehiculul se afla * in apropierea altor vehicule ce ar putea prelua mesajul si ar putea * sa il livreze vehiculului destinatie */ if (getDecision(nextCar) < 0) { /** * * se creaza un mesaj de tip MesageSCFT ce va contine * - id vehicul sursa * - id vehicul destinatie * - pozitia orizontala a vehicului sursa * - pozitia verticala a vehicului sursa * - pozitia orizontala a vehicului destinatie * - pozitia verticala a vehicului destinatie * - timpul de sosire a mesajului - secunde * - TTL definit */ mesage = new MesageSCFT(vehicleId,nextCar, (long)xs, (long)ys, (long)x, (long)y, Globals.engine.getCrtTime(),ttl); insertKey++; msgQueue.put(insertKey, mesage); /*System.out.println(); System.out.println("afisarea cozii"); System.out.println("distanta "+getDistance()+" fitnesul "+getFitness(nextCar)+" decizia " +getDecision(nextCar)); System.out.println("afisam vehicle id :"+ vehicleId +" "+nextCar+" id "+" "+x+" "+y); System.out.println("viteza destinatie "+sci.getSpeed()+" "+ sci.getDirection()+" " +" viteza sursa " + speed +" "+direction); System.out.println("introducem in coada "+ Globals.engine.getCrtTime()); System.out.println();*/ } else{ /** * daca decizia de transmitere a mesajelor este pozitiva * mesajul se va transmite direct fara a mai fi stocat in coada de mesaje * pentru fiecare eveniment send se creeaza un eveniment receive */ bb.clear(); bb.putInt(1); bb.putInt(vehicleId); bb.putInt(nextCar); bb.putLong((long)xs); bb.putLong((long)ys); bb.putLong((long)x); bb.putLong((long)y); bb.putLong(Globals.engine.getCrtTime()); bb.putInt(ttl); /** * la fiecare mesaj nou transmis se creste numarul de mesaje * care au fost transmise */ synchronized (lock) { nrPleaca++; if ((float)nrLivrate/ nrPleaca <=1) { out.println((long)((float)Globals.engine.crtTime / Globals.SECOND * 1000L)+" "+(float)nrLivrate/nrPleaca * 100+" "+Math.abs(nrPleaca-nrLivrate)); out.flush(); } else { out.println((long)((float)Globals.engine.crtTime / Globals.SECOND * 1000L)+" "+ 100+" "+Math.abs(nrPleaca-nrLivrate)); out.flush(); } } /*System.out.println(); System.out.println("distanta "+getDistance()+" fitnesul "+getFitness(nextCar)+" decizia " +getDecision(nextCar)); System.out.println(" roadidx "+ this.roadIdx +xs+" "+ys); System.out.println("afisam vehicle id :"+vehicleId+" "+nextCar +" "+x+" "+y); System.out.println("viteza destinatie "+sci.getSpeed() +" "+ sci.getDirection()+" " +" viteza sursa " + speed +" "+direction ); System.out.println("trimitem mesajul - raza de actiune directa"); System.out.println();*/ } localinfo = bb.array(); return localinfo; } else { return super.prepareMessage(messageType); } } }