defstar { name { Host } domain { DE } derivedfrom { RepeatStar } author { Ed Knightly } version { 1.1 03/22/93 } location { ~knightly/Ptolemy/de/stars } desc { Acts as host applications requesting channel access from RCAP entity. The Host also sends the packets to the network according to various traffic patterns. If a receiving host declares a channel to be a video channel, then the received video frame will be displayed. } input { name { fromRCAP } type { message } desc { Receives messages from RCAP to tell a sending or receiving host that a new channel has been established or torn down. } } input { name { fromNetwork } type { message } desc { Receives packets from the network at the destination. } } output { name { toRCAP } type { message } desc { Used to sends out establish request or tear-down packets to the node's RCAP. } } output { name { toNetwork } type { message } desc { Used to send the actual traffic to the network. } } defstate { name { chansToTry } type { int } default { 15 } desc { number of channels to be established (0 for receiver) } } defstate { name { nodeAddress } type { int } default { 0 } desc { Node address } } defstate { name { fileName } type { string } default { "tracefile" } desc { Input file } } defstate { name { displayOptions } type { int } default { 0 } desc { 0 text, 1 graphs, 2 frames, 3 video } } defstate { name { options } type { string } default { "-0 'RT chan' -x Delay -y '# pkts'" } desc { command line options for xgraph } } defstate { name { binWidth } type { float } default { "0.1" } desc { Width of bins for histogram. } } hinclude { "Tenet.h", "RCAP.h", "Message.h", "Host.h", "streamCompat.h", "pt_fstream.h", , , , "Histogram.h" } ccinclude { , "DEScheduler.h" } protected { XHistogram his; Time currMin, nextMin; // for scheduling star firings Time firstFire; // refire time of first accepted channel Time nextTearDownTime; HostData *chan, *headChan, *tmpChan; GenState *genState; Stats *stats; unsigned char *imageData, *imagePktRec; int width, height, maxval, maxPkts; NegativeExpntl *rndExp; Normal *rndDelb; Uniform *rndUnif; istream* input; int answers, first, chansTried; int numItems; // number of parameters in each // line not including routing information const int MaxChans = 400; float params[MaxChans][50]; // params[channel number][item number] int rndChans, typeOfChan, mode; int numNodes, chansInFile, tmp, index; long ID; float delta, videoLcid; const float requestInterval = 0.001; u_int showHist, receiveFrame, histValid, receiveVideo; #define epsilon 0.00000001 const float SLACK = 300.0; class Trace { // index is seq. number public: int pktReceived; // 1 if pkt received float recTime; }; Trace *videoTrace; } code { extern ACG* gen; } constructor { delayType = TRUE; // Necessary for delay-free loops input = 0; fromRCAP.before(fromNetwork); } destructor { delete input; } setup { nextTearDownTime = currMin = nextMin = infinity; first = 1; histValid = 0; if ((displayOptions == 1) || (displayOptions == 2)) showHist = TRUE; else showHist = FALSE; if (displayOptions == 2) receiveFrame = TRUE; else receiveFrame = FALSE; if (displayOptions == 3) receiveVideo = TRUE; else receiveVideo = FALSE; if (showHist) his.initialize(this,binWidth,options, "Delay Distribution", "delay.xg"); answers = 0; index = 0; headChan = NULL; chansTried = 0; ID = (long) nodeAddress * (long) 1000; // chansToTry should be 0 for a passive host int check; if (chansToTry) check = readFile(); if (check == -1) Error::abortRun(*this, "can't open file ", fileName); if (check == -2) Error::abortRun(*this, "Wrong input file format."); rndUnif = new Uniform(0.0, requestInterval, gen); delta = (*rndUnif)(); // Send out all establish requests in this loop. They are // scheduled at the time defined in the input file. while ((chansTried < chansToTry) && (check > 0)) { if (rndChans) genRndRequest(); else genDetRequest(); chansTried++; rndUnif = new Uniform(0.0, requestInterval, gen); delta += (*rndUnif)(); } delta = (*rndUnif)(); DERepeatStar :: setup(); if (nextTearDownTime != infinity) refireAtTime(nextTearDownTime); // To start tear-downs, although this channel was not necessarily // accepted. } go { if (fromNetwork.dataNew) updateStats(); if (fromRCAP.dataNew) updateRcap(); if (chansToTry && canGetFired()) generateTraffic(); if (floatEq(arrivalTime, nextTearDownTime)) tearDown(); } // canGetFired() indicates that go was triggered from // internal feedback inline method { name { generateTraffic } access { public } code { // Go through all source channels and send a packet if (!headChan) return; // null list chan = headChan; currMin = nextMin; nextMin = infinity; while (chan) { if (chan->header->src_add == nodeAddress) { generatePkt(chan); nextMin = min(nextMin, chan->genState->nextFire); chan = chan->next; } else chan = chan->next; } // end while(chan) // cout << "refire time is " << currMin << "\n"; refireAtTime(currMin); } } inline method { name { generatePkt } access { public } arglist { "(HostData *sendingChan)" } code { sendingChan->genState->prevFire = sendingChan->genState->currFire; sendingChan->genState->currFire = sendingChan->genState->nextFire; if ( (sendingChan->genState->prevFire - SLACK) > currMin) { // Channel is too far ahead (in time), don't send out pkt, // copy time into next. sendingChan->genState->nextFire = sendingChan->genState->currFire; } else { // Send out packet. sendingChan->genState->sent++; sendPkt(sendingChan); float interval = calcIntvl(sendingChan); sendingChan->genState->nextFire = sendingChan->genState->currFire + interval; } } } inline method { name { sendPkt } access { public } arglist { "(HostData *sendingChan)" } code { Time localTime = sendingChan->genState->currFire; TenetPkt* tenetPkt = new TenetPkt(sendingChan->header, sendingChan->routeInfo); tenetPkt->header->seq_num = sendingChan->genState->sent; tenetPkt->header->timeStamp = localTime; tenetPkt->header->size = sendingChan->traffic->smax; Envelope pkt(*tenetPkt); toNetwork.put(localTime) << pkt; } } method { name { updateRcap } access { public } code { // RCAP has sent a control message indicating that a // channel has been established or torn down. This is // the message for the source or the destination. Envelope pkt; fromRCAP.get().getMessage(pkt); const RCAPpkt* rcapPkt = (const RCAPpkt*) pkt.myData(); if (rcapPkt->header->src_add == nodeAddress) { answers++; if (rcapPkt->header->mess_type == establish_accept) { // node is source, add specs to list genState = new GenState(); genState->nextFire = arrivalTime; stats = new Stats(); chan = new HostData(rcapPkt->header, rcapPkt->traffic, rcapPkt->requirements, rcapPkt->routeInfo, genState, stats, headChan); reverseRoute(chan->routeInfo); rndUnif = new Uniform(0.4, 1.0, gen); chan->tornDown = FALSE; chan->burst_prob = (*rndUnif)(); chan->genState->currFire = arrivalTime; chan->genState->gs_nextI = chan->genState->currFire + chan->traffic->I; rndUnif = new Uniform(0, chan->traffic->xmin, gen); float phase = (*rndUnif)(); chan->genState->nextFire = chan->genState->currFire + phase; headChan = chan; // update linked list if (answers == 1) { // treat first answer differently generatePkt(chan); firstFire = chan->genState->nextFire; generatePkt(chan); refireAtTime(firstFire); } else { if (arrivalTime < firstFire) { while (chan->genState->nextFire < firstFire) { generatePkt(chan); } nextMin = min(nextMin, chan->genState->nextFire); // Send packets through firstFire } else { // later establishment while (chan->genState->currFire < currMin) { generatePkt(chan); } } } // end if not first answer } // end if est accept } // end if node is source else if (rcapPkt->header->dest_add == nodeAddress) { if (rcapPkt->header->mess_type == establish_accept) { // node is destination, prepare to receive stats = new Stats(); genState = new GenState(); chan = new HostData(rcapPkt->header, rcapPkt->traffic, rcapPkt->requirements, rcapPkt->routeInfo, genState, stats, headChan); reverseRoute(chan->routeInfo); headChan = chan; if (first) { first = 0; if (showHist) { videoLcid = chan->header->src_lcid; } if (receiveFrame || receiveVideo) { videoLcid = chan->header->src_lcid; float simTime = ((DEScheduler*) scheduler())->getStopTime(); maxPkts = (int) ceil(simTime/chan->traffic->xmin); if (receiveFrame) { imagePktRec = new unsigned char[maxPkts]; for (int i = 0; i < maxPkts; i++) imagePktRec[i] = 0; } else if (receiveVideo) { videoTrace = new Trace[maxPkts]; for (int i = 0; i < maxPkts; i++) { videoTrace[i].pktReceived = 0; videoTrace[i].recTime = -1; } } } } } else if (rcapPkt->header->mess_type == close_conf_for) { // Destination does nothing when channels are torn down. // Keep the data structures to report statistics. } } } } method { name { tearDown } access { public } code { // Compare the tearDownTime with the arrival time and if they are // floatEq then tear it down. Then refire at the next minimum time. completionTime = arrivalTime; chan = headChan; tmpChan = headChan; while (chan) { if (floatEq(chan->requirements->tEnd, arrivalTime) && (chan->header->src_add == nodeAddress) && (!chan->tornDown)) { tearDownChannel(chan->header->src_lcid); // Delete data structure if (chan == headChan) { chan = chan->next; delete headChan; headChan = chan; tmpChan = chan; } else { tmpChan->next = chan->next; delete chan; chan = tmpChan->next; } } else { tmpChan = chan; chan = chan->next; } } // Loop again for nextTearDownTime chan = headChan; nextTearDownTime = infinity; while (chan) { if (chan->header->src_add == nodeAddress) { float tTearDown = chan->requirements->tEnd; nextTearDownTime = min(nextTearDownTime, tTearDown); } chan = chan->next; } if (nextTearDownTime != infinity) refireAtTime(nextTearDownTime); } } method { name { tearDownChannel } access { public } arglist { "(long lcid)" } code { completionTime += delta; RCAPpkt *rcapPkt = new RCAPpkt(); // Fill in the route list (better to use constructor) rcapPkt->routeInfo->numNodes = chan->routeInfo->numNodes; for (int j = 0; j < numNodes; j++) rcapPkt->routeInfo->routeList[j] = chan->routeInfo->routeList[j]; rcapPkt->header->mess_type = close_conf_for; rcapPkt->header->src_lcid = lcid; Envelope env(*rcapPkt); toRCAP.put(completionTime) << env; } } method { name { calcIntvl } access { public } arglist { "(HostData *sendingChan)" } type { "float" } code { float xmin = sendingChan->traffic->xmin; float xave = sendingChan->traffic->xave; float I = sendingChan->traffic->I; float intvl; switch (sendingChan->traffic->model) { // Regular case regular : return xave; // Uniform case unif : rndUnif = new Uniform(xmin, 2*xave - xmin, gen); return (*rndUnif)(); // Markov case markov : float prob = sendingChan->burst_prob; genState = sendingChan->genState; switch (genState->gs_state) { case 0 : Time lim = 2.0 * prob * (xave-xmin)/(1.0 - prob); rndUnif = new Uniform(0.0, lim, gen); intvl = xmin + (*rndUnif)(); genState->gs_state = 1 - genState->gs_state; break; case 1 : intvl = xmin; rndUnif = new Uniform(0.0, 1.0, gen); if ( (*rndUnif)() > prob) genState->gs_state = 1 - genState->gs_state; }; // end switch markov state genState->gs_count++; if (genState->gs_nextI < arrivalTime) { genState->gs_count = 1; genState->gs_nextI = arrivalTime + I; } if (genState->gs_count > I/xave) { // Already sent the maximum number of pkts in interval genState->gs_count = 1; intvl = max(genState->gs_nextI - arrivalTime, intvl); // go to next interval genState->gs_nextI = max(arrivalTime, genState->gs_nextI); genState->gs_nextI += I; if (intvl < 0.0) Error::abortRun(*this, "Error in interval."); } return intvl; // Peaked case peaked : // Send all packets at interval xmin for as long as // allowed. int bsize = int (floor(I / xave)); genState = sendingChan->genState; if (genState->gs_nextI < arrivalTime) { genState->gs_nextI = arrivalTime + I; genState->gs_count = 0; } if (genState->gs_count == 0) { // Start of new interval // Add rnd phase rndUnif = new Uniform(0.0,(I-xmin*(bsize+1)),gen); intvl = (*rndUnif)(); intvl = max(intvl,xmin); genState->gs_count = 1; } else if ((genState->gs_count + 1 ) < bsize ) { // One more packet can be sent intvl = xmin; genState->gs_count++; } else { intvl = genState->gs_nextI - arrivalTime; rndUnif = new Uniform(0.0,(I-xmin*(bsize+1)),gen); intvl += max(0.0, (*rndUnif)() ); intvl = max(intvl, xmin ); genState->gs_nextI +=I; genState->gs_count = 1; } return intvl; case synced : break; case poisson : // This process does not obey the xmin, xave, I model rndExp = new NegativeExpntl(double(xave), gen); return max(xmin, (*rndExp)() ); case malicious : return xmin; case null : return infinity; break; }; // end switch traffic pattern cout << "Error with traffic model.\n"; return -1; } } inline method { name { updateStats } access { public } code { // Update the statistics of the receiving channel. // cout << "."; Envelope pkt; fromNetwork.get().getMessage(pkt); const TenetPkt* currTenPkt = (const TenetPkt*) pkt.myData(); // search chan for correct src_lcid chan = findChan(currTenPkt->header->src_lcid); float delay = arrivalTime - currTenPkt->header->timeStamp; if ( videoLcid == chan->header->src_lcid ) { if (showHist) { histValid = 1; his.addPoint(delay); } if (receiveFrame && (delay < chan->requirements->D)) { imagePktRec[currTenPkt->header->seq_num] = 1; } else if (receiveVideo) { videoTrace[currTenPkt->header->seq_num].pktReceived = 1; videoTrace[currTenPkt->header->seq_num].recTime = arrivalTime; } } chan->stats->received++; chan->stats->sent = currTenPkt->header->seq_num; // check to see that it's on time if (delay > chan->requirements->D) chan->stats->late++; chan->stats->Dsum += delay; if (delay > chan->stats->Dmax) chan->stats->Dmax = delay; } } method { name { reverseRoute } access { public } arglist { "(RouteInfo* routeInfo)" } code { int temp; int nodeCount = routeInfo->numNodes; if (nodeCount == 1) return; int halfWay = (int) ceil( (float) nodeCount / 2.0); int last = nodeCount - 1; for (int i = 0; i < halfWay; i++) { temp = routeInfo->routeList[i]; routeInfo->routeList[i] = routeInfo->routeList[last]; routeInfo->routeList[last--] = temp; } } } method { name { genDetRequest } access { public } code { // Alternate among channels in the file ID++; tmp = index % chansInFile; // timeOut will be used to check for an incorrect input file // format (i.e., chansToTry > 0 for this node but this node // does not appear as a source on the input file's route lists) int timeOut = 1; while ((params[tmp][numItems + 1] != nodeAddress) && (timeOut < MaxChans)) { timeOut++; index++; tmp = index % chansInFile; } if (timeOut >= MaxChans) { Error::warn(*this,"Warning: check input file format.\nChansToTry > 0 but node does not appear as source."); chansTried = chansToTry; return; } float tStart = params[tmp][0] + delta; float tTearDown = params[tmp][1]; nextTearDownTime = min(nextTearDownTime, params[tmp][1]); RCAPpkt* rcapPkt = new RCAPpkt(); long groupNumber = (long) (1e6 * params[tmp][18]); rcapPkt->header->src_lcid = ID + groupNumber; rcapPkt->header->protocol = useRMTP; rcapPkt->header->mess_type = establish_request; rcapPkt->header->subProtocol = EDD; rcapPkt->traffic->xmin = params[tmp][2]; rcapPkt->traffic->xave = params[tmp][3]; rcapPkt->traffic->I = params[tmp][4]; rcapPkt->traffic->smax = params[tmp][5]; rcapPkt->requirements->D = params[tmp][6]; int numNodes = (int) params[tmp][numItems]; rcapPkt->flex->Df = params[tmp][7] / (float) numNodes; rcapPkt->requirements->J = params[tmp][8]; rcapPkt->flex->Jf = params[tmp][9] / (float) numNodes; rcapPkt->requirements->Z = params[tmp][10]; rcapPkt->flex->Zf = params[tmp][11] / (float) numNodes; rcapPkt->requirements->W = params[tmp][12]; rcapPkt->flex->Wf = params[tmp][13] / (float) numNodes; rcapPkt->requirements->U = params[tmp][14]; rcapPkt->flex->Uf = params[tmp][15] / (float) numNodes; rcapPkt->requirements->type = (int) params[tmp][16]; rcapPkt->requirements->tBegin = tStart; rcapPkt->requirements->tEnd = tTearDown; rcapPkt->traffic->model = (int) params[tmp][17]; rcapPkt->routeInfo->numNodes = numNodes; for (int k = 0; k < numNodes; k++) rcapPkt->routeInfo->routeList[k] = (int) params[tmp][k+numItems+1]; // Assign the rest of the stuff... rcapPkt->header->src_add = rcapPkt->routeInfo->routeList[0]; rcapPkt->header->dest_add = rcapPkt->routeInfo->routeList[rcapPkt->routeInfo->numNodes -1]; rcapPkt->forwardInfo->prodNodeZ = 1.0; rcapPkt->forwardInfo->prodNodeW = 1.0; rcapPkt->forwardInfo->cummDelay = 0.0; rcapPkt->forwardInfo->prevJitter = 0.0; Envelope pkt(*rcapPkt); toRCAP.put(tStart) << pkt; index++; } // end code } // end method method { name { genRndRequest } access { public } code { // For now, each channel is assigned an ID number for // the src_lcid. This number is the hosts address + // (Magic * number of Channels) ID++; tmp = index % chansInFile; int timeOut = 1; while ((params[tmp][numItems + 1] != nodeAddress) && (timeOut < MaxChans)) { timeOut++; index++; tmp = index % chansInFile; } if (timeOut >= MaxChans) { Error::warn(*this,"Warning: check input file format.\nChansToTry> 0 but node does not appear as source."); chansTried = chansToTry; return; } float tStart = params[tmp][0] + delta; float tTearDown = params[tmp][1]; nextTearDownTime = min(nextTearDownTime, params[tmp][1]); RCAPpkt* rcapPkt = new RCAPpkt(); long groupNumber = (long) (1e6 * params[tmp][21]); rcapPkt->header->src_lcid = ID + groupNumber; rcapPkt->header->protocol = useRMTP; rcapPkt->header->mess_type = establish_request; rcapPkt->header->subProtocol = EDD; rndUnif = new Uniform(params[tmp][2], params[tmp][3], gen); float Xmin = (*rndUnif)(); rcapPkt->traffic->xmin = Xmin; rndUnif = new Uniform(Xmin, params[tmp][4], gen); float Xave = (*rndUnif)(); if (Xave < Xmin) Xave = Xmin; rcapPkt->traffic->xave = Xave; rcapPkt->traffic->I = params[tmp][5]; rcapPkt->traffic->smax = params[tmp][6]; rndDelb = new Normal(params[tmp][7], params[tmp][8], gen); rcapPkt->requirements->D = (*rndDelb)(); rcapPkt->requirements->J = params[tmp][9]; rndUnif = new Uniform(params[tmp][10], params[tmp][11], gen); rcapPkt->requirements->Z = (*rndUnif)(); rndUnif = new Uniform(params[tmp][12], params[tmp][13], gen); rcapPkt->requirements->W = (*rndUnif)(); rndUnif = new Uniform(params[tmp][14], params[tmp][15], gen); rcapPkt->requirements->U = (*rndUnif)(); rcapPkt->requirements->tBegin = tStart; rcapPkt->requirements->tEnd = tTearDown; int numNodes = (int) params[tmp][numItems]; rcapPkt->flex->Df = params[tmp][16] / (float) numNodes; rcapPkt->flex->Jf = params[tmp][16] / (float) numNodes; rcapPkt->flex->Zf = params[tmp][17] / (float) numNodes; rcapPkt->flex->Wf = params[tmp][17] / (float) numNodes; rcapPkt->flex->Uf = params[tmp][17] / (float) numNodes; rndUnif = new Uniform(0.0, 1.0, gen); float u01 = (*rndUnif)(); if (u01 <= params[tmp][18]) typeOfChan = determ; else if (u01 > (1.0 - params[tmp][19])) typeOfChan = statistical; else typeOfChan = bestEff; if (typeOfChan == determ) { rcapPkt->requirements->Z = 1.0; rcapPkt->requirements->W = 1.0; rcapPkt->requirements->U = 1.0; } if (typeOfChan == bestEff) { rcapPkt->requirements->Z = 0.0; rcapPkt->requirements->W = 0.0; rcapPkt->requirements->U = 0.0; } rcapPkt->requirements->type = typeOfChan; rcapPkt->traffic->model = (int) params[tmp][20]; rcapPkt->routeInfo->numNodes = numNodes; for (int k = 0; k < numNodes; k++) rcapPkt->routeInfo->routeList[k] = (int) params[tmp][k+numItems+1]; // Assign the rest of the stuff... rcapPkt->header->src_add = rcapPkt->routeInfo->routeList[0]; rcapPkt->header->dest_add = rcapPkt->routeInfo->routeList[rcapPkt->routeInfo->numNodes-1]; rcapPkt->forwardInfo->prodNodeZ = 1.0; rcapPkt->forwardInfo->prodNodeW = 1.0; rcapPkt->forwardInfo->cummDelay = 0.0; rcapPkt->forwardInfo->prevJitter = 0.0; // cout << Xmin << "\t" << Xave << "\t" << typeOfChan << "\t" << rcapPkt->requirements->Z << "\t" << rcapPkt->requirements->W << "\t" << rcapPkt->requirements->D << "\n"; Envelope pkt(*rcapPkt); toRCAP.put(tStart) << pkt; index++; } // end code } // end method method { name { readFile } access { public } type { int } code { // Take care of all input file functions here... // Since it's less storage, read file as 2-D array delete input; input = 0; int fd = open(expandPathName(fileName), O_RDONLY); if (fd < 0) { return -1; } LOG_NEW; input = new ifstream(fd); int i = 0; char inBuf[80]; (*input) >> inBuf; if (!strcmp(inBuf,"Random")) { (*input) >> chansInFile; numItems = 22; rndChans = 1; } else if (!strcmp(inBuf,"Deterministic")) { (*input) >> chansInFile; numItems = 19; rndChans = 0; } else return -2; while ( (i < chansInFile) && ((*input) >> tmp) && !input->eof()) { params[i][0] = tmp; // params[channel number][item number] for (int j = 1; j < numItems; j++) (*input) >> params[i][j]; (*input) >> numNodes; params[i][numItems] = numNodes; for (int k = (numItems+1); k <= (numItems+numNodes); k++) { (*input) >> params[i][k]; } i++; } return 1; } } inline method { name { findChan } access { public } arglist { "(long lcid)" } type { "HostData *" } code { // FIXME use indexing tmpChan = headChan; while (tmpChan != NULL) { if (tmpChan->header->src_lcid == lcid) return (tmpChan); tmpChan = tmpChan->next; } cout << "Error, Host received bad message.\n"; return NULL; } } method { name { readImage } access { public } code { // The image is named originalImage by default // Extend this to display image.1, ..., image.N for a sequence // of images. Use these images along with their receive // time stamps to display the received video. FILE* fp = fopen("/n/tenet/da/users/knightly/mm/video/originalImage", "r"); if (fp == (FILE*) NULL) Error::abortRun(*this, "File not opened."); char magic[80]; fscanf(fp, "%s %d %d %d%*c", magic, &width, &height, &maxval); if (strcmp(magic, "P5")) { // "P5" is PGM magic number. cout << "Error in PGM magic number.\n"; } if (maxval > 255) { cout << "Error in maxval.\n"; } imageData = new unsigned char[width*height]; fread((char*)imageData, sizeof(unsigned char), unsigned(width*height), fp); fclose(fp); } } method { name { editImage } access { public } code { // Each packet represents an atm cell and 48 bytes of data. // Therefore, for each unreceived packet, black out 48 pixels // of the image. int max = width * height; int modulator; for (int i = 0; i < max; i++) { index = (int) ceil( i / (48.0 * 4.0 * 8.0)); if (index < maxPkts) modulator = imagePktRec[index]; else modulator = 0; imageData[i] = imageData[i] * modulator; } } } method { name { displayImage } access { public } code { char *outFile = "/n/tenet/da/users/knightly/mm/video/receivedImage"; FILE *fd = fopen(outFile, "w"); if (fd == (FILE*) NULL) { Error::abortRun(*this, "can not create: ", outFile); return; } fprintf (fd, "P5\n %d %d 255\n", width, height); fwrite((char*)imageData, sizeof(unsigned char), (unsigned) width * height, fd); fclose(fd); char cmdbuf[256]; system("xv -geometry +0+0 /n/tenet/da/users/knightly/mm/video/originalImage &"); sprintf (cmdbuf, "(%s %s", "xv -geometry -0+0 ", outFile); strcat (cmdbuf, ")&"); system (cmdbuf); } } method { name { saveVideoTrace } access { public } code { char *outFile = "video.trace"; FILE *fd = fopen(outFile, "w"); if (fd == (FILE*) NULL) { Error::abortRun(*this, "can not create: ", outFile); return; } int numPkts = 1; while (videoTrace[numPkts].recTime >= 0) numPkts++; numPkts--; // There are numPkts video packets with the array indexed // from 1 to numPkts. fprintf(fd, "%d\n", numPkts); for (int j = 1; j <= numPkts; j++) fprintf(fd, "%d %f\n", videoTrace[j].pktReceived, videoTrace[j].recTime); fclose(fd); // DEBUG // cout << "sequence # " << currTenPkt->header->seq_num << " has timeStamp " << videoTrace[currTenPkt->header->seq_num].recTime << "\n"; } } wrapup { delete input; input = 0; chan = headChan; if (headChan == NULL) return; if (showHist && histValid) his.terminate(); if (receiveFrame) { // Display the received image readImage(); editImage(); displayImage(); } if (receiveVideo) { saveVideoTrace(); } if (chan) { cout << "Receive statistics at node " << nodeAddress << ":\n"; cout << "Chan ID\tType\tSent\tRecvd\tLate\tWreal\tZreal\tdAve\tdMax\n"; cout << "------------------------------------------------------------------------\n"; } while (chan) { if (chan->header->dest_add == nodeAddress) { float Wreal, Zreal, dAve; stats = chan->stats; Wreal = float(stats->received) / max(float(stats->sent), 0.000001); Zreal = 1.0 - (float(stats->late) / max(float(stats->received), 0.000001)); dAve = float(stats->Dsum) / max(float(stats->received), 0.000001); cout.precision(6); cout.setf(ios::fixed, ios::dec); cout << chan->header->src_lcid << "\t"; cout.precision(5); cout.setf(ios::dec, ios::fixed); cout << chan->requirements->type << "\t" << stats->sent << "\t" << stats->received << "\t" << stats->late << "\t" << Wreal << "\t" << Zreal << "\t" << dAve << "\t" << stats->Dmax << "\n"; } tmpChan = chan; chan = chan->next; delete tmpChan; } } } // end defstar