OPNET学习笔记之defer模块(ethcoax_station_adv节点模型)

defer模块的进程模型是eth_defer_v2,功能是"Deference:For CSMA/CD Ethernet, the process by which a station delays its transmission when the channel is busy to avoid contention with ongoing transmission",就是检测链路的情况,并保持一个延迟标志(deference flag),使mac模块能通过统计线读取来确定传输是否被允许,以避免冲突。

该模块没有model attribute、global statistics和global attributes,有两个local statistics,分别为deference time和deference variable,注意1,process interface中beginsim interrput为不触发。2,该模块没有包流,只有3条统计线,如下:

statwire : defer.Ethcoax.Deference Variable -> mac.instat [0]  //通知mac模块         falling enabled       

statwire : mac.Ethcoax.Frame Waiting -> defer.instat [0]    //来自mac,是否有帧在等待    falling enabled
statwire : bus_rx0.channel [0].bus receiver.busy -> defer.instat [1]  //来自rcv,收信机是否忙  rising/falling enabled

 

状态机如下:

OPNET学习笔记之defer模块(ethcoax_station_adv节点模型)

由于beginsim interrput为不触发,所以INIT的触发条件???

一,header block中定义的全局宏定义:

/* Output statistic wires */
#define DEFERENCE_OUTSTAT 0  //到mac模块的统计线,表示deference flag

/* Input statistic wires */
#define FRAME_WAITING_INSTAT 0  //从mac模块接收的统计线,表示是否有frame等待,到instat[0]
#define CARRIER_SENSE_INSTAT 1  //从接收器模块的统计线,表示信道是否忙,到instat[1]

/* Interframe spacing set to 9.6 microseconds. */  //帧间隔???或退避时间???
#define INTERFRAME_SPACING 9.6E-06

/* Macros for state transitions */
#define FRAME_WAITING (frame_waiting != 0)  //有frame等待,临时变量,结果从函数eth_defer_frame_waiting()得到
#define FRAME_WAITING_LOW (intrpt_stat_index == FRAME_WAITING_INSTAT && !FRAME_WAITING)  //当前无frame等待,且产生统计量中断源为FRAME_WAITING_INSTAT,注意这个中断只有在输入统计量变低时产生,表示没有frame等待???(或frame发送完成???)

#define CHANNEL_BUSY (carrier_sense != 0)  //信道状态为忙,通过eth_defer_carrier_sense()函数查询得到
#define BUSY_HIGH (intrpt_stat_index == CARRIER_SENSE_INSTAT && CHANNEL_BUSY)//当前信道忙,产生统计量中断源为rx0(含义为信道变忙???)
#define BUSY_LOW (intrpt_stat_index == CARRIER_SENSE_INSTAT && !CHANNEL_BUSY)//当前信道空闲,(含义为信道变空闲???)

#define SPACING_ELAPSED (op_intrpt_type () == OPC_INTRPT_SELF)  //中断源为自中断
#define ENABLE_INTRPTS (op_intrpt_enable_all ())        //使能所有中断

 

二,INIT状态的入口代码:

/* Initialize variables and register statistics. */  //都是state variable
def_on_time = 0.0;
def_off_time = 0.0;
total_deference_time = 0.0;

/* Declare statistics handles. */  //注册局部统计量,返回句柄
local_deference_handle = op_stat_reg ("Ethcoax.Deference Time (sec)", OPC_STAT_INDEX_NONE, OPC_STAT_LOCAL);
def_handle = op_stat_reg ("Ethcoax.Deference Variable", OPC_STAT_INDEX_NONE, OPC_STAT_LOCAL);  //注意这个统计量是统计线的源

该状态是强制状态,完成后会直接跳转到DIFF_OFF状态并执行入口代码:

 

