Sending messages to another node
We will start over with our code, for simplicity. We will write a simulation with two blue nodes. Both nodes will change to RED at time 10 and then change the color every now and then randomly. We already know how to do this.
Additionally, each node will send a message to the other node to tell it to change to YELLOW. This behavior is new to us. We will break it up in two phases: First, we will schedule a self-message to ourselves to remind us of sending the message. Upon reception of this self-message, we will actually send the message out.
During initialization:
#include "Node.h"
Define_Module(Node);
#define CHANGE_TO_BLUE 100
#define CHANGE_TO_RED 101
#define SEND_CHANGE_TO_YELLOW 102
#define CHANGE_TO_YELLOW 103
void Node::initialize()
{
// create a simple message and send it to ourselves at simulation time 10.
cMessage *msg = new cMessage("changeColorSelf");
msg->setKind(CHANGE_TO_RED);
scheduleAt(10, msg);
// create another self-message to trigger the message to the other node.
cMessage *msg_to_trigger = new cMessage("triggerSelfChangeColor");
msg_to_trigger->setKind(SEND_CHANGE_TO_YELLOW);
scheduleAt(intuniform(500,5000), msg_to_trigger);
}
Nothing really new so far. However, the handleMessage() is now more complex:
void Node::handleMessage(cMessage *msg)
{
// In this scenario, we can receive two types of messages:
// self-messages and external messages.
// First, let us check whether it is a self-message or not:
if (msg->isSelfMessage()) {
// first, ask for the kind with a switch statement
if (msg->getKind() == CHANGE_TO_RED) {
cDisplayString& dispStr = getDisplayString();
dispStr.parse("b=60,10,rect,red,black,2");
msg->setKind(CHANGE_TO_BLUE);
scheduleAt(simTime()+intuniform(10,1000), msg);
EV << "Changing to RED at time " << simTime() << "\n";
}
else if (msg->getKind() == CHANGE_TO_BLUE) {
cDisplayString& dispStr = getDisplayString();
dispStr.parse("b=60,10,rect,blue,black,2");
msg->setKind(CHANGE_TO_RED);
scheduleAt(simTime()+intuniform(10,1000), msg);
EV << "Changing to BLUE at time " << simTime() << "\n";
}
else if (msg->getKind() == SEND_CHANGE_TO_YELLOW) {
cMessage *msg_new = new cMessage("triggerOther");
msg_new->setKind(CHANGE_TO_YELLOW);
send(msg_new, "my_gate$o");
EV << "Sending a message to the other node at time " << simTime() << "\n";
delete msg;
}
else {
EV << "UNEXPECTED SELF EVENT at time " << simTime() << "\n";
}
}
...
In this part of handleMessage(), we only check for all types of self messages: we have a total of three.
{% hint style="info" %} Always check for all types present in the simulation AND add a final else statement. This makes sure that you handle all messages, expected or not. Otherwise the simulation might crash. {% endhint %}
Pay attention to the send() function. The second parameter is the name of the outgoing gate of this node. However, we defined a single in-out gate. In order to reference it correctly, we need to say explicitly: Use the out part of the inout gate. This is the meaning of "my_gate$o".
Next, we need to take care of all messages coming from the outside (non-self messages):
...
// if the message comes from somewhere else
else {
if (msg->getKind() == CHANGE_TO_YELLOW) {
cDisplayString& dispStr = getDisplayString();
dispStr.parse("b=60,10,rect,yellow,black,2");
EV << "Changing to YELLOW at time " << simTime() << "\n";
} else
EV << "UNEXPECTED EXTERNAL EVENT at time " << simTime() << "\n";
delete msg;
}
}
We only expect one message to come from the outside: CHANGE_TO_YELLOW. However, we will explicitly check for its kind and only then we will change the color to yellow and then delete the message.
{% hint style="info" %}
Again, always check explicitly for all types of messages and add an else statement at the end. Remember, a simulation is always work in progress and the number and types of messages will change all the time.
{% endhint %}
Try the code out!