Error in submodule connection in OMNeT++ - omnet++

I have two submodules in compound module. I try to connect them using gate, but it creates this error:
Error in module(cmodule) wnetwork.host0 during network setup.
Gate 'wnetwork.host[0].gate$i[0]' is not connected to a submodule(or
internally to another gate of the same module)
My compound module code is
wirelessnode.ned:
package core;
import org.mixim.modules.power.battery.BatteryStats;
import org.mixim.modules.power.battery.SimpleBattery;
module wirelessnode
{
parameters:
volatile double Energy #unit(mW) = default(10.0mW);
double Tx_energy #unit(mW) = default(0.8mW);
double Tx_interval #unit(s) = default(0.5s);
#display("bgb=210,450,white;i=device/palm;i2=status/battery;b=40,40,rect");
submodules:
batteryStats: BatteryStats {
#display("p=110,221;i=block/table,#FF8040");
}
battery: SimpleBattery {
#display("p=101,90;i=block/plug,#FF8000");
}
}
wirelessnodehost.ned:
package core;
module wirelessnodehost extends wirelessnode
{
gates:
inout gate[];
}
wnetwork.ned:
package core;
import core.wirelessnodehost;
network wnetwork
{
parameters:
int numDevices=default(3);
submodules:
host[numDevices]: wirelessnodehost;
connections:
for i = 0..numDevices-2 {
host[i].gate++ <--> host[i+1].gate++;
}
}
How to solve this error?

If you check the error message, it says: wnetwork.host[0].gate$i[0] is not connected to a submodule (or internally to another gate of the same module). (see emphasis), so the problem is NOT that connecting the two module is wrong somehow, but instead the internals of the wirelessnodehost are incorrect.
Specifically, you are defining the wirelessnodehost as a compound module (a module built up from other modules by connecting them together, while you do not specify any submodules in it). I assume that you have some C++ code for the wirelessnodehost. In this case you must define it as simple wirelessnodehost. Only simple modules have a corresponding code and they are allowed to process the incoming messages using their code. On the other hand compound modules should always pass the incoming message to a submodule for processing, that's why the runtime complaining. You have not connected the gate internally so the runtime does not know where to pass the incoming message.
As a side note, the fact that you extend wirelessnode module (which itself should have a corresponding C++ code and should be defined as 'simple') is rather suspicious. If the code that handles the behavior of the node is implemented in the wirelessnode class, then it does not know anything about the gate that is defined in the wirelessnodehost. I would suggest to take a deeper look at the part of the OMNeT++ manual which describes the differences between simple and compound modules.

Related

Unable to successfully run packaged version of functional options pattern (FOP) that uses Go generics and embedded interfaces

In an effort to learn idiomatic Go, I am trying to write a reusable package (saybase for purposes of this question). This package provides a Base interface, with minimally required functions and a BaseStruct to implement those functions. Base is to be embedded in other application-domain specific packages, say composite packages.
type Base interface {
defaultCfg()
setID(string)
setEnqSize(int)
}
type BaseStruct struct {
id string
enqSize int
}
func New[T Base](t T, opts ...func(T)) T {
// Code is provided in playground below.
}
type Comp interface {
Base
setConn(string)
}
type CompStruct struct {
Base
conn string
}
// Other code in playground.
Critical requirements for me:
Create new instances of composite structs using some constructional pattern like builder or functional options pattern. I was able to get FOP working with the New function.
Provide a 'default' set of values using defaultCfg for the base and each composite, which can be overridden during the process of construction of the composite structures.
Disallow modification of the structs' fields directly. Modifications occur either through private setters for construction, and public messages for state changes.
I'm basically writing an actor model framework that uses an actor-tree based communication pattern. The framework mostly works (message passing, etc.) barring this ability to reliably construct the actors prior to their launch.
Being a novice at Go, I have hit a brick wall trying to understand and resolve run-time panic when packaging my functions.
I wrote up some minimal code to isolate the issue. The playgrounds below do not have any actor model code, just renamed units to demonstrate my issue. The working code for instantiation is in this playground. The output of working code:
defBase: {id:"DefaultID", enqSize:1}
idBase: {id:"Non-Def-ID", enqSize:1}
myBase: {id:"Non-Def-ID", enqSize:4}
defComp: {Base:{id:"DefaultID", enqSize:1}, conn:"DefaultConn"}
idComp: {Base:{id:"Non-Def-ID", enqSize:1}, conn:"DefaultConn"}
myComp: {Base:{id:"Non-Def-ID", enqSize:4}, conn:"Non-Def-Conn"}
Program exited.
However, when I re-packaged the code as in this non-working playground, the code runs to a panic when constructing even the default composite structure. Output (the first two lines are just a check for me.):
Type of BaseStruct is: base.BaseStruct
Type of CompStruct is: comp.CompStruct
defBase: {id:"DefaultID", enqSize:1}
idBase: {id:"Non-Def-ID", enqSize:1}
myBase: {id:"Non-Def-ID", enqSize:4}
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x18 pc=0x482f44]
goroutine 1 [running]:
play.ground/comp.(*CompStruct).play.ground/base.defaultCfg(0x1?)
<autogenerated>:1 +0x24
play.ground/base.withDefault[...].func1()
/tmp/sandbox109723629/base/base.go:16 +0x2f
play.ground/base.New[...]({0x4bafe0?, 0xc00006e060}, {0x0, 0x0, 0x1})
/tmp/sandbox109723629/base/base.go:6 +0x47
main.main()
/tmp/sandbox109723629/prog.go:34 +0x379
Program exited.
I have a workaround, as taken from Dave Cheney, where the New function gets repeated in the comp package as well. Definition is something like:
func NewComp(options ...func(Comp)) Comp {
var e Comp = &CompStruct{
Base: base.NewBase(),
conn: "DefaultConn",
}
for _, option := range options {
option(e.(Comp))
}
return e.(Comp)
}
However, I would like to avoid creating variants of New for each composite package that is dependent on Base (or another composite). Referring to the complete code in either playground, I would also like to avoid specifying the instance of a generic for each WithXxx option; and instead have it use the instance specified for the New function. Is that possible?
Any pointers for a fix and any suggestions for writing code or this post better are gladly welcome.
Thank you.
The program panics because the CompStruct.Base field is nil. Initialize the field by changing all uses of new(comp.CompStruct) with &comp.CompStruct{Base: &base.BaseStruct{}}.

