现在的位置: 首页 > 综合 > 正文

OPNET学习笔记之ethcoax_net—–mac

2018年02月20日 ⁄ 综合 ⁄ 共 11490字 ⁄ 字号 评论关闭

 开始学习 eth_mac_v2   

状态机如上图所示:

 

 

START出口代码   start状态为什么作用是确保地址正确呢??????

/* Obtain the address assigned to this node as it might  */
/* have changed during auto-addressing.      */
op_ima_obj_attr_get (mac_attr_objid, "Address", &my_32bit_address);

/* Store the address as 64-bit integer, since ARP was  */
/* enhanced to support 48-bit MAC addresses.    */
my_address = my_32bit_address;

/* Register station's MAC address into model-wide    */
/* registery, since the address assignment is final now. */
oms_pr_attr_set (own_process_record_handle,
 "address",    OMSC_PR_INT64,  my_address,
 "protocol",    OMSC_PR_STRING,  "mac",
 "mac_type",    OMSC_PR_STRING,  "eth_coax",
 "auto address handle", OMSC_PR_POINTER, oms_aa_handle,
 OPC_NIL);

/* Set the destination as an invalid destination if the MAC */
/* is part of a  bridge/switch.        */
if (mac_port_of_a_bridge_switch_node == OPC_TRUE)
 oms_aa_dest_status_set (oms_aa_handle, (int) my_address, OmsC_Aa_Invalid_Destination);

TX_WAIT入口代码

/* In this state the MAC layer waits for a new */
/* frame to arrive from the higher layer.  */

/* Physical layer events are not of interest and */
/* may be masked until frame processing begins. */
eth_mac_phys_layer_ignore ();     一直等待从高层发来的帧 忽略物理层的中断

 

FB中函数定义

static void
eth_mac_phys_layer_ignore ()            忽略物理层的中断
 {
 /** Disable reception of physical layer events. **/
 FIN (eth_mac_phys_layer_ignore ());

 op_intrpt_disable (OPC_INTRPT_STAT, DEFERENCE_INSTAT, OPC_FALSE);     op_intrpt_disable(type,code,next)  next boolean型,OPC_TURE只失能以后来的中断//OPC_FALSE 无限制中断来的时间
 op_intrpt_disable (OPC_INTRPT_STAT, COLLISION_DETECT_INSTAT, OPC_FALSE);
 op_intrpt_disable (OPC_INTRPT_STAT, TRANSMITTING_INSTAT, OPC_FALSE);

 FOUT;
 }

 

 

当有帧到来时  TX_WAIT出口函数

/* Store interrupt related information into   */ 
保存中断相关信息
以便以后调用
/* temporary variables for quick access.   */
intrpt_type = op_intrpt_type ();
if (intrpt_type == OPC_INTRPT_STRM)
 {
 intrpt_strm = op_intrpt_strm ();
 }

/* If the event was an arrival from the physical */
/* layer, accept and decapsulate the packet.  */
if (intrpt_type == OPC_INTRPT_STRM &&
 intrpt_strm == LOW_LAYER_INPUT_STREAM)
 {
 eth_mac_phys_pk_accept ();
 }

/* Otherwise, if the event is an arrival from the */
/* higher layer, accept and enqueue the packet.  */
else if (intrpt_type == OPC_INTRPT_STRM &&
 ((intrpt_strm == strm_from_ip) ||
 (intrpt_strm == strm_from_ipx) ||
 (intrpt_strm == HIGH_LAYER_INPUT_STREAM)))
 {
 eth_mac_llc_pk_accept ();
 }

 

 

FRM_START  强制状态入口函数

/* Dequeue a new frame for transmission. */  取出一个新的帧用于传输
current_frame = op_subq_pk_remove (0, OPC_QPOS_HEAD);  // op_subq_pk_remove(subq_index, pos_index)获得指定序列指定位置中的包的指针,并把包从序列中删除

if (current_frame == OPC_NIL)   {
 eth_mac_error ("Unable to get outgoing frame from queue.",  
  "Queue is not empty: some error must have occurred.",
  OPC_NIL);
 }

/* Initialize transmission state variables. */ 初始化传输的状态变量
attempts = 0;
tx_comp_status = STATUS_OK;
frame_waiting = 1;          将帧等待的标志位置高

/* Notify the deference process that a frame is waiting. */
op_stat_write (frame_handle, 1.0);    将帧句柄也置高,来通知进程有帧在等待

 

分支1  当DEFERENCE_OFF  发生时   进入TX_START状态

