Statistics
| Branch: | Revision:

root / src / sim / cgate.cc @ 08285dff

History | View | Annotate | Download (18.1 KB)

1 01873262 Georg Kunz
//========================================================================
2
//  CGATE.CC - part of
3
//
4
//                 OMNeT++/OMNEST
5
//              Discrete System Simulation in C++
6
//
7
//   Member functions of
8
//    cGate      : a module gate
9
//
10
//  Author: Andras Varga
11
//
12
//========================================================================
13
14
/*--------------------------------------------------------------*
15
  Copyright (C) 1992-2008 Andras Varga
16
  Copyright (C) 2006-2008 OpenSim Ltd.
17

18
  This file is distributed WITHOUT ANY WARRANTY. See the file
19
  `license' for details on this and other legal matters.
20
*--------------------------------------------------------------*/
21
22
#include <math.h>            // pow
23
#include <stdio.h>           // sprintf
24
#include <string.h>          // strcpy
25
#include "cmessage.h"
26
#include "cmodule.h"
27
#include "carray.h"
28
#include "cenvir.h"
29
#include "csimulation.h"
30
#include "globals.h"
31
#include "cgate.h"
32
#include "cchannel.h"
33
#include "cdataratechannel.h"
34
#include "cdisplaystring.h"
35
#include "ccomponenttype.h"
36
#include "stringutil.h"
37
#include "stringpool.h"
38
#include "simutil.h"
39
#include "cmodelchange.h"
40
41
USING_NAMESPACE
42
43
using std::ostream;
44
45
46
/*
47
 * Interpretation of gate Ids (32-bit int):
48
 *     H (12+ bits) + L (20 bits)
49
 *
50
 * When H=0: nonvector gate
51
 *     L/2 = descIndex
52
 *     L&1 = 0: inputgate, 1: outputgate
53
 *   note: this allows ~500,000 scalar gates
54
 *
55
 * When H>0: vector gate
56
 *     H = descIndex+1  (so that H>0)
57
 *     bit19 of L = input (0) or output (1)
58
 *     bits0..18 of L = array index into inputgate[] or outputgate[]
59
 *   note: gateId must not be negative (for historical reasons, -1 is used as "none"),
60
 *         so H is effectively 11 bits, allowing ~2046 vector gates max.
61
 *   note2: 19 bits allow a maximum vector size of ~500,000
62
 *
63
 * Mostly affected methods are cGate::getId() and cModule::gate(int id).
64
 */
