home  

How to Add Support for Multiple Radios in SWANS

 

 

I was recently asked how to extend JiST/SWANS to support multiple radios. I will share my opinion on how I think this could be done.
SWANS currently does not include a support for multiple radios. Therefore, one has to introduce some changes. However, I think that it is not so hard to do in SWANS. SWANS is written with a very well structured object oriented design and the modules separation resembles the real networking stack a lot. Therefore, those changes can be introduced pretty easily.

First, before delving into the code, one must answer two important design questions:
1) Do you want the radios to interfere with each other or not? Specifically, it means: do you want one radio to sense the signal (and noise) of the other radio from the other type.
2) Do you want to make a routing decisions (over which radio to send which message) at the application level (above NetIP and above Transport) or at the routing level?

A notice: My proposed design tries to minimize the number of changes to the existing SWANS stack design, without (or with minimal) breaking the current abstractions of the networking stack. The proposed design below is not complete. It is more of a high level design suggestions and one still needs to think more thoroughly of some points. I hope you will find it useful.
 

Restructuring Radios:

Usually, one would like multiple radios not to interfere with each other. This mimics the behavior of multiple channels. Usually, radios on different channels do to interfere with each other, since the PHY hardware can separate the signals on different channels quite effectively. So lets talk first about non-interfering radios.

There are two problems we need to tackle:
1) delivering the signal from the radio on some channel only to the radios on this channel;
2) taking care of movements of radios. If a radio that belonging to channel X of some node moves (the node moves), the other radio should move with it as well.

I suggest to have a separate radio object to represent every radio. Those two physical radios will be combined into one virtual radio, which will be placed on the field (kind of a field node object). The virtual radio will represent the node towards the field object.
Movement: when the Field moves the node, it will move the virtual radio.
Signal transmission: there are a number of ways to implement it. I suggest the following way: every physical radio is also connected directly to the Field. When the physical radio wants to transmit a signal it does so directly on the field, as it is done now. The function void FieldInterface.transmit(RadioInfo srcInfo, Message msg, long duration) will have an additional parameter: channel.  When the field gets a signal sent on some channel, it passes the channel parameter to spatial.visitTransmit, which passes it also to the SpatialTransmitVisitor.visitTransmit(). Inside the function Spatial.SpatialTransmitVisitor.visitTransmit() the RadioInfo dstInfo is the virtual radio. In this place we simply iterate over all physical radios inside the virtual radio and take only those for which their channel equals the srcInfo channel. On those destination radios we call the original  SpatialTransmitVisitor.visitTransmit function (without the channel parameter).

Some code details:

1) In the driver class, when you assemble the node in function createNode() you should create 3 radios. Two physical radios and one virtual radio:

// you may create 2 different radioInfoShared object, each for every channel. Lets say on one channel you have a powerful radio transmitting
// at power level 20dBm and the second channel radio transmitting at power level 15dBm.
RadioNoise phyRadio1 = new RadioNoiseAdditive(i, radioInfoShared1);
RadioNoise phyRadio2 = new RadioNoiseAdditive(i, radioInfoShared2);
RadioNoise virtRadio = new VirtualRadio(i, radioInfoShared, phyRadio1, phyRadio2);

// You add to the field only the virtual radio (the field will move only the virtual radio), while you connect to every physical radio its own mac.
field.addRadio(virtRadio.getRadioInfo(), virtRadio.getProxy(), location);
field.startMobility(virtRadio.getRadioInfo().getUnique().getID());

// Here I connect every physical radio to the field and I will demultiplex the signals based on the additional channel parameter (passed by the transmit method).
// Another way would be to connect the virtual radio to the field and then to do the demultiplexing inside the virtula radio object. This would introduce for my opinion more abstractions breaking:
// you will need to add a channel parameter to the message and also make the virtual radio expose a unified RadioInfoShared object  to the field
// (with the largest power level for example.  I found this to be more hacky than the first solution).
phyRadio1.setFieldEntity(field.getProxy());
phyRadio2.setFieldEntity(field.getProxy());

// since every MAC is connected only to its own radio, on one channel, this MAC will sense signals and noise only on this channel
phyRadio1.setMacEntity(mac1.getProxy());
phyRadio2.setMacEntity(mac2.getProxy());
mac1.setRadioEntity(radio1.getProxy());
mac2.setRadioEntity(radio2.getProxy());


byte intId = net.addInterface(mac1.getProxy());
byte intId = net.addInterface(mac2.getProxy());
mac1.setNetEntity(net.getProxy(), intId);
mac2.setNetEntity(net.getProxy(), intId);

net.setProtocolHandler(Constants.
NET_PROTOCOL_HEARTBEAT, app.getNetProxy());
app.setNetEntity(net.getProxy());
app.getAppProxy().run(null);

2) The VirtualRadio class will represent the physical radios towards the Field. Therefore, the VirtualRadio must have the same id as its physical radios.

3) In the Field object: as described above.

If you want to have interference between the radios of different channels, you still need one virtual radio for movements, but you do not need to demultiplex the signals with channels.

 

Routing Decision:

One option is to have two IP objects, with different IP addresses, each one connected to a separate MAC. This way we decide over which channel (interface) to send the message at the application level. This is like having two different interfaces in the real networking stack and deciding to which one to bind a socket to.

Another way is to have one IP layer and to make all decisions inside the routing object. The IP is connected to two MACs, each one with different interfaceId. The routing object gets the message and sends it back via function NetIp.send(NetMessage.Ip msg, int interfaceId, MacAddress nextHop) on the appropriate interfaceId. There is one delicate point here thought: broadcast messages. Currently, all broadcast messages (to NetAddress.ANY) are sent over the first, default MAC. You will need to change the method NetIp.sendIp(NetMessage.Ip msg) to direct the broadcast messages over the right channel as well.
This design mimics the concept of virtual interface in Linux - you can have one networking interface to the applications and it is connected below to two physical interfaces. This is also called "bridge" in Lunix.

 

* I was assisted by Alex Kogan with the above multiple radios design.

 

Gabriel Kliot

12/31/2008