OMNET++: How do I send a message to a specific node based on probability? - omnet++

I want to make a simulation such that node 1 has a chance to send its message to node 2 or node 3 based on a given probability, and node 2 should do the same. However, if node 3 receives the message at anytime, then the message is deleted. I tried to make it myself, but it is not working how as I planned. Out1 is an output that goes to either node 1 or 2, while Out2 is an output that goes to node 3. When the message starts at node 1 and it goes to node 3 first, then the message gets properly deleted, but other times it will immediately pop up that there are no more events and that the simulation is completed. I attached my node's cc files, and I am sure the other connections and stuff are correct. Any advice would be much appreciated, I'm still very new to omnet++. Thanks!
#include "nodes.h"
Define_Module(Nodes);
void Nodes::initialize()
{
prob1 = .9;
if(strcmp("node1", getName()) == 0){
if (uniform(0, 1) > prob1){
EV << "Sending initial message\n";
cMessage *msg = new cMessage("hw4Msg");
send(msg, "out1");
}
else {
EV << "Sending initial message\n";
cMessage *msg = new cMessage("hw4Msg");
send(msg, "out2");
}
}}
void Nodes::handleMessage(cMessage *msg) {
counter ++;
if((counter == 1)&&(strcmp("node3", getName()) == 0)) {
EV << getName() << "'s counter is " << counter << ", meaning ";
EV << getName() << " has captured the packet. The message will now be deleted.";
delete msg;
}
prob2 = .9;
if(strcmp("node1", getName()) == 0) {
if (uniform(0, 1) > prob2) {
EV << getName() << " Received message " << msg->getName() << " ,sending it out again\n";
EV << getName() << "'s counter is " << counter;
send(msg, "out1");
}
else {
EV << getName() << " Received message " << msg->getName();
send(msg, "out2");
}}
if(strcmp("node2", getName()) == 0) {
if (uniform(0, 1) < prob2) {
EV << getName() << " Received message " << msg->getName() << " ,sending it out again\n";
EV << getName() << "'s counter is " << counter;
send(msg, "out1");
}
else {
EV << getName() << " Received message " << msg->getName();
send(msg, "out2");
}
}}

What you are missing from your model: how you intend to generate packets. In your current code, you generate a single message (in the initialize() method in node1) and then send that towards other nodes. Once it finds its way to node3 the message is deleted and there is no more events for the simulation to simulate, so it stops.
Otherwise, it cannot immediately finish as the first message either goes first to node3 and gets deleted there in the next event, or it goes to node2 where it is forwarded to either node1 or node3 according to your code.
Unless you have mistyped the node2 name in your NED file. But either way, you should single step this in Qtenv and see each events one by one.
As a side note, this scenario can (almost) fully modeled using the modules from the samples/queueinglib, (a Source, Sink and a Classifier module). I highly recommend to take a look at that sample.

Related

Problem with multiple controllers in OMNeT++ SDN

