EPONImplementationforOMNet++  0.8Beta
ONUMacCtl_P Class Reference

TODO - Generated class. More...

#include <ONUMacCtl_P.h>

Inheritance diagram for ONUMacCtl_P:
ONUMacCtlBase

List of all members.

Public Member Functions

 ONUMacCtl_P ()
virtual ~ONUMacCtl_P ()

Protected Member Functions

virtual void initialize ()
virtual void startTxOnPON ()
 Directly called for start Messages and called if a frame arrives in IDLE.
virtual void handleMessage (cMessage *msg)
virtual void processFrameFromHigherLayer (cMessage *msg)
virtual void processMPCP (EthernetIIFrame *frame)
virtual void clockSync ()
virtual void scheduleStartTxMsgFromRegister ()
virtual void sendReport ()
virtual void scheduleReport ()

Protected Attributes

ONUQPerLLiDBaseqpl
cMessage * sendReportMsg

Detailed Description

TODO - Generated class.


Constructor & Destructor Documentation

                        {
      sendReportMsg = new cMessage("Send Report", SEND_REPORT);
}
                         {
      if (startTxMsg)
            cancelAndDelete(startTxMsg);
      if (sendReportMsg)
            cancelAndDelete(sendReportMsg);
}

Member Function Documentation

void ONUMacCtl_P::clockSync ( ) [protected, virtual]
                           {
      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();

      // Update the clock
      clock_reg = simT;
      EV << clock_reg << "=======================\n";
      return;
}
void ONUMacCtl_P::handleMessage ( cMessage *  msg) [protected, virtual]
{
      // Sync Clock
      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->getKind()==SEND_REPORT){
                  sendReport();
            }
            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_P: Message came FROM THE WRONG DIRRECTION???? Dropping\n";
            delete msg;
      }
}
void ONUMacCtl_P::initialize ( ) [protected, virtual]

Reimplemented from ONUMacCtlBase.

{
      // Do the common stuff...
      ONUMacCtlBase::initialize();

      // That will cause the ONU not to send REPORTs...
      qpl = dynamic_cast<ONUQPerLLiDBase *>(queue_mod);

}
void ONUMacCtl_P::processFrameFromHigherLayer ( cMessage *  msg) [protected, virtual]
                                                          {
      EV << "ONUMacCtl_P: Outgoing message, forwarding...\n";
      numFramesFromHL++;

      // Pre-Configuration ... Check and send only MPCP
      EV << "ONUMacCtl_P: Packet " << msg << " arrived from higher layers, sending\n";
      if (start_reg == 0 ){
            EV<<"ONUMacCtl_P: 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_P: 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;

            // Ignore WAKE UP if we are already transmitting
            if (startTxMsg->isScheduled()) return;
      }else{
            // ENQUEUE
            EV << "Queuing message..." << endl;
            tmp_queue.insert(msg);
      }


      // Check clock and transmit only if it is our time
      dumpReg();
      if (clock_reg>=start_reg && clock_reg<start_reg+len_reg)
            startTxOnPON();



}
void ONUMacCtl_P::processMPCP ( EthernetIIFrame *  frame) [protected, virtual]