三,分析其function block:
static int eth_defer_carrier_sense ()  //读取bus_rx0模块的统计量,测试介质是否空闲,返回值为bool型,1:buzy,0:idle
{
double stat_val;

/** Return 1 if there is traffic on the bus, zero if not. **/
FIN (eth_defer_carrier_sense ());

/* Read the carrier status. Check for errors. */
stat_val = op_stat_local_read (CARRIER_SENSE_INSTAT);  //读取统计线的值,为bus_rx0的统计量buzy,是一个bool型(1/0)
if (stat_val == OPC_DBL_INVALID)
{
eth_defer_error ("Unable to read carrier sense statistic.", OPC_NIL, OPC_NIL);  //读取统计线数据错误
}

if (stat_val == 1.0)  //buzy,返回1
{
FRET (1);    //注意函数的返回值形式
}
else
{
FRET (0);
}
}

static int eth_defer_frame_waiting ()  //和上一个函数类似,读取mac模块的统计量frame waiting,测试是否有帧需要发送,1:waiting,0:idle
{
double stat_val;

/** Return 1 if a frame is waiting to be sent, zero if not. **/
FIN (eth_defer_frame_waiting ());

/* Read the frame waiting statistic. Check for errors. */
stat_val = op_stat_local_read (FRAME_WAITING_INSTAT);  //注意在header block中定义的宏,为统计线instat[0]
if (stat_val == OPC_DBL_INVALID)
{
eth_defer_error ("Unable to read frame waiting statistic.", OPC_NIL, OPC_NIL);
}

if (stat_val == 1.0)
{
FRET (1);
}
else
{
FRET (0);
}
}

static void eth_defer_error (const char* msg0, const char* msg1, const char* msg2)  //这两个函数都是进行错误处理,给出错误信息并结束仿真
{
/** Print an error message and exit the simulation. **/
FIN (eth_defer_error (msg0, msg1, msg2));

op_sim_end ("Error in Ethernet deference model (eth_defer):", msg0, msg1, msg2);

FOUT;
}


static void eth_defer_warn (const char* msg0, const char* msg1, const char* msg2)

{
/** Print a warning message and exit the simulation. **/
FIN (eth_defer_warn (msg0, msg1, msg2));

op_prg_odb_print_major ("Warning from Ethernet deference model (eth_defer):",
msg0, msg1, msg2, OPC_NIL);

FOUT;

}

四,DEF_OFF状态是强制状态,首先执行入口代码:

/* Test for waiting frames and busy carrier. */  //测试介质是否忙及是否有frame需要发送
carrier_sense = eth_defer_carrier_sense ();    //(0:idle,1:busy)
frame_waiting = eth_defer_frame_waiting ();

/* If a frame is waiting and the carrier is not busy, turn deference off.*/  //介质空闲,或者有frame需要发送,则写0到统计量,允许发送???
if (frame_waiting || !carrier_sense)  //这里感觉应该是与的关系,怎么是或呢???
{
def_off_time = op_sim_time();      //开始计算off的时间
deference_time = def_off_time - def_on_time;  //def_on_time开始时为0
total_deference_time += deference_time;
op_stat_write (local_deference_handle, total_deference_time); 
op_stat_write (def_handle, 0.0);    //写统计量,def_handle为0,注意到mac模块的统计线的触发器为低触发,会将deference flag置0。
}

然后根据条件跳转:

(一)FRAME_WAITING:当存在帧需要传递,到FRAME_WAIT状态,等待帧发送完成。

//定义在header block中:#define FRAME_WAITING(frame_waiting != 0)

由于在上一状态中deference是低,则mac模块可以发送帧,当发送完成后,发给defer模块统计量中断???

等待统计量中断,然后执行其出口函数(一直等到帧发送完):

/* Make sure that this is a statistic interrupt. */  //首先判断是否是统计量中断(只允许这种中断),这时候有两种中断,一是来自mac的frame waiting变低,表示帧发送完成;二是来自rcv的busy变化,表示碰撞???但是本状态会一直等到帧发送完后,判断rcv状态再跳转,否则等待。
if (op_intrpt_type () != OPC_INTRPT_STAT)
{
eth_defer_error ("Received unexpected interrupt type in state FRM_WAIT.",
"Only statistic interrupts are allowed in this state.",OPC_NIL);
}
intrpt_stat_index = op_intrpt_stat ();    //得到中断统计量的index,以操作之