I'm trying to build multiple controllers. The original code that connect all switches to one controller is as follows:
void OFA_switch::connect()
{
socket.renewSocket();
int connectPort = par("connectPort");
/*
const char *connectAddress= par("connectAddress");
EV << "connectAddress = " << connectAddress << " connectPort =" << connectPort << endl;
if (getParentModule()->getParentModule()->getSubmodule("controller") != NULL)
{
// multiple controllers; full path is needed for connect address
connectAddress = (getParentModule()->getParentModule())->getSubmodule("controller")->getFullPath().c_str();
cModule *ctl = getSystemModule()->getSubmodule("controller");
if(ctl != NULL) {
EV << "ctl->getFullPath() = " << ctl->getFullPath().c_str() << endl;
connectAddress = ctl->getFullPath().c_str();
}
EV << "After: connectAddress = " << connectAddress << endl;
}
*/
L3Address ctlIPAddr;
EV << "connect L3Address = " << L3AddressResolver().tryResolve("controller", ctlIPAddr) << endl;
// EV << "result: connectAddress = " << ctlIPAddr << endl;
// socket.connect(L3AddressResolver().resolve(connectAddress), connectPort);
socket.connect(ctlIPAddr, connectPort);
}
I'm trying to make some switches connected to controller1 while the other switches connected to controller2, so I tried to adapt the following code to:
void My_OFA_switch::connect() {
socket.renewSocket();
int connectPort = par("connectPort");
const char *connectAddress = par("connectAddress");
EV << "connectAddress = " << connectAddress << " connectPort =" << connectPort << endl;
const char *connectAddr;
cModule *ctl;
if (strcmp (connectAddress, "controller1")==0)
{ connectAddr = (getParentModule())->getSubmodule("controller1")->getFullPath().c_str();
ctl = getSystemModule()->getSubmodule("controller1");
}
else if (strcmp (connectAddress, "controller2")==0)
{ connectAddr = (getParentModule())->getSubmodule("controller2")->getFullPath().c_str();
ctl = getSystemModule()->getSubmodule("controller2");
}
if(ctl != NULL) {
EV << "ctl->getFullPath() = " << ctl->getFullPath().c_str() << endl;
connectAddr = ctl->getFullPath().c_str();
}
L3Address ctlIPAddr;
EV << "connect L3Address = " << L3AddressResolver().tryResolve(connectAddr, ctlIPAddr) << endl;
socket.connect(ctlIPAddr, connectPort);
}
Also, there is a file Switch.cc which represents the controller behavior
"in ini file :
*.controller.behavior = "Switch" "that contain:
void Switch::initialize() {
cModule *ITModule =
getParentModule()->getSubmodule("ofa_controller");
controller = check_and_cast<OFA_controller *>(ITModule);
getParentModule()->subscribe("PacketIn",this); }
Should I change something here?
But when I run it the following runtime error appears and immediately close the simulation:
Simulation run has encountered a problem. Finished with error.
And in console it appeared:
Simulation terminated with exit code: -1073741819
Working directory: D:/omnet/OpenFlowOmnet/omnetpp-5.6.2-src-windows/omnetpp-5.6.2/myws/openflow/scenarios
Command line: ../openflow.exe -m -n ..;../../inet/src;../../inet/examples;../../inet/tutorials;../../inet/showcases --image-path=../images;../../inet/images -l ../../inet/src/INET My_2Domain_Ctrl.ini
Environment variables:
PATH=;D:/omnet/OpenFlowOmnet/omnetpp-5.6.2-src-windows/omnetpp-5.6.2/myws/inet/src;D:\omnet\OpenFlowOmnet\omnetpp-5.6.2-src-windows\omnetpp-5.6.2\bin;D:\omnet\OpenFlowOmnet\omnetpp-5.6.2-src-windows\omnetpp-5.6.2\tools\win64\mingw64\bin;D:\omnet\OpenFlowOmnet\omnetpp-5.6.2-src-windows\omnetpp-5.6.2\tools\win64\usr\bin;;D:/omnet/OpenFlowOmnet/omnetpp-5.6.2-src-windows/omnetpp-5.6.2/ide/jre/bin/server;D:/omnet/OpenFlowOmnet/omnetpp-5.6.2-src-windows/omnetpp-5.6.2/ide/jre/bin;D:/omnet/OpenFlowOmnet/omnetpp-5.6.2-src-windows/omnetpp-5.6.2/ide/jre/lib/amd64;.;D:\omnet\OpenFlowOmnet\omnetpp-5.6.2-src-windows\omnetpp-5.6.2\bin;D:\omnet\OpenFlowOmnet\omnetpp-5.6.2-src-windows\omnetpp-5.6.2\tools\win64\mingw64\bin;D:\omnet\OpenFlowOmnet\omnetpp-5.6.2-src-windows\omnetpp-5.6.2\tools\win64\usr\local\bin;D:\omnet\OpenFlowOmnet\omnetpp-5.6.2-src-windows\omnetpp-5.6.2\tools\win64\usr\bin;D:\omnet\OpenFlowOmnet\omnetpp-5.6.2-src-windows\omnetpp-5.6.2\tools\win64\usr\bin;C:\Windows\System32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0;D:\omnet\OpenFlowOmnet\omnetpp-5.6.2-src-windows\omnetpp-5.6.2\tools\win64\usr\bin\site_perl;D:\omnet\OpenFlowOmnet\omnetpp-5.6.2-src-windows\omnetpp-5.6.2\tools\win64\usr\bin\vendor_perl;D:\omnet\OpenFlowOmnet\omnetpp-5.6.2-src-windows\omnetpp-5.6.2\tools\win64\usr\bin\core_perl;D:\omnet\OpenFlowOmnet\omnetpp-5.6.2-src-windows\omnetpp-5.6.2;
OMNETPP_ROOT=D:/omnet/OpenFlowOmnet/omnetpp-5.6.2-src-windows/omnetpp-5.6.2/
OMNETPP_IMAGE_PATH=D:\omnet\OpenFlowOmnet\omnetpp-5.6.2-src-windows\omnetpp-5.6.2\images
I really appreciate any guidance and help because I must do a lot of work and I'm running out of time.
enter image description here
One has to remember that strcmp() returns 0 if the contents of both strings are equal. And in C++ zero means false.
So if you want to do something when connectAddress is equal to "controller1", you should write:
if (strcmp (connectAddress, "controller1") == 0) {
// ...
}
Generally, in order to deal with a runtime exception in OMNeT++ do:
Set debug-on-errors=true in your omnetpp.ini.
Build the project in debug mode.
Start the simulation in debug (i.e. Run | Debug).
The simulation will stop in the line that causes an error and in the stack trace you may see the referenced calls.
Reference: Learn OMNeT++ with TicToc - Runtime errors

