悲怆的音乐家是:使用ubigraph可视化仿真ctp协议

来源:百度文库 编辑:中财网 时间:2024/05/13 18:19:08
上一篇“在Tinyos 2.x下用TOSSIM仿真CTP协议”已经搭建好了CTP协议仿真的环境,可以得到详细的调试信息。但是光看调试信息就想搞明白CTP的工作流程非吾辈所能也。

幸好有matrix67大仙介绍的3D动画生成软件Ubigraph!可以编程控制各种立体结构,而且自动布局,确实是又酷又好使。不过只有linux和mac版。按照官方手册运行起来没什么问题,只是我archlinux 下缺freeglut和libidn两个库,pacman上就行。默认对python支持最好,其它语言像C之类要自己加xmlrpc库。自带的 python例子也最多,那就用python写吧。

基本思想是每一条调试信息对应一个演示动作。比如Forwarder转发一个包会有调试信息DEBUG (3): CtpForwardingEngineP$0$SubSend$sendDone to 2 and 0,DEBUG(3)表示是TOS_ID为3的节点所产生的调试信息,后面2和0的意义需要看一下源码,可以知道2是转发的目标,0是转发成功。可以用正则表达式来匹配并提取有用的信息,然后执行相应的演示动作。

下面是我写的代码,演示了建路由、广播和转发包三种事件:

#!/usr/bin/env python
import xmlrpclib,time
import re

nodes = 10
server = xmlrpclib.Server('http://localhost:20738/RPC2')
G = server.ubigraph

G.clear()

node = [0 for col in range(nodes)]

for i in range(0,nodes):
 node[i] = G.new_vertex()
 G.set_vertex_attribute(node[i], 'label', str(i))
 G.set_vertex_attribute(node[i], 'shape','sphere')
 G.set_vertex_attribute(node[i], 'size','0.5')
 G.set_vertex_attribute(node[i], 'color','#1E90FF')

edge = [[0 for col in range(nodes)] for row in range(nodes)]

for i in range(0,nodes):
 for j in range(i+1, nodes):
  edge[i][j] = G.new_edge(node[i], node[j])
  edge[j][i] = edge[i][j]

topo = open('topo.txt', 'r')
lines = topo.readlines()
for line in lines:
 s = line.split()
 if s[0] == 'gain':
  if int(s[1]) < nodes and int(s[2]) < nodes and int(s[1]) < int(s[2]):
  G.set_edge_attribute(edge[int(s[1])][int(s[2])], 'strength', str(1 + float(s[3]) / 120.0))
  #G.set_edge_attribute(edge[int(s[1])][int(s[2])], 'label', s[3]) # add gain value

G.set_vertex_attribute(node[0], 'color', '#FFFF00') # root node

def node_spark(node_id):
 node_id = int(node_id)
 G.set_vertex_attribute(node[node_id], 'color', '#FF0000')
 G.set_vertex_attribute(node[node_id], 'color', '#FFFFFF')
 G.set_vertex_attribute(node[node_id], 'color', '#FF0000')
 G.set_vertex_attribute(node[node_id], 'color', '#FFFFFF')
 if node_id != 0:
  G.set_vertex_attribute(node[node_id], 'color', '#1E90FF')
 else:
  G.set_vertex_attribute(node[node_id], 'color', '#FFFF00')


def node_display_debug_str(node_id, debug_str):
 G.set_vertex_attribute(node[int(node_id)], 'label', node_id+": "+debug_str)

def process_boot_at_time(node_id, time):
 G.set_vertex_attribute(node[int(node_id)], 'label','boot at:'+time)

def process_parent_change(node_id, origin_parent, new_parent):
 node_id = int(node_id)
 origin_parent = int(origin_parent)
 new_parent = int(new_parent)
 if origin_parent != 65535:
  G.set_edge_attribute(edge[node_id][origin_parent], 'color', '#C0C0C0')
  G.set_edge_attribute(edge[node_id][origin_parent], 'width','1')
 G.set_edge_attribute(edge[node_id][new_parent], 'color', '#FF00FF')
 G.set_edge_attribute(edge[node_id][new_parent], 'width','7')
 time.sleep(0.5)

def animateArrow(e, reverse):
  pos = 0.0
  if reverse:
  pos = 1.0
  G.set_edge_attribute(e, "arrow_position", str(pos))
  G.set_edge_attribute(e, "arrow_reverse", str(reverse))
  G.set_edge_attribute(e, "arrow", "true")
  for i in range(0,20):
  a = i / 19.0
  if reverse:
  a = 1.0 - a
  G.set_edge_attribute(e, "arrow_position", str(a))
  time.sleep(0.05)
  G.set_edge_attribute(e, "arrow", "false")

def animate_broadcast(node_id):
 node_id = int(node_id)
 for j in range(2):
  for i in range(21):
  G.set_vertex_attribute(node[node_id], 'size', str(0.5 + i / 20.0))
  for i in range(21):
  G.set_vertex_attribute(node[node_id], 'size', str(0.5 + (20 - i)/20.0))

def process_send_beacon(node_id):
 node_id = int(node_id)
 animate_broadcast(node_id)
 

def process_forwoard_subsend(node_id, dest):
 print node_id, dest
 node_id = int(node_id)
 dest = int(dest)
 if node_id == dest:
  return
 G.set_edge_attribute(edge[node_id][dest], 'arrow','true')
 if node_id > dest:
  G.set_edge_attribute(edge[node_id][dest], "arrow_reverse", 'true')
 speed = 10 # the smaller, the faster
 for pos in range(speed+1):
  if node_id < dest:
  G.set_edge_attribute(edge[node_id][dest], "arrow_position", str(pos / float(speed)))
  else:
  G.set_edge_attribute(edge[node_id][dest], "arrow_position", str(1- pos / float(speed)))
  time.sleep(0.05)
 G.set_edge_attribute(edge[node_id][dest], "arrow_reverse", 'false')
 G.set_edge_attribute(edge[node_id][dest], 'arrow','false')

def dispatch_each_line(line):
 re_boot_at_time = r'Booting (/d+) at time (/d+)'
 re_debug = r'^DEBUG \((\d+)\): (.*)'

 re_parent_change = r'Changed parent. from (\d+) to (\d+)'
 re_send_beacon = r'CtpRoutingEngineP\$0\$sendBeaconTask\$runTask parent: (\d+) etx: (\d+)' # 1.parent, 2.etx
 re_forward_subsend = r'CtpForwardingEngineP\$0\$SubSend\$sendDone to (\d+) and (\d+)' # 1.dest, 2. error

 match = re.match(re_boot_at_time, line)
 if match:
  process_boot_at_time(match.group(1), match.group(2))
 else: # match debug messages
  match = re.match(re_debug, line)
  if match:
  node_id = match.group(1)
  node_spark(node_id)
  debug_str = match.group(2)
  node_display_debug_str(node_id, debug_str)
   
  if re.match(re_parent_change, debug_str):
  match = re.match(re_parent_change, debug_str)
  process_parent_change(node_id, match.group(1), match.group(2))
  elif re.match(re_send_beacon, debug_str):
  process_send_beacon(node_id)
  elif re.match(re_forward_subsend, debug_str): # Forwarder send a packet
  match = re.match(re_forward_subsend, debug_str)
  process_forwoard_subsend(node_id, match.group(1))

line = raw_input()
while line:
 dispatch_each_line(line)
 line = raw_input()



可以看到它是从标准输入读调试信息的,因此只要把调试信息通过管道重定向给它就行。进入tinyos-2.x/apps/tests/TestNetwork,有上次生的仿真脚本test.py。把上面的代码放入新文件ctpsim.py,运行以下命令进行3D演示:

ubigraph_server &
python test.py|python ctpsim.py



默认只仿真10个节点,如果要改的话要同时改test.py和ctpsim.py里的nodes变量。打算以后把这两个文件合并成一个,或许看上去会更统一一些。