//==========================================================================
// FDDI_MAC.CC - Simple module definitions of the FDDI MAC model for
// Discrete System Simulation in OMNeT++
//
// Author: Gabor.Lencse@hit.bme.hu
//==========================================================================
/*--------------------------------------------------------------*
Copyright (C) 1996,97 Gabor Lencse,
Technical University of Budapest, Dept. of Telecommunications,
Stoczek u.2, H-1111 Budapest, Hungary.
This file is distributed WITHOUT ANY WARRANTY. See the file
`license' for details on this and other legal matters.
*--------------------------------------------------------------*/
#include <string.h>
#include <omnetpp.h>
#include "fddi_def.h"
#include "fddi_mac.h"
#define TRACE_MSG // turn on output messages
// #define STATE_CHK // turn on E-FSM state checking
static bool accelerated = false;
Define_Module( FDDI_MAC )
Define_Module( FDDI_MAC4Ring )
Define_Module( FDDI_MAC4Sniffer )
char *mysimtimeToStr(simtime_t t, char *dest=0)
{ // place result either into dest
static char buf[64]; // or into a static buffer
if (dest==NULL) dest=buf;
double ts = (double)t+0.000000005; // ts: sim.time(secs)+0.005us
long h; int m,s,ms; double us;
h = (long) (ts/3600); ts -= h*3600;
m = (int) (ts/60); ts -= m*60;
s = (int) (ts); ts -= s;
ms = (int) (ts*1000); ts -= ms/1000.0;
us = (ts*1000000L); us=( (long) (100L*us))/100.0;
sprintf(dest,"%ds %dms %.2fu", s,ms,us);
return dest;
}
void printMsg(cMessage &msg)
{
char time1[64],time2[64];
char msgname[32];
const char *s=msg.fullName();
const int LEN = 21;
strncpy(msgname,s,LEN);
int i;
for (i=strlen(s); i<LEN; i++)
msgname[i]=' ';
msgname[LEN]=0;
ev.printf( "%s #%2i %15.15s #%2i %15.15s %4d %3d\n",
msgname,msg.senderModuleId(),
mysimtimeToStr( msg.sendingTime(), time1),
msg.arrivalModuleId(),
mysimtimeToStr( msg.arrivalTime(), time2),
(int) msg.length(),
(int) msg.kind() );
}
void FDDI_MAC::StateCheck(MACState required_state, MACState also_good_state)
{
if ( (State & required_state)|!required_state )
; // system is in the required state, OK
else
{
ev.printf("FDDI MAC error: During processing event of type %i\n", CurrentEvent);
ev.printf("FDDI MAC is NOT in the required State 0x%x, ", required_state);
ev.printf("Current State is 0x%x\n", State);
endSimulation();
}
if ( State&~required_state&~also_good_state )
{
ev.printf("FDDI MAC error: During processing event #%i\n", CurrentEvent);
ev.printf("Current sate is 0x%x, but 0x%x is/are not allowed\n",
State,(State&~also_good_state)&~required_state);
endSimulation();
}
}
void FDDI_MAC::TokenArrived(cMessage *msg)
{
cMessage *m;
CurrentEvent=TOKEN_ARRIVED;
#ifdef STATE_CHK
//Required State: -
//Also Good State: REPEAT
StateCheck(IDLE,REPEAT);
#endif
RestrictedToken=msg->par("restricted");
// ?? the address of the 2 stations, who have the restr. token ...
// capture the token if it is usable, repeat it otherwise:
if ( !sync_buf.empty() ||
(!async_buf.empty()&&!LateCounter&&((double)TRT>token_time)) )
{ // according to the STANDARD, it should be: TRT>token_time+station_latency
State |= TOKEN_CAPTURE;
m = new cMessage("TOKEN_CAPTURE_END",TOKEN_CAPTURE_END,0);
scheduleAt(simTime()+token_time,m);
}
else
{
State |= TOKEN_RECEIVE | BEFORE_TOKEN_REPEAT;
m = new cMessage("TOKEN_RECEIVE_END",TOKEN_RECEIVE_END,0);
scheduleAt(simTime()+token_time,m);
m = new cMessage("TOKEN_REPEAT_BEGIN",TOKEN_REPEAT_BEGIN,0);
scheduleAt(simTime()+station_latency,m);
}
delete msg;
}
void FDDI_MAC::TokenRepeatBegin(cMessage *msg)
{
CurrentEvent=TOKEN_REPEAT_BEGIN;
#ifdef STATE_CHK
//Required State: BEFORE_TOKEN_REPEAT
//Also Good State: TOKEN_RECEIVE
StateCheck(BEFORE_TOKEN_REPEAT,TOKEN_RECEIVE);
#endif
State &= ~BEFORE_TOKEN_REPEAT;
State |= TOKEN_REPEAT;
cMessage *tok = new cMessage("FDDI_TOKEN", FDDI_TOKEN);
tok->setLength(TokenLength);
tok->addPar("restricted") = (bool)RestrictedToken;
send( tok, "out");
cMessage *m = new cMessage("TOKEN_REPEAT_END",TOKEN_REPEAT_END,0);
scheduleAt(simTime()+token_time,m);
delete msg;
}
void FDDI_MAC::TokenRepeatEnd(cMessage *msg)
{
CurrentEvent=TOKEN_REPEAT_END;
#ifdef STATE_CHK
//Required State: TOKEN_REPEAT
//Also Good State: -
StateCheck(TOKEN_REPEAT,IDLE);
#endif
State &= ~TOKEN_REPEAT;
delete msg;
}
void FDDI_MAC::TokenReceiveEnd(cMessage *msg)
{
CurrentEvent=TOKEN_RECEIVE_END;
#ifdef STATE_CHK
//Required State: TOKEN_RECEIVE
//Also Good State: TOKEN_REPEAT
StateCheck(TOKEN_RECEIVE,TOKEN_REPEAT);
#endif
State &= ~TOKEN_RECEIVE;
if ( (EarlyToken=!LateCounter) != 0 )
{
TRT=T_Opr; // it is auto enabled
cancelEvent(TRTExpire);
scheduleAt(simTime()+T_Opr,TRTExpire);
}
else
LateCounter=0;
delete msg;
}
void FDDI_MAC::TokenCaptureEnd(cMessage *msg)
{
CurrentEvent=TOKEN_CAPTURE_END;
#ifdef STATE_CHK
//Required State: TOKEN_CAPTURE
//Also Good State: -
StateCheck(TOKEN_CAPTURE,IDLE);
#endif
State &= ~TOKEN_CAPTURE;
State |= BEFORE_TRANSMIT_OWN;
scheduleAt(simTime()+station_latency,new cMessage("TRANSMIT_OWN_BEGIN",TRANSMIT_OWN_BEGIN,0));
if ( (EarlyToken=!LateCounter) != 0 )
{
THT=(double)TRT; // it is auto enabled
THT.disable(); // only BeforeTransmitEnd should disable it! see STANDARD
TRT=T_Opr; // it is auto enabled
cancelEvent(TRTExpire);
scheduleAt(simTime()+T_Opr,TRTExpire);
}
else
LateCounter=0;
SyncFinished=false;
UsedSyncBandwidth=0;
delete msg;
}
void FDDI_MAC::TransmitOwnBegin(cMessage *msg)
{
CurrentEvent=TRANSMIT_OWN_BEGIN;
#ifdef STATE_CHK
//Required State: BEFORE_TRANSMIT_OWN
//Also Good State: -
StateCheck(BEFORE_TRANSMIT_OWN,IDLE);
#endif
State &= ~BEFORE_TRANSMIT_OWN; // this must be unset here, PlayTTRP unsets only TRANSMIT_OWN
// do the actions on the basis of the protocol, set the new state too:
PlayTTRP();
delete msg;
}
void FDDI_MAC::TransmissionEnd(cMessage *msg)
{
CurrentEvent=TRANSMISSION_END;
#ifdef STATE_CHK
//Required State: TRANSMIT_OWN
//Also Good State: FRAME_STRIP
StateCheck(TRANSMIT_OWN,FRAME_STRIP);
#endif
// do the actions on the basis of the protocol, set the new state too:
PlayTTRP();
delete msg;
}
void FDDI_MAC::TokenSendEnd(cMessage *msg)
{
CurrentEvent=TOKEN_SEND_END;
#ifdef STATE_CHK
//Required State: TOKEN_SEND
//Also Good State: FRAME_STRIP
StateCheck(TOKEN_SEND,FRAME_STRIP);
#endif
State &= ~TOKEN_SEND;
delete msg;
}
void FDDI_MAC::OwnFrameArrived(cMessage *msg)
{
CurrentEvent=OWN_FRAME_ARRIVED;
#ifdef STATE_CHK
//Required State: -
//Also Good State: TRANSMIT_OWN,TOKEN_SEND
StateCheck(IDLE,TRANSMIT_OWN|TOKEN_SEND);
#endif
State |= FRAME_STRIP;
cMessage *m = new cMessage("FRAME_STRIP_END",FRAME_STRIP_END,0);
scheduleAt(simTime()+msg->length()*byte_tr_time-inorder_epsilon, m);
delete msg;
}
void FDDI_MAC::FrameStripEnd(cMessage *msg)
{
CurrentEvent=FRAME_STRIP_END;
#ifdef STATE_CHK
//Required State: FRAME_STRIP
//Also Good State: TRANSMIT_OWN,TOKEN_SEND
StateCheck(FRAME_STRIP,TRANSMIT_OWN|TOKEN_SEND);
#endif
State &= ~FRAME_STRIP;
delete msg;
}
void FDDI_MAC::Frame2MeArrived(cMessage *msg)
{
CurrentEvent=FR2ME_ARRIVED;
#ifdef STATE_CHK
//Required State: -
//Also Good State: REPEAT
StateCheck(IDLE,REPEAT);
#endif
State |= FR2ME_RECEIVE;
cMessage *m = new cMessage("FR2ME_RECEIVE_END",FR2ME_RECEIVE_END,0);
scheduleAt(simTime()+msg->length()*byte_tr_time-inorder_epsilon, m);
msg_being_recd = msg;
if ( !accelerated )
{
State |= BEFORE_REPEAT;
//msg_to_repeat = new cMessage(*msg); <-- this may cause segmentation fault
msg_to_repeat = (cMessage *) msg->dup();
scheduleAt(simTime()+station_latency,new cMessage("REPEAT_BEGIN",REPEAT_BEGIN,0));
}
}
void FDDI_MAC::FrameToMeReceiveEnd(cMessage *msg)
{
CurrentEvent=FR2ME_RECEIVE_END;
#ifdef STATE_CHK
//Required State: FR2ME_RECEIVE
//Also Good State: REPEAT
StateCheck(FR2ME_RECEIVE,REPEAT);
#endif
State &= ~FR2ME_RECEIVE;
send(msg_being_recd,"to_LLC");
delete msg;
}
void FDDI_MAC::Frame2RepArrived(cMessage *msg)
{
CurrentEvent=FR2REP_ARRIVED;
#ifdef STATE_CHK
//Required State: -
//Also Good State: REPEAT
StateCheck(IDLE,REPEAT);
#endif
State |= BEFORE_REPEAT;
msg_to_repeat=msg;
scheduleAt(simTime()+station_latency,new cMessage("REPEAT_BEGIN",REPEAT_BEGIN,0));
}
void FDDI_MAC::RepeatEnd(cMessage *msg)
{
CurrentEvent=REPEAT_END;
#ifdef STATE_CHK
//Required State: REPEAT
//Also Good State: BEFORE_REPEAT,FR2ME_RECEIVE,TOKEN_RECEIVE,BEFORE_TOKEN_REPEAT,TOKEN_CAPTURE (but NOT at the same time ...)
StateCheck(REPEAT,BEFORE_REPEAT|FR2ME_RECEIVE|TOKEN_RECEIVE|BEFORE_TOKEN_REPEAT|TOKEN_CAPTURE);
#endif
State &= ~REPEAT;
delete msg;
}
void FDDI_MAC::RepeatBegin(cMessage *msg)
{
CurrentEvent=REPEAT_BEGIN;
#ifdef STATE_CHK
//Required State: BEFORE_REPEAT
//Also Good State: FR2ME_RECEIVE
StateCheck(BEFORE_REPEAT,FR2ME_RECEIVE);
#endif
State &= ~BEFORE_REPEAT;
State |= REPEAT;
RepeatEndsAt = simTime()+msg_to_repeat->length()*byte_tr_time;
scheduleAt(RepeatEndsAt-inorder_epsilon, new cMessage("REPEAT_END",REPEAT_END,0));
send(msg_to_repeat,"out");
delete msg;
IdleTimes=0; // a packet is repeated => not idle
}
void FDDI_MAC::TRTExpired(cMessage *msg)
{
CurrentEvent=TRT_EXPIRED;
if ( LateCounter == 0 )
{
LateCounter++;
TRT=T_Opr; // it is auto enabled
scheduleAt(simTime()+T_Opr,msg); // Recycling: *msg is reused
}
else
{
State = TOKEN_LOST;
delete msg;
error("FDDI_MAC Error: Token was lost (TRT expired twice in %s)\n",fullPath());
}
}
void FDDI_MAC::PlayTTRP() // Play the Timed Token Ring Protocol
{
if ( !SyncFinished && !sync_buf.empty() )
{ // try to ransmit the first sync. packet
cMessage *m=(cMessage *)sync_buf.pop();
int length = m->length();
if ( AllocatedSyncBandwidth >= UsedSyncBandwidth+length )
{ // this packet can be transmitted
UsedSyncBandwidth+=length;
m->addPar("sendtime") = simTime();
send(m,"out");
State |= TRANSMIT_OWN;
double sending_time=length*byte_tr_time;
scheduleAt(simTime()+sending_time, new cMessage("TRANSMISSION_END",TRANSMISSION_END,0));
IdleTimes=0; // a packet is transmitted => not idle
return; // !! HEY there is a RETURN here!
// ^ the next sync may be transmitted by the next call of this function
}
}
// the function didn't return => no more sync could be transmitted
if ( !SyncFinished )
{
SyncFinished=true;
if ( EarlyToken )
{
THT.enable();
priority_i=7;
}
}
// here SyncFinished is true
if ( EarlyToken && !async_buf.empty() &&
(!RestrictedToken || IAmRestrictedOwner) && ((double)THT)>0 )
{ // the 1st packet can be transmitted
cMessage *m = (cMessage *)async_buf.pop();
m->addPar("sendtime") = simTime();
send(m,"out");
State |= TRANSMIT_OWN;
int length=m->length();
double tr_time=length*byte_tr_time;
scheduleAt(simTime()+tr_time, new cMessage("TRANSMISSION_END",TRANSMISSION_END,0));
IdleTimes=0; // a packet is transmitted => not idle
return; // !! HEY there is a RETURN here!
// ^ the next async may be transmitted by the next call of this function
}
// the function didn't return => no more async could be transmitted
// now the token must be passed
cMessage *tok = new cMessage("FDDI_TOKEN", FDDI_TOKEN);
tok->setLength(TokenLength);
tok->addPar("restricted") = RestrictedToken;
send( tok, "out");
State &= ~TRANSMIT_OWN;
State |= TOKEN_SEND;
scheduleAt(simTime()+TokenLength*byte_tr_time,
new cMessage("TOKEN_SEND_END",TOKEN_SEND_END,0));
}
FDDI_MAC::FDDI_MAC(const char *namestr, cModule *parentmod) :
cSimpleModule(namestr, parentmod, FDDI_MAC_HEAPSIZE),
sync_buf("sync_buf"),
async_buf("async_buf")
{
State=IDLE;
CurrentEvent=0;
msg_being_recd=0; // message is currently being received
msg_to_repeat=0; // this msg will be repeated when REPEAT_BEGIN event arrives
RepeatEndsAt=-1; // the current repeating will end at this time
EarlyToken=0; // Token is early
RestrictedToken=0; // Token is restricted
LateCounter=0; // TRT expired LateCounter times since last TOKEN_ARRIVE
TRTExpire=0; // holds a pointer to the TRT expire event
AllocatedSyncBandwidth=0; // Allocated Synchronous Bandwidth (in bytes)
UsedSyncBandwidth=0; // Used Synchronous Bandwidth (in bytes)
RingID=-1; // To cause error, if not set later
IdleTimes=0; // # of tokens arrived since packet was transmitted for the last time
IAmRestrictedOwner=false; // This station is a/the ResrictedToken owner
SyncFinished=false; // transm. of sync. packets is already finished
}
FDDI_MAC4Ring::FDDI_MAC4Ring(const char *namestr, cModule *parentmod) :
FDDI_MAC(namestr,parentmod)
{
}
void FDDI_MAC::activity()
{
RingID = (short) (long) parentModule()->parentModule()->par("RingID");
T_Opr = parentModule()->parentModule()->par("TTRT");
if ( findPar("StationID") < 0 )
my_station_id = parentModule()->index(); // RO: use only in a ring made by indexing ...
else
my_station_id = par("StationID");
IAmRestrictedOwner=false;
TRT=T_Opr; // it is auto enabled
TRTExpire = new cMessage("TRT_EXPIRED",TRT_EXPIRED,0);
scheduleAt(simTime()+T_Opr,TRTExpire);
if (my_station_id == 0)
{
// Issue a token:
cMessage *tok = new cMessage("FDDI_TOKEN", FDDI_TOKEN);
tok->setLength(TokenLength);
tok->addPar("restricted") = false;
send( tok, "out");
}
for(;;)
{
cMessage *msg = receive();
#ifdef TRACE_MSG
ev.printf("0x%04x ",State);
printMsg(*msg);
#endif
if ( msg->arrivedOn("from_LLC") ) // new message from the generator
async_buf.insert( msg ); // insert message into the asynchronous send buffer
else
{
int msgkind = msg->kind();
if ( msgkind >= FDDI_MAC_MSG2SELF ) // if it is just a self message
switch ( msgkind )
{
case TOKEN_RECEIVE_END : TokenReceiveEnd(msg); break;
case TRANSMISSION_END : TransmissionEnd(msg); break;
case TOKEN_SEND_END : TokenSendEnd(msg); break;
case FRAME_STRIP_END : FrameStripEnd(msg); break;
case FR2ME_RECEIVE_END : FrameToMeReceiveEnd(msg); break;
case REPEAT_END : RepeatEnd(msg); break;
case TRT_EXPIRED : TRTExpired(msg); break;
case REPEAT_BEGIN : RepeatBegin(msg); break;
case TOKEN_REPEAT_BEGIN : TokenRepeatBegin(msg); break;
case TOKEN_REPEAT_END : TokenRepeatEnd(msg); break;
case TOKEN_CAPTURE_END : TokenCaptureEnd(msg); break;
case TRANSMIT_OWN_BEGIN : TransmitOwnBegin(msg); break;
default:
error("FDDI_MAC Error: Bad msgkind: %i in %s", msgkind, fullPath());
}
else if ( msgkind == FDDI_TOKEN )
TokenArrived(msg);
else if ( msgkind == FDDI_FRAME )
{
int source = (long) msg->par ("source");
if ( source == my_station_id )
OwnFrameArrived(msg);
else
{
int dest = (long) msg->par ("dest");
if ( dest == my_station_id )
Frame2MeArrived(msg);
else
Frame2RepArrived(msg);
}
}
else
{
ev.printf("Msg pointer=%p\n", msg);
error("(2)FDDI_MAC Error: Bad msgkind: %i in %s", msgkind, fullPath());
}
}
} // endfor
}
void FDDI_MAC4Sniffer::OwnFrameArrived(cMessage *msg)
{ // The code is taken from: virtual void FDDI_MAC::OwnFrameArrived(cMessage *)
CurrentEvent=OWN_FRAME_ARRIVED;
#ifdef STATE_CHK
//Required State: -
//Also Good State: TRANSMIT_OWN,TOKEN_SEND
StateCheck(IDLE,TRANSMIT_OWN|TOKEN_SEND);
#endif
State |= FRAME_STRIP;
cMessage *m = new cMessage("FRAME_STRIP_END",FRAME_STRIP_END,0);
scheduleAt(simTime()+msg->length()*byte_tr_time-inorder_epsilon, m);
// delete msg;
// CHANGE: the message is not deleted, but it is forwarded to the Monitor
sendDelayed(msg,msg->length()*byte_tr_time,"to_LLC");
}
void FDDI_MAC4Sniffer::Frame2RepArrived(cMessage *msg)
{ // The code is taken from: virtual void FDDI_MAC::Frame2RepArrived(cMessage *msg)
CurrentEvent=FR2REP_ARRIVED;
#ifdef STATE_CHK
//Required State: -
//Also Good State: REPEAT
StateCheck(IDLE,REPEAT);
#endif
State |= BEFORE_REPEAT;
// CHANGE: msg is copied and sent to LLC:
cMessage *msgcpy = (cMessage *) msg->dup();
sendDelayed(msgcpy,msg->length()*byte_tr_time,"to_LLC");
// END OF CHANGE
msg_to_repeat=msg;
scheduleAt(simTime()+station_latency,new cMessage("REPEAT_BEGIN",REPEAT_BEGIN,0));
}
syntax highlighted by Code2HTML, v. 0.9.1