How can I get cTopology in omnet++?

I want to get the list of neighbor addresses (nodes that are in transmission range). I found this code on omnet++ manual, but when I compile, I get the error of no member named 'extractByModuleType' in 'cTopology', i did go back to the class cTopology, and the function 'extractByModuleType()' does not exist. I tried other functions but I did not succeed. Please, if someone knows how to access cTopology answer my question.
Best regards;
cTopology topo;
topo.extractByModuleType("Host", nullptr);
for (int i = 0; i < topo.getNumNodes(); i++) {
cTopology::Node *node = topo.getNode(i);
EV << "Node i=" << i << " is " << node->getModule()->getFullPath() << endl;
EV << " It has " << node->getNumOutLinks() << " conns to other nodes\n";
EV << " and " << node->getNumInLinks() << " conns from other nodes\n";
EV << " Connections to other modules are:\n";
for (int j = 0; j < node->getNumOutLinks(); j++) {
cTopology::Node *neighbour = node->getLinkOut(j)->getRemoteNode();
cGate *gate = node->getLinkOut(j)->getLocalGate();
EV << " " << neighbour->getModule()->getFullPath()
<< " through gate " << gate->getFullName() << endl;
}
}
That should be
topo.extractByNedTypeName("Host");
according to the documentation.
Additionally, you indicate that you want to get the list of the nodes in 'transmission range'. So presumably, you have a wireless network where there are no connections between the nodes. cTopology discovers topology based on the connections and a wireless network does not have any, so you will not get meaningful results anyway.
Unless your nodes are not moving and you actually create a connection between neighboring nodes. This SO answer my give you help, how to do that: Connect, repetitively, nodes based at their euclidean distance in omnet++
If you do connect them, then you just have to iterate through all your connections to reach the neighbor nodes and you will not need any cTopology magic.

Serial Communication data problem between Windows and embedded System (STM32) (C/C++)

