I have to extend the UdpBasicApp module from INET4 in OMNeT++ 5.6.1 (Ubuntu 18.04.4) and execute two overridden methods (initialize and handleMessageWhenUp).
It seems an easy task, and looked like it was all fine when I built the project (momentarily stored inside the "examples" folder in inet4) with no errors but, after starting the simulation the code isn't successfully overridden. The original code (the one from UdpBasicApp) is executed instead.
In fact, after inspecting the code in the editor, the methods' name isn't bold (as should be) and the keywords aren't colored as they normally should be.
My C++ skill is not high (nor my OMNeT one) hence I'm not sure what is really happening.
The extended simple module is called "PriorityApp" (I added just an integer field more).
This is the .ned code (not sure if you need it)
package inet.examples.MyProject.src;
import inet.applications.udpapp.UdpBasicApp;
// The module extends UdpBasicApp adding a priority parameter
simple PriorityApp extends UdpBasicApp
{
parameters:
int priority = default(0); // priority 0 = higher priority
}
This is the .h code
#ifndef __INET4_PRIORITYAPP_H_
#define __INET4_PRIORITYAPP_H_
#include "inet/applications/udpapp/UdpBasicApp.h"
namespace inet {
class PriorityApp : public UdpBasicApp
{
protected:
int priority;
virtual void initialize(int stage) override;
virtual void handleMessageWhenUp(cMessage *msg) override;
};
} // namespace inet
#endif // ifndef __INET_PRIORITYAPP_H
This is the .cc code
#include "PriorityApp.h"
namespace inet {
Define_Module(PriorityApp);
void PriorityApp::initialize(int stage)
{
msg = new cMessage("priority");
EV << "Example Message" << endl;
}
void PriorityApp::handleMessageWhenUp(cMessage *msg)
{
}
} //namespace inet
This is the .ini file
[General]
[Config SwitchedNet1G]
description = "1Gbps Switched Network"
network = SwitchedNet
**.dataRate = 1Gbps # 1 Gbps channel datarate
# Priority stuff
**.host[0].app[0].priority = 1
# Dst Params
**.sink.app[*].typename = "UdpSink" # Destination host (it receives messages)
**.sink.app[*].localPort = 2500
# Src Params
**.host[0].app[0].packetName = "Host0-Data"
**.host[*].app[0].typename = "PriorityApp" # Source host (they send messages)
**.host[*].app[0].destPort = 2500
**.host[*].app[0].destAddresses = "sink"
**.host[0].app[0].sendInterval = 3s
**.host[*].app[0].startTime = uniform (0s, 3s)
# EthInterface Setup
**.eth[*].qEncap.typename = "Ieee8021qEncap" # 8021Q Encapsulation
**.etherSwitch.numEthInterfaces = 2 # Switch ethInterfaces total number (2)
**.numEthInterfaces = 1
# Global Params
**.messageLength = 100B
**.numHosts = 1
**.numApps = 1 # every host has 1 app (UdpBasicApp or UdpSink)
There are two independent faults here:
1.) You should NOT add C++ code into INET's examples folder. That folder is NOT designated as a source folder, so the build system will not pick up, build and link to the executable, meaning that your code is not present in the model. That's one reason why you are not getting your new behavior.
2.) Even if you place your source code in the src folder along with the UdpBasicApp and the build system would properly link it in, you still have to properly set up the NED part. Specifically you have to specify the #class property to tell NED which C++ class you intend to use to specify behavior: #class(PriorityApp) Otherwise your PriorityApp module would inherit the value of #class property from UdpBasicApp and would use the CdpBasicApp C++ class.
import inet.applications.udpapp.UdpBasicApp;
// The module extends UdpBasicApp adding a priority parameter
simple PriorityApp extends UdpBasicApp
{
#class(PriorityApp)
parameters:
int priority = default(0); // priority 0 = higher priority
}
Related
I am creating a telemetry server using websocketpp, and have followed the example here. My application will be running as a linux daemon which starts on boot, and therefore I won't be able to write logs to standard out. I would therefore like to add a customer logger using spdlog, and understand that it can be done based on what's on this page. Looks like I need to use the websocketpp::log::stub interface to create my own customer logger. The issue is, the documentation on this is quite limited regarding logging, and I am not sure where to begin and how to incorporate it in the context of the telemetry server example linked above. I am not sure how to specify the logger when I define my server: typedef websocketpp::server<websocketpp::config::asio> server;.
How do I go about extending the stub class, and how do I initialize my server with this customer logger?
The only sample code I could find is in this thread here, but based on the linked comment this code is no longer relevant after V 0.3.x+.
For anyone wanting sample code using spdlog as a customer logger, here it is:
Create a new file customerLogger.hpp with the contents:
#pragma once
#include <websocketpp/logger/basic.hpp>
#include <websocketpp/common/cpp11.hpp>
#include <websocketpp/logger/levels.hpp>
#include "spdlog/logger.h"
#include "spdlog/sinks/rotating_file_sink.h"
namespace websocketpp {
namespace log {
/// Basic logger that outputs to syslog
template <typename concurrency, typename names>
class myLogger : public basic<concurrency, names> {
public:
typedef basic<concurrency, names> base;
/// Construct the logger
/**
* #param hint A channel type specific hint for how to construct the logger
*/
myLogger<concurrency,names>(channel_type_hint::value hint =
channel_type_hint::access)
: basic<concurrency,names>(hint), m_channel_type_hint(hint) {
auto max_size = 1048576 * 5;
auto max_files = 3;
auto rotating_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt> ("/var/logs/my_logger.log", max_size, max_files);
m_logger = std::make_shared<spdlog::logger>("my_logger", rotating_sink);
m_logger->flush_on(spdlog::level::info);
m_logger->set_level(spdlog::level::level_enum::info);
}
/// Construct the logger
/**
* #param channels A set of channels to statically enable
* #param hint A channel type specific hint for how to construct the logger
*/
myLogger<concurrency,names>(level channels, channel_type_hint::value hint =
channel_type_hint::access)
: basic<concurrency,names>(channels, hint), m_channel_type_hint(hint) {
auto max_size = 1048576 * 5;
auto max_files = 3;
auto rotating_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt> ("/var/logs/my_logger.log", max_size, max_files);
m_logger = std::make_shared<spdlog::logger>("my_logger", rotating_sink);
m_logger->flush_on(spdlog::level::info);
m_logger->set_level(spdlog::level::level_enum::info);
}
/// Write a string message to the given channel
/**
* #param channel The channel to write to
* #param msg The message to write
*/
void write(level channel, std::string const & msg) {
write(channel, msg.c_str());
}
/// Write a cstring message to the given channel
/**
* #param channel The channel to write to
* #param msg The message to write
*/
void write(level channel, char const * msg) {
scoped_lock_type lock(base::m_lock);
if (!this->dynamic_test(channel)) { return; }
if (m_channel_type_hint == channel_type_hint::access) {
m_logger->info(msg);
} else {
if (channel == elevel::devel) {
m_logger->debug(msg);
} else if (channel == elevel::library) {
m_logger->debug(msg);
} else if (channel == elevel::info) {
m_logger->info(msg);
} else if (channel == elevel::warn) {
m_logger->warn(msg);
} else if (channel == elevel::rerror) {
m_logger->error(msg);
} else if (channel == elevel::fatal) {
m_logger->critical(msg);
}
}
}
private:
std::shared_ptr<spdlog::logger> m_logger;
typedef typename base::scoped_lock_type scoped_lock_type;
channel_type_hint::value m_channel_type_hint;
};
} // log
} // websocketpp
Next, create another file, customConfig.hpp which has the following content:
#pragma once
#include "./customLogger.hpp"
#include <websocketpp/logger/syslog.hpp>
#include <websocketpp/extensions/permessage_deflate/enabled.hpp>
// Custom server config based on bundled asio config
struct my_config : public websocketpp::config::asio {
// Replace default stream logger with the custom logger
typedef websocketpp::log::myLogger<concurrency_type, websocketpp::log::elevel> elog_type;
typedef websocketpp::log::myLogger<concurrency_type, websocketpp::log::alevel> alog_type;
};
typedef websocketpp::server<my_config> my_server;
Finally, when you want to create the server, you simple do my_server endpoint;
Building a custom logger has two steps. First, write a policy class with the appropriate interface then create a custom config that uses that policy.
To write the policy class websocketpp::log::stub is a minimal implementation that doesn't actually do anything (it is primarily used for stubbing out logging in the unit tests) but it demonstrates and documents the interface that a logging class needs to implement. The logging class does not need to be a subclass of websocketpp::log::stub. You can look at other examples in the websocketpp/logger/* folder. The syslog logger in particular might be interesting as an example of a logging policy that outputs to something other than standard out.
To set up the custom config you will create a config class. It can be standalone or a subclass of one of the standard ones, like websocketpp::config::asio, that just overrides a small number of things. Your config might only override the loggers, for example. Once created, you will pass your config class into the endpoint template parameter instead of websocketpp::config::asio.
More details about what you can override at compile time via this config system can be found at https://docs.websocketpp.org/reference_8config.html. There is an example on this page that shows a custom config that replaces the default logger (among other changes).
I am using this module hierarchy :
Node: {udpApp[0]<->udp<->networkLayer->wlan[0]} and wlan[0]: {CNPCBeacon<->mac<->radio}
With some ini parameter for udpApp as:
I have given some initial parameter in the ini file for udpApp as :
**.host*.numUdpApps = 2
**.host*.udpApp[0].typename = "UDPBasicApp"
**.host*.udpApp[0].destAddresses = "gw1"
**.host*.udpApp[0].startTime = 1.32s
**.host*.udpApp[0].stopTime = 1.48s
But at run time I want to change the startTime and stopTime for udpAPP[0] through CNPCBeacon module.
Hence I changed CNPCBeacon.cc as:-
cModule* parentmod = getParentModule();
cModule* grantParentmod = parentmod->getParentModule();
cModule* udpmod = grantParentmod->getSubmodule("udpApp",0);
double varHoldingStartTime = udpmod->par("startTime").doubleValue();
double varGoldingStopTime = udpmod->par("stopTime").doubleValue();
varHoldingStartTime = SIMTIME_DBL(4.2);
varGoldingStopTime = SIMTIME_DBL(4.5);
udpmod->par("startTime").setDoubleValue(varHoldingStartTime);
udpmod->par("stopTime").setDoubleValue(varGoldingStopTime);
EV<<"New start and stop time is "<<udpmod->par("startTime").str()<<"\t"<<udpmod->par("stopTime").str()<<endl;`
Which successfully change the parameters. However it doesn't initiate the udpApp[0] module again. So I try to use dynamic casting of this module as:
UDPBasicApp* udpBasicMod = dynamic_cast<UDPBasicApp*>(udpmod);
sendTimer = new cMessage("sendTimer");
scheduleAt(iniSchduleTime, sendTimer);
and it resulted in following error:-
error in module (CNPCBeacon) BSoneNode.gw1.wlan[0].CNPCBeacon (id=23) at event #1496, t=4: scheduleAt() of module (UDPBasicApp)BSoneNode.gw1.udpApp[0] called in the context of module (CNPCBeacon)BSoneNode.gw1.wlan[0].CNPCBeacon: method called from the latter module lacks Enter_Method() or Enter_Method_Silent()?.
Is there also any other way to instantiate a module through other sub module.
Thanks for this help.
The solution for reinitializing a module (target module) through another module (requesting module) is creating handleParamterChange() function in target module. handleParameterChange() is used to reread the changed parameter at tun time. However it won't start scheduleAt() event to reinitialize the event for the target module. So I just added the scheduleAt() event in this function as :
void UDPBasicApp:: handleParameterChange(const char* parname)
{
if(parname)
{
if((strcmp(parname, "startTime")==0) &&
(startTime != par("startTime").doubleValue())
startTime = par("startTime").doubleValue();
if(strcmp(parname,"stopTime")==0)&&
(stopTime != par("stopTime").doubleValue())
{
stopTime = par("stopTime").doubleValue();
selfMsg->setKind(START);
scheduleAt((simtime_t)(startTime), selfMsg);
}
}
Note here that selfMsg is defined in the initialize function of UdpBasciApp.cc in INET framework.
I am a bit lost in the hierarchy and relation between your modules and sub-modules, however I think if your want to create (or re-create) a module dynamically you could use the built-in approach suggested by OMNeT++: https://omnetpp.org/doc/omnetpp/manual/usman.html#sec186
Maybe you could use the one-liner directly once you have (re-)defined the parameter values:
cModuleType *moduleType = cModuleType::get("foo.nodes.WirelessNode");
cModule *mod = moduleType->createScheduleInit("node", this);
On the other hand you error message complains about: Enter_Method() and/or Enter_Method_Silent()
These macros should be used in case that you try to call a function of a module (example X::get()) from within another module:
Y::doSmthWithXsGet()
{
x->get();
}
For this to work Enter_Method() (or Enter_Method_Silent()) has to be written in the beginning of X::get()
X::get()
{
Enter_Method();
/* rest of the code */
}
You can read Direct Method Calls section of the OMNeT++ userman to see what that means.
The weird thing is that you are getting this error for the scheduleAt() method, which is a method which belongs to the fundamental OMNeT++ class cSimpleModule. That means, in order to use this method in your class you will have to inherit from cSimpleModule in your class definition.
Maybe simply doing something like:
class MyCurrentClass: public cSimpleModule
{
/* further class definition */
};
... could solve your prob.
I am trying to test a document reader using Google Test.
My code is organized as follow: there is a Document class which opens the file. A document contains one or more Element, which is a struct with a pointer (field) to a wstring and value.
Obviously I would like to open the file just once and then cycle though the various Elements.
class DocumentTest : public ::testing::Test {
protected:
virtual void SetUp() {
string path = "path/to/file";
Document doc;
doc.Open(path);
}
Element* el;
el = doc.Read();
};
TEST_F(DocumentTest, ReadTest) {
while (file has still elements) {
wchar_t* expectedField = L"expectingThis";
wchar_t* readString = el->field;
EXPECT_EQ(expectedField,readString);
}
but this is clearly not working. Where should I declare my init code?
https://github.com/google/googletest/blob/main/docs/advanced.md
In general googletest allows three different modes of resource management:
SetUp and TearDown() (run before and after each test function)
SetUpTestCase() and TearDownTestCase() (run before and after each class, or "Case")
The Environment class which is run before/after the first and last test, respectively.
I have the following bit of code in my Windows 8 Store app:
public static void ConvertUpdateStreamToCollection<T>(this IObservable<UpdateInfo<T>> input, ObservableCollection<T> list)
{
input
.ObserveOnDispatcher()
.Subscribe(upInfo => UpdateList(upInfo, list));
}
That ObserveOnDispatcher is there b.c. this will often be called on a background thread, and when it updates the observable list I will need it to be on the UI dispatcher. To first order this looks like it works fine when I run the app.
But I wish to test this with unit tests. I'm using the built in MSTest. The ObserveOnDispatcher throws, however, complaining there is no valid Window from which to get a CoreDispatcher.
I've seen work arounds for WPF in other places in Stack overflow. But that looks like just something to make the dispatcher run. This error seems more fundamental. Is there a known workaround?
(edit: better formatting now that I have a keyboard instead of a phone)
There's another way to achieve the same functionality:
.ObserveOnDispatcher()
Is fairly equivalent to:
.ObserveOn(new DispatcherScheduler(Dispatcher.CurrentDispatcher))
Now, instead of that DispatcherScheduler, have a class like:
public static class Schedulers
{
public static IScheduler Dispatcher {get; internal set;}
}
And change usage to:
.ObserveOn(Schedulers.Dispatcher)
Example:
void Main()
{
// For normal usage, we'll set this to the proper DispatcherScheduler
Schedulers.Dispatcher = new DispatcherScheduler(Dispatcher.CurrentDispatcher);
// Do stuff
new Thingy().DoStuff();
// for testing usage, we'll set this to be the immediate scheduler
Schedulers.Dispatcher = Scheduler.Immediate;
// Do stuff
new Thingy().DoStuff();
}
public class Thingy
{
public void DoStuff()
{
var query = Observable.Range(0, 10).ObserveOn(Schedulers.Dispatcher);
query.Subscribe(Console.WriteLine);
}
}
I am relatively new to using MSpec and as I write more and more tests it becomes obvious to reduce duplication you often have to use a base class for your setup as per Rob Conery's article
I am happy with using the AssertWasCalled method to verify my expectations, but where do you set up a stub's return value, I find it useful to set the context in the base class injecting my dependencies but that (I think) means that I need to set my stubs up in the Because delegate which just feels wrong.
Is there a better approach I am missing?
The initialization/setup of stubs belongs to the arrange phase. The arrange phase is used to get the system into a known state before you exercise it.
In MSpec, the arrange phase is performed in Establish fields. For example:
public class When_the_temperature_threshold_is_reached
{
static ITemperatureSensor Sensor;
static Threshold Threshold;
Establish context = () =>
{
Sensor = MockRepository.GenerateStub<ITemperatureSensor>();
Sensor
.Stub(x => x.GetTemperature())
.Return(42);
Threshold = new Threshold(Sensor);
};
Because of = () => Reached = Threshold.IsReached(40);
It should_report_that_the_threshold_was_reached =
() => Reached.ShouldBeTrue();
}
When you write more tests using that kind of ITemperatureSensor, you should extract a base class that does complicated or repeated setup.
public abstract class TemperatureSpecs
{
protected static ITemperatureSensor CreateSensorAlwaysReporting(int temperature)
{
var sensor = MockRepository.GenerateStub<ITemperatureSensor>();
sensor
.Stub(x => x.GetTemperature())
.Return(temperature);
return sensor;
}
}
public class When_the_temperature_threshold_is_reached : TemperatureSpecs
{
// Everything else cut for brevity.
Establish context = () =>
{
Sensor = CreateSensorAlwaysReporting(42);
Threshold = new Threshold(Sensor);
};
}
This gives you the advantage that you can influence the stub's return value from the context itself: You do this by keeping as much information as possible local to the context and provide a good name for the "setup" method in the base class.
There is no need to specifiy or expect anything stub-related in Because. When Because is run, your system should be in a state where it can be exercised without further preparation.