/* file: main.c */ /* * Tom Laramee - ECE 671 - Homework #3 * * This program is an event-drvien simulation of the 802.11 IEEE proposed * standard on wireless LANs (with simplifications of course). * * It is to be used in conjunction with 2 UNIX script called: * sim.sh * sim.gnuplot.sh * and a UNIX makefile called: * makefile * * The script (sim.sh) will compile a new binary from scratch using make * and will then run the program using the desired command line parameters. * * If you'd like to change the command line parameters, the place to do * so is in the script. It should be clear where to do so once you look * at the script. * */ #include #include #include #define SHOWREPORT NULL #define SHOWPARAMS NULL #include "main.h" #include "event.h" #define MAXNODES 60 /* Maximum number of nodes in the system */ #define maxPack 1000 /* Maximum number of packets to simulate for */ #define LIGHT 3E+8 /* The speed of light (m/s) */ tEventPtr evList; /* Head of the event list */ tEventPtr newEvent; /* A new event to be malloc()d and inserted onto event list */ tEventPtr currEvent; /* A pointer to the current event */ tProcPtr qptr[MAXNODES]; /* Each nodes proc queue */ tProcPtr currProc; /* The current proc */ FILE * fEvent; /* Pointer to file of events */ short isDeferring[MAXNODES], /* is the node deferring? */ channelBusy, /* Is the channel busy? */ DEBUGGING, done; /* Are we done with the simulation yet? */ int numNodes, /* number of nodes in the system */ NUM_REARRIVAL=0, channelLength, /* length of the channel */ bitsPerPac, /* number of bits / packet */ bitsPerAck, /* number of bits / ack */ buffPerNode, /* Maximum size of buffer for each node */ maxCWindow, /* Maximum contention window size */ minCWindow, /* Minimum contention window size */ curCWindow, /* The current contention window size */ numCollisions, /* The total number of collisions */ numPacketsLost, /* the number of packets which overflow the nodes' buffers */ numInQ[MAXNODES], /* The number of packets in queue for a node */ numDeferring, /* Number of nodes deferring */ totalPackets, /* Total number of packets sent so far.. */ loopcounter, /* Count the total number of events */ iseed; /* Seed of random number generator */ double propDelay, /* End-to-end propagation delay */ channelCapacity, /* Capacity of the channel */ probError, /* Probability[no error] when transmitting a packet */ SIFS, /* SIFS interval */ DIFS, /* DIFS interval */ T3, /* Time out interval */ slotTime, /* Approximation of the slot time */ packetDelay, /* The delay a packet has incurred in the system */ totalPacketDelay, /* The total delay of all the packets incur in the system */ timeNextEvent, /* Time of next event occurance */ lambdaN, /* Node arrival rate */ lambdaS, /* System arrival rate */ sysTime, /* Global clock */ timeXAck, /* time to transmit an ACK */ timeXPac; /* time to transmit a packet */ /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ short initParams(int argc, char * argv[]) { /* This function read in all command line parameters and assigns * the proper values to the corresponding variables */ int counter; numNodes=10; /* set default values - in case not */ channelLength=100; /* all command line args are present */ propDelay=3.3e-07; channelCapacity=2048000; bitsPerPac=2048; bitsPerAck=8; buffPerNode=30; maxCWindow=1024; minCWindow=4; SIFS=(2.5)*(3.3e-07); DIFS=(4.0)*(3.3e-07); T3=(3.0)*(3.3e-07); lambdaS=1.0; probError=0; DEBUGGING=0; /* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> command line options */ if (argc==1) { printf ("\nUsing the default parameters..."); return (1); } for (counter=1; counter70) fatal ("initParms", "too many nodes (<50 or 60 is good)"); if (channelCapacity<=0) fatal ("initParms", "need positive channel capacity"); /* etc */ } /* End of initAll; /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ void showParams(FILE * fp) { /* This function shows all of the values of the command line * argument variables after they have been entered and processed */ if (fp!=NULL) { /* end of going through all of the command line args */ fprintf (fp, "\n\nNumber of Nodes............: %d", numNodes); fprintf (fp, "\nChannel length.............: %d ", channelLength); fprintf (fp, "\nPropagation Delay..........: %1.2e", propDelay); fprintf (fp, "\nChannel capacity...........: %1.3e", channelCapacity); fprintf (fp, "\nBits/packet................: %d", bitsPerPac); fprintf (fp, "\nBits/ACK...................: %d ", bitsPerAck); fprintf (fp, "\nMax number of buffers/node.: %d", buffPerNode); fprintf (fp, "\nMax contention window......: %d", maxCWindow); fprintf (fp, "\nMin contention window......: %d", minCWindow); fprintf (fp, "\nSIFS.......................: %1.2e", SIFS); fprintf (fp, "\nDIFS.......................: %1.2e", DIFS); fprintf (fp, "\nT3.........................: %1.2e", T3); fprintf (fp, "\nProb[unsuccessful Packet]..: %1.1lf", probError); fprintf (fp, "\nSystem packet arrival rate.: %lf", lambdaS); fprintf (fp, "\nNodal packet arrival rate..: %lf", lambdaN); fprintf (fp, "\nTime to transmit an ack....: %lf", timeXAck); fprintf (fp, "\nTime to transmit a packet..: %lf\n", timeXPac); } } /* showParams */ /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ void showEventList(FILE * fp) { /* This function shows all of the events which are currently * on the event list */ tEventPtr q=NULL; if (!evList) fatal("showEventList", "No events on the list"); if (fp != NULL) { fprintf (fp, "\nEvent list for system time: %1.8lf", sysTime); fprintf (fp, "\nEVtime EVcode NODEcode JOBdest"); for (q=evList; q!=NULL; q=q->next) { fprintf (fp, "\n%1.8lf %s %2d %2d", q->evtime, printEVENT(q->evcode), q->nodecode, q->jobdest); } } /* End of if (fp !=NULL) */ } /* End of showEventList */ /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ void showCurrentEvent(FILE * fp) { /* This function shows the current event being processed */ tEventPtr q=NULL; if (currEvent==NULL) fatal("showCurrentEvent", "No event to show"); q=currEvent; if (fp != NULL) { fprintf (fp, "\nCurrent event for system time: %1.8lf", sysTime); fprintf (fp, "\nEVtime EVcode NODEcode JOBdest"); fprintf (fp, "\n%1.8lf %s %2d %2d", q->evtime, printEVENT(q->evcode), q->nodecode, q->jobdest ); } /* End of if (fp !=NULL) */ } /* End of showCurrentEvent */ /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ void showReport ( FILE * fp ) { /* This function displays summary information at the end of a simulation */ double throughput, avgPacketDelay, avgQueueLength; FILE * fp1; FILE * fp2; FILE * fp3; FILE * fp4; throughput=(totalPackets*timeXPac)/sysTime; avgPacketDelay=(totalPacketDelay/totalPackets); avgQueueLength=avgPacketDelay*lambdaN; /* Little's law */ /* collect statistics to external file for plotting */ fp1=fopen("a", "w"); fp2=fopen("b", "w"); fp3=fopen("c", "w"); fp4=fopen("d", "w"); if ((!fp1) || (!fp2) || (!fp3) || (!fp4)) fatal ("showReport", "Cannot open file to write to "); fprintf (fp1, "\n%lf %lf", lambdaS, throughput); fprintf (fp2, "\n%lf %lf", lambdaS, avgPacketDelay); fprintf (fp3, "\n%lf %lf", lambdaS, avgQueueLength); fprintf (fp4, "\n%lf %d", lambdaS, NUM_REARRIVAL); fclose(fp1); fclose(fp2); fclose(fp3); fclose(fp4); /* collect statistics to the screeen */ if (fp != NULL) { fprintf (fp, "\nSimulation results"); fprintf (fp, "\n\nNumber of Nodes.................: %d", numNodes); fprintf (fp, "\nChannel length..................: %d ", channelLength); fprintf (fp, "\nChannel capacity................: %1.3e", channelCapacity); fprintf (fp, "\nBits/packet.....................: %d", bitsPerPac); fprintf (fp, "\nBits/ACK........................: %d ", bitsPerAck); fprintf (fp, "\nProb[unsuccessful Packet].......: %1.1lf", probError); fprintf (fp, "\nSystem packet arrival rate......: %lf", lambdaS); fprintf (fp, "\nNodal packet arrival rate.......: %lf", lambdaN); fprintf (fp, "\nTime to transmit an ack.........: %lf", timeXAck); fprintf (fp, "\nTime to transmit a packet.......: %lf", timeXPac); fprintf (fp, "\nTotal number of collisions......: %d", numCollisions); fprintf (fp, "\nTotal # of packets transmitted..: %d", totalPackets); fprintf (fp, "\nThroughput (percent)............: %3.2lf", (throughput*100) ); fprintf (fp, "\nTotal time of simulation........: %1.8lf", sysTime); fprintf (fp, "\nTotal packet delay..............: %1.8lf ", totalPacketDelay ); fprintf (fp, "\nAverage delay / packet..........: %1.8lf ", avgPacketDelay ); fprintf (fp, "\nQvg length of a node's queue....: %2.1lf ", avgQueueLength ); fprintf (fp, "\nTotal # of packets lost.........: %d\n\n", numPacketsLost); } } /* End of report() */ /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ void gen_arrival(int node) { /* This function assigns a time to an arrival based on the nodal * arrival rate and the poisson assumption. It also fills the * required fields of the structure */ double timeArrival; nextarrival(); /* Calculate a poisson arrival time */ timeArrival = timeNextEvent; /* Assign arrival time (poisson) */ newEvent = alloc_evrec(); /* Allocate room for an event */ newEvent->evtime = timeArrival; /* Set it's time to occur randomly */ newEvent->evcode = ARRIVAL; /* Set the type of event */ newEvent->nodecode = node; /* Attach ownership to a node */ newEvent->jobdest=node; /* we don't care who the dest is */ newEvent->next=NULL; /* initialize pointers */ newEvent->prev=NULL; insertevent(newEvent); /* Add the event to the event list */ } /* End of gen_arrival() */ /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ void gen_re_arrival(int node) { /* This function generates a RE_ARRIVAL event for the time when * there is a collision and multiple nodes are competing for the * channel */ double timeReArrival; NUM_REARRIVAL++; nextarrival(); timeReArrival=timeNextEvent; newEvent = alloc_evrec(); /* Allocate room for an event */ newEvent->evtime = timeReArrival; /* Set it's random backoff time */ newEvent->evcode = RE_ARRIVAL; /* Set the type of event */ newEvent->nodecode = node; /* Attach ownership to a node */ newEvent->jobdest=node; /* we don't care who the dest is */ newEvent->next=NULL; /* initialize pointers */ newEvent->prev=NULL; insertevent(newEvent); /* Add the event to the event list */ } /* End of gen_arrival() */ /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ void gen_x_successful( int node ) { /* this function generates an "X_SUCCESSFUL" event - or "successful * transmission" event, and inserts it into the event list * * pd = propagation delay * timeXPac = time to transmit a packet * * | DIFS | pd | timeXPac | pd | SIFS | pd | * ----------------------------------------------> time */ double timeOccur; /* Calculate time to occur */ timeOccur = sysTime + 3*propDelay + DIFS + timeXPac + SIFS; newEvent = alloc_evrec(); /* Allocate room for an event */ newEvent->evtime = timeOccur; /* Set it's time to occur randomly */ newEvent->evcode = X_SUCCESSFUL; /* Set the type of event */ newEvent->nodecode=node; /* Owner of the event */ newEvent->jobdest=node; /* unnecessary */ newEvent->next=NULL; /* initialize pointers */ newEvent->prev=NULL; insertevent(newEvent); /* Add the event to the event list */ } /* End of gen_x_successful() */ /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ void gen_x_unsuccessful( void ) { /* this function generates an "X_UNSUCCESSFUL" event - or "unsuccessful * transmission" event, and inserts it into the event list * * pd = propagation delay * timeXPac = time to transmit a packet * * | DIFS | pd | timeXPac | pd | * ----------------------------------------------> time */ double timeOccur; /* Calculate time to occur */ timeOccur = sysTime + 2*propDelay + DIFS + timeXPac; newEvent = alloc_evrec(); /* Allocate room for an event */ newEvent->evtime = timeOccur; /* Set it's time to occur randomly */ newEvent->evcode = X_unSUCCESSFUL; /* Set the type of event */ newEvent->next=NULL; /* initialize pointers */ newEvent->prev=NULL; insertevent(newEvent); /* Add the event to the event list */ } /* End of gen_x_UNsuccessful() */ /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ void queueItUp( int node ) { /* This function inserts an arrival event into the queue of * the corresponding node */ tProcPtr pProc; if (numInQ[node]jobid = node; pProc->sys_arrival_time = sysTime; pProc->next=NULL; pProc->prev=NULL; insertproc(pProc, node ); } else numPacketsLost++; /* otherwise there is an overflow */ } /* End of queueItUp */ /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ short Prob( void ) { /* This function will return a "0" if the transmission is going * to be un-successful, and a "1" if it is going to be successful, * based on the Prob[unsuccessful transmission] */ short x; x = ( (uni() ) < probError )?0:1; return(x); } /* End of Prob */ /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ short willCollide( void ) { /* This function looks at the 1st 2 arrivals (or rearrivals) in the * event list to see if they will collide. They will collide when * they're scheduled to start closer together than the propDelay. */ double time1=0, time2=0; short found1=0, found2=0; tEventPtr r=NULL; for (r=evList; (r!=NULL); r=r->next) { if ( ((r->evcode==ARRIVAL) || (r->evcode==RE_ARRIVAL)) && (!found1)) { time1=r->evtime; found1=TRUE; } else if ( ((r->evcode==ARRIVAL) || (r->evcode==RE_ARRIVAL)) && (!found2)) { time2=r->evtime; found2=TRUE; } if ((found1) && (found2)) break; } if (DEBUGGING) if (fEvent) fprintf (fEvent,"\n\nFound 1: %1.8lf", time1); if (DEBUGGING) if (fEvent) fprintf (fEvent,"\nFound 2: %1.8lf", time2); if ((time1<0) || (time2<0)) fatal ("willCollide", "strange time"); if ((time2-time1)nodecode; if (DEBUGGING) if (fEvent) fprintf (fEvent, "\n\nProcess - data arrival"); if (DEBUGGING) if (fEvent) fprintf (fEvent, "\nMedia free? %s", (channelBusy==FALSE)?"YES":"NO"); if (DEBUGGING) if (fEvent) fprintf (fEvent, "\nThe node: %d", theNode); /* Determine time for next data arrival, insert into event list */ gen_arrival(theNode); /* ~~~~~~~~~~~~~~~~~~~~~~~~~~ If the channel is free ~~~~~~~~~~~~~~~~~~ */ if (!channelBusy) { if (Prob()) /* Prob of successful transmission */ { if (DEBUGGING) if (fEvent) fprintf (fEvent, "\nSuccessful\n"); channelBusy=TRUE; /* Set the channel to busy */ queueItUp(currEvent->nodecode); /* Add the packet to the queue */ gen_x_successful(theNode); /* schedule X_SUCCESSFUL event */ } else /* Prob of unsuccessful transmission */ { if (DEBUGGING) if (fEvent) fprintf (fEvent, "\nUn-successful\n"); channelBusy=TRUE; /* Set the channel to busy */ queueItUp(currEvent->nodecode); /* Add the packet to the queue */ numDeferring++; isDeferring[theNode]=TRUE; /* Set the node deferring to simulate */ gen_x_unsuccessful(); /* the node being aware that there was */ } /* a collision on it's last transmission */ } /* ~~~~~~~~~~~~~~~~~ If the channel is not free... ~~~~~~~~~~~~~~~~~~~~ */ else { if (isDeferring[theNode]==FALSE) /* If the node is already */ { /* deferring, don't count it */ numDeferring++; /* twice...just queue the packet */ isDeferring[theNode]=TRUE; } queueItUp(currEvent->nodecode); /* Add the packet to the queue */ } } /* End of processarrival */ /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ short processReArrival( void ) { int theNode; theNode=currEvent->nodecode; if (DEBUGGING) if (fEvent) fprintf (fEvent, "\n\nProcess - data RE-arrival"); if (DEBUGGING) if (fEvent) fprintf (fEvent, "\nMedia free? %s", (channelBusy==FALSE)?"YES":"NO"); if (DEBUGGING) if (fEvent) fprintf (fEvent, "\nThe node: %d\n", theNode); /* ~~~~~~~~~~~~~~~~~~~~~~~~~ If the channel is free ~~~~~~~~~~~~~~~~~~ */ if (!channelBusy) { if (Prob()) { channelBusy=TRUE; /* Set the channel to busy */ gen_x_successful(theNode); /* schedule X_SUCCESSFUL event */ } else { numDeferring++; isDeferring[theNode]=TRUE; /* schedule X_UN_SUCCESSFUL event */ channelBusy=TRUE; /* Set the channel to busy */ gen_x_unsuccessful(); } } /* ~~~~~~~~~~~~~~~ If the channel is not free... ~~~~~~~~~~~~~~~~~~~~ */ else { numDeferring++; /* Defer until end of transmission */ isDeferring[theNode]=TRUE; /* or end of collision */ } } /* Process re-arrival */ /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ short processXSuccessful( void ) { /* Processing which occurrs @ the end of a successful transmission */ /* Check the numDeferring to see how many and schedule them as */ /* is appropriate */ int theNode, /* the particular node we're processing */ i; /* dummy counter */ struct proc * p; /* temporary procedure pointer */ channelBusy=FALSE; /* Free up the channel */ theNode=currEvent->nodecode; /* simplify the code */ /* make sure there is a packet in the queue to be collected */ if (qptr[theNode]==NULL) fatal ("processXSuccessful", "no proc for this successful Xmission"); /* collect stats */ p=get_firstproc(theNode); /* Use the packet @ the front of the queue */ packetDelay= sysTime-(p->sys_arrival_time); /* Packets delay */ totalPacketDelay+=packetDelay; /* Total packet delay */ totalPackets++; /* INC # of packets */ numInQ[theNode]--; /* decrement the number in queue */ if (DEBUGGING) if (fEvent) fprintf (fEvent, "\nCollect statistics...rm packet from queue"); if (DEBUGGING) if (fEvent) fprintf (fEvent, "\nStats: Packet arrival: %1.8lf", p->sys_arrival_time); if (DEBUGGING) if (fEvent) fprintf (fEvent, "\nStats: delay: %lf", packetDelay); if (DEBUGGING) if (fEvent) fprintf (fEvent, "\nStats: Total pakect delay: %lf", totalPacketDelay); if (DEBUGGING) if (fEvent) fprintf (fEvent, "\nStats: num Packets Xmitted: %d", totalPackets); if (DEBUGGING) if (fEvent) fprintf (fEvent, "\nNum deferring: %d", numDeferring); /* Processing from here on in is exactly the same as for a collision * event - the only difference is that a successful collision requires * statistics to be taken/updated - but the process of finding out * how many nodes are deferring and rescheduling them, etc, is * exactly the same */ processXunSuccessful(); return(0); } /* End of processXSuccessful */ /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ short processXunSuccessful( void ) { /* Processing which occurrs @ the end of an UNsuccessful transmission */ /* Check the numDeferring to see how many and back them off */ int i, theNode; double fTime, sTime; if (DEBUGGING) if (fEvent) fprintf (fEvent, "\nprocess XunSuccessful\n"); channelBusy=FALSE; /* Set the channel to free */ theNode=currEvent->nodecode; /* set the current node */ /* -------------- 0 are deferring - nothing to do */ if (numDeferring==0) return (0); /* ------------------- 1 is deferring */ if (numDeferring==1) { for (i=0; ievtime; /* Update the system clock */ if (DEBUGGING) if (fEvent) fprintf (fEvent, "\n\n>>>>>>>>>>>>>>>> Current Event No: %d", ++eventNum); if (DEBUGGING) showCurrentEvent(fEvent); /* Output the current event */ /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ process events */ switch(currEvent->evcode) { case ARRIVAL: /* Arrival of a node to the channel */ processArrival(); break; case RE_ARRIVAL: /* Re-Arrival of a node to the channel */ processReArrival(); break; case X_SUCCESSFUL: /* End of successful transmission */ processXSuccessful(); break; case X_unSUCCESSFUL: /* End of successful transmission */ processXunSuccessful(); break; default: fatal("main", "unknown event to process"); } /* End of switch(currEvent->evcode) */ /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ free_evrec(currEvent); /* Free up the memory */ currEvent=NULL; /* point current event to NULL */ if (totalPackets>=maxPack) done=TRUE; /* Are we done ? */ /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ /* ~~~~~~~~~~~ this is where "showReport() should begin ~~~~~~~~~~~~~~~~ */ if (DEBUGGING) /* Debugging info */ { for (i=0; inext) fprintf (fEvent, "\nSys arrival time: %1.8lf", p->sys_arrival_time); } if (fEvent) fprintf (fEvent, "\nEnd of queue..."); if (fEvent) fprintf (fEvent, "\n------------Who is deferring?"); for (i=0; i