I currently try to set up communication between a Windows program and a µC.
I'll show you the code to initialize the port:
int serialCommunication::serialInit(void){
//non overlapped communication
hComm = CreateFile( gszPort.c_str(),
GENERIC_READ | GENERIC_WRITE,
0,
0,
OPEN_EXISTING,
0,
0);
if (hComm == INVALID_HANDLE_VALUE){
cout << "Error opening port." << endl;
return 0;
}
else{
cout << "Opened Port successfully." << endl;
}
if (SetCommMask(hComm, EV_RXCHAR) == FALSE){
cout << "Error setting communications mask." << endl;
return 0;
}
else{
SetCommMask(hComm, EV_RXCHAR);
cout << "Communications mask set successfully." << endl;
}
if (GetCommState(hComm, &dcbSerialParams) == FALSE){
cout << "Error getting CommState." << endl;
return 0;
}
else{
GetCommState(hComm, &dcbSerialParams);
cout << "CommState retrieved successfully" << endl;
}
dcbSerialParams.BaudRate = CBR_115200; // Setting BaudRate = 115200
dcbSerialParams.ByteSize = 8; // Setting ByteSize = 8
dcbSerialParams.StopBits = ONESTOPBIT; // Setting StopBits = 1
dcbSerialParams.Parity = NOPARITY; // Setting Parity = None
if (SetCommState(hComm, &dcbSerialParams) == FALSE){
cout << "Error setting CommState" << endl;
return 0;
}
else{
SetCommState(hComm, &dcbSerialParams);
cout << "CommState set successfully" << endl << endl;
cout << "+---CommState Parameters---+" << endl;
cout << "Baudrate = " << dcbSerialParams.BaudRate << endl;
cout << "ByteSize = " << static_cast<int>(dcbSerialParams.ByteSize) << endl; //static Cast, um int auszugeben und kein char
cout << "StopBits = " << static_cast<int>(dcbSerialParams.StopBits) << endl; //static Cast, um int auszugeben und kein char
cout << "Parity = " << static_cast<int>(dcbSerialParams.Parity) << endl; //static Cast, um int auszugeben und kein char
cout << "+--------------------------+" << endl;
}
/*------------------------------------ Setting Timeouts --------------------------------------------------*/
timeouts.ReadIntervalTimeout = 50;
timeouts.ReadTotalTimeoutConstant = 50;
timeouts.ReadTotalTimeoutMultiplier = 10;
timeouts.WriteTotalTimeoutConstant = 50;
timeouts.WriteTotalTimeoutMultiplier = 10;
if (SetCommTimeouts(hComm, &timeouts) == FALSE){
cout << "Error setting timeouts" << endl;
return 0;
}
else{
SetCommTimeouts(hComm, &timeouts);
cout << "Timeouts set successfully." << endl;
cout << "+--------------------------+" << endl;
return 1;
}
My Read function looks like this:
void serialCommunication::serialRead(void){
bool readStatus;
bool purgeStatus = 0;
bool correctData = 0;
cout << "Waiting for Data..." << endl; // Programm waits and blocks Port (like Polling)
readStatus = WaitCommEvent(hComm, &dwEventMask, 0);
if (readStatus == FALSE){
cout << "Error in setting WaitCommEvent." << endl;
}
else{
cout << "Data received." << endl;
do{
readStatus = ReadFile(hComm, &TempChar, sizeof(TempChar), &NoBytesRead, 0);
SerialBuffer += TempChar; // add tempchar to the string
}while (NoBytesRead > 0);
SerialBuffer.pop_back(); // Delete last sign in buffer, otherwise one "0" too much shows up, for example "23900" instead of "2390"
cout << endl << SerialBuffer << endl;
SerialBuffer = ""; // Reset string
}
So at some point, my µC sends the String "Init complete...!\r\n" after initializing some things. This works well.Init complete proof
Now after that, the communcation produces errors. I am getting Data I should not receive. The µC can only send data, if a specific string is sent to it by the PC. While debugging I could detect, that the µC never receives this specific string and therefore never sends data. In the following picture, I show you what gibberish I am receiving constantly though.
Receiving Gibberish
/EDIT: I am constantly receiving the same gibberish
The funny thing is, I even receive that data, when the µC is completely switched off (Serial Cables are still connected). So there has to be some data at the port, which just is not deleted. I tried to restart the PC aswell, but it didn't help either.
I will also show you my while loop on PC:
while (testAbbruch != 1){
pointer = acMessung(anzahlMessungen, average); // measurement with external multimeter
cout << endl;
cout << "Average: " << average << endl << endl;
if (average >= 30){
testAbbruch = 1; // there won't be a next while iteration
befehl = "stopCalibration\r\n";
serialTest.serialWrite(befehl);
serialTest.serialRead();
}
else{
cout << "Aktion: ";
std::getline (cin, befehl);
befehl = "increment"; //for debugging
if (befehl == "increment"){
befehl.append("\r\n"); // adding it, so the µC can detect the string correctly
serialTest.serialWrite(befehl);
serialTest.serialRead(); // µC has to answer
}
else if(befehl == "decrement"){
befehl.append("\r\n"); // adding it, so the µC can detect the string correctly
serialTest.serialWrite(befehl);
serialTest.serialRead(); // µC has to answer
}
befehl = ""; // string leeren für nächsten Aufruf
}
}
I know my program is far from perfect, but if I understood the serial Communication with Windows correctly, the buffer is deleted while reading.
Is there any clue you could give me?
EDIT// I just wrote a program that expects one of two inputs: One input is called "increment" the other one is called "decrement". Those inputs are sent to the µC via the serial communication port. Every time I try to send "increment" and instantly after that I am reading from the port, I receive the weird data from this picture. Now, every time I try to send "decrement" and instantly after that I am reading from the port, I receive the weird data from that picture.
//
So my guess is that the data somehow is changed and then looped back to the PC? But why and how?!

Why the obtained rxPower () is always Zero, every where?

void Ieee80211AgentSTA::dumpAPList(Ieee80211Prim_ScanConfirm *resp)
{
EV << "Received AP list:\n";
for (int i = 0; i < (int)resp->getBssListArraySize(); i++) {
Ieee80211Prim_BSSDescription& bssDesc = resp->getBssList(i);
EV << " " << i << ". "
<< " address=" << bssDesc.getBSSID()
<< " channel=" << bssDesc.getChannelNumber()
<< " SSID=" << bssDesc.getSSID()
<< " beaconIntvl=" << bssDesc.getBeaconInterval()
<< " rxPower=" << bssDesc.getRxPower()
<< endl;
// later: supportedRates
}
}
I executed the existing mobileIPv6 example, noticed that everywhere the returned value of rxpower is equal to zero.
I changed the MN's position near and far from the access point but nothing change about the rxpower
Another thing I want to know is: is the rxpower equal to RSSI (received signal strength indicator)? or can I get RSSI from rxPower?
Events of the simulation log:
** Event #256 t=0.165239371312 mIPv6Network.MN[0].wlan[0].agent (Ieee80211AgentSTA, id=127), on selfmsg startUp' (cMessage, id=28)
Starting up Sending ScanRequest primitive to mgmt
** Event #1372 t=0.815239371312 mIPv6Network.MN[0].wlan[0].agent (Ieee80211AgentSTA, id=127), on
inet::ieee80211::Ieee80211Prim_ScanConfirm' (cMessage, id=1680)
Processing confirmation from mgmt:
inet::ieee80211::Ieee80211Prim_ScanConfirm DEBUG: current position =
(180.408, 100, 0) Received AP list:
0. address=10-AA-00-00-00-01 channel=1 SSID=HOME beaconIntvl=0.1 rxPower=0 Chosen AP address=10-AA-00-00-00-01 from list, starting authentication Sending AuthenticateRequest primitive to mgmt
** Event #1460 t=0.81767038585 mIPv6Network.MN[0].wlan[0].agent (Ieee80211AgentSTA, id=127), on
inet::ieee80211::Ieee80211Prim_AuthenticateConfirm' (cMessage,
id=1823) Processing confirmation from mgmt:
inet::ieee80211::Ieee80211Prim_AuthenticateConfirm Authentication
successful, let's try to associate Sending AssociateRequest primitive
to mgmt
** Event #1513 t=0.81913139312 mIPv6Network.MN[0].wlan[0].agent (Ieee80211AgentSTA, id=127), on
inet::ieee80211::Ieee80211Prim_AssociateConfirm' (cMessage, id=1908)
Processing confirmation from mgmt:
inet::ieee80211::Ieee80211Prim_AssociateConfirm Association successful

how do i correctly fork() and exit a child process when i'm using ZeroMQ

I have a simple application that listens on a ZeroMQ socket. When the client connects and requests a worker node, I fork() my process, the forked child process creates a new context and a new ZeroMQ socket. The client and the worker node perform a REQ-REP formal behaviour on that socket.
My problem is how do I can gracefully handle a shutdown of my worker node.
The client sends an EXIT message to my worker node, who needs to close its socket and its context (?)
From what I can see, the child process exits however, new clients cannot now talk to my original parent process.
Psuedo Code
while (looping) {
zmq::message_t request;
try {
socket.recv(&request); // Wait
string reqStr = string(static_cast<char *>(request.data()), request.size());
if (reqStr.compare("exit") == 0) {
LOG(INFO) << "exiting.." << endl;
looping = false;
}
LOG(INFO) << "******************************************************************" << endl;
LOG(INFO) << "Received request for an endpoint " << reqStr << endl;
int port = doFork(reqStr);
if (port > 0) {
LOG(INFO) << "Returning endPoint: " << reqStr << " on port: " << port << endl;
string result = NumberToString(port);
zmq::message_t reply(result.length());
memcpy((void *) reply.data(), result.c_str(), result.length());
socket.send(reply);
}
else {
// Child Process exiting OR error in Fork"
looping = false;
child = true;
}
}
catch (zmq::error_t &e) {
LOG(INFO) << "W: Caught Exception OR Interrupt: " << e.what() << " : and pid is " << getpid() << endl;
}
}
if (!child) {
socket.close();
context.close();
LOG(INFO) << "Closed socket and context for pid " << getpid() << endl;
}}
int Forker::doFork(string reqStr) {
pid_t pid;
int port = ++startingPort;
switch (pid = fork()) {
case -1:
LOG(INFO) << "Error in fork";
return -1;
case 0:
LOG(INFO) << "Created child process with pid: " << getpid() << endl;
{
ServicePtr servicePtr(new Service(NumberToString(port)));
LOG(INFO) << "Spawning on port: " << port << endl;
servicePtr->spawn();
}
LOG(INFO) << "Child Process exiting on port: " << port << endl;
return 0;
default:
LOG(INFO) << "Parent process. My process id is " << getpid() << endl;
}
return port;
}
Your psuedocode isn't enough to get much of anywhere - notably you don't define your sockets there, so I don't even know which side is the REQ and which side is the REP (or, indeed, that you're actually using those socket types), or which side binds and which side connects.
But, my first guess is that you've got an uneven send/receive pairing, and something like the following is happening:
Client binds on REQ socket, worker connects on REP socket
Client sends a request (client expects recv next)
Worker sends response (client expects send next)
Client sends a follow up message (client expects recv next)
Worker shuts down
New worker spins up
Client sends a request (ERROR - REQ sockets are strictly send/recv ordering)
IF that's what's causing your issue, you can either make sure to respond back to reset the client socket, or you can use a DEALER socket instead of REQ.

Resources