EPONImplementationforOMNet++
0.8Beta
|
ONUMacCtl class controls the below MAC layer transmission times. More...
#include <ONUMacCtl_NP.h>
Public Member Functions | |
ONUMacCtl_NP () | |
virtual | ~ONUMacCtl_NP () |
Protected Member Functions | |
virtual void | initialize () |
virtual void | handleMessage (cMessage *msg) |
virtual void | processFrameFromHigherLayer (cMessage *msg) |
virtual void | processMPCP (EthernetIIFrame *frame) |
virtual void | scheduleStartTxPeriod () |
virtual void | scheduleStopTxPeriod () |
virtual void | startTxOnPON () |
Directly called for start Messages and called if a frame arrives in IDLE. | |
virtual void | handleStopTxPeriod () |
virtual void | clockSync () |
Update the clock. | |
virtual void | shiftStart1Slot () |
This method shifts the start register for one SuperSlot. | |
virtual void | shiftStartXSlots (uint32_t X) |
This method handles the start register when the module wakes up from SLEEP state and it has lost many SuperSlots. | |
Protected Attributes | |
cMessage * | stopTxMsg |
Private Member Functions | |
virtual void | goToIDLE () |
virtual void | goToSLEEP () |
ONUMacCtl class controls the below MAC layer transmission times.
This version is fairly more complicated from the OLT one because we have transmit in specific times. The module can come to IDLE or SLEEP states which means that the clock and the start register are left back. (The clock is updated on each message reception).
Also this class has a pointer to the EPON_Q_mgmt module and it uses it as a simple queue in order to get frames. Finally note that missing mac addresses and LLIDs (from frames) are filled in here, cause the lower layer expects them.
{ startTxMsg=0; stopTxMsg=0; }
ONUMacCtl_NP::~ONUMacCtl_NP | ( | ) | [virtual] |
{ cancelAndDelete(startTxMsg); cancelAndDelete(stopTxMsg); }
void ONUMacCtl_NP::clockSync | ( | ) | [protected, virtual] |
Update the clock.
Note that the clock can be reseted back to 0 (zero) cause it is define by MPCP as 32bit register (of 16 nanoseconds granularity). This is also handled here.
Multi shift
Check Slot Shift... NOTE: skew introduced
{ EV << "\n\n============= CLOCK: "; // NOTE: Clock is in sync with the simulation clock // a small skew can be added here (random) // Reset start/stop uint32_t simT = MPCPTools::simTimeToNS16(); // No clock shift if (simT>=clock_reg){ // Update the clock clock_reg = simT; EV << clock_reg << "=======================\n"; return; } if (start_reg<simT){ EV << "MULTI SHIFT =====================\n" <<endl; clock_reg = simT; // Super Slot ... uint64_t slotTime16ns = (double)slotLength/16*slotNumber; uint32_t lostSlots = ceil((double)(clock_reg - start_reg)/slotTime16ns); shiftStartXSlots(lostSlots); return; } // Single shift (1 reg loop) // Reschedule the clock // In ANY case start reg is wrong transmitState = TX_OFF; cancelEvent(startTxMsg); cancelEvent(stopTxMsg); EV << " SHIFT =======================\n"; // Update the clock clock_reg = simT; dumpReg(); EV << "===========================================\n\n\n"; }
void ONUMacCtl_NP::goToIDLE | ( | ) | [private, virtual] |
{ transmitState = TX_IDLE; cancelEvent(stopTxMsg); cancelEvent(startTxMsg); scheduleStopTxPeriod(); }
void ONUMacCtl_NP::goToSLEEP | ( | ) | [private, virtual] |
{ EV << "\n==ONUMacCtl_NP: CHANGING STATE FROM ?? TO _SLEEP_\n"; queue_mod->requestPacket(); transmitState = TX_SLEEP; return; }
void ONUMacCtl_NP::handleMessage | ( | cMessage * | msg | ) | [protected, virtual] |
{ // Update clock from simTime // The clock MUST be in sync // when stop is scheduled. Stop // is called only when entering IDLE clockSync(); // Self Message if (msg->isSelfMessage()) { EV << "Self-message " << msg << " received\n"; if (msg == startTxMsg){ if (transmitState == TX_IDLE) {std::cout<<*msg<<endl; delete msg; error("?"); } startTxOnPON(); } else if (msg == stopTxMsg) handleStopTxPeriod(); else error("Unknown self message received!"); return; } // Network Message cGate *ingate = msg->getArrivalGate(); EV << "Frame " << msg << " arrived on port " << ingate->getName() << "...\n"; if (ingate->getId() == gate( "lowerLayerIn")->getId()){ processFrameFromMAC(msg); } else if (ingate->getId() == gate( "upperLayerIn")->getId()){ processFrameFromHigherLayer(msg); }else{ EV << "ONUMacCtl_NP: Message came FROM THE WRONG DIRRECTION???? Dropping\n"; delete msg; } }
void ONUMacCtl_NP::handleStopTxPeriod | ( | ) | [protected, virtual] |
{ transmitState = TX_OFF; EV << "\n==ONUMacCtl_NP: CHANGING STATE FROM ?? TO _OFF_\n"; /* * Do NOT call start all the time... * * WE TRIED... :-) */ if (tmp_queue.isEmpty()){ goToSLEEP(); // DO NOT RESCHEDULE START... return; } // Shift the start_reg shiftStart1Slot(); }
void ONUMacCtl_NP::initialize | ( | ) | [protected, virtual] |
Reimplemented from ONUMacCtlBase.
{ // Do the common stuff... ONUMacCtlBase::initialize(); stopTxMsg = new cMessage("stopTxMsg", STOPTXMSG); }
void ONUMacCtl_NP::processFrameFromHigherLayer | ( | cMessage * | msg | ) | [protected, virtual] |
{ EV << "ONUMacCtl_NP: Outgoing message, forwarding...\n"; numFramesFromHL++; // Pre-Configuration ... Check and send only MPCP EV << "ONUMacCtl_NP: Packet " << msg << " arrived from higher layers, sending\n"; if (start_reg == 0 ){ EV<<"ONUMacCtl_NP: Frame arrived in pre-conf stage "<<endl; // Send only if it is an MPCP message EthernetIIFrame * frame = dynamic_cast<EthernetIIFrame *>(msg); if (frame && frame->getEtherType() == MPCP_TYPE){ send(msg, "lowerLayerOut"); return; } EV<<"ONUMacCtl_NP: DROPPING "<<endl; delete msg; return; } // Check for a WAKE UP message if (msg->getKind() == WAKEUPMSG){ EV << "Wake UP message received..." << endl; // Discard it... delete msg; }else{ // ENQUEUE EV << "Queuing message..." << endl; tmp_queue.insert(msg); } // Re-schedule tx period // Check if we are idle, if yes start transmission if (transmitState == TX_IDLE){ EV << "ONUMacCtl_NP: CHANGING STATE FROM _IDLE_ TO _ON_\n"; // Cancel Previous DeadLine cancelEvent(stopTxMsg); startTxOnPON(); } // Check if we are asleep else if (transmitState == TX_SLEEP){ // IF start_reg is in the future just reschedule startTX // ELSE shift the clock the lost slots... if (clock_reg < start_reg){ cancelEvent(startTxMsg); scheduleStartTxPeriod(); }else if (clock_reg >= start_reg && clock_reg < start_reg + len_reg){ cancelEvent(stopTxMsg); startTxOnPON(); }else { // Super Slot ... uint64_t slotTime16ns = (double)slotLength/16*slotNumber; uint32_t lostSlots = ceil((double)(clock_reg - start_reg)/slotTime16ns); shiftStartXSlots(lostSlots); } } }
void ONUMacCtl_NP::processMPCP | ( | EthernetIIFrame * | frame | ) | [protected, virtual] |
NOTE: Announced time IS NOT ALWAYS ON THE FUTURE IF we want the announced times to be on the future then the DBA algorithms MUST CONSIDER RTT. For simplicity we do accept to loose some slots...
Implements ONUMacCtlBase.
{ EV << "ONUMacCtl_NP: MPCP Frame processing\n"; MPCP * mpcp = check_and_cast<MPCP *>(frame); // DONT... DONT EVEN THINK OF IT // EV << "ONUMacCtl_NP: Updating our clock from: "<<clock_reg<<" to "; // clock_reg=mpcp->getTs(); // EV << clock_reg << endl; switch (mpcp->getOpcode()) { case MPCP_GATE: { MPCPGate * gate = check_and_cast<MPCPGate *>(frame); EV << "ONUMacCtl_NP: Type is MPCP_GATE\n"; if (gate->getListLen() == 0) { EV << "ONUMacCtl_NP: !!! NO ALLOCATION FOR US :-( (bitches...)"; break; } // Update with 1st alloc start_reg = gate->getStartTime(0); len_reg = gate->getDuration(0); slotLength = gate->getSlotTime(); slotNumber = gate->getSlotsNum(); if ( numGates == 0){ EV << "ONUMacCtl_NP: MPCP_GATE arrived, IT IS INITIAL - MAC: "<<frame->getDest()<<endl; // Cancel ALL an scheduled TX cancelEvent(startTxMsg); cancelEvent(stopTxMsg); scheduleStartTxPeriod(); }else{ if (clock_reg>start_reg + len_reg){ // Time assigned is in past EV << "ONUMacCtl_NP: MPCP_GATE arrived, calculating lost slots"<<endl; // Super Slot ... uint64_t slotTime16ns = (double)slotLength/16*slotNumber; uint32_t lostSlots = ceil((double)(clock_reg - start_reg)/slotTime16ns); shiftStartXSlots(lostSlots); }else if (clock_reg>=start_reg && clock_reg < start_reg + len_reg){ EV << "ONUMacCtl_NP: MPCP_GATE arrived, it is our time"<<endl; // Now is our time scheduleStopTxPeriod(); startTxOnPON(); }else{ // Time assigned is in future EV << "ONUMacCtl_NP: MPCP_GATE arrived, no lost slots"<<endl; scheduleStartTxPeriod(); } } numGates++; break; } default: break; }; }
void ONUMacCtl_NP::scheduleStartTxPeriod | ( | ) | [protected, virtual] |
{ EV << "\n==ONUMacCtl_NP: CHANGING STATE FROM ?? TO _OFF_\n"; transmitState = TX_OFF; /* * start_reg shifted clock_reg did not * HANDLE AND RETURN. * * NOTE: This should occur only on shifted registers. * MPCP could have the same result but we are fixing * it by shifting the clock on receive. */ if (start_reg!=0 && (uint64_t)start_reg+len_reg<clock_reg) { EV<<"ONUMacCtl_NP: Start_reg shifted clock_reg did not"<<endl; dumpReg(); //error("start_reg+len_reg<clock_reg "); simtime_t nextTx; nextTx.setRaw(simTime().raw() + // NOW MPCPTools::ns16ToSimTime(MPCP_CLOCK_MAX - clock_reg + // Remaining (not shifted clock) start_reg )); EV<<"...."<<(MPCP_CLOCK_MAX - clock_reg +start_reg)<<endl; EV<<"scheduleStartTxPeriod: "<<nextTx<<endl; cancelEvent(startTxMsg); scheduleAt(nextTx, startTxMsg); return; } simtime_t nextTx; // Start the next moment... nextTx.setRaw(simTime().raw()); // If start time is ahead sim time Start now // clock_reg == MPCPTools::simTimeToNS16().... if (start_reg>=clock_reg){ nextTx.setRaw(simTime().raw()+ //Now (NOTE: not the clock_reg) MPCPTools::ns16ToSimTime(start_reg-clock_reg) //Remaining time to Start ); EV << "ONUMacCtl_NP: Start scheduled. Clock: "<<clock_reg<<" Start: "<<start_reg<<endl; }else{ EV << "ONUMacCtl_NP: Starting NOW. Clock: "<<clock_reg<<" Start: "<<start_reg<<endl; } cancelEvent(startTxMsg); scheduleAt(nextTx, startTxMsg); }
void ONUMacCtl_NP::scheduleStopTxPeriod | ( | ) | [protected, virtual] |
{ // You cannot calculate next time from registers... // Simulation time may be different (regs are shifted) // So calculate the remaining time... simtime_t stopTX; stopTX.setRaw( simTime().raw() + // Now MPCPTools::ns16ToSimTime(start_reg +len_reg - clock_reg) // Remaining ); dumpReg(); EV << "Scheduled after (ns16): " << (start_reg +len_reg - clock_reg) <<endl; EV << "Scheduled after (raw): " << MPCPTools::ns16ToSimTime(start_reg +len_reg - clock_reg) <<endl; // Just in case.. cancelEvent(stopTxMsg); scheduleAt(stopTX, stopTxMsg); }
void ONUMacCtl_NP::shiftStart1Slot | ( | ) | [protected, virtual] |
This method shifts the start register for one SuperSlot.
SuperSlot is defined as the summation of all the slot lengths.
{ uint64_t slotTime16ns = ((double)slotLength/16)*slotNumber; EV << "Increasing Start Reg.: old=" << start_reg <<" + " << slotTime16ns; // NOTE: start_reg may OVERFLOW TOOooo... tsouf start_reg = ((uint64_t)start_reg+slotTime16ns)%MPCP_CLOCK_MAX; EV<<" = "<<start_reg<<" Clock Now: "<<clock_reg<<endl; EV<<"SlotLength: "<<slotTime16ns<<endl<<endl; // Reschedule next TX scheduleStartTxPeriod(); }
void ONUMacCtl_NP::shiftStartXSlots | ( | uint32_t | X | ) | [protected, virtual] |
This method handles the start register when the module wakes up from SLEEP state and it has lost many SuperSlots.
{ uint64_t slotTime16ns = (double)slotLength/16*slotNumber; EV << "Increasing Start: old=" << start_reg <<" + " << X*slotTime16ns; start_reg = ((uint64_t)start_reg+X*slotTime16ns)%MPCP_CLOCK_MAX; EV<<" = "<<start_reg<<endl; EV<<"Lost Slots: "<<X<<" SlotLength: "<<slotTime16ns<<endl<<endl; // Reschedule next TX scheduleStartTxPeriod(); }
void ONUMacCtl_NP::startTxOnPON | ( | ) | [protected, virtual] |
Directly called for start Messages and called if a frame arrives in IDLE.
Check to be sure...
Sometimes because we add 0.001 to startTx schedule, results to clock_reg = start+len +1
So, shift a slot.
Check that the MAC layer is not in TX mode
This happens because the 2 messages EndTransmission (EPON_mac) and startTx (ONUMacCtl) are scheduled at the same EXACT time.
Some extra delay is used to avoid (internal) message collision This is set to 5*pow(10,simTime().getScaleExp()); (5*10^-12 in most cases). This reduces the collision times but do not eliminate them.
Therefore, when it happens we make the MacCtl to wait for the minimum frame transmission time (64Bytes)
Request next packet and set to IDLE state
Check That he allocated time is more than the frame... If it is not discart the frame, it is going to block all the rest...
Implements ONUMacCtlBase.
{ if (clock_reg>start_reg+len_reg && start_reg!=0) { std::cout<<"ONUMacCtl_NP: SHIT: "<<simTime()<<endl; std::cout << "Sim(ns16): "<<MPCPTools::simTimeToNS16()<<endl; std::cout << "Clock: "<<clock_reg<<endl; std::cout << "Start: "<<start_reg<<endl; std::cout << "Length: "<<len_reg<<endl; shiftStart1Slot(); std::cout << "Clock: "<<clock_reg<<endl; std::cout << "Start: "<<start_reg<<endl; std::cout << "Length: "<<len_reg<<endl; return; } if (emac->getQueueLength()>0){ EV<<"DELAYing MAC busy: "<<simTime()<<endl; cancelEvent(startTxMsg); simtime_t delayTx = ((double)64*8)/txrate; simtime_t timerem; timerem.setRaw( MPCPTools::ns16ToSimTime( start_reg+len_reg-clock_reg )); if (timerem>delayTx){ scheduleAt(delayTx+simTime(), startTxMsg); }else{ shiftStart1Slot(); } return; } if (tmp_queue.isEmpty()){ queue_mod->requestPacket(); // MPCP period if (start_reg == 0){ transmitState = TX_OFF; EV << "\n==ONUMacCtl_NP: CHANGING STATE FROM _ON_ TO _OFF_\n"; return; } EV << "\n==ONUMacCtl_NP: CHANGING STATE FROM _ON_ TO _IDLE_ (no message in tmp queue)\n"; goToIDLE(); return; } EV << "\n==ONUMacCtl_NP: CHANGING STATE FROM "<<getStateStr()<<" TO _ON_\n"; transmitState = TX_ON; uint32_t nextMsgSize = ((cPacket *)tmp_queue.front())->getByteLength(); // Calculate TX and remaining time // NOTE: Change here for more bandwidth if (nextMsgSize<64) nextMsgSize=64; uint32_t bytes=nextMsgSize+PREAMBLE_BYTES+SFD_BYTES; bytes+=INTERFRAME_GAP_BITS/8; // TODO: Add laser on/off delay simtime_t timereq = ((double)bytes*8)/txrate; EV << "Total Bytes: "<<bytes<<" Total bits: "<<bytes*8<<" TX RATE: "<<txrate<<endl; simtime_t timerem; timerem.setRaw( MPCPTools::ns16ToSimTime( start_reg+len_reg-clock_reg )); EV << "*** It will take (sim): "<<timereq<<endl; EV << "*** We Still have (sim): "<<timerem<<endl; EV << "*** It will take (ns16): "<<MPCPTools::simTimeToNS16(timereq.raw())<<endl; EV << "*** We Still have (ns16): "<<MPCPTools::simTimeToNS16(timerem.raw())<<endl; dumpReg(); // If we dont have time break if (timerem<timereq){ simtime_t totaltime; totaltime.setRaw( MPCPTools::ns16ToSimTime( len_reg )); if (totaltime<timereq){ EV << "ONUMacCtl_NP: Frame is too big to FIT THE WHOLE TIME SLOT!\n"; // Discard and continue (the code)... // TODO: Maybe add a counter! cancelAndDelete(dynamic_cast<cMessage *>(tmp_queue.pop())); } // Log fragmented time EV << "ONUMacCtl_NP: Fragmented TimeSlot... Frame is too big\n"; EV << "\n==ONUMacCtl_NP: CHANGING STATE FROM _ON_ TO _OFF_\n"; transmitState = TX_OFF; fragmentedTime += timerem; // Shift the start_reg shiftStart1Slot(); // cancel the stop message // (else we lose a time slot) cancelEvent(stopTxMsg); return; } cPacket * msg = dynamic_cast<cPacket *>(tmp_queue.pop()); // Check the user implementation of the Queues if (!msg){ error( "Shit... we should never reach here: " "UNKNOWN message... NOT A cPACKET"); return; } // Add CURRENT TIME STAMP MPCP * mpcp = dynamic_cast<MPCP *>(msg); if (mpcp){ mpcp->setTs(clock_reg); } // We have enough time for the frame... //Send send(msg, "lowerLayerOut"); numFramesFromHL++; EV << "*** Current simTime (RAW): \t"<<simTime().raw()<<endl; EV << "*** Next Message simTime(RAW): \t"<<simTime().raw() + timereq.raw()<<endl; EV << "*** Current simTime (ns16): \t"<<MPCPTools::simTimeToNS16(simTime().raw())<<endl; EV << "*** Next Message simTime(ns16): \t"<<MPCPTools::simTimeToNS16(simTime().raw() + timereq.raw())<<endl; simtime_t nextTx; // LOOK at the NOTE on the begging nextTx = simTime() + timereq; nextTx+= 5*pow(10,simTime().getScaleExp()); cancelEvent(startTxMsg); scheduleAt(nextTx, startTxMsg); }
cMessage* ONUMacCtl_NP::stopTxMsg [protected] |