source: proiecte/ptvs/src/vnsim/applications/trafficview/SimulatedCarInfo.java @ 31

Last change on this file since 31 was 31, checked in by (none), 14 years ago
File size: 18.8 KB
Line 
1/************************************************************************************
2 * Copyright (C) 2008 by Politehnica University of Bucharest and Rutgers University
3 * All rights reserved.
4 * Refer to LICENSE for terms and conditions of use.
5 ***********************************************************************************/
6package vnsim.applications.trafficview;
7
8
9import java.io.ByteArrayInputStream;
10import java.io.ByteArrayOutputStream;
11import java.io.IOException;
12import java.io.Serializable;
13import java.nio.ByteBuffer;
14import java.util.ArrayList;
15import java.util.LinkedList;
16import java.util.ListIterator;
17import java.util.Random;
18import java.util.TreeMap;
19
20import vnsim.core.CarInfo;
21import vnsim.core.Communicator;
22import vnsim.core.Engine;
23import vnsim.core.events.ReceiveEvent;
24import vnsim.core.events.SendEvent;
25import vnsim.core.events.UnicastSendEvent;
26import vnsim.map.object.Globals;
27import vnsim.map.object.PeanoKey;
28import vnsim.map.object.Point;
29import vnsim.map.object.Road;
30import vnsim.network.RadioDev;
31import vnsim.vehicular.simulator.CarInstance;
32import vnsim.vehicular.simulator.intersections.Intersection;
33
34
35
36/**
37 * Class that implements the TrafficView applications. Vehicle datasets are
38 * broadcasted on a regular basis. The vehicle dataset is maintained based on
39 * incoming messages from neighbor vehicles.
40 */
41public class SimulatedCarInfo extends CarInfo implements Communicator
42{
43//      protected int vehicleId;
44
45        private CarInstance realPos;
46
47//      public ArrayList <SimulatedCarInfo> neighbors = new ArrayList<SimulatedCarInfo>();
48        public ArrayList <CarInfo> trafficDB = new ArrayList<CarInfo>();
49       
50        private int lastMediumTransmission = 0;
51       
52        //the following moments of time when a packet should be received completely (ReceiveEvents)
53        public LinkedList<ReceiveEvent> receiveEvents = new LinkedList<ReceiveEvent>(); 
54       
55        //Petroaca - the emergency channel receive events
56        public LinkedList<ReceiveEvent> receiveEventsEmergency = new LinkedList<ReceiveEvent>(); 
57       
58        public TreeMap<Integer,Integer> messagePeriods = new TreeMap<Integer,Integer>(); 
59       
60        public int messageNo = 1;
61        public int singleMessageNo = -2;
62       
63        public boolean isEquipped;
64       
65        public boolean promiscuousMode = false;
66        public boolean pulseMessage = true;
67        int reportedNeighbors = 0;
68        double neighPlusDistance = 0;
69        double neighMinusDistance = 0;
70       
71//      public SimulationRecord record;
72       
73        public static final int STANDARD_MESSAGE_PERIOD = 500; // milis 
74        public static int STANDARD_MESSAGE_ID = 1;
75
76        public int infoTime = -1;
77        public int currentPhase = -1;
78        public int phaseRemainingTime = -1;
79        public double queueSize = -1;
80        public int interGreenPhaseTime = -1;
81        public int cycleLength = -1;
82       
83        public Intersection intersection; //the following intersection
84
85        private static Random random = new Random(System.currentTimeMillis());
86
87        private RadioDev radio;
88       
89        public SimulatedCarInfo(){
90        }
91
92        public SimulatedCarInfo(int vehicleId){
93                this.vehicleId = vehicleId;
94//              radio = new RadioDev(this);
95        }
96       
97        public SimulatedCarInfo(int vehicleId, byte lane, double speed, short roadIdx, short pointIdx, byte direction, double offset)
98        {
99                super(speed, roadIdx, pointIdx, direction, offset, lane);
100                this.vehicleId = vehicleId;
101               
102                int chance = (int) (100.0 * random.nextDouble());
103                if (chance < Globals.PERCENT_EQUIPPED_VEHICLES) {
104                        isEquipped = true;
105                } else {
106                        isEquipped = false;
107                }
108                radio = new RadioDev(this);
109        }
110
111        public SimulatedCarInfo(SimulatedCarInfo sci)
112        {
113                super(sci.speed, sci.roadIdx, sci.pointIdx, sci.direction, sci.offset, sci.lane);
114                this.vehicleId = sci.vehicleId;
115                this.timestamp = sci.timestamp;
116                radio = new RadioDev(this);
117        }
118       
119        public void init()
120        {
121                int standardFPSPeriod = (int)((double)(STANDARD_MESSAGE_PERIOD * Globals.engine.fps) / 1000);
122                messagePeriods.put(STANDARD_MESSAGE_ID, new Integer(standardFPSPeriod));
123        }
124       
125        public void update()
126        {
127                this.direction = realPos.getDirection();
128                this.roadIdx = realPos.getRoadIdx();
129                this.pointIdx = realPos.getPointIdx();
130                this.speed = realPos.getSpeed();
131                this.lane = realPos.getLane();
132                this.offset = realPos.getOffset();
133                this.timestamp = realPos.getTimestamp();
134                this.intersection = realPos.intersection;
135        }
136       
137        public boolean isPromiscuousMode() {
138                return promiscuousMode;
139        }
140        public void setPromiscuousMode(boolean promiscuousMode) {
141                this.promiscuousMode = promiscuousMode;
142        }
143
144        public boolean equals(Object arg0) {
145                if (!(arg0 instanceof CarInfo)) {
146//                      System.out.println(arg0.getClass().getCanonicalName());
147                        return false;
148                }
149                CarInfo sci = (CarInfo)arg0;
150                return (vehicleId == sci.getVehicleId());
151        }
152       
153        /**
154         * NeighborDiscovery mode
155         * @param bytesReceived
156         */
157        public void onReceive(byte[] bytesReceived, Serializable message, Communicator sender){
158                if (!isEquipped || bytesReceived == null)
159                        return;
160               
161                if (bytesReceived[0] == Globals.PROT_SETOFCARS){
162                        parsePacket(bytesReceived);
163                }
164                if (bytesReceived[0] == Globals.PROT_NEIGHBOR_DISCOVERY){
165                // first record in message - the sender
166                        CarInfo sc = new CarInfo();
167                        sc.wrap(bytesReceived, 2);
168                       
169                        boolean added = false; 
170                        for (int i=0;i<trafficDB.size();i++)
171                                if ((trafficDB.get(i)).getVehicleId() == sc.getVehicleId()){
172                                        synchronized(trafficDB){
173                                                trafficDB.set(i,sc);
174                                                added = true;
175                                        }
176                                        break;
177                                }
178                        if (!added) 
179                                synchronized(trafficDB){
180                                        trafficDB.add(sc);
181                                }
182                }
183                if (bytesReceived[0] == Globals.PROT_TL_FEEDBACK){
184                       
185                        PeanoKey pkx = null;
186                        if (realPos.intersection != null){
187                                Road rx = Globals.map.roads.get(realPos.intersection.segments.get(0).roadIndex);
188                                Point px = rx.points.get(realPos.intersection.segments.get(0).pointIndex);
189                                pkx = Globals.map.peanoKeys.get(px.getPeanoKeyIdx());
190                        }
191                       
192                        ByteBuffer bb = ByteBuffer.wrap(bytesReceived);
193                        bb.get();
194                       
195                        int cycleLength = bb.getShort();
196                        int segno = bb.get();
197                        int ridx, pidx;
198                        Road r = null;
199                        Point p = null;
200                        try{
201                                ridx = bb.getShort();
202                                r = Globals.map.roads.get(ridx);
203                                pidx = bb.getShort();
204                                p = r.points.get(pidx);
205                                PeanoKey pk = Globals.map.peanoKeys.get(p.getPeanoKeyIdx());
206                                if (pkx != null && !pk.equals(pkx))
207                                        return;
208                        }catch(Exception e){
209                                System.out.println("Bad TL feedback message: \n");
210                                e.printStackTrace();
211                                return;
212                        }
213                        phaseRemainingTime = -1;
214                        currentPhase = -1;
215                        queueSize = -1;
216                        infoTime = Globals.engine.crtTime;
217                        interGreenPhaseTime = -1;
218                        this.cycleLength = cycleLength;
219                       
220                        for (int i = 0; i < segno; i++){
221                                int dir = bb.get();
222                                int color = bb.get();
223                                int remaining = bb.getShort();
224                                int interPhase = bb.getShort();
225                               
226                                double qsize = -1;
227                                for (int j = 1; j <= r.laneNo; j++){
228                                        double qs = bb.getDouble();
229                                        if (j == this.getLane())
230                                                qsize = qs;
231                                }
232                                if (ridx == this.roadIdx
233                                                && ((this.getPointIdx() > pidx && this.direction == 0 && dir == 1) || 
234                                                                (this.getPointIdx() < pidx && this.direction == 1 && dir == 0))
235                                                                ){
236                                        phaseRemainingTime = remaining;
237                                        currentPhase = color;
238                                        queueSize = qsize;
239                                        interGreenPhaseTime = interPhase;
240                                        if (Globals.engine.startedWithGUI && Globals.demo.mv.currentCar != null && this.equals(Globals.demo.mv.currentCar)){
241                                                Globals.demo.st.setSemTime(color, remaining);
242                                                Globals.demo.st.setDemand("sw", (int)(queueSize*1000), 0, false);
243                                        }
244                                }
245                               
246                               
247                               
248                                if (i <segno - 1) 
249                                        try{
250                                                ridx = bb.getShort();
251                                                r = Globals.map.roads.get(ridx);
252                                                pidx = bb.getShort();
253                                                p = r.points.get(pidx);
254                                        }catch(Exception e){
255                                                System.out.println("Bad TL feedback message: \n");
256                                                e.printStackTrace();
257                                                return;
258                                        }
259                        }
260                }
261        }
262       
263        public static int CRTDIR = 0;   
264        static int OPPDIR = 1;
265        static int REST = 2;
266        int comState = CRTDIR;          //send records for the same street and direction as localInfo                   
267//      ArrayList<SimulatedCarInfo> trafficDBcopy = null;
268        static vnsim.map.object.Map map = Globals.map;
269       
270        /**
271         * Create the message to be broadcasted to neighbors. This contains either
272         * the vehicles going in the same direction, oposite direction or all the
273         * other cars
274         *
275         */
276        public byte[] prepareMessage(int messageType){
277                byte[] bytesToSend = null;
278                if (realPos.finished)
279                        return null;
280                if (!isEquipped)
281                        return null;
282               
283                //for messageType = 0, standard neighborDiscovery message
284                if (messageType == STANDARD_MESSAGE_ID){
285                        //neighbor discovery
286                        if (messageType == Globals.PROT_NEIGHBOR_DISCOVERY){
287                                byte[] localinfo = toBytes();
288                                ByteArrayOutputStream outBytes = new ByteArrayOutputStream();
289                                outBytes.write(Globals.PROT_NEIGHBOR_DISCOVERY);
290                                outBytes.write(CRTDIR);
291                                try{
292                                        outBytes.write(localinfo);
293                                }catch(IOException e){
294                                }
295                                bytesToSend = outBytes.toByteArray();
296                        }
297                        if (messageType == Globals.PROT_SETOFCARS){
298                               
299                                if (Globals.probabilisticModel){
300                                        decideTransmissionMode();
301                                       
302                                        if (pulseMessage){
303                                                if (isPromiscuousMode() && speed > 1){
304                                                        super.state = 0;
305                                                        setPromiscuousMode(false);
306                                                }
307                                                if (super.state == 3){
308                                                        setPromiscuousMode(true);
309                                                        return null;
310                                                }
311                                        }
312                                        else
313                                        {
314                                                setPromiscuousMode(false);
315                                                super.state = 0;
316                                        }
317                                }
318//                              if (li.getToSend().getRoadIdx() != li.getPrevSent().getRoadIdx()){
319//                              state = CRTDIR;
320//                              }
321                               
322                                int carsno;
323                                ByteArrayOutputStream outBytes = null;
324                               
325                                while(true){
326                                        int roadIndex = -1, roadIndex1 = -1;
327                                        int dir = -1, direction1 = -1;
328                                        carsno = 1;
329                                        int off = 0;
330                                        outBytes = new ByteArrayOutputStream();
331
332                                        if (comState == CRTDIR){
333                                                roadIndex = getRoadIdx();
334                                                dir = getDirection();
335                                        }else
336                                                if (comState == OPPDIR){
337                                                        roadIndex = getRoadIdx();
338                                                        dir = 1 - getDirection();
339                                                } 
340                                       
341                                        outBytes.write(Globals.PROT_SETOFCARS); // leave room for number of records
342                                        outBytes.write(0); // leave room for number of records
343                                        outBytes.write(comState);
344                                        off++;
345                                       
346                                        try{
347                                                //local information
348                                                if (this.speed < 1 ){
349                                                        super.state = 3; //promiscuous mode
350                                                }else{
351                                                        super.state = 0;
352                                                }
353                                                if (realPos.turningLeft)
354                                                        setSignal((byte)1);
355                                                else
356                                                        setSignal((byte)0);
357                                                byte[] car = toBytes();
358                                                outBytes.write(car);
359                                                off += car.length;
360                                               
361                                               
362                                                if (!pulseMessage){
363                                                        ListIterator<CarInfo> it = trafficDB.listIterator();
364                                                        for (; it.hasNext(); ){
365                                                                CarInfo sc = it.next();
366                                                                if (sc.getRoadIdx() == roadIndex && sc.getDirection() == dir){
367                                                                        car = sc.toBytes();
368                                                                        if (off + car.length > Globals.MTU_SIZE - 100){
369                                                                                // no more room in the packet for this car
370                                                                                //TODO
371                                                                                break;         
372                                                                        }
373                                                                        outBytes.write(car);
374                                                                        off += car.length;
375                                                                        carsno ++;
376                                                                }
377                                                               
378                                                        }
379                                                }
380                                        }catch(IOException e){
381                                                System.out.println("Error sending cars");
382                                                e.printStackTrace();
383                                        }
384                                       
385                                        if (comState == OPPDIR && carsno == 1){
386                                                // no cars on the opposed movement
387//                                              comState = REST;
388                                                comState = CRTDIR;
389                                                continue;
390                                        }
391//                                      if (comState == REST && carsno == 1){
392//                                      // no more cars
393//                                      comState = CRTDIR;
394//                                      }
395                                        break;
396                                }
397                               
398                                bytesToSend = outBytes.toByteArray();
399                                bytesToSend[1] = (byte)carsno;  //set the first byte to be the number of records
400                               
401                                if (comState == CRTDIR){
402                                        comState = OPPDIR;
403                                        reportedNeighbors = 0;
404                                }else
405                                        if (comState == OPPDIR)
406                                                comState = CRTDIR;
407//                              comState = REST;
408                        }
409                }
410               
411                return bytesToSend;
412        }
413       
414        static Random randgen = new Random();
415        public static int count = 0;
416        public void decideTransmissionMode(){
417                pulseMessage = false;
418                double liderProbability;
419               
420                if (reportedNeighbors == 0){
421                        return;
422                }
423                if (neighMinusDistance + neighPlusDistance < 0.010){
424                        liderProbability = (double)1 / (reportedNeighbors);
425                }else
426                        if (neighMinusDistance + neighPlusDistance < Engine.WIRELESS_RANGE){
427                                liderProbability = (double)3 / (reportedNeighbors);
428                        }else{
429                                liderProbability = (double)5 / (reportedNeighbors);
430                        }
431                double rand = randgen.nextDouble();
432
433               
434//              System.out.println(liderProbability + " " +reportedNeighbors+ " "+(neighMinusDistance + neighPlusDistance));
435                if (rand > liderProbability)
436                        pulseMessage = true;
437               
438        }
439        /**
440         * Parses a TrafficView packet, and updates the local database accordingly.
441         *
442         * @param buffer
443         */
444        public void parsePacket(byte buffer[]){
445                ByteArrayInputStream byteStream = new ByteArrayInputStream(buffer);
446                byte numberOfRecords, recordsRead = 0;
447                int offset;
448                byte[] b = new byte[Globals.NONAGG_RECORD_SIZE];
449               
450                // read protocol byte
451                byteStream.read();
452                numberOfRecords = (byte)byteStream.read();
453                if (numberOfRecords == -1)
454                        return;
455                offset = 2;
456                int messageRoadDirection = byteStream.read();
457               
458                //The records in the packet represent cars that run on a street in a
459                //certain direction.
460                //The first record is always the car that sent the packet even if it is on
461                //a different street or runs in the opposite direction
462                while (recordsRead < numberOfRecords){
463                       
464                        int n = byteStream.read(b, 0, Globals.NONAGG_RECORD_SIZE);
465                        if (n == -1 || n < Globals.NONAGG_RECORD_SIZE){
466                                break;
467                        }
468                        offset += Globals.NONAGG_RECORD_SIZE;
469                        recordsRead ++;
470                       
471                        CarInfo sc = new CarInfo();
472                        sc.wrap(b);
473                        if (recordsRead == 1 && sc.getRoadIdx() != getRoadIdx()){ 
474                                return;
475                        }
476                       
477                       
478                        if (sc.getVehicleId() == getVehicleId() ||
479                                        Globals.engine.crtTime - sc.getTimestamp() > Globals.NEIGHBOR_EXPIRES)
480                                continue;
481                                               
482                        CarInfo storedCar = null;
483                        //no validation, other than timestamp check for each incoming car record
484                        int i = trafficDB.indexOf(sc);
485                        if (i!=-1){
486                                storedCar = trafficDB.get(i);
487                                if (storedCar.getVehicleId() == sc.getVehicleId()){
488                                                if (storedCar.getTimestamp() <= sc.getTimestamp())
489                                                {
490                                                        synchronized(trafficDB){
491                                                                trafficDB.set(i,sc);
492                                                        }
493                                                }
494                                }
495                               
496
497                        }else{
498                                synchronized(trafficDB){
499                                        trafficDB.add(sc);
500//                                      System.out.println("Add "+dc +" at "+(Globals.trafficDB.size()-1));
501                                }
502                        }
503                        if (recordsRead == 1){
504                                //first record is the car that sent the packet
505
506                                reportedNeighbors ++;
507                                Road r = Globals.map.roads.get(roadIdx);
508                                Point p1 = r.points.get(pointIdx);
509                                Point p2 = r.points.get(sc.getPointIdx());
510                               
511                                double distance = Math.abs(p1.getDistance() - p2.getDistance());
512                                if (sc.getPointIdx() > this.getPointIdx() && distance > neighPlusDistance)
513                                        neighPlusDistance = distance;
514                                if (sc.getPointIdx() < this.getPointIdx() && distance > neighMinusDistance)
515                                        neighMinusDistance = distance;
516                        }
517
518                        // For the moment, I'm interested only in road I'm driving on, or in roads
519                        // connected to it. This is the relevance area.
520                        // If I receive a packet for cars that are not in this area, I drop the
521                        // packet, after I store the direct neighbor.
522                        if (recordsRead == 1 && sc.getRoadIdx() != getRoadIdx()){ 
523//                                      && map.connectionPoint(sc.getRoadIdx(), getRoadIdx()) ==-1 ){
524                                return;
525                        }
526                }
527        }
528       
529       
530       
531       
532       
533        /**
534         * delay and period of the new event (in frames)
535         * @return the identifier of the new message type
536         */
537        public int scheduleNewSendEvent(int delay, int period){
538                Engine engine = Globals.engine;
539                int newType = messageNo;
540                messageNo ++;
541               
542                messagePeriods.put(newType, new Integer(period));
543                engine.schedEvent(new SendEvent(engine.crtTime + delay, this, newType));
544                return newType;
545        }
546       
547        /**
548         * delay and period of the new event (in frames)
549         * if id is not null then, the transmission will be a unicast to the car with the specified id
550         * @return the identifier of the new message type
551         */
552        public int scheduleSingleSendEvent(int delay, Integer id){
553                Engine engine = Globals.engine;
554                int newType = singleMessageNo;
555                singleMessageNo --;
556               
557                // if (singleMessageNo < MIN_NEG_INT) singleMessageNo = -1;
558               
559                if (id == null){
560                        engine.schedEvent(new SendEvent(engine.crtTime + delay, this, newType));
561                }else{
562                        engine.schedEvent(new UnicastSendEvent(engine.crtTime + delay, this, newType, id.intValue()));
563                }
564                return newType;
565        }
566       
567        //Petroaca - emergency type message scheduler
568        public void scheduleEmergencySendEvent(int delay)
569        {
570                Engine engine=Globals.engine;
571               
572                if(Globals.MULTI_CHANNEL)
573                        engine.schedEventEmergency(new SendEvent(engine.crtTime+delay,this,-1));
574                else
575                        engine.schedEvent(new SendEvent(engine.crtTime+delay,this,-1));
576               
577        }
578       
579        public boolean isPeriodicalMessage(int messageType){
580                return (messageType >= 0);
581        }
582
583        public int getPeriod(int messageType){
584                try{
585                        return messagePeriods.get(new Integer(messageType)).intValue();
586                }catch(Exception e){
587                        return -1;
588                }
589        }
590       
591        public String toString(){
592                return "("+super.toString()+")";
593        }
594       
595//      public String getRealPos(){
596//              return "("+getVehicleId()+" - "+realPos.toString()+")";
597//      }
598       
599        public void setRealPos(CarInstance realPos) {
600                if (this.realPos != null){
601                        realPos.deleteCarToPointMapping();
602                }
603                this.realPos = realPos;
604                realPos.setSimulatedCarInfo(this);
605                realPos.updateCarToPointMapping();
606               
607        }
608        public CarInstance getRealPos() {
609                return realPos;
610        }
611       
612        public int getLastMediumTransmition() {
613                return lastMediumTransmission;
614        }
615        public void setLastMediumTransmition(int lastMediumTransmission) {
616                this.lastMediumTransmission = lastMediumTransmission;
617        }
618       
619        public boolean mediumAvailable(int crtTime){
620                int fps = Globals.engine.fps;
621                if (crtTime - lastMediumTransmission >= Globals.WIRELESS_TRANSMISSION_FRAMES)
622                        return true;
623                return false;
624        }
625       
626        public RadioDev getRadio(){
627                return radio;
628        }
629       
630        public ReceiveEvent getReceiveEventForTime(int t){
631                int i = receiveEvents.indexOf(new ReceiveEvent(t, null, null, null, 0));
632                if (i == -1)
633                        return null;
634                return receiveEvents.get(i);
635        }
636
637        public void addReceiveEventForTime(ReceiveEvent re){
638                receiveEvents.add(re);
639        }
640        public void removeReceiveEventForTime(int t){
641                int i = receiveEvents.indexOf(new ReceiveEvent(t, null, null, null, 0));
642                if (i == -1)
643                        return;
644                receiveEvents.remove(i);
645        }
646
647        //Petroaca - for the emergency receive events list
648       
649        public ReceiveEvent getReceiveEventEmergencyForTime(int t){
650                int i = receiveEventsEmergency.indexOf(new ReceiveEvent(t, null, null, null, 0));
651                if (i == -1)
652                        return null;
653                return receiveEventsEmergency.get(i);
654        }
655
656        public void addReceiveEventEmergencyForTime(ReceiveEvent re){
657                receiveEventsEmergency.add(re);
658        }
659        public void removeReceiveEventEmergencyForTime(int t){
660                int i = receiveEventsEmergency.indexOf(new ReceiveEvent(t, null, null, null, 0));
661                if (i == -1)
662                        return;
663                receiveEventsEmergency.remove(i);
664        }
665}
Note: See TracBrowser for help on using the repository browser.