#define DEFERENCE_OFF  (op_stat_local_read (DEFERENCE_INSTAT) == 0.0)  
DEFERENCE_INSTAT标志变低时   mac层即可发送帧 什么事件触发标志变低呢

 

分支2  当deference flag 标志为高时  进入DEF_WAIT状态 

DEF_WAIT入口函数

/* Enable physical layer events. */
eth_mac_phys_layer_listen ();   使能物理层中断
在此处等待,直到DEFERENCE_LOW发生   进入TX_START状态

#define DEFERENCE_LOW  (op_intrpt_type () == OPC_INTRPT_STAT &&    \
        op_intrpt_stat () == DEFERENCE_INSTAT &&   \
        DEFERENCE_OFF)

 

 

TX_START 强制状态入口函数  

/* Deference variable is low, so transmission can */
/* begin now.  Create a copy of the current frame. */ mac开始发送帧了
tx_frame = op_pk_copy (current_frame); 复制当前帧
if (tx_frame == OPC_NIL)
 {
 eth_mac_error ("Unable to copy current outgoing frame.",
  OPC_NIL, OPC_NIL);
 }

/* Increment the number of attempts made */
/* so far on the current frame.    */
attempts++;                      attempts代表什么???

/* The frame is no longer waiting. */   帧不再等待,将帧等待标志位置低,并且置低句柄
/* Notify the deference process. */
frame_waiting = 0;
op_stat_write (frame_handle, frame_waiting);

/* Allow for debugger breaking at this point. */
op_prg_odb_bkpt ("tx_start"); 设置一个断点
以便
ODB调试

if (op_prg_odb_pktrace_active (tx_frame))   确定指定的包是否被ODB跟踪返回boolean
 {
 sprintf (str, "packet id (" SIMC_PK_ID_FMT ")", op_pk_id (tx_frame));
 op_prg_odb_print_major ("Sending New Frame", str, OPC_NIL);   
输出
Sending New Frame
 }

/* Record the start time for the transmission attempt */记录开始传输的时间,以便判断是否发生延迟碰撞(即碰撞超过一个时间片)
/* in order to determine if late collisions (collisions */
/* beyond one slot time) occur.       */
frame_start_time = op_sim_time ();

 

/* send frame to bus transmitter */           将帧发到总线发射机
op_pk_send (tx_frame, LOW_LAYER_OUTPUT_STREAM);

TXEV_WAIT入口函数

/* Enable physical layer events. */ 使能物理层事件
eth_mac_phys_layer_listen ();

 

static void
eth_mac_phys_layer_listen ()
 {
 /** Disable reception of physical layer events. **/
 FIN (eth_mac_phys_layer_listen ());

 op_intrpt_enable (OPC_INTRPT_STAT, DEFERENCE_INSTAT);
 op_intrpt_enable (OPC_INTRPT_STAT, COLLISION_DETECT_INSTAT);
 op_intrpt_enable (OPC_INTRPT_STAT, TRANSMITTING_INSTAT);

 FOUT;
 }

 

 

分支1     当XMITTING_LOW  发生时 :当传送标志为低时

#define XMITTING_LOW  (op_intrpt_type () == OPC_INTRPT_STAT &&  \
        op_intrpt_stat () == TRANSMITTING_INSTAT &&  \
        op_stat_local_read (TRANSMITTING_INSTAT) == 0.0)

执行出口函数:

/* Store interrupt related information into   */
/* temporary variables for quick access.   */
intrpt_type = op_intrpt_type ();
if (intrpt_type == OPC_INTRPT_STRM)
 {
 intrpt_strm = op_intrpt_strm ();
 }

/* If the event was an arrival from the physical  */
/* layer, accept and decapsulate the packet.  */
if (intrpt_type == OPC_INTRPT_STRM &&
 intrpt_strm == LOW_LAYER_INPUT_STREAM)
 {
 eth_mac_phys_pk_accept ();
 }

/* Otherwise, if the event is an arrival from the */
/* higher layer, accept and enqueue the packet.  */
else if (intrpt_type == OPC_INTRPT_STRM &&
 ((intrpt_strm == strm_from_ip) ||
 (intrpt_strm == strm_from_ipx) ||
 (intrpt_strm == HIGH_LAYER_INPUT_STREAM)))
 {
 eth_mac_llc_pk_accept ();
 }                                                  
到此之前的函数与
TX_WAIT出口函数相同 
功能也相同

if (XMITTING_LOW)        如果执行XMITTING_LOW这条路径,就把attempts的值写到retrans_handle
 {
 op_stat_write (retrans_handle, attempts);
 }

