/************************************************************************************ * Copyright (C) 2008 by Politehnica University of Bucharest and Rutgers University * All rights reserved. * Refer to LICENSE for terms and conditions of use. ***********************************************************************************/ //Petroaca - package vnsim.network.dsrc; import java.io.ByteArrayInputStream; import java.util.Random; import java.util.ArrayList; import vnsim.core.events.ReceiveEvent; import vnsim.core.events.SendEvent; import vnsim.map.object.Globals; public class MAC80211 { private int ChannelState; private int RXState,TXState; private int currentTime; private DsrcFrame currentFrame; private static final double relError= 1E-12; //the timer which decides how many simulation times the station will wait until it will reschedule the packet private int backoffTimer; //the sinr threshold for the BPSK code rate private double SINRThreshold=Globals.SINRThresholdBPSK; private Random randBackoff; //contention window ; varies according to the transmission success or failure private int CWSafety,CWVehicleState,CW; //the EDCA mechanism //the safety Access Category in EDCA private ArrayList ACSafety; //the vehicle state Access Category in EDCA private ArrayList ACVehicleState; private double receptionRate; private int receivedOk; public MAC80211(int currentTime) { this.ChannelState=Globals.CCA_IDLE; this.RXState=Globals.RX_IDLE; this.TXState=Globals.TX_IDLE; this.currentTime=currentTime; this.currentFrame=new DsrcFrame(); this.randBackoff=new Random(); this.CWVehicleState=2; this.CWSafety=1; this.CW=0; this.backoffTimer=this.randBackoff.nextInt(this.CWSafety+1); /* this.CWVehicleState=7; this.ACSafety=new ArrayList(); this.ACVehicleState=new ArrayList(); */ this.receptionRate=0; this.receivedOk=0; } public int getChannelState() { return this.ChannelState; } public void setChannelState(int set) { this.ChannelState=set; } public byte[] recvFromPhysical(ReceiveEvent re,double sinr,int currentTime) { //first check SINR to see if frame is corrupted if(re.getSender()==null) { if(sinrGlobals.DSRC_PER_THRESHOLD) { //per checked ok //return data to application this.RXState=Globals.RX_RECV; Globals.DSRC_PACKETS_RECEIVED_OK++; this.receivedOk++; return re.getMessage(); } //packet dropped due to bad per check Globals.DSRC_PACKETS_LOST_PER++; return null; } public byte[] sendToPhysical(byte[] message,int currentTime) { //DsrcFrame frame=new DsrcFrame(); //check channel state ; employ backoff timer if(this.ChannelState==Globals.CCA_BUSY) { //channel busy ; pause backoff timer //this.setBackoffTimer(this.backoffTimer+1); //the reason for the faliure to send if(this.RXState!=Globals.RX_RECV) Globals.DSRC_PACKETS_SEND_FALIURE_RX++; else Globals.DSRC_PACKETS_SEND_FALIURE_NOISE++; if(this.TXState!=Globals.TX_RECV) this.TXState=Globals.TX_RECV; return null; } //EDCA scheduler - sets the CW to the respective value depending on the message priority this.EDCAScheduler(message[0]); //if(this.TXState==Globals.TX_IDLE) //{ if(this.backoffTimer==0) { this.setBackoffTimer(this.randBackoff.nextInt(this.CW+1)); this.TXState=Globals.TX_IDLE; return message; } else { this.backoffTimer--; this.TXState=Globals.TX_RECV; return null; } //} //return null; } public void refreshFrameTime(int currentTime) { if(currentTime-this.currentTime>=Globals.WIRELESS_TRANSMISSION_FRAMES) { this.RXState=Globals.RX_IDLE; this.ChannelState=Globals.CCA_IDLE; if(currentTime%4==0) this.receivedOk=0; } this.currentTime=currentTime; } public double calculatePER(double sinr,double preambleNbits,double headerNbits,double dataNbits) { double psr=1; psr*=calculateBER(sinr,preambleNbits,Globals.DSRC_DATA_RATE); psr*=calculateBER(sinr,headerNbits,Globals.DSRC_PCLP_RATE); psr*=calculateBER(sinr,dataNbits,Globals.DSRC_DATA_RATE); return 1-psr; } public double calculateBER(double sinr,double nbits,double dataRate) { double ber=BPSKBER(sinr,dataRate); double csr=Math.pow(1-ber, nbits); return csr; } public double BPSKBER(double sinr,double dataRate) { double EbNo=sinr * Globals.DSRC_SIGNAL_SPREAD/dataRate; double z=Math.sqrt(EbNo); double ber=0.5 * erfc(z); return ber; } public double erf(double x) { final double twoSqrtPi=2/Math.sqrt(Math.PI); if(Math.abs(x) > 2.2) return 1.0-erfc(x); double sum=x,term=x,xsqr=x*x; int j=1; do{ term*= xsqr/j; sum-= term/(2*j+1); ++j; term*= xsqr/j; sum+= term/(2*j+1); ++j; } while (Math.abs(term/sum) > relError); return twoSqrtPi*sum; } public double erfc(double x) { final double oneSqrtPi=1/Math.sqrt(Math.PI); if(Math.abs(x) < 2.2) return 1.0-erf(x); if(x<0) return 2.0-erfc(-x); double a=1, b=x; //last two convergent numerators double c=x, d=x*x+0.5; //last two convergent denominators double q1, q2= b/d; //last two convergents (a/c and b/d) double n= 1.0, t; do { t= a*n+b*x; a= b; b= t; t= c*n+d*x; c= d; d= t; n+= 0.5; q1= q2; q2= b/d; } while (Math.abs(q1-q2)/q2 > relError); return oneSqrtPi*Math.exp(-x*x)*q2; } public void setBackoffTimer(int set) { this.backoffTimer=(set>this.CWSafety)?this.CWSafety:set; } public int getBackoffTimer() { return this.backoffTimer; } public void recalculateCW(int totalPackets,int currentTime) { if(currentTime%4==0 && totalPackets!=0) { double aux=((double)this.receivedOk/totalPackets*100); if(aux-this.receptionRate>Globals.RECEPTION_RATE_THRESHOLD) { this.receptionRate=aux; this.CWSafety=(this.CWSafety==0)?0:this.CWSafety-1; this.CWVehicleState=(this.CWVehicleState==0)?0:this.CWVehicleState-1; return; } if(-(aux-this.receptionRate)>Globals.RECEPTION_RATE_THRESHOLD) { this.receptionRate=aux; this.CWSafety++; this.CWVehicleState++; } } } public void EDCAScheduler(int messageType) { //to be completed with other message types switch(messageType) { case Globals.PROT_EMERGENCY: this.CW=this.CWSafety; break; default: this.CW=this.CWVehicleState; break; } } }