EPONImplementationforOMNet++
0.8Beta
|
TODO - Generated class. More...
#include <ONUMacCtl_P.h>
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 | |
ONUQPerLLiDBase * | qpl |
cMessage * | sendReportMsg |
TODO - Generated class.
{ sendReportMsg = new cMessage("Send Report", SEND_REPORT); }
ONUMacCtl_P::~ONUMacCtl_P | ( | ) | [virtual] |
{ if (startTxMsg) cancelAndDelete(startTxMsg); if (sendReportMsg) cancelAndDelete(sendReportMsg); }
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); }
ONUQPerLLiDBase* ONUMacCtl_P::qpl [protected] |
cMessage* ONUMacCtl_P::sendReportMsg [protected] |