65
66
67
// non-refcounting pool for gate fullnames
68
static CommonStringPool gateFullnamePool;
69
70
71
cGate::Name::Name(const char *name, Type type)
72
{
73
    this->name = name;
74
    this->type = type;
75
    if (type==cGate::INOUT) {
76
        namei = opp_concat(name, "$i");
77
        nameo = opp_concat(name, "$o");
78
    }
79
}
80
81
bool cGate::Name::operator<(const Name& other) const
82
{
83
    int d = opp_strcmp(name.c_str(), other.name.c_str());
84
    if (d<0)
85
        return true;
86
    else if (d>0)
87
        return false;
88
    else
89
        return type < other.type;
90
}
91
92
cGate::cGate()
93
{
94
    desc = NULL;
95
    pos = 0;
96
    prevgatep = nextgatep = NULL;
97
    channelp = NULL;
98
}
99
100
cGate::~cGate()
101
{
102
    dropAndDelete(channelp);
103
}
104
105
void cGate::clearFullnamePool()
106
{
107
    gateFullnamePool.clear();
108
}
109
110
void cGate::forEachChild(cVisitor *v)
111
{
112
    if (channelp)
113
        v->visit(channelp);
114
}
115
116
const char *cGate::getBaseName() const
117
{
118
    return desc->namep->name.c_str();
119
}
120
121
const char *cGate::getName() const
122
{
123
    if (desc->namep->type==INOUT)
124
        return desc->isInput(this) ? desc->namep->namei.c_str() : desc->namep->nameo.c_str();
125
    else
126
        return desc->namep->name.c_str();
127
}
128
129
const char *cGate::getNameSuffix() const
130
{
131
    if (desc->namep->type==INOUT)
132
        return desc->isInput(this) ? "$i" : "$o";
133
    else
134
        return "";
135
}
136
137
const char *cGate::getFullName() const
138
{
139
    // if not in a vector, normal getName() will do
140
    if (!isVector())
141
        return getName();
142
143
    // otherwise, produce fullname in a temp buffer, and return its stringpooled copy
144
    // note: this implementation assumes that this method will be called infrequently
145
    // (ie. we reproduce the string every time).
146
    if (opp_strlen(getName()) > 100)
147
        throw cRuntimeError(this, "getFullName(): gate name too long, should be under 100 characters");
148
149
    static char tmp[128];
150
    strcpy(tmp, getName());
151
    opp_appendindex(tmp, getIndex());
152
    return gateFullnamePool.get(tmp); // non-refcounted stringpool
153
}
154
155
std::string cGate::info() const
156
{
157
    const char *arrow;
158
    cGate const *g;
159
    cGate const *conng;
160
    cChannel const *chan;
161
162
    if (getType()==OUTPUT)
163
        {arrow = "--> "; g = nextgatep; conng = this; chan = channelp; }
164
    else if (getType()==INPUT)
165
        {arrow = "<-- "; g = prevgatep; conng = prevgatep; chan = prevgatep ? prevgatep->channelp : NULL;}
166
    else
167
        ASSERT(0);  // a cGate is never INOUT
168
169
    // append useful info to buf
170
    if (!g)
171
        return "not connected";
172
173
    std::stringstream out;
174
    out << arrow;
175
176
    out << (g->getOwnerModule()==getOwnerModule()->getParentModule() ? "<parent>" : g->getOwnerModule()->getFullName());
177
    out << "." << g->getFullName();
178
179
    if (chan)
180
        out << ", " << chan->getComponentType()->getFullName() << " " << chan->info();
181
182
    return out.str();
183
}
184
185
cObject *cGate::getOwner() const
186
{
187
    // note: this function cannot go inline because of circular dependencies
188
    return desc->ownerp;
189
}
190
191
cModule *cGate::getOwnerModule() const
192
{
193
    return desc->ownerp;
194
}
195
196
int cGate::getId() const
197
{
198
    int descIndex = desc - desc->ownerp->descv;
199
    int id;
200
    if (!desc->isVector())
201
        id = (descIndex<<1)|(pos&1);
202
    else
203
        // note: we use descIndex+1 otherwise h could remain zero after <<LBITS
204
        id = ((descIndex+1)<<GATEID_LBITS) | ((pos&1)<<(GATEID_LBITS-1)) | (pos>>2);
205
    return id;
206
}
207
208
const char *cGate::getTypeName(Type t)
209
{
210
    switch (t) {
211
        case INPUT: return "input";
212
        case OUTPUT: return "output";
213
        case INOUT: return "inout";
214
        default: return "(unknown type)";
215
    }
216
}
217
218
cProperties *cGate::getProperties() const
219
{
220
    cComponent *component = check_and_cast<cComponent *>(getOwner());
221
    cComponentType *componentType = component->getComponentType();
222
    cProperties *props = componentType->getGateProperties(getBaseName());
223
    return props;
224
}
225
226
cChannel *cGate::connectTo(cGate *g, cChannel *chan, bool leaveUninitialized)
227
{
228
    if (nextgatep)
229
        throw cRuntimeError(this, "connectTo(): gate already connected");
230
    if (!g)
231
        throw cRuntimeError(this, "connectTo(): destination gate cannot be NULL pointer");
232
    if (g->prevgatep)
233
        throw cRuntimeError(this, "connectTo(): destination gate already connected");
234
235
    // notify pre-change listeners
236
    cModule *mod = getOwnerModule();
237
    if (mod->hasListeners(PRE_MODEL_CHANGE)) {
238
        cPreGateConnectNotification tmp;
239
        tmp.gate = this;
240
        tmp.targetGate = g;
241
        tmp.channel = chan;
242
        mod->emit(PRE_MODEL_CHANGE, &tmp);
243
    }
244
    cGate *pathStartGate = getPathStartGate();
245
    cGate *pathEndGate = g->getPathEndGate();
246
    cModule *pathStartModule = pathStartGate->getOwnerModule();
247
    cModule *pathEndModule = pathEndGate->getOwnerModule();
248
    if (pathStartModule->hasListeners(PRE_MODEL_CHANGE) || pathEndModule->hasListeners(PRE_MODEL_CHANGE)) {
249
        cPrePathCreateNotification tmp;
250
        tmp.pathStartGate = pathStartGate;
251
        tmp.pathEndGate = pathEndGate;
252
        tmp.changedGate = this;
253
        pathStartModule->emit(PRE_MODEL_CHANGE, &tmp);
254
        pathEndModule->emit(PRE_MODEL_CHANGE, &tmp);
255
    }
256
257
    // build new connection
258
    nextgatep = g;
259
    nextgatep->prevgatep = this;
260
    if (chan)
261
        installChannel(chan);
262
263
    checkChannels();
264
265
    // notify envir
266
    if (chan)
267
        ev.configure(chan);
268
    EVCB.connectionCreated(this);
269
270
    // initialize the channel here, to simplify dynamic connection creation.
271
    // Heuristics: if parent module is not yet initialized, we expect that
272
    // this channel will be initialized as part of it, so don't do it here;
273
    // otherwise initialize the channel now.
274
    if (chan && !leaveUninitialized && (!chan->getParentModule() || chan->getParentModule()->initialized()))
275
        chan->callInitialize();
276
277
    // notify post-change listeners
278
    if (mod->hasListeners(POST_MODEL_CHANGE)) {
279
        cPostGateConnectNotification tmp;
280
        tmp.gate = this;
281
        mod->emit(POST_MODEL_CHANGE, &tmp);
282
    }
283
    if (pathStartModule->hasListeners(POST_MODEL_CHANGE) || pathEndModule->hasListeners(POST_MODEL_CHANGE)) {
284
        cPostPathCreateNotification tmp;
285
        tmp.pathStartGate = pathStartGate;
286
        tmp.pathEndGate = pathEndGate;
287
        tmp.changedGate = this;
288
        pathStartModule->emit(POST_MODEL_CHANGE, &tmp);
289
        pathEndModule->emit(POST_MODEL_CHANGE, &tmp);
290
    }
291
292
    return chan;
293
}
294
295
void cGate::installChannel(cChannel *chan)
296
{
297
    ASSERT(channelp==NULL && chan!=NULL);
298
    channelp = chan;
299
    channelp->setSourceGate(this);
300
    take(channelp);
301
302
    // update cached signal state
303
    channelp->repairSignalFlags();
304
}
305
306
void cGate::disconnect()
307
{
308
    if (!nextgatep)
309
        return;
310
311
    // notify pre-change listeners
312
    cModule *mod = getOwnerModule();
313
    if (mod->hasListeners(PRE_MODEL_CHANGE)) {
314
        cPreGateDisconnectNotification tmp;
315
        tmp.gate = this;
316
        mod->emit(PRE_MODEL_CHANGE, &tmp);
317
    }
318
    cGate *pathStartGate = getPathStartGate();
319
    cGate *pathEndGate = nextgatep->getPathEndGate();
320
    cModule *pathStartModule = pathStartGate->getOwnerModule();
321
    cModule *pathEndModule = pathEndGate->getOwnerModule();
322
    if (pathStartModule->hasListeners(PRE_MODEL_CHANGE) || pathEndModule->hasListeners(PRE_MODEL_CHANGE)) {
323
        cPrePathCutNotification tmp;
324
        tmp.pathStartGate = pathStartGate;
325
        tmp.pathEndGate = pathEndGate;
326
        tmp.changedGate = this;
327
        pathStartModule->emit(PRE_MODEL_CHANGE, &tmp);
328
        pathEndModule->emit(PRE_MODEL_CHANGE, &tmp);
329
    }
330
331
    // notify envir that old conn gets removed
332
    EVCB.connectionDeleted(this);
333
334
    // remove connection (but preserve channel object for the notification)
335
    cGate *oldnextgatep = nextgatep;
336
    nextgatep->prevgatep = NULL;
337
    nextgatep = NULL;
338
339
    cChannel *oldchannelp = channelp;
340
    channelp = NULL;
341
342
    // notify post-change listeners
343
    if (mod->hasListeners(POST_MODEL_CHANGE)) {
344
        cPostGateDisconnectNotification tmp;
345
        tmp.gate = this;
346
        tmp.targetGate = oldnextgatep;
347
        tmp.channel = oldchannelp;
348
        mod->emit(POST_MODEL_CHANGE, &tmp);
349
    }
350
    if (pathStartModule->hasListeners(POST_MODEL_CHANGE) || pathEndModule->hasListeners(POST_MODEL_CHANGE)) {
351
        cPostPathCutNotification tmp;
352
        tmp.pathStartGate = pathStartGate;
353
        tmp.pathEndGate = pathEndGate;
354
        tmp.changedGate = this;
355
        pathStartModule->emit(POST_MODEL_CHANGE, &tmp);
356
        pathEndModule->emit(POST_MODEL_CHANGE, &tmp);
357
    }
358
359
    // delete channel object
360
    dropAndDelete(oldchannelp);
361
}
362
363
void cGate::checkChannels() const
364
{
365
    int n = 0;
366
    for (const cGate *g=getPathStartGate(); g->nextgatep!=NULL; g=g->nextgatep)
367
        if (g->channelp && g->channelp->isTransmissionChannel())
368
            n++;
369
    if (n>1)
370
        throw cRuntimeError("More than one channel with data rate found in the "
371
                            "connection path between gates %s and %s",
372
                            getPathStartGate()->getFullPath().c_str(),
373
                            getPathEndGate()->getFullPath().c_str());
374
}
375
376
cChannel *cGate::reconnectWith(cChannel *channel, bool leaveUninitialized)
377
{
378
    cGate *otherGate = getNextGate();
379
    if (!otherGate)
380
        throw cRuntimeError(this, "reconnectWith(): gate must be already connected");
381
    disconnect();
382
    return connectTo(otherGate, channel, leaveUninitialized);
383
}
384
385
cGate *cGate::getPathStartGate() const
386
{
387
    const cGate *g;
388
    for (g=this; g->prevgatep!=NULL; g=g->prevgatep);
389
    return const_cast<cGate *>(g);
390
}
391
392
cGate *cGate::getPathEndGate() const
393
{
394
    const cGate *g;
395
    for (g=this; g->nextgatep!=NULL; g=g->nextgatep);
396
    return const_cast<cGate *>(g);
397
}
398
399
void cGate::setDeliverOnReceptionStart(bool d)
400
{
401
    if (!getOwnerModule()->isSimple())
402
        throw cRuntimeError(this, "setDeliverOnReceptionStart() may only be invoked on a simple module gate");
403
    if (getType() != INPUT)
404
        throw cRuntimeError(this, "setDeliverOnReceptionStart() may only be invoked on an input gate");
405
406
    // set b1 on pos
407
    if (d)
408
        pos|=2;
409
    else
410
        pos&=~2;
411
}
412
413
bool cGate::deliver(cMessage *msg, simtime_t t)
414
{
415
    if (!nextgatep)
416
    {
417
        getOwnerModule()->arrived(msg, this, t);
418
        return true;
419
    }
420
    else if (!channelp)
421
    {
422
        EVCB.messageSendHop(msg, this);
423
        return nextgatep->deliver(msg, t);
424
    }
425
    else
426
    {
427
        if (!channelp->initialized())
428
            throw cRuntimeError(channelp, "Channel not initialized (did you forget to invoke "
429
                                          "callInitialize() for a dynamically created channel or "
430
                                          "a dynamically created compound module that contains it?)");
431
        if (!channelp->isTransmissionChannel())
432
        {
433
            cChannel::result_t tmp;
434
            channelp->processMessage(msg, t, tmp);
435
            if (tmp.discard)
436
                return false;
437
            EVCB.messageSendHop(msg, this, tmp.delay, SIMTIME_ZERO); // tmp.duration ignored for non-transmission channels
438
            return nextgatep->deliver(msg, t + tmp.delay);
439
        }
440
        else
441
        {
442
            // transmission channel:
443
            // channel must be idle
444
            if (channelp->getTransmissionFinishTime() > t)
445
                throw cRuntimeError("Error sending message (%s)%s on gate %s: channel is currently "
446
                                    "busy with an ongoing transmission -- please rewrite the sender "
447
                                    "simple module to only send when the previous transmission has "
448
                                    "already finished, using cGate::getTransmissionFinishTime(), scheduleAt(), "
449
                                    "and possibly a cQueue for storing messages waiting to be transmitted",
450
                                    msg->getClassName(), msg->getFullName(), getFullPath().c_str());
451
452
            // message must not have its duration set already
453
            bool isPacket = msg->isPacket();
454
            if (isPacket && ((cPacket *)msg)->getDuration() != SIMTIME_ZERO)
455
                throw cRuntimeError(this, "Packet (%s)%s already has a duration set; there "
456
                    "may be more than one channel with data rate in the connection path, or "
457
                    "it was sent with a sendDirect() call that specified duration as well",
458
                    msg->getClassName(), msg->getName());
459
460
            // process
461
            cChannel::result_t tmp;
462
            channelp->processMessage(msg, t, tmp);
463
            if (tmp.discard)
464
                return false;
465
            if (isPacket)
466
                ((cPacket *)msg)->setDuration(tmp.duration);
467
            EVCB.messageSendHop(msg, this, tmp.delay, tmp.duration);
468
            return nextgatep->deliver(msg, t + tmp.delay);
469
        }
470
    }
471
}
472
473
cChannel *cGate::findTransmissionChannel() const
474
{
475
    for (const cGate *g=this; g->nextgatep!=NULL; g=g->nextgatep)
476
        if (g->channelp && g->channelp->isTransmissionChannel())
477
            return g->channelp;
478
    return NULL;
479
}
480
481
cChannel *cGate::getTransmissionChannel() const
482
{
483
    cChannel *chan = findTransmissionChannel();
484
    if (chan)
485
        return chan;
486
487
    // transmission channel not found, try to issue a helpful error message
488
    if (nextgatep)
489
        throw cRuntimeError(this, "getTransmissionChannel(): no transmission channel "
490
                            "found in the connection path between gates %s and %s",
491
                            getFullPath().c_str(),
492
                            getPathEndGate()->getFullPath().c_str());
493
    else if (getType()==OUTPUT)
494
        throw cRuntimeError(this, "getTransmissionChannel(): no transmission channel found: "
495
                            "gate is not connected");
496
    else
497
        throw cRuntimeError(this, "getTransmissionChannel(): cannot be invoked on a "
498
                            "simple module input gate (or a compound module "
499
                            "input gate which is not connected on the inside)");
500
}
501
502
cChannel *cGate::findIncomingTransmissionChannel() const
503
{
504
    for (const cGate *g=this->prevgatep; g!=NULL; g=g->prevgatep)
505
        if (g->channelp && g->channelp->isTransmissionChannel())
506
            return g->channelp;
507
    return NULL;
508
}
509
510
cChannel *cGate::getIncomingTransmissionChannel() const
511
{
512
    cChannel *chan = findIncomingTransmissionChannel();
513
    if (chan)
514
        return chan;
515
516
    // transmission channel not found, try to issue a helpful error message
517
    if (prevgatep)
518
        throw cRuntimeError(this, "getIncomingTransmissionChannel(): no transmission channel "
519
                            "found in the connection path between gates %s and %s",
520
                            getFullPath().c_str(),
521
                            getPathStartGate()->getFullPath().c_str());
522
    else if (getType()==INPUT)
523
        throw cRuntimeError(this, "getIncomingTransmissionChannel(): no transmission channel found: "
524
                            "gate is not connected");
525
    else
526
        throw cRuntimeError(this, "getIncomingTransmissionChannel(): cannot be invoked on a "
527
                            "simple module output gate (or a compound module "
528
                            "output gate which is not connected on the inside)");
529
}
530
531
bool cGate::pathContains(cModule *mod, int gate)
532
{
533
    cGate *g;
534
535
    for (g=this; g!=NULL; g=g->prevgatep)
536
        if (g->getOwnerModule()==mod && (gate==-1 || g->getId()==gate))
537
            return true;
538
    for (g=nextgatep; g!=NULL; g=g->nextgatep)
539
        if (g->getOwnerModule()==mod && (gate==-1 || g->getId()==gate))
540
            return true;
541
    return false;
542
}
543
544
bool cGate::isConnectedOutside() const
545
{
546
    if (getType()==INPUT)
547
        return prevgatep!=NULL;
548
    else
549
        return nextgatep!=NULL;
550
}
551
552
bool cGate::isConnectedInside() const
553
{
554
    if (getType()==INPUT)
555
        return nextgatep!=NULL;
556
    else
557
        return prevgatep!=NULL;
558
}
559
560
bool cGate::isConnected() const
561
{
562
    // for compound modules, both inside and outside must be non-NULL,
563
    // for simple modules, only check outside.
564
    if (!getOwnerModule()->isSimple())
565
        return prevgatep!=NULL && nextgatep!=NULL;
566
    else
567
        return isConnectedOutside();
568
}
569
570
bool cGate::isPathOK() const
571
{
572
    return getPathStartGate()->getOwnerModule()->isSimple() &&
573
           getPathEndGate()->getOwnerModule()->isSimple();
574
}
575
576
cDisplayString& cGate::getDisplayString()
577
{
578
    if (!getChannel())
579
    {
580
        installChannel(cIdealChannel::create("channel"));
581
        channelp->callInitialize();
582
    }
583
    return getChannel()->getDisplayString();
584
}
585
586
void cGate::setDisplayString(const char *dispstr)
587
{
588
    getDisplayString().set(dispstr);
589
}