carrier_sense = eth_defer_carrier_sense ();  //更新temp variable
frame_waiting = eth_defer_frame_waiting ();

然后判断转换条件:

<1>如果是FRAME_WAITING_LOW && !CHANNEL_BUSY,

  #define FRAME_WAITING_LOW(intrpt_stat_index == FRAME_WAITING_INSTAT && !FRAME_WAITING)

即mac中没有帧等待发送了,且信道空闲;这时跳转到BSY_WAIT状态,注意

等待中断,期待的这个中断是BUZY_HIGH,即信道变忙了

/* Make sure that this is a statistic interrupt. */    //首先判断是否是统计量中断(只允许这种中断)
if (op_intrpt_type () != OPC_INTRPT_STAT)
{
eth_defer_error ("Received unexpected interrupt type in state BSY_WAIT.",
"Only statistic interrupts are allowed in this state.",OPC_NIL);
}
intrpt_stat_index = op_intrpt_stat ();  //得到中断统计量的index

carrier_sense = eth_defer_carrier_sense ();

然后跳转到DEF_ON状态。

<2>如果是FRAME_WAITING_LOW && CHANNEL_BUSY,

即mac中没有帧等待发送了,且信道忙;这时跳转到DEF_ON状态,

<3>如果是其它(只可能是从bus_rx0来的,这时mac模块的帧发送未完成),保持原状态。

(2)!FRAME_WAITING && !CHANNEL_BUSY:没有帧等待且信道空闲,进入BUZY_WAIT状态。

(3)default:其它,没有帧等待且信道忙,进入DEF_ON状态。

(二)!FRAME_WAITING&&!CHANNEL_BUSY,没有帧等待且信道空闲,直接进入BUZY_WAIT状态。

(三)default,表示没有帧等待且信道忙,进入DEF_ON状态。

五,DEF_ON状态,执行入口代码:

/* Channel just became busy. Turn on deference. */  //更新def_on_time,使deference flag为1
def_on_time = op_sim_time();
op_stat_write (def_handle, 1.0);

由于DEF_ON状态是强制状态,马上跳转到FREE_WAIT状态,等待中断

六,FREE_WAIT状态

由于deference flag为高,这时mac模块应不能发送,期待的中断应该是信道空闲,当BUZY_LOW条件满足时,执行出口代码:

/* Make sure that this is a statistic interrupt. */  //只接收统计量中断
if (op_intrpt_type () != OPC_INTRPT_STAT)
{
eth_defer_error ("Received unexpected interrupt type in state FREE_WAIT.",
"Only statistic interrupts are allowed in this state.",OPC_NIL);
}
intrpt_stat_index = op_intrpt_stat ();

carrier_sense = eth_defer_carrier_sense ();

然后跳转到SPACING状态。

七,SPACING状态,首先执行入口代码:

/* Schedule an interrupt to mark */
/* the end of the interframe gap. */
evh = op_intrpt_schedule_self (op_sim_time () + INTERFRAME_SPACING, 0);  //自中断,等待帧间隔时间唤醒自己
if (op_ev_valid (evh) == OPC_FALSE)
{
eth_defer_error ("State SPACING: Unable to schedule end of interframe gap.",
OPC_NIL, OPC_NIL);
}

/* During the interframe gap, ignore all statistic wire interrupts. */  //在此期间忽略一切中断
op_intrpt_disable (OPC_INTRPT_STAT, FRAME_WAITING_INSTAT, OPC_FALSE);
op_intrpt_disable (OPC_INTRPT_STAT, CARRIER_SENSE_INSTAT, OPC_FALSE);

当自中断完成后,开启中断:

#define SPACING_ELAPSED (op_intrpt_type () == OPC_INTRPT_SELF)
#define ENABLE_INTRPTS (op_intrpt_enable_all ())

然后回到def_off状态。

总结:

OPNET学习笔记之defer模块(ethcoax_station_adv节点模型)

你可能感兴趣的:(学习笔记)