Cyclic imports and lack of generics causing headache

Say I have these two files in golang:
// main/a/a.go
import "main/b"
type Model struct {
ID int `json:"id"`
Me int `json:"me"`
You int `json:"you"`
}
func zoom(v b.Injection){
}
func Start(){
// ...
}
and then the second file looks like:
// main/b/b.go
import "main/a"
type Injection struct {
ModelA a.Model
}
func GetInjection() Injection {
return Injection{
ModelA: a.Start(),
}
}
so as you can see, these are circular imports, each file imports the other.
So I need to use a 3rd file, and have these two files import the 3rd file.
But I am really struggling how to get this functionality and avoid cyclic imports.
My first step, is to move the Injection type into a 3rd file:
// main/c/c.go
type Injection struct {
ModelA interface{} // formerly a.Model
}
so now this is what it looks like:
a imports c
b imports a,c
so no more cycles, however the problem is that I don't know how to create an interface for a.Model in c.go? An empty interface{} like I used above doesn't work, for the normal reasons.
How do I solve this cyclic import problem with these 2 original files?
If you want them to put into separate packages, you can't have Model and zoom() in the same package, as zoom() refers to Injection and Injection refers to Model.
So a possible solution is to put Model into package a, zoom() into package b, and Injection into package c. c.Injection can refer to a.Model, b.zoom() can refer to c.Injection. There's no circle in this:
b.zoom() --------> c.Injection ---------> a.Model
I assume there are other references in your real code which are not in the question which may prevent this from working, but you can move "stuff" around between packages, or you can break it down into more.
Also, if things are coupled this "tight", you should really consider putting them into the same package, and then there is no problem to solve.
Another way to solve circular import issue is to introduce interfaces. E.g. if your zoom() function would not refer to Injection, the package containing Model and zoom() would not need to refer to Injection's package.
Inspect what zoom() needs to do with Injection. If that is method calls, that's already good. If not, add methods to Injection. Then you may define an interface in zoom()'s package containing the methods zoom() needs to call, and change its parameter type to this interface. Implementing interfaces in Go is implicit, there is no declaration of intent. So you can remove the reference in the parameter type, still you will be able to pass Injection values to zoom().
Also related, check Dave Cheney's thoughts about organizing code:
I believe code should be organised into packages names for what the package provides, not what it contains. This can sometimes be subtle, but usually not.
For example, http, provides http clients and servers.
As a counter example, package utils is a poor name, yes it provides utilities, but you have no idea what from the name, in truth this package is named for what it contains.
If your project is a library, it should contain one package (excluding examples and possibly utility commands), if it contains more packages, that is a sign that the library is trying to do too many things.
Prefer to avoid multiple packages by default, only split code by package if there is a clear separation of concerns. In my experience many frustrations with complex and possibly circular package structures are the result of too many packages in a project.

check_and_cast() error in Omnet++

I'm simulating network in Omnet++, with INET framework. I want to get the position (coordination x & y) of node. So I do this code:
cModule *host = getContainingNode(this);
IMobility *mobility = check_and_cast<IMobility *>(host->getSubmodule("mobility"));
... = mobility -> getCurrentPosition();
But, when I ran the simulation, I got this error
check_and_cast(): cannot cast nullptr to type 'inet::IMobility *'
Can you explain to me this error?
As I see, if the simulator notify that, so host->getSubmodule("mobility") is nullptr?
By the way, I have define mobilityType in the NED file and include IMobility.h
The NED code you shared shows that you have a simple module that implements the IMobility interface, while the C++ code looks like something that is inside a simple module which is INSIDE a compound module that represent the network host and this compound module also contains a separate simple module called "mobility" that implements the IMobility interface. (this is how code is implemented in INET).
You should either:
arrange your code so you have a compound module as a networkNode with several simple modules inside it (one of them is the mobility module).
if you insist having a simple module which already implements the IMobility interface (in C++) then you already have access to the position on that object using the getCurrentPosition method.
I assume (and recommend) that you co on the first route, so you should reaarange your NED file.

Getting the location of two different modules

I have 2 types of submodules in my network.
AdhocHost which is standard definition in INET framework.
module of type IMobility with its mobility type
of type RandomWPMobility, both are standard INET modules.
I can get the location of modules of type AdhocHost by this code:
module = simulation.getModuleByPath("Mynet.host[1]");
c = MobilityAccess().get(module)->getCurrentPosition();
host[*] being of type AdhocHost.
But when I replace host[1] with blockage[1] (blockage is of type IMobility), before running simulation this error appears:
Error in module (MyMobileController) Mynet.mymobilecontroller during
network initialization: Model error: module (IMobility)mobility not
found.
The module mymobilecontroller is the module that contains this fraction of code. This module does not need to move. Its duty is just to record the location of mobile modules in the network.
What is the problem?
The 'MobilityAccess' code expects that you pass a NetworkNode to it that contains a submodule named mobility with the type IMobility. In the first case it is true (with a StandardHost) however in the second case you pass directly an module that has a type of IMobility.
Long story short, a module with a type of IMobility is meant to exist INSIDE of a network node and not at the network level.
Solution: I'm not sure what is the blockage module supposed to do, but it should NOT be a type of IMobility, instead it should be a module that contains a submodule with a type IMobility.

Public, Private - Upper Case, Lower Case:

New to GoLang, coming from Delphi, C++ :
First time I tried to create my own package in Go, I followed all the instructions about how to lay out the workspace, etc, but I kept on getting a compiler error:
./myPackage.go:52: undefined: myFunc
After poking around a bit I discovered that the public access modifier in Go is achieved simply by declaring a function in upper case. Great.
But when I started experimenting with the container classes - List for starters, I discovered I had to declare a List reference return value like this:
func GetFactors(value *int64) *list.List {...
*list is in lower case.
Same when I declared a local reference to a list - I had to use:
l := list.New()
Again, lower case for list.
So, I'm confused. What is the rule? The list calls and references are obviously public, or I wouldn't be able to call/use them - so why are they in lower case?
In this case, list is the name of the package, which you are importing via import "container/list", and its public members are upper case, like List.
The rule is that public functions, types, etc., should be upper case.
You can alias imported packages however you want, but by default it is just the name of the last part of the package path--in this case, list.
Update: It's not the last part of the package path. It's the actual package name (which is often the same thing).
Note: starting Go 1.5 (Q2/Q3 2015), you will get "protected" import as well (named "internal")!
See Go 1.4 doc:
Go's package system makes it easy to structure programs into components with clean boundaries, but there are only two forms of access: local (unexported) and global (exported).
Sometimes one wishes to have components that are not exported, for instance to avoid acquiring clients of interfaces to code that is part of a public repository but not intended for use outside the program to which it belongs.
The Go language does not have the power to enforce this distinction, but as of Go 1.4 the go command introduces a mechanism to define "internal" packages that may not be imported by packages outside the source subtree in which they reside.
To create such a package, place it in a directory named internal or in a subdirectory of a directory named internal.
When the go command sees an import of a package with internal in its path, it verifies that the package doing the import is within the tree rooted at the parent of the internal directory.
For example, a package .../a/b/c/internal/d/e/f can be imported only by code in the directory tree rooted at .../a/b/c.
It cannot be imported by code in .../a/b/g or in any other repository.
For Go 1.4, the internal package mechanism is enforced for the main Go repository;
from 1.5 and onward it will be enforced for any repository.
Note: the Go Spec for package name don't mention that a package name is always in lowercase.
It only state that its name is represented by an identifier, which is composed of a collection of "letter".
This thread does clarify:
Package names can be anything, you can start them with an uppercase letter if you want to.
But the convention is all lowercase, which I guess saves you the hassle of typing an uppercase letter.
The uppercase/lowercase exportability isn't really relevant to packages since you can't have a private package.
Once you know that, it is easier to recognize:
list.New() for a constructor (always at the package level, to build an initialized instance of a type), like os.NewFile(),
list.List for a struct type of the package list (the other struct type of that same package being list.Element).

Resources