FRM_END强制状态入口函数

/* Enable all interrupts */
op_intrpt_enable_all (); 使能所有中断

/* Deallocate the frame stored for retransmission purposes. */ 释放用于重传的帧
op_pk_destroy (current_frame);

/* Record extra data-points to enable proper computation of */  使用额外的数据点来记录sum/time 的性能
/* the "sum/time" based statistics.       */
op_stat_write(bit_sec_load_handle,    0.0);
op_stat_write(packet_sec_load_handle, 0.0);

 

分支1 .1  当QUEUE_EMPTY   时  又回到TX_WAIT状态

#define QUEUE_EMPTY   (op_q_stat (OPC_QSTAT_PKSIZE) == 0.0)

分支1.2   如果队列不为空    跳到FRM_START状态

 

 分支2  当COLL_DET_HIGH    发生时   执行TXEV_WAIT状态的出口函数 和SET_ENTRY    进入collision状态

 #define COLL_DET_HIGH       (op_intrpt_type () == OPC_INTRPT_STAT &&    \
        op_intrpt_stat () == COLLISION_DETECT_INSTAT &&\
        op_stat_local_read (COLLISION_DETECT_INSTAT) == 1.0)
 

TXEV_WAIT出口函数  保存中断相关信息
以便以后调用

 

SET_ENTRY

#define SET_ENTRY   reentry = 0;

 

collision状态入口函数

if (!reentry)                                                   default情况下将reentry置高 还如何进入程序????
 {
 /* A collision has occured.  Continue transmitting for */
 /* JAM_SIZE bit-times, at which time the transmission */
 /* will be aborted.          */
 op_stat_write (collision_num_handle, 1.0);    将碰撞标志位置高
 evh = op_intrpt_schedule_self (op_sim_time () + JAM_SIZE / bit_rate, 0);    获取碰撞时间
 if (op_ev_valid (evh) == OPC_FALSE)
  {
  eth_mac_error ("Unable to schedule end of post-collision jamming.",
   OPC_NIL, OPC_NIL);
  }

 /* During the jam period, ignore physical layer events. */
 eth_mac_phys_layer_ignore ();    碰撞期间忽略物理层的事件

 /* Compute time from leading edge of frame to */
 /* the time at which the collision occurred. */       计算从帧开始传输到现在碰撞所用时间  写入frag_time中
 frag_time = op_sim_time () - frame_start_time;
 }
 

default中为什么把reentry中置高了????

 

当JAM_END时,

#define JAM_END    (op_intrpt_type () == OPC_INTRPT_SELF)  有自中断产生         //  #define JAM_END    (op_intrpt_type () == OPC_INTRPT_SELF)
//#define BACKOFF_END   (op_intrpt_type () == OPC_INTRPT_SELF)?????为什么条件一样

执行collision出口函数  此处同TX_WAIT     TXEV_WAIT的出口函数,保存中断信息

/* Store interrupt re lated information into   */
/* temporary variables for quick access.   */
intrpt_type = op_intrpt_type ();
if (intrpt_type == OPC_INTRPT_STRM)
 {
 intrpt_strm = op_intrpt_strm ();
 }

/* If the event was an arrival from the physical */
/* layer, accept and decapsulate the packet.  */
if (intrpt_type == OPC_INTRPT_STRM &&
 intrpt_strm == LOW_LAYER_INPUT_STREAM)
 {
 eth_mac_phys_pk_accept ();
 }

/* Otherwise, if the event is an arrival from the */
/* higher layer, accept and enqueue the packet.  */
else if (intrpt_type == OPC_INTRPT_STRM &&
 ((intrpt_strm == strm_from_ip) ||
 (intrpt_strm == strm_from_ipx) ||
 (intrpt_strm == HIGH_LAYER_INPUT_STREAM)))
 {
 eth_mac_llc_pk_accept ();
 }

 

进入强制状态ABORT    入口函数

/* Jamming bit sequence has been transmitted. */
/* Stop the remainder of the packet from being */
/* transmitted.         */
if (op_ima_obj_command (tx_channel_objid, "abort") == OPC_COMPCODE_FAILURE)    

 /******op_ima_obj_command (objid,
cmd_name)       在指定的对象中执行cmd_name 命令       “abort” 对于 point-to-point link     bus link    radio transmitter channel  方式:immediately aborts the current packet transmission                                                                    "flush"对于radio receiver
channel   :immediately removes all packets in the process of being received   *******/

 {
 eth_mac_warn ("Unable to issue ABORT command to transmitter channel.",
  OPC_NIL, OPC_NIL);
 }

/* If the length of the fragment is greater  */  判断是否为延迟碰撞
/* than a slot time, this is a late collision. */
if (frag_time > SLOT_TIME)
 tx_comp_status = STATUS_ERR_LATE_COLL;
else if (attempts >= ATTEMPT_LIMIT)
 tx_comp_status = STATUS_ERR_EXCESS_COLL;
else
 tx_comp_status = STATUS_RETRANSMIT_PENDING;

 

分支2.1

如果此时  EXCESS_COL  或者LATE_COL发生,则进入FRM_END状态
 #define EXCESS_COL   (tx_comp_status == STATUS_ERR_EXCESS_COLL)
#define LATE_COL   (tx_comp_status == STATUS_ERR_LATE_COLL)

分支2.2

其他情况,执行SET_ENTRY

#define SET_ENTRY   reentry = 0;

进入BACK_OFF状态  入口代码

if (!reentry)
 {
 /* Compute backoff interval using truncated */  使用截断的二进制指数进程 计算补偿间隔
 /* binary exponential process.    */

 /* Unit for retransmission scheduling is the slot time and */ 重传调度的单位是时间片

  /* the upper bound is based on number of transmissions to */上层绑定是基于当前帧的传输数目
 /* to date of the current frame.       */

 /* If this is the first attempt, there */ 如果是第一次尝试,则有两种可能的补偿时间片
 /* are two possible backoff slots.  */
 if (attempts == 1)
  max_backoff = 2;

 /* Otherwise the number of possible slots grows  */否则时间片数目会按照指数增长直到一定界限
 /* exponentially until it exceeds a fixed limit. */
 else if (attempts <= BACKOFF_LIMIT)
  max_backoff = max_backoff * 2;

 /* Obtain a uniformly distributed random integer */ 在0-界限中获取唯一的指数分布
 /* between 0 and the backoff limit.     */
 backoff_slots = op_dist_uniform (max_backoff);
 if (backoff_slots == OPC_DBL_INVALID)
  {
  eth_mac_error ("Unable to choose a number of backoff slots.", OPC_NIL, OPC_NIL);
  }

 /* Set a timer for the end of the backoff interval. */
 evh = op_intrpt_schedule_self (op_sim_time () + (int) backoff_slots * SLOT_TIME, 0);    此处不理解???
 if (op_ev_valid (evh) == OPC_FALSE)
  {
  eth_mac_error ("Unable to schedule end to backoff interval.", OPC_NIL, OPC_NIL);
  }
 }

 

分支2.2.1   当BACKOFF_END&&DEFERENCE_OFF    执行出口代码,进入TX_START状态
 

#define BACKOFF_END   (op_intrpt_type () == OPC_INTRPT_SELF)

#define DEFERENCE_OFF  (op_stat_local_read (DEFERENCE_INSTAT) == 0.0)

 

分支2.2.2  当BACKOFF_END &&  DEFERENCE_ON   执行出口函数 并执行SET_FRM_WAIT      进入DEF_WAIT状态

#define BACKOFF_END   (op_intrpt_type () == OPC_INTRPT_SELF)

#define DEFERENCE_ON  (op_stat_local_read (DEFERENCE_INSTAT) == 1.0)

 

#define SET_FRM_WAIT  {frame_waiting = 1;                         
        op_stat_write (frame_handle, 1.0);} 

 

 

 

BACKOFF出口代码   保存中断信息以便调用  同TX_WAIT和  DEF_WAIT的出口函数

/* Store interrupt related information into   */
/* temporary variables for quick access.   */
intrpt_type = op_intrpt_type ();
if (intrpt_type == OPC_INTRPT_STRM)
 {
 intrpt_strm = op_intrpt_strm ();
 }

/* If the event was an arrival from the physical */
/* layer, accept and decapsulate the packet.  */
if (intrpt_type == OPC_INTRPT_STRM &&
 intrpt_strm == LOW_LAYER_INPUT_STREAM)
 {
 eth_mac_phys_pk_accept ();
 }

/* Otherwise, if the event is an arrival from the */
/* higher layer, accept and enqueue the packet.  */
else if (intrpt_type == OPC_INTRPT_STRM &&
 ((intrpt_strm == strm_from_ip) ||
 (intrpt_strm == strm_from_ipx) ||
 (intrpt_strm == HIGH_LAYER_INPUT_STREAM)))
 {
 eth_mac_llc_pk_accept ();
 }

 

状态转换图如下所示

 

 

 

 

 

抱歉!评论已关闭.