开始学习 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 ();
}
状态转换图如下所示