EtherMACBase.cc

Go to the documentation of this file.
00001 //
00002 // Copyright (C) 2006 Levente Meszaros
00003 // Copyright (C) 2004 Andras Varga
00004 //
00005 // This program is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU Lesser General Public License
00007 // as published by the Free Software Foundation; either version 2
00008 // of the License, or (at your option) any later version.
00009 //
00010 // This program is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 // GNU Lesser General Public License for more details.
00014 //
00015 // You should have received a copy of the GNU Lesser General Public License
00016 // along with this program; if not, see <http://www.gnu.org/licenses/>.
00017 //
00018 
00019 #include <stdio.h>
00020 #include <string.h>
00021 #include <omnetpp.h>
00022 #include "EtherMACBase.h"
00023 #include "IPassiveQueue.h"
00024 #include "IInterfaceTable.h"
00025 #include "InterfaceTableAccess.h"
00026 
00027 static const double SPEED_OF_LIGHT = 200000000.0;
00028 
00029 EtherMACBase::EtherMACBase()
00030 {
00031     nb = NULL;
00032     queueModule = NULL;
00033     interfaceEntry = NULL;
00034     endTxMsg = endIFGMsg = endPauseMsg = NULL;
00035 }
00036 
00037 EtherMACBase::~EtherMACBase()
00038 {
00039     cancelAndDelete(endTxMsg);
00040     cancelAndDelete(endIFGMsg);
00041     cancelAndDelete(endPauseMsg);
00042 }
00043 
00044 void EtherMACBase::initialize()
00045 {
00046     physOutGate = gate("phys$o");
00047 
00048     initializeFlags();
00049 
00050     initializeTxrate();
00051     WATCH(txrate);
00052 
00053     initializeMACAddress();
00054     initializeQueueModule();
00055     initializeNotificationBoard();
00056     initializeStatistics();
00057 
00058     registerInterface(txrate); // needs MAC address
00059 
00060     // initialize queue
00061     txQueue.setName("txQueue");
00062 
00063     // initialize self messages
00064     endTxMsg = new cMessage("EndTransmission", ENDTRANSMISSION);
00065     endIFGMsg = new cMessage("EndIFG", ENDIFG);
00066     endPauseMsg = new cMessage("EndPause", ENDPAUSE);
00067 
00068     // initialize states
00069     transmitState = TX_IDLE_STATE;
00070     receiveState = RX_IDLE_STATE;
00071     WATCH(transmitState);
00072     WATCH(receiveState);
00073 
00074     // initalize pause
00075     pauseUnitsRequested = 0;
00076     WATCH(pauseUnitsRequested);
00077 
00078     // initialize queue limit
00079     txQueueLimit = par("txQueueLimit");
00080     WATCH(txQueueLimit);
00081 }
00082 
00083 void EtherMACBase::initializeQueueModule()
00084 {
00085     if (par("queueModule").stringValue()[0])
00086     {
00087         cModule *module = getParentModule()->getSubmodule(par("queueModule").stringValue());
00088         queueModule = check_and_cast<IPassiveQueue *>(module);
00089         EV << "Requesting first frame from queue module\n";
00090         queueModule->requestPacket();
00091     }
00092 }
00093 
00094 void EtherMACBase::initializeMACAddress()
00095 {
00096     const char *addrstr = par("address");
00097 
00098     if (!strcmp(addrstr,"auto"))
00099     {
00100         // assign automatic address
00101         address = MACAddress::generateAutoAddress();
00102 
00103         // change module parameter from "auto" to concrete address
00104         par("address").setStringValue(address.str().c_str());
00105     }
00106     else
00107     {
00108         address.setAddress(addrstr);
00109     }
00110 }
00111 
00112 void EtherMACBase::initializeNotificationBoard()
00113 {
00114     hasSubscribers = false;
00115     if (interfaceEntry) {
00116         nb = NotificationBoardAccess().getIfExists();
00117         notifDetails.setInterfaceEntry(interfaceEntry);
00118         nb->subscribe(this, NF_SUBSCRIBERLIST_CHANGED);
00119         updateHasSubcribers();
00120     }
00121 }
00122 
00123 void EtherMACBase::initializeFlags()
00124 {
00125     // initialize connected flag
00126     connected = physOutGate->getPathEndGate()->isConnected();
00127     if (!connected)
00128         EV << "MAC not connected to a network.\n";
00129     WATCH(connected);
00130 
00131     // TODO: this should be settable from the gui
00132     // initialize disabled flag
00133     // Note: it is currently not supported to enable a disabled MAC at runtime.
00134     // Difficulties: (1) autoconfig (2) how to pick up channel state (free, tx, collision etc)
00135     disabled = false;
00136     WATCH(disabled);
00137 
00138     // initialize promiscuous flag
00139     promiscuous = par("promiscuous");
00140     WATCH(promiscuous);
00141 }
00142 
00143 void EtherMACBase::initializeStatistics()
00144 {
00145     framesSentInBurst = 0;
00146     bytesSentInBurst = 0;
00147 
00148     numFramesSent = numFramesReceivedOK = numBytesSent = numBytesReceivedOK = 0;
00149     numFramesPassedToHL = numDroppedBitError = numDroppedNotForUs = 0;
00150     numFramesFromHL = numDroppedIfaceDown = 0;
00151     numPauseFramesRcvd = numPauseFramesSent = 0;
00152 
00153     WATCH(framesSentInBurst);
00154     WATCH(bytesSentInBurst);
00155 
00156     WATCH(numFramesSent);
00157     WATCH(numFramesReceivedOK);
00158     WATCH(numBytesSent);
00159     WATCH(numBytesReceivedOK);
00160     WATCH(numFramesFromHL);
00161     WATCH(numDroppedIfaceDown);
00162     WATCH(numDroppedBitError);
00163     WATCH(numDroppedNotForUs);
00164     WATCH(numFramesPassedToHL);
00165     WATCH(numPauseFramesRcvd);
00166     WATCH(numPauseFramesSent);
00167 
00168     numFramesSentVector.setName("framesSent");
00169     numFramesReceivedOKVector.setName("framesReceivedOK");
00170     numBytesSentVector.setName("bytesSent");
00171     numBytesReceivedOKVector.setName("bytesReceivedOK");
00172     numDroppedIfaceDownVector.setName("framesDroppedIfaceDown");
00173     numDroppedBitErrorVector.setName("framesDroppedBitError");
00174     numDroppedNotForUsVector.setName("framesDroppedNotForUs");
00175     numFramesPassedToHLVector.setName("framesPassedToHL");
00176     numPauseFramesRcvdVector.setName("pauseFramesRcvd");
00177     numPauseFramesSentVector.setName("pauseFramesSent");
00178 }
00179 
00180 void EtherMACBase::registerInterface(double txrate)
00181 {
00182     IInterfaceTable *ift = InterfaceTableAccess().getIfExists();
00183     if (!ift)
00184         return;
00185 
00186     interfaceEntry = new InterfaceEntry();
00187 
00188     // interface name: our module name without special characters ([])
00189     char *interfaceName = new char[strlen(getParentModule()->getFullName())+1];
00190     char *d=interfaceName;
00191     for (const char *s=getParentModule()->getFullName(); *s; s++)
00192         if (isalnum(*s))
00193             *d++ = *s;
00194     *d = '\0';
00195 
00196     interfaceEntry->setName(interfaceName);
00197     delete [] interfaceName;
00198 
00199     // data rate
00200     interfaceEntry->setDatarate(txrate);
00201 
00202     // generate a link-layer address to be used as interface token for IPv6
00203     interfaceEntry->setMACAddress(address);
00204     interfaceEntry->setInterfaceToken(address.formInterfaceIdentifier());
00205     //InterfaceToken token(0, simulation.getUniqueNumber(), 64);
00206     //interfaceEntry->setInterfaceToken(token);
00207 
00208     // MTU: typical values are 576 (Internet de facto), 1500 (Ethernet-friendly),
00209     // 4000 (on some point-to-point links), 4470 (Cisco routers default, FDDI compatible)
00210     interfaceEntry->setMtu(par("mtu"));
00211 
00212     // capabilities
00213     interfaceEntry->setMulticast(true);
00214     interfaceEntry->setBroadcast(true);
00215 
00216     // add
00217     ift->addInterface(interfaceEntry, this);
00218 }
00219 
00220 
00221 bool EtherMACBase::checkDestinationAddress(EtherFrame *frame)
00222 {
00223     // If not set to promiscuous = on, then checks if received frame contains destination MAC address
00224     // matching port's MAC address, also checks if broadcast bit is set
00225     if (!promiscuous && !frame->getDest().isBroadcast() && !frame->getDest().equals(address))
00226     {
00227         EV << "Frame `" << frame->getName() <<"' not destined to us, discarding\n";
00228         numDroppedNotForUs++;
00229         numDroppedNotForUsVector.record(numDroppedNotForUs);
00230         delete frame;
00231 
00232         return false;
00233     }
00234 
00235     return true;
00236 }
00237 
00238 void EtherMACBase::calculateParameters()
00239 {
00240     if (disabled || !connected)
00241     {
00242         bitTime = slotTime = interFrameGap = jamDuration = shortestFrameDuration = 0;
00243         carrierExtension = frameBursting = false;
00244         return;
00245     }
00246 
00247     if (txrate != ETHERNET_TXRATE && txrate != FAST_ETHERNET_TXRATE &&
00248         txrate != GIGABIT_ETHERNET_TXRATE && txrate != FAST_GIGABIT_ETHERNET_TXRATE)
00249     {
00250         error("nonstandard transmission rate %g, must be %g, %g, %g or %g bit/sec",
00251             txrate, ETHERNET_TXRATE, FAST_ETHERNET_TXRATE, GIGABIT_ETHERNET_TXRATE, FAST_GIGABIT_ETHERNET_TXRATE);
00252     }
00253 
00254     bitTime = 1/(double)txrate;
00255 
00256     // set slot time
00257     if (txrate==ETHERNET_TXRATE || txrate==FAST_ETHERNET_TXRATE)
00258         slotTime = SLOT_TIME;
00259     else
00260         slotTime = GIGABIT_SLOT_TIME;
00261 
00262     // only if Gigabit Ethernet
00263     frameBursting = (txrate==GIGABIT_ETHERNET_TXRATE || txrate==FAST_GIGABIT_ETHERNET_TXRATE);
00264     carrierExtension = (slotTime == GIGABIT_SLOT_TIME && !duplexMode);
00265 
00266     interFrameGap = INTERFRAME_GAP_BITS/(double)txrate;
00267     jamDuration = 8*JAM_SIGNAL_BYTES*bitTime;
00268     shortestFrameDuration = carrierExtension ? GIGABIT_MIN_FRAME_WITH_EXT : MIN_ETHERNET_FRAME;
00269 }
00270 
00271 void EtherMACBase::printParameters()
00272 {
00273     // Dump parameters
00274     EV << "MAC address: " << address << (promiscuous ? ", promiscuous mode" : "") << endl;
00275     EV << "txrate: " << txrate << ", " << (duplexMode ? "duplex" : "half-duplex") << endl;
00276 #if 0
00277     EV << "bitTime: " << bitTime << endl;
00278     EV << "carrierExtension: " << carrierExtension << endl;
00279     EV << "frameBursting: " << frameBursting << endl;
00280     EV << "slotTime: " << slotTime << endl;
00281     EV << "interFrameGap: " << interFrameGap << endl;
00282     EV << endl;
00283 #endif
00284 }
00285 
00286 void EtherMACBase::processFrameFromUpperLayer(EtherFrame *frame)
00287 {
00288     EV << "Received frame from upper layer: " << frame << endl;
00289 
00290     if (frame->getDest().equals(address))
00291     {
00292         error("logic error: frame %s from higher layer has local MAC address as dest (%s)",
00293               frame->getFullName(), frame->getDest().str().c_str());
00294     }
00295 
00296     if (frame->getByteLength() > MAX_ETHERNET_FRAME)
00297         error("packet from higher layer (%d bytes) exceeds maximum Ethernet frame size (%d)", (int)(frame->getByteLength()), MAX_ETHERNET_FRAME);
00298 
00299     // must be EtherFrame (or EtherPauseFrame) from upper layer
00300     bool isPauseFrame = (dynamic_cast<EtherPauseFrame*>(frame)!=NULL);
00301     if (!isPauseFrame)
00302     {
00303         numFramesFromHL++;
00304 
00305         if (txQueueLimit && txQueue.length()>txQueueLimit)
00306             error("txQueue length exceeds %d -- this is probably due to "
00307                   "a bogus app model generating excessive traffic "
00308                   "(or if this is normal, increase txQueueLimit!)",
00309                   txQueueLimit);
00310 
00311         // fill in src address if not set
00312         if (frame->getSrc().isUnspecified())
00313             frame->setSrc(address);
00314 
00315         // store frame and possibly begin transmitting
00316         EV << "Packet " << frame << " arrived from higher layers, enqueueing\n";
00317         txQueue.insert(frame);
00318     }
00319     else
00320     {
00321         EV << "PAUSE received from higher layer\n";
00322 
00323         // PAUSE frames enjoy priority -- they're transmitted before all other frames queued up
00324         if (!txQueue.empty())
00325             txQueue.insertBefore(txQueue.front(), frame);  // front() frame is probably being transmitted
00326         else
00327             txQueue.insert(frame);
00328     }
00329 
00330 }
00331 
00332 void EtherMACBase::processMsgFromNetwork(cPacket *frame)
00333 {
00334     EV << "Received frame from network: " << frame << endl;
00335 
00336     // frame must be EtherFrame or EtherJam
00337     if (dynamic_cast<EtherFrame*>(frame)==NULL && dynamic_cast<EtherJam*>(frame)==NULL)
00338         error("message with unexpected message class '%s' arrived from network (name='%s')",
00339                 frame->getClassName(), frame->getFullName());
00340 
00341     // detect cable length violation in half-duplex mode
00342     if (!duplexMode && simTime()-frame->getSendingTime()>=shortestFrameDuration)
00343         error("very long frame propagation time detected, maybe cable exceeds maximum allowed length? "
00344               "(%lgs corresponds to an approx. %lgm cable)",
00345               SIMTIME_STR(simTime() - frame->getSendingTime()),
00346               SIMTIME_STR((simTime() - frame->getSendingTime())*SPEED_OF_LIGHT));
00347 }
00348 
00349 void EtherMACBase::frameReceptionComplete(EtherFrame *frame)
00350 {
00351     int pauseUnits;
00352     EtherPauseFrame *pauseFrame;
00353 
00354     if ((pauseFrame=dynamic_cast<EtherPauseFrame*>(frame))!=NULL)
00355     {
00356         pauseUnits = pauseFrame->getPauseTime();
00357         delete frame;
00358         numPauseFramesRcvd++;
00359         numPauseFramesRcvdVector.record(numPauseFramesRcvd);
00360         processPauseCommand(pauseUnits);
00361     }
00362     else
00363     {
00364         processReceivedDataFrame((EtherFrame *)frame);
00365     }
00366 }
00367 
00368 void EtherMACBase::processReceivedDataFrame(EtherFrame *frame)
00369 {
00370     // bit errors
00371     if (frame->hasBitError())
00372     {
00373         numDroppedBitError++;
00374         numDroppedBitErrorVector.record(numDroppedBitError);
00375         delete frame;
00376         return;
00377     }
00378 
00379     // strip preamble and SFD
00380     frame->addByteLength(-PREAMBLE_BYTES-SFD_BYTES);
00381 
00382     // statistics
00383     numFramesReceivedOK++;
00384     numBytesReceivedOK += frame->getByteLength();
00385     numFramesReceivedOKVector.record(numFramesReceivedOK);
00386     numBytesReceivedOKVector.record(numBytesReceivedOK);
00387 
00388     if (!checkDestinationAddress(frame))
00389         return;
00390 
00391     numFramesPassedToHL++;
00392     numFramesPassedToHLVector.record(numFramesPassedToHL);
00393 
00394     // pass up to upper layer
00395     send(frame, "upperLayerOut");
00396 }
00397 
00398 void EtherMACBase::processPauseCommand(int pauseUnits)
00399 {
00400     if (transmitState==TX_IDLE_STATE)
00401     {
00402         EV << "PAUSE frame received, pausing for " << pauseUnitsRequested << " time units\n";
00403         if (pauseUnits>0)
00404             scheduleEndPausePeriod(pauseUnits);
00405     }
00406     else if (transmitState==PAUSE_STATE)
00407     {
00408         EV << "PAUSE frame received, pausing for " << pauseUnitsRequested << " more time units from now\n";
00409         cancelEvent(endPauseMsg);
00410         if (pauseUnits>0)
00411             scheduleEndPausePeriod(pauseUnits);
00412     }
00413     else
00414     {
00415         // transmitter busy -- wait until it finishes with current frame (endTx)
00416         // and then it'll go to PAUSE state
00417         EV << "PAUSE frame received, storing pause request\n";
00418         pauseUnitsRequested = pauseUnits;
00419     }
00420 }
00421 
00422 void EtherMACBase::handleEndIFGPeriod()
00423 {
00424     if (transmitState!=WAIT_IFG_STATE)
00425         error("Not in WAIT_IFG_STATE at the end of IFG period");
00426 
00427     if (txQueue.empty())
00428         error("End of IFG and no frame to transmit");
00429 
00430     // End of IFG period, okay to transmit, if Rx idle OR duplexMode
00431     cPacket *frame = (cPacket *)txQueue.front();
00432     EV << "IFG elapsed, now begin transmission of frame " << frame << endl;
00433 
00434     // Perform carrier extension if in Gigabit Ethernet
00435     if (carrierExtension && frame->getByteLength() < GIGABIT_MIN_FRAME_WITH_EXT)
00436     {
00437         EV << "Performing carrier extension of small frame\n";
00438         frame->setByteLength(GIGABIT_MIN_FRAME_WITH_EXT);
00439     }
00440 
00441     // start frame burst, if enabled
00442     if (frameBursting)
00443     {
00444         EV << "Starting frame burst\n";
00445         framesSentInBurst = 0;
00446         bytesSentInBurst = 0;
00447     }
00448 }
00449 
00450 void EtherMACBase::handleEndTxPeriod()
00451 {
00452     // we only get here if transmission has finished successfully, without collision
00453     if (transmitState!=TRANSMITTING_STATE || (!duplexMode && receiveState!=RX_IDLE_STATE))
00454         error("End of transmission, and incorrect state detected");
00455 
00456     if (txQueue.empty())
00457         error("Frame under transmission cannot be found");
00458 
00459     // get frame from buffer
00460     cPacket *frame = (cPacket *)txQueue.pop();
00461 
00462     numFramesSent++;
00463     numBytesSent += frame->getByteLength();
00464     numFramesSentVector.record(numFramesSent);
00465     numBytesSentVector.record(numBytesSent);
00466 
00467     if (dynamic_cast<EtherPauseFrame*>(frame)!=NULL)
00468     {
00469         numPauseFramesSent++;
00470         numPauseFramesSentVector.record(numPauseFramesSent);
00471     }
00472 
00473     EV << "Transmission of " << frame << " successfully completed\n";
00474     delete frame;
00475 }
00476 
00477 void EtherMACBase::handleEndPausePeriod()
00478 {
00479     if (transmitState != PAUSE_STATE)
00480         error("At end of PAUSE not in PAUSE_STATE!");
00481     EV << "Pause finished, resuming transmissions\n";
00482     beginSendFrames();
00483 }
00484 
00485 void EtherMACBase::processMessageWhenNotConnected(cMessage *msg)
00486 {
00487     EV << "Interface is not connected -- dropping packet " << msg << endl;
00488     delete msg;
00489     numDroppedIfaceDown++;
00490 }
00491 
00492 void EtherMACBase::processMessageWhenDisabled(cMessage *msg)
00493 {
00494     EV << "MAC is disabled -- dropping message " << msg << endl;
00495     delete msg;
00496 }
00497 
00498 void EtherMACBase::scheduleEndIFGPeriod()
00499 {
00500     scheduleAt(simTime()+interFrameGap, endIFGMsg);
00501     transmitState = WAIT_IFG_STATE;
00502 }
00503 
00504 void EtherMACBase::scheduleEndTxPeriod(cPacket *frame)
00505 {
00506     scheduleAt(simTime()+frame->getBitLength()*bitTime, endTxMsg);
00507     transmitState = TRANSMITTING_STATE;
00508 }
00509 
00510 void EtherMACBase::scheduleEndPausePeriod(int pauseUnits)
00511 {
00512     // length is interpreted as 512-bit-time units
00513     simtime_t pausePeriod = pauseUnits*PAUSE_BITTIME*bitTime;
00514     scheduleAt(simTime()+pausePeriod, endPauseMsg);
00515     transmitState = PAUSE_STATE;
00516 }
00517 
00518 bool EtherMACBase::checkAndScheduleEndPausePeriod()
00519 {
00520     if (pauseUnitsRequested>0)
00521     {
00522         // if we received a PAUSE frame recently, go into PAUSE state
00523         EV << "Going to PAUSE mode for " << pauseUnitsRequested << " time units\n";
00524 
00525         scheduleEndPausePeriod(pauseUnitsRequested);
00526         pauseUnitsRequested = 0;
00527         return true;
00528     }
00529 
00530     return false;
00531 }
00532 
00533 void EtherMACBase::beginSendFrames()
00534 {
00535     if (!txQueue.empty())
00536     {
00537         // Other frames are queued, therefore wait IFG period and transmit next frame
00538         EV << "Transmit next frame in output queue, after IFG period\n";
00539         scheduleEndIFGPeriod();
00540     }
00541     else
00542     {
00543         transmitState = TX_IDLE_STATE;
00544         if (queueModule)
00545         {
00546             // tell queue module that we've become idle
00547             EV << "Requesting another frame from queue module\n";
00548             queueModule->requestPacket();
00549         }
00550         else
00551         {
00552             // No more frames set transmitter to idle
00553             EV << "No more frames to send, transmitter set to idle\n";
00554         }
00555     }
00556 }
00557 
00558 void EtherMACBase::fireChangeNotification(int type, cPacket *msg)
00559 {
00560     if (nb) {
00561         notifDetails.setPacket(msg);
00562         nb->fireChangeNotification(type, &notifDetails);
00563     }
00564 }
00565 
00566 void EtherMACBase::finish()
00567 {
00568     if (!disabled)
00569     {
00570         simtime_t t = simTime();
00571         recordScalar("simulated time", t);
00572         recordScalar("txrate (Mb)", txrate/1000000);
00573         recordScalar("full duplex", duplexMode);
00574         recordScalar("frames sent",    numFramesSent);
00575         recordScalar("frames rcvd",    numFramesReceivedOK);
00576         recordScalar("bytes sent",     numBytesSent);
00577         recordScalar("bytes rcvd",     numBytesReceivedOK);
00578         recordScalar("frames from higher layer", numFramesFromHL);
00579         recordScalar("frames from higher layer dropped (iface down)", numDroppedIfaceDown);
00580         recordScalar("frames dropped (bit error)",  numDroppedBitError);
00581         recordScalar("frames dropped (not for us)", numDroppedNotForUs);
00582         recordScalar("frames passed up to HL", numFramesPassedToHL);
00583         recordScalar("PAUSE frames sent",  numPauseFramesSent);
00584         recordScalar("PAUSE frames rcvd",  numPauseFramesRcvd);
00585 
00586         if (t>0)
00587         {
00588             recordScalar("frames/sec sent", numFramesSent/t);
00589             recordScalar("frames/sec rcvd", numFramesReceivedOK/t);
00590             recordScalar("bits/sec sent",   8*numBytesSent/t);
00591             recordScalar("bits/sec rcvd",   8*numBytesReceivedOK/t);
00592         }
00593     }
00594 }
00595 
00596 void EtherMACBase::updateDisplayString()
00597 {
00598     // icon coloring
00599     const char *color;
00600     if (receiveState==RX_COLLISION_STATE)
00601         color = "red";
00602     else if (transmitState==TRANSMITTING_STATE)
00603         color = "yellow";
00604     else if (transmitState==JAMMING_STATE)
00605         color = "red";
00606     else if (receiveState==RECEIVING_STATE)
00607         color = "#4040ff";
00608     else if (transmitState==BACKOFF_STATE)
00609         color = "white";
00610     else if (transmitState==PAUSE_STATE)
00611         color = "gray";
00612     else
00613         color = "";
00614     getDisplayString().setTagArg("i",1,color);
00615     if (!strcmp(getParentModule()->getClassName(),"EthernetInterface"))
00616         getParentModule()->getDisplayString().setTagArg("i",1,color);
00617 
00618     // connection coloring
00619     updateConnectionColor(transmitState);
00620 
00621 #if 0
00622     // this code works but didn't turn out to be very useful
00623     const char *txStateName;
00624     switch (transmitState) {
00625         case TX_IDLE_STATE:      txStateName="IDLE"; break;
00626         case WAIT_IFG_STATE:     txStateName="WAIT_IFG"; break;
00627         case TRANSMITTING_STATE: txStateName="TX"; break;
00628         case JAMMING_STATE:      txStateName="JAM"; break;
00629         case BACKOFF_STATE:      txStateName="BACKOFF"; break;
00630         case PAUSE_STATE:        txStateName="PAUSE"; break;
00631         default: error("wrong tx state");
00632     }
00633     const char *rxStateName;
00634     switch (receiveState) {
00635         case RX_IDLE_STATE:      rxStateName="IDLE"; break;
00636         case RECEIVING_STATE:    rxStateName="RX"; break;
00637         case RX_COLLISION_STATE: rxStateName="COLL"; break;
00638         default: error("wrong rx state");
00639     }
00640 
00641     char buf[80];
00642     sprintf(buf, "tx:%s rx: %s\n#boff:%d #cTx:%d",
00643                  txStateName, rxStateName, backoffs, numConcurrentTransmissions);
00644     getDisplayString().setTagArg("t",0,buf);
00645 #endif
00646 }
00647 
00648 void EtherMACBase::updateConnectionColor(int txState)
00649 {
00650     const char *color;
00651     if (txState==TRANSMITTING_STATE)
00652         color = "yellow";
00653     else if (txState==JAMMING_STATE || txState==BACKOFF_STATE)
00654         color = "red";
00655     else
00656         color = "";
00657 
00658     cGate *g = physOutGate;
00659     while (g && g->getType()==cGate::OUTPUT)
00660     {
00661         g->getDisplayString().setTagArg("ls",0,color);
00662         g->getDisplayString().setTagArg("ls",1, color[0] ? "3" : "1");
00663         g = g->getNextGate();
00664     }
00665 }
00666 
00667 void EtherMACBase::receiveChangeNotification(int category, const cPolymorphic *)
00668 {
00669     if (category==NF_SUBSCRIBERLIST_CHANGED)
00670         updateHasSubcribers();
00671 }
00672 
00673