Implements ONUMacCtlBase.

                                                    {
      EV << "ONUMacCtl_P: MPCP Frame processing\n";
      MPCP * mpcp = check_and_cast<MPCP *>(frame);

      switch (mpcp->getOpcode())
      {

            case MPCP_GATE:
            {
                  MPCPGate * gate = check_and_cast<MPCPGate *>(frame);
                  EV << "ONUMacCtl_P: Type is MPCP_GATE\n";

                  if (gate->getListLen() == 0) {
                        EV << "ONUMacCtl_P: !!! NO ALLOCATION FOR US :-( (bitches...)";
                        break;
                  }

                  if (gate->getListLen() == 1 &&
                        gate->getDest().isBroadcast()) {

                        EV << "ONUMacCtl_P: MPCP Registration! Ignoring...";
                        break;
                  }


                  // Update with 1st alloc
                  start_reg = gate->getStartTime(0);
                  len_reg = gate->getDuration(0);
                  slotLength = gate->getSlotTime();
                  slotNumber = gate->getSlotsNum();

                  // Start Tx since we have been polled...
                  // DO NOT call startTxOnPON() cause the allocation
                  // may be in the future...
                  scheduleStartTxMsgFromRegister();


                  // Schedule the report
                  scheduleReport();


                  numGates++;
                  break;
            }
            default:
                  break;
      };
}
void ONUMacCtl_P::scheduleReport ( ) [protected, virtual]
                                {
      // Nothing we can do...
      if (qpl==NULL) return;

      // ... +12 for the IFG
      uint16_t repsize = qpl->getMPCPRepSize()+12;

      EV << "REPORT SIZE: "<<repsize<<" ns16="<<MPCPTools::bytesToNS16(repsize, 1)<<endl;
      simtime_t timereq_rep;
      timereq_rep.setRaw(MPCPTools::ns16ToSimTime(
                                    MPCPTools::bytesToNS16(repsize, 1)
                                ));
      simtime_t slotend;
      // Offset from now to slot end
      uint32_t sendoffset = (start_reg+len_reg)-clock_reg;
      // end of slot in sec
      slotend.setRaw(MPCPTools::ns16ToSimTime(sendoffset));
      slotend = simTime()+slotend;

      EV << "Required time: "<<timereq_rep<<endl;
      EV << "Slot ends at: "<<slotend<<endl;
      EV << "Scheduling REPORT at: "<<slotend-timereq_rep<<endl;
      EV << "NOW: "<<simTime()<<endl;
      scheduleAt(slotend-timereq_rep, sendReportMsg);

}
void ONUMacCtl_P::scheduleStartTxMsgFromRegister ( ) [protected, virtual]
                                                {
      if (startTxMsg->isScheduled())
            cancelEvent(startTxMsg);

      // Start is in the past... schedule NOW
      if (clock_reg>start_reg)
            EV << "ONUMacCtl_P: WARNING: MPCP GATE WITH START REG IN THE PAST!!!"<<endl;
      if (clock_reg>start_reg && clock_reg<start_reg+len_reg){
            scheduleAt(simTime(), startTxMsg);
            return;
      }

      // Start in the PAST: MISSED TIMESLOT!
      if (clock_reg>start_reg+len_reg){
            EV << "ONUMacCtl_P: WARNING: MISSED SLOT ... clock > start+len!!!"<<endl;
            return;
      }


      // Calc. the difference between clock and start
      uint diff = start_reg - clock_reg;
      simtime_t simoffset;
      simoffset.setRaw(MPCPTools::ns16ToSimTime(diff));

      EV<<"Scheduling StartTxMsg in future: diff="<<diff<<" simoffset="<<simoffset<<endl;
      scheduleAt(simTime()+simoffset, startTxMsg);

}
void ONUMacCtl_P::sendReport ( ) [protected, virtual]
                            {
      // StartTxOnPon will handle the report
      if (startTxMsg->isScheduled()) return;

      EV << "*** Sending MPCP REPORT ***"<<endl;
      dumpReg();
      // enqueue the frame (in case the Q layer is empty!)
      if (tmp_queue.length()==0)
            tmp_queue.insert(qpl->requestMPCP_REPORT());
      // trigger tx
      startTxOnPON();
      if (tmp_queue.length()==1){
            EV << "*** Removing MPCP REPORT: StartTx re-aquired it ***"<<endl;
            delete tmp_queue.pop();
      }
}
void ONUMacCtl_P::startTxOnPON ( ) [protected, virtual]

Directly called for start Messages and called if a frame arrives in IDLE.

Check to be sure... THIS SHOULD NEVER HAPPEN

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

Before requesting data packet check if we should send REPORT

Check That he allocated time is more than the frame... If it is not discard 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_P: 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;
            return;
      }

      if (emac->getQueueLength()>0){
            EV<<"DELAYing MAC busy: "<<simTime()<<endl;
            std::cout<<"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);
            return;
      }



      if (tmp_queue.isEmpty()){
            queue_mod->requestPacket();

            // MPCP period
            if (start_reg == 0){
                  transmitState = TX_OFF;
                  EV << "\n==ONUMacCtl_P: CHANGING STATE FROM _ON_ TO _OFF_\n";
                  return;
            }

            EV << "\n==ONUMacCtl_P: CHANGING STATE FROM _ON_ TO _IDLE_ (no message in tmp queue)\n";

            return;
      }


      EV << "\n==ONUMacCtl_P: 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
      // TODO: Make a method in MPCPTools for this... (bytes to simtime)
      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 ));

      if (qpl!=NULL){
            uint16_t repsize = qpl->getMPCPRepSize();

            simtime_t timereq_rep;
            timereq_rep.setRaw(MPCPTools::ns16ToSimTime(
                                          MPCPTools::bytesToNS16(repsize, 1)
                                      ));
            // Total time for both packets
            simtime_t totaltime = timereq_rep+timereq;

            // only one can be send... so send the REPORT
            if (totaltime>=timerem){
                  EV << "*** Total Req time (sim): "<<totaltime<<endl;
                  EV << "*** Remaining time (sim): "<<timerem<<endl;
                  EV << "*** Sending MPCP REPORT : "<<timereq_rep<<endl;
                  send(qpl->requestMPCP_REPORT(), "lowerLayerOut");

                  numFramesFromHL++;

                  // no need to reschedule startTx...
                  // end of time slot

                  // cancel tho report sending
                  if (sendReportMsg->isScheduled()) cancelEvent(sendReportMsg);
                  return;
            }
      }

      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;

            // ON SHIFTING HERE

            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 at the top...
      nextTx = simTime() + timereq;
      nextTx+= 5*pow(10,simTime().getScaleExp());
      cancelEvent(startTxMsg);
      scheduleAt(nextTx, startTxMsg);
}

Member Data Documentation

cMessage* ONUMacCtl_P::sendReportMsg [protected]

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