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