TP 4: Découverte de voisinage et routage simple en anneau
Auteur: Congduc Pham, UPPA
TRES IMPORTANT: Avant toute
manipulation pour enlever des composants électroniques des
capteurs, il faut que le capteur soit éteint ou non alimenté par
le port USB par exemple.
Préliminaires
- Si vous n'avez pas encore utiliser les
Arduino, faites ce TP sur les
Arduino pour installer l'IDE et faire les premiers tests.
Découverte de voisinage
En se basant sur le code de Arduino_tutorial_Xbee_Send
et Arduino_tutorial_Xbee_Receive,
proposer ume implémentation simple d'un mécanisme de découverte de
voisinage. Utilisez un format ASCII pour les paquets de contrôle
afin de permettre un débogage plus facile. Exemple : "H12" pourrait
indiquer un paquet "HELLO" envoyé par le noeud 12.
Routage simple en anneau
La suite consiste à implémenter un protocole de routage simple en
anneau. Dans ce mode de routage, un noeud est le puit de données et
indique sa présence par un message initial (SETUP par exemple)
permettant aux noeuds voisins de connaître leur "distance" par
rapport au puit. Tous les noeuds recevant directement un message du
puit se trouvent donc à 1 saut du puit. Ces noeuds rediffusent le
message SETUP pour que les noeuds se trouvant à 2 sauts du puit
puissent se reconnaître. Une fois que tous les noeuds connaissent
leur "distance" au puit, le routage d'un paquet vers le puit
s'effectue en diffusant le paquet des niveaux N vers les niveaux N-1
jusqu'à atteindre le puit (niveau 0 par exemple).
Vous pouvez vous inspirer du code C++ suivant emprunté au simulateur
Castalia, qui implémente ce routage en anneau.
Dans la fonction startup(), c'est le puit qui initie
l'envoie d'un paquet de contrôle SETUP. La fonction fromMacLayer()
traite les paquets reçus par la couche MAC, et donc effectue un
traitement afin de déterminer la "distance" du noeud par rapport au
puit , et rediffuse si besoin le message SETUP. La fonction fromApplicationLayer()
reçoit une paquet de données qu'il faut relayer vers le puit. Dans
votre implémentation, vous pouvez avoir un code spécifique pour le
puit et un code pour les noeuds qui ne sont pas puits. Il est
possible de dire que le puit a l'adresse 0 par exemple.
MultipathRingsRouting.h
/*******************************************************************************
*
Copyright:
National ICT Australia, 2007 -
2011
*
*
Developed
at the ATP lab, Networked Systems research
theme
*
*
Author(s):
Athanassios Boulis, Yuriy
Tselishchev
*
*
This
file is distributed under the terms in the attached LICENSE
file. *
*
If
you do not find this file, copies can be found by writing
to:
*
*
*
*
NICTA,
Locked Bag 9013, Alexandria, NSW 1435,
Australia
*
*
Attention:
License
Inquiry.
*
*
*
*******************************************************************************/
#ifndef
_MULTIPATHRINGSROUTING_H_
#define
_MULTIPATHRINGSROUTING_H_
#include
<map>
#include
"VirtualRouting.h"
#include
"MultipathRingsRoutingPacket_m.h"
#include
"MultipathRingsRoutingControl_m.h"
#define
NO_LEVEL -110
#define
NO_SINK -120
using
namespace std;
enum
MultipathRingsRoutingTimers {
TOPOLOGY_SETUP_TIMEOUT
= 1,
};
class
MultipathRingsRouting: public VirtualRouting {
private:
int
mpathRingsSetupFrameOverhead; // in bytes
double
netSetupTimeout;
//
multipathRingsRouting-related member variables
int
currentSequenceNumber;
int
currentSinkID;
int
currentLevel;
int
tmpSinkID;
int
tmpLevel;
bool
isSink; //is a .ned file
parameter of the Application module
bool
isConnected; //attached under a parent node
bool
isScheduledNetSetupTimeout;
protected:
void
startup();
void
fromApplicationLayer(cPacket *, const char *);
void
fromMacLayer(cPacket *, int, double, double);
void
sendTopologySetupPacket();
void
sendControlMessage(multipathRingsRoutingControlDef);
void
timerFiredCallback(int);
void
processBufferedPacket();
};
#endif
//MULTIPATHRINGSROUTINGMODULE
MultipathRingsRouting.cc
/*******************************************************************************
* Copyright:
National ICT Australia, 2007 -
2011
*
* Developed at the
ATP lab, Networked Systems research
theme
*
* Author(s):
Athanassios Boulis, Yuriy
Tselishchev
*
* This file is
distributed under the terms in the attached LICENSE
file. *
* If you do not
find this file, copies can be found by writing
to: *
*
*
*
NICTA,
Locked Bag 9013, Alexandria, NSW 1435,
Australia
*
*
Attention:
License
Inquiry.
*
*
*
*******************************************************************************/
#include
"MultipathRingsRouting.h"
Define_Module(MultipathRingsRouting);
void
MultipathRingsRouting::startup()
{
netSetupTimeout = (double)par("netSetupTimeout") / 1000.0;
mpathRingsSetupFrameOverhead =
par("mpathRingsSetupFrameOverhead");
// check
that the Application module used has the boolean parameter
"isSink"
cModule
*appModule =
getParentModule()->getParentModule()->getSubmodule("Application");
if
(appModule->hasPar("isSink"))
isSink = appModule->par("isSink");
else
opp_error("\nMultiPathRings routing has to be
used with an application that defines the parameter isSink");
currentLevel = tmpLevel = isSink ? 0 : NO_LEVEL;
currentSinkID = tmpSinkID = isSink ? self : NO_SINK;
isConnected
= (isSink) ? true : false;
isScheduledNetSetupTimeout = false;
currentSequenceNumber = 0;
if (isSink)
sendTopologySetupPacket();
}
void
MultipathRingsRouting::sendTopologySetupPacket()
{
MultipathRingsRoutingPacket *setupPkt =
new MultipathRingsRoutingPacket("Multipath
rings routing setup packet", NETWORK_LAYER_PACKET);
setupPkt->setMultipathRingsRoutingPacketKind(MPRINGS_TOPOLOGY_SETUP_PACKET);
setupPkt->setSource(SELF_NETWORK_ADDRESS);
setupPkt->setDestination(BROADCAST_NETWORK_ADDRESS);
setupPkt->setSinkID(currentSinkID);
setupPkt->setSenderLevel(currentLevel);
toMacLayer(setupPkt, BROADCAST_MAC_ADDRESS);
}
void
MultipathRingsRouting::sendControlMessage(multipathRingsRoutingControlDef
kind)
{
MultipathRingsRoutingControlMessage *ctrlMsg =
new
MultipathRingsRoutingControlMessage("Multipath routing control
message",NETWORK_CONTROL_MESSAGE);
ctrlMsg->setMultipathRingsRoutingControlMessageKind(kind);
ctrlMsg->setLevel(currentLevel);
ctrlMsg->setSinkID(currentSinkID);
toApplicationLayer(ctrlMsg);
}
void
MultipathRingsRouting::timerFiredCallback(int index)
{
if (index
!= TOPOLOGY_SETUP_TIMEOUT)
return;
isScheduledNetSetupTimeout = false;
if
(tmpLevel == NO_LEVEL) {
setTimer(TOPOLOGY_SETUP_TIMEOUT,
netSetupTimeout);
isScheduledNetSetupTimeout = true;
} else if
(currentLevel == NO_LEVEL) {
//Broadcast to all nodes of currentLevel-1
currentLevel = tmpLevel + 1;
currentSinkID = tmpSinkID;
if (!isConnected) {
isConnected = true;
sendControlMessage(MPRINGS_CONNECTED_TO_TREE);
trace() << "Connected
to " << currentSinkID << " at level " <<
currentLevel;
if (!TXBuffer.empty())
processBufferedPacket();
} else {
sendControlMessage(MPRINGS_TREE_LEVEL_UPDATED);
trace() <<
"Reconnected to " << currentSinkID << " at level "
<< currentLevel;
}
sendTopologySetupPacket();
}
tmpLevel =
isSink ? 0 : NO_LEVEL;
tmpSinkID =
isSink ? self : NO_SINK;
}
void
MultipathRingsRouting::processBufferedPacket()
{
while
(!TXBuffer.empty()) {
toMacLayer(TXBuffer.front(),
BROADCAST_MAC_ADDRESS);
TXBuffer.pop();
}
}
void
MultipathRingsRouting::fromApplicationLayer(cPacket * pkt, const
char *destination)
{
string
dst(destination);
MultipathRingsRoutingPacket *netPacket =
new MultipathRingsRoutingPacket("Multipath
rings routing data packet", NETWORK_LAYER_PACKET);
netPacket->setMultipathRingsRoutingPacketKind(MPRINGS_DATA_PACKET);
netPacket->setSource(SELF_NETWORK_ADDRESS);
netPacket->setDestination(destination);
netPacket->setSinkID(currentSinkID);
netPacket->setSenderLevel(currentLevel);
encapsulatePacket(netPacket, pkt);
if
(dst.compare(SINK_NETWORK_ADDRESS) == 0 ||
dst.compare(PARENT_NETWORK_ADDRESS) == 0) {
netPacket->setSequenceNumber(currentSequenceNumber);
currentSequenceNumber++;
if (bufferPacket(netPacket)) {
if (isConnected)
processBufferedPacket();
else
sendControlMessage(MPRINGS_NOT_CONNECTED);
} else {
//Here we could send a
control message to upper layer informing that our buffer is full
}
} else
{ //++++ need to control
flooding
toMacLayer(netPacket, BROADCAST_MAC_ADDRESS);
}
}
void
MultipathRingsRouting::fromMacLayer(cPacket * pkt, int macAddress,
double rssi, double lqi)
{
MultipathRingsRoutingPacket *netPacket = dynamic_cast
<MultipathRingsRoutingPacket*>(pkt);
if
(!netPacket)
return;
switch
(netPacket->getMultipathRingsRoutingPacketKind()) {
case MPRINGS_TOPOLOGY_SETUP_PACKET:{
if (isSink)
break;
if
(!isScheduledNetSetupTimeout) {
isScheduledNetSetupTimeout = true;
setTimer(TOPOLOGY_SETUP_TIMEOUT, netSetupTimeout);
tmpLevel
= NO_LEVEL;
tmpSinkID
= NO_SINK;
}
if (tmpLevel == NO_LEVEL ||
tmpLevel > netPacket->getSenderLevel()) {
tmpLevel
= netPacket->getSenderLevel();
tmpSinkID
= netPacket->getSinkID();
}
break;
}
case MPRINGS_DATA_PACKET:{
string
dst(netPacket->getDestination());
string
src(netPacket->getSource());
int senderLevel =
netPacket->getSenderLevel();
int sinkID =
netPacket->getSinkID();
if
(dst.compare(BROADCAST_NETWORK_ADDRESS) == 0 ||
dst.compare(SELF_NETWORK_ADDRESS) == 0) {
// We are
not filtering packets that are sent to this node directly or to
//
broadcast network address, making application layer responsible
for them
toApplicationLayer(pkt->decapsulate());
} else if
(dst.compare(SINK_NETWORK_ADDRESS) == 0) {
if
(senderLevel == currentLevel + 1) {
if (self == sinkID) {
// Packet is for this node,
if filter passes, forward it to application
if
(isNotDuplicatePacket(pkt))
toApplicationLayer(decapsulatePacket(pkt));
else
trace()
<< "Discarding duplicate packet from node " << src;
} else if (sinkID == currentSinkID) {
// We want to rebroadcast
this packet since we are not its destination
// For this, a copy of the
packet is created and sender level field is
// updated before calling
toMacLayer() function
MultipathRingsRoutingPacket
*dupPacket = netPacket->dup();
dupPacket->setSenderLevel(currentLevel);
toMacLayer(dupPacket,
BROADCAST_MAC_ADDRESS);
}
}
} else if
(dst.compare(PARENT_NETWORK_ADDRESS) == 0) {
if
(senderLevel == currentLevel + 1 && sinkID ==
currentSinkID) {
// Packet is for this node, if filter passes,
forward it to application
if (isNotDuplicatePacket(pkt))
toApplicationLayer(decapsulatePacket(pkt));
else
trace() << "Discarding
duplicate packet from node " << src;
}
}
break;
}
}
}