Now we have the simulation script, and also added our protocol to the NS2 simulator, which is still a placeholder. Now we're going the actually implement our own random MAC protocol.
Protocol Description
According to the project specification, when sending out an packet, our protocol
is supposed to send out X
copies of the packet at random time before sending
out next packet. As long as the receiver receive at least one of the X
duplicates, we say this packet was successfully delivered.
Protocol Parameters
From the protocol description, it's obvious that we need to know:
- How many copies to send for one packet? I.e., the
X
- The interval of sending packet from up layer, so that we can schedule resending before up layer pass down the next packet.
So we add two class variables in mac/rmac.h
int repeatTx_;
double interval_;
And in the constructor function of RMAC
class, we need to bind the variables
through TCL so that we can pass values in TCL script.
bind("repeatTx_", &repeatTx_);
bind("interval_", &interval_);
TCL Object Binding
We also need to let TCL runtime to know our protocol. That is, when we write this in TCL script.
set val(mac) Mac/RMAC
TCL runtime would have to know the corresponding class of the Mac/RMAC
.
Since we copied code from mac-simple.cc
and also made the changes, this part
has been done, but let's just review the code snippet that does the binding.
static class RMACClass : public TclClass {
public :
RMACClass() : TclClass("Mac/RMAC") {}
TclObject* create(int, const char* const*) {
return (new RMAC());
}
} class_rmac;
Here the Mac/RMAC
string will be our protocol name.
Interaction with Adjacent Layer
The most important function in any NS2 MAC protocol is the recv
function. It's
the interface to upper (Network Layer) and also lower (Physical Layer) layers.
The recv
of our MAC protocol will look like this.
void
RMAC::recv(Packet *p, Handler *h) {
struct hdr_cmn *hdr = HDR_CMN(p);
/* let RMAC::send handle the outgoing packets */
if (hdr->direction() == hdr_cmn::DOWN) {
sendDown(p,h);
}
else {
sendUp(p,h);
}
}
Here we first get the header of the packet, and check it's directory.
hdr_cmn::DOWN
means this packet is from upper layer, and we need to send it
out. hdr_cmn::UP
means this packet is from lower layer (received packet), we
need to deliver it to upper layer.
Repeat Sending
The key part of our MAC protocol is to repeated send multiple copies when
sending out a packet. So we need to mainly modify the sendDown
function.
double max_delay = 0;
// generate repeatTx_ number of random delays
double* delays = new double[repeatTx_];
for (int i = 0; i < repeatTx_; i++) {
delays[i] = (rand() % 100) / 100.0 * interval_;
if (delays[i] > max_delay) {
max_delay = delays[i];
}
}
// use dummy tx handler for first repeatTx_-1 packets
for (int i = 0; i < repeatTx_; i++) {
if (delays[i] != max_delay) {
Scheduler::instance().schedule(&resendHandler_, (Event*)p->copy(), delays[i]);
}
}
delete delays;
waitTimer->restart(max_delay);
if (rx_state_ == MAC_IDLE ) {
// we're idle, so start sending now
sendTimer->restart(max_delay + ch->txtime());
} else {
// we're currently receiving, so schedule it after
// we finish receiving
sendTimer->restart(max_delay + ch->txtime()
+ HDR_CMN(pktRx_)->txtime());
}
We first generate repeatTx_
number of delays before next interval. Except for
the max_delay
, which will be the last copy to send, we use the Scheduler
to
resend the duplicated packets, and for last packet, we just use the timer
scheme of SimpleMac
.
Here is the resendHander_
looks like.
void
RMACResendHandler::handle(Event* p) {
mac_->resend((Packet*) p);
}
void
RMAC::resend(Packet* p) {
downtarget_->recv(p, NULL);
}
You can find the complete code for rmac.cc
and rmac.h
here.