EPONImplementationforOMNet++  0.8Beta
ONUMacCtl_NP Class Reference

ONUMacCtl class controls the below MAC layer transmission times. More...

#include <ONUMacCtl_NP.h>

Inheritance diagram for ONUMacCtl_NP:
ONUMacCtlBase

List of all members.

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 ()

Detailed Description

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.


Constructor & Destructor Documentation

                           {

      cancelAndDelete(startTxMsg);
      cancelAndDelete(stopTxMsg);

}

Member Function Documentation

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);
}

Member Data Documentation

cMessage* ONUMacCtl_NP::stopTxMsg [protected]

The documentation for this class was generated from the following files:
 All Classes Files Functions Variables Typedefs Friends Defines