OMNeT++ 基础语法:模块参数、门和连接的访问

消息参数的访问

NED 文件中申明的模块参数在运行时用 cPar 类表示。在调用 cComponent 中的成员函数 par() 可以访问模块指针,如:

1
cPar& delayPar = par("delay");

其中,cPar 类是一个存储值的对象。可以使用与参数的 NED 类型对应的方法读取cPar 的值: boolValue()intValue()doubleValue()stringValue()stdstringValue()xmlValue(),例如

1
2
long numJobs = par("numJobs").intValue();
double processingDelay = par("processingDelay");

cPar 有两种返回字符串值的方法: stringValue():返回const char *,和 stdstringValue():返回std::string。对于时常改变的参数,只能使用stdstringValue()

如果在表达式中使用 par("foo") 参数(例如 4*par("foo")+2),C++ 编译器可能无法在重载运算符之间做出决定并报告歧义。可以通过添加显式转换(例如 (double)par("foo") )、使用 doubleValue()intValue() 方法来解决此问题。

对于需要随时间动态读取常数的值时,可以使用表示随机数据包生成间隔参数的函数或者将参数对象的指针存储到类变量中,如:

1
2
3
4
5
6
void Source::handleMessage(cMessage *msg)
{
...
scheduleAt(simTime() + par("interval").doubleValue(), timerMsg);
...
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Source : public cSimpleModule
{
protected:
cPar *intervalp;
virtual void initialize();
virtual void handleMessage(cMessage *msg);
...
};

void Source::initialize()
{
intervalp = &par("interval");
...
}

void Source::handleMessage(cMessage *msg)
{
...
scheduleAt(simTime() + intervalp->doubleValue(), timerMsg);
...
}

需要注意的是,参数的类型不能在运行时改变,必须保持在 NED 文件中声明的类型。也不能在运行时添加或删除模块参数。设置参数值的方法有 setBoolValue()setLongValue()setStringValue()setDoubleValue()setXMLValue() 等。

门的访问

门模块由 cGate 对象表示,该对象知道其连接到那些门,也知道与其关联的连接对象。

按名称访问

对于输入输出门,可以使用 gate() 函数按名称查找门,例如:

1
cGate *outGate = gate("out");

当我们不能确定一个门是否存在时,可以使用 hasGate() 函数:

1
2
if (hasGate("optOut"))
send(new cMessage(), "optOut");

此外,也可以通过门的数字 ID 来识别和查找门。可以从门本身或通过门名称获取 ID:

1
2
int gateId = gate("in")->getId();
int gateId = findGate("in");

门向量

门向量每个元素拥有一个 cGate 对象。要访问向量中的各个门,需要使用附加索引参数调用 gate() 函数。可以使用gateSize() 方法读取门向量的大小,如果门向量存在并且索引在界限内,gate() 永远不会返回 nullptr 或抛出错误。

遍历一个门向量中的所有元素可以通过以下方式:

1
2
3
4
for (int i = 0; i < gateSize("out"); i++) {
cGate *gate = gate("out", i);
//...
}

用于添加和删除门的 cModule 方法是 addGate(name, type, isvector=false)deleteGate(name)。可以使用 setGateSize(name,size) 更改门矢量大小。

门 ID

通过门 ID 也可以访问到对应的门。门 ID 在门向量中是连续的,也就是说,门 g[k] 的 ID 可以计算为 g[0] 的 ID 加上 k。这使得通过 ID 检索门比通过名称和索引更有效。第一个门的索引可以使用 gate("out",0)->getId() 获得,但最好使用专用方法gateBaseId(),因为它在门向量大小为零时也有效。使用门 ID 遍历门向量的示例如下所示:

1
2
3
4
5
int baseId = gateBaseId("out"); 
int size = gateSize("out");
for (int i = 0; i < size; i++) { cGate *gate = gate(baseId + i);
//...
}

门 ID 有两个重要的特性是稳定和模块内唯一。稳定是指门的 ID 永远不会改变;唯一性不仅意味着在任何给定时间没有两个门具有相同的 ID,而且删除的门的 ID 以后不会被重用,因此门 ID 在模拟运行的生命周期中是唯一的。

cGate 方法

cGategetName() 方法返回不带索引的门或门向量的名称。getFullName() 返回一个包含门索引的字符串;getType() 方法返回门类型,值为 cGate::INPUTcGate::OUTPUTgetId() 方法返回门 ID。getOwnerModule() 方法返回门对象所属的模块。此外,还有 isVector ()getIndex()getVectorSize() 等方法。

连接的访问

概述

简单的模块门通常通过一个连接通信。然而,复合模块门需要在模块的内部和外部都连接起来才能使用。一系列连接(与复合模块门连接)称为连接路径或路径。一条路径是有向的,它通常从一个简单模块的输出门开始,到一个简单模块的输入门结束,然后经过几个复合模块门。

每个 cGate 对象都包含指向路径中上一个门和下一个门的指针(由 getPreviousGate()getNextGate() 方法返回),因此可以将路径视为双链表。

门类型

可以使用 getPathStartGate()getPathEndGate() 方法找到路径的开始门和结束门,它们一直访问前一个门或后一个门指针直到 nullptr

isConnectedOutside()isConnectedInside() 方法返回门是连接在外部还是内部。他们根据门的类型(输入或输出)检查前一个或后一个指针。例如,如果后一个指针为非 nullptr,则输出门连接到外部;输入门以相同方式检查前一个指针。

isConnected()方法有点不同:如果门是连接的,则返回 true ,也就是说,对于内部和外部的复合模块门,以及对于外部的简单模块门。

信道

与连接相关联的信道对象可以通过存储在连接源节点的门的指针访问。指针由门的 getChannel() 函数返回:

1
cChannel *channel = gate->getChannel();

当没有关联的信道对象时,结果返回 nullptr

当具有一个信道指针时,可以通过 getSourceGate() 函数获得源门:

1
cGate *gate = channel->getSourceGate();

信道示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
void cDatarateChannel ::processMessage( cMessage *msg, simtime_t t, result_t& result) 
{
// 如果通道被禁用,则表示应该删除消息
if (isDisabled) {
result.discard = true;
return;
}

// 数据速率建模
if (datarate!=0 && msg->isPacket()) {
simtime_t duration = ((cPacket *)msg)->getBitLength() / datarate;
result.duration = duration;
txfinishtime = t + duration;
}
else {
txfinishtime = t;
}

// 传播延迟建模
result.delay = delay;

// 误码建模
if ((ber!=0 || per!=0) && msg->isPacket()) { cPacket *pkt = ( cPacket *)msg;
if (ber!=0 && dblrand() < 1.0 - pow(1.0-ber, (double)pkt->getBitLength())
pkt->setBitError(true);
if (per!=0 && dblrand() < per)
pkt->setBitError(true);
}
}
打赏
  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2022-2024 lgc0208@foxmail.com
  • 访问人数: | 浏览次数:

请我喝杯咖啡吧~

支付宝
微信