近期要做一个简单的无线ad hoc模型,其中路由部分采用OLSR路由协议,MAC部分需要自定义,物理层采用跳频模型。
首先,搭建一个可以通信的多节点ad hoc网络。此时可以使用modeler自带的wizard。进入方式如下。
创建出来的节点网络如下所示,可以通过拓扑下拉中的轨迹定义里,设置每个节点的移动形式。
按照上述设置完成后,需要额外设置每个节点的traffic,才能使通信成功存在。
另外注意,如果采用jammer模型,需要设置jammer的影响时间间隔,如果设置的过长会导致影响失败。
在通信成功,并可以找到方法阻止节点通信阶段之后,我进入了很长一个时间的错误学习,方式是阅读代码。这段时间进展极其缓慢。其原因在于不熟悉OPNET的函数集。
之后,我改变了策略,大致学习了如何在modeler中编程,及常见的函数。
以下列出个人认为比较重要的函数,及其使用方法。
1. 创建一个指定格式的包 mac_frame_ptr = op_pk_create_fmt(“fddi_mac_fr”);//括号里面是格式的名字,可以通过pk.m文件定义,也可以采取现有的包格式,在declared里面 op_pk_nfd_set(mac_frame_ptr, “svc_class”, svc_class); op_pk_nfd_set(mac_frame_ptr, “dest_addr”, dest_addr); op_pk_nfd_set(mac_frame_ptr, “src_addr”, src_addr); op_pk_nfd_set(mac_frame_ptr, “info”, pdu_ptr);//给该格式的packet的补贴字段赋值
2. 获取中断流中的包 pkptr = op_pk_get(op_intrpt_strm());//如果需要获得连续的输入流(包)。可以采用op_strm_pksize()得到队列中包的数量 op_pk_nfd_get(pkptr,”int_value”,&i);//放到i的地址
if (op_subq_pk_insert(0,pkptr,OPC_QPOS_HEAD) != OPC_QINS_OK) { op_pk_destroy(pkptr);//插入失败则销毁该包 在HELP Symbolic Constants中有描述 }
3. 队列函数集——插入与清空 subq_index = op_intrpt_code();//确定哪些子队列正在传输 if(op_subq_empty(subq_index) == OPC_FALSE) { pkptr = op_subq_pk_remove(subq_index,OPQ_QPOS_HEAD); op_pk_send_quiet(pkptr,subq_index);//使用安静模式传输 } 4. 标识、拓扑和内部模型访问函数集 own_id = op_id_self();//返回类型是objid标识本进程处理器或队列的对象ID op_ima_obj_attr_get(own_id, “service_rate”,&service_rate);//获取对象的属性,其中service rate需要预先定义 ppid = op_topo_parent(own_id);//得到特定对象父对象的对象id op_ima_obj_attr_get(ppid, “service_rate”,&service_rate);//获取对象的属性 同理还有子id op_topo_child() 5. 中断函数集(很关键,描述4个例子) a. op_intrpt_schedule_self() pkptr = op_subq_pk_access(0,OPC_QPOS_HEAD); pk_len = op_pk_total_size_get(pkptr); pk_svc_time = pk_len/service_rate; op_intrpt_schedule_self(op_sim_time()+pk_svc_time, 0); server_busy = 1; 在特定时间里面,为激活进程调度一个中断;常见的是等待ACK,此时需要采用op_ev_cancel(evh)取消进程 b. op_intrpt_type() type = op_intrpt_type();//获取中断类型 switch(type) { case(OPC_INTRPT_STRM): break; case(OPC_INTRPT_SELF): break; case(OPC_INTRPT_STAT)://一般用在MAC层判断无线信道是否空闲 break; default: } c. op_intrpt_code()返回值是int,和当前中断相关的数字代码,便于从中断中读取用户自定义的代码可以获得该中断的目的,当有几个不同目的的中断存在时,该值非常必要,例如存在多个超时自中断。 If (op_intrpt_code() == X25C_T13)
d. op_intrpt_strm() 返回值是int类型,当前中断的流索引,当一个包通过op_pk_deliver()或者op_pk_send()转入,或者通过op_strm_access()读取时,该值被明确定义 if (op_intrpt_type() == OPC_INTRPT_STRM && op_intrpt_strm() == LOW_LAYER_INPUT_STREAM) { eth_mac_phys_pk_accept(); } else if (op_intrpt_type() == OPC_INTRPT_STRM && op_intrpt_strm() == HIGH_LAYER_INPUT_STREAM) { eth_mac_llc_pk_accept();
} 6. 统计量函数集 frms_ete_del_lhandle = op_stat_reg(“Frame Relay PVC. Delay(sec)”, conn_id, OPC_STAT_LOCAL);//参数一是统计量,参数二是索引号,参数三是局部或全局索引
7. 分布函数集 主要有两个函数 op_dist_load()返回值是一个指向分布函数的指针 job_type_dist = op_dist_load(“uniform_int”,1,job_type_range) if (job_type_dist == OPC_NIL)://抛出错误 jsd_gen_error(“unable to load job type distribution”); op_dist_outcome()通过调用获得分布结果,返回值是根据特定分布得到的随机值 next_pk_arrvl_time = op_sim_time() + op_dist_outcome(int_arrival_distptr); if (next_pk_arrvl_time < gen_end_time || gen_end_time == FRMSC_ARRL_END_OF_SIM) { op_intrpt_schedule_self(next_pk_arrvl_time,FRMSC_FR_APPL_TRAF_GEN); } 8. 事件与仿真函数集 op_ev_cancel() this_event = op_ev_current(); next_event = op_ev_next_local(this_event); while (op_ev_valid(next_event)) { If (op_ev_type(next_event) == OPC_INTRPT_SELF && op_ev_code(next_event) == RETRANS_TIMER) { retrains_timer = next_event; next_event = op_ev_next_local(retrains_timer); op_ev_cancel(retrains_timer); } else next_event = op_ev_next_local(next_event); } 9. 接口函数集 for (i = send_ |