xref: /btstack/tool/create_packet_log.py (revision 1ca3442b095800932529ce1cb5cf48a479563c50)
1*1ca3442bSMatthias Ringwald#!/usr/bin/env python
2*1ca3442bSMatthias Ringwald# BlueKitchen GmbH (c) 2014
3*1ca3442bSMatthias Ringwald
4*1ca3442bSMatthias Ringwald# convert log output to PacketLogger format
5*1ca3442bSMatthias Ringwald# can be viewed with Wireshark
6*1ca3442bSMatthias Ringwald
7*1ca3442bSMatthias Ringwald# APPLE PacketLogger
8*1ca3442bSMatthias Ringwald# typedef struct {
9*1ca3442bSMatthias Ringwald# 	uint32_t	len;
10*1ca3442bSMatthias Ringwald# 	uint32_t	ts_sec;
11*1ca3442bSMatthias Ringwald# 	uint32_t	ts_usec;
12*1ca3442bSMatthias Ringwald# 	uint8_t		type;   // 0xfc for note
13*1ca3442bSMatthias Ringwald# }
14*1ca3442bSMatthias Ringwald
15*1ca3442bSMatthias Ringwaldimport re
16*1ca3442bSMatthias Ringwaldimport sys
17*1ca3442bSMatthias Ringwaldimport time
18*1ca3442bSMatthias Ringwald
19*1ca3442bSMatthias Ringwaldpacket_counter = 0
20*1ca3442bSMatthias Ringwaldlast_time = None
21*1ca3442bSMatthias Ringwald
22*1ca3442bSMatthias Ringwalddef chop(line, prefix):
23*1ca3442bSMatthias Ringwald	if line.startswith(prefix):
24*1ca3442bSMatthias Ringwald		return line[len(prefix):]
25*1ca3442bSMatthias Ringwald	return None
26*1ca3442bSMatthias Ringwald
27*1ca3442bSMatthias Ringwalddef str2hex(value):
28*1ca3442bSMatthias Ringwald	if value:
29*1ca3442bSMatthias Ringwald		return int(value, 16)
30*1ca3442bSMatthias Ringwald	return None
31*1ca3442bSMatthias Ringwald
32*1ca3442bSMatthias Ringwalddef arrayForNet32(value):
33*1ca3442bSMatthias Ringwald	return bytearray([value >> 24, (value >> 16) & 0xff, (value >> 8) & 0xff, value & 0xff])
34*1ca3442bSMatthias Ringwald
35*1ca3442bSMatthias Ringwalddef generateTimestamp(t):
36*1ca3442bSMatthias Ringwald	global last_time
37*1ca3442bSMatthias Ringwald	global packet_counter
38*1ca3442bSMatthias Ringwald
39*1ca3442bSMatthias Ringwald	# use last_time if time missing for this entry
40*1ca3442bSMatthias Ringwald	if not t:
41*1ca3442bSMatthias Ringwald		t = last_time
42*1ca3442bSMatthias Ringwald	if t:
43*1ca3442bSMatthias Ringwald		last_time = t
44*1ca3442bSMatthias Ringwald		# handle ms
45*1ca3442bSMatthias Ringwald		try:
46*1ca3442bSMatthias Ringwald			(t1, t2) = t.split('.')
47*1ca3442bSMatthias Ringwald			if t1 and t2:
48*1ca3442bSMatthias Ringwald				t_obj = time.strptime(t1, "%Y-%m-%d %H:%M:%S")
49*1ca3442bSMatthias Ringwald				tv_sec  = int(time.mktime(t_obj))
50*1ca3442bSMatthias Ringwald				tv_usec = int(t2) * 1000
51*1ca3442bSMatthias Ringwald				return (tv_sec, tv_usec)
52*1ca3442bSMatthias Ringwald		except ValueError:
53*1ca3442bSMatthias Ringwald			# print 'Cannot parse time', t
54*1ca3442bSMatthias Ringwald			pass
55*1ca3442bSMatthias Ringwald	packet_counter += 1
56*1ca3442bSMatthias Ringwald	return (packet_counter, 0)
57*1ca3442bSMatthias Ringwald
58*1ca3442bSMatthias Ringwalddef dumpPacket(fout, timestamp, type, data):
59*1ca3442bSMatthias Ringwald	length = 9 + len(data)
60*1ca3442bSMatthias Ringwald	(tv_sec, tv_usec) = generateTimestamp(timestamp)
61*1ca3442bSMatthias Ringwald	fout.write(arrayForNet32(length))
62*1ca3442bSMatthias Ringwald	fout.write(arrayForNet32(tv_sec))
63*1ca3442bSMatthias Ringwald	fout.write(arrayForNet32(tv_usec))
64*1ca3442bSMatthias Ringwald	fout.write(bytearray([type]))
65*1ca3442bSMatthias Ringwald	fout.write(data)
66*1ca3442bSMatthias Ringwald
67*1ca3442bSMatthias Ringwalddef handleHexPacket(fout, timestamp, type, text):
68*1ca3442bSMatthias Ringwald	try:
69*1ca3442bSMatthias Ringwald		data = bytearray(map(str2hex, text.strip().split()))
70*1ca3442bSMatthias Ringwald		dumpPacket(fout, timestamp, type, data)
71*1ca3442bSMatthias Ringwald	except TypeError:
72*1ca3442bSMatthias Ringwald		print 'Cannot parse hexdump', text.strip()
73*1ca3442bSMatthias Ringwald
74*1ca3442bSMatthias Ringwaldif len(sys.argv) == 1:
75*1ca3442bSMatthias Ringwald	print 'BTstack Console to PacketLogger converter'
76*1ca3442bSMatthias Ringwald	print 'Copyright 2014, BlueKitchen GmbH'
77*1ca3442bSMatthias Ringwald	print ''
78*1ca3442bSMatthias Ringwald	print 'Usage: ', sys.argv[0], 'asci-log-file.txt [hci_dump.pkgl]'
79*1ca3442bSMatthias Ringwald	print 'Converted hci_dump.pklg can be viewed with Wireshark and OS X PacketLogger'
80*1ca3442bSMatthias Ringwald	exit(0)
81*1ca3442bSMatthias Ringwald
82*1ca3442bSMatthias Ringwaldinfile = sys.argv[1]
83*1ca3442bSMatthias Ringwaldoutfile = 'hci_dump.pklg'
84*1ca3442bSMatthias Ringwaldif len(sys.argv) > 2:
85*1ca3442bSMatthias Ringwald	outfile = sys.argv[2]
86*1ca3442bSMatthias Ringwald
87*1ca3442bSMatthias Ringwald# with open(outfile, 'w') as fout:
88*1ca3442bSMatthias Ringwaldwith open (outfile, 'wb') as fout:
89*1ca3442bSMatthias Ringwald	with open (infile, 'rb') as fin:
90*1ca3442bSMatthias Ringwald		packet_counter = 0
91*1ca3442bSMatthias Ringwald		for line in fin:
92*1ca3442bSMatthias Ringwald			# print line
93*1ca3442bSMatthias Ringwald			timestamp = None
94*1ca3442bSMatthias Ringwald			parts = parts = re.match('\[(.*)\] (.*)', line)
95*1ca3442bSMatthias Ringwald			if parts and len(parts.groups()) == 2:
96*1ca3442bSMatthias Ringwald				(timestamp, line) = parts.groups()
97*1ca3442bSMatthias Ringwald			rest = chop(line,'CMD => ')
98*1ca3442bSMatthias Ringwald			if rest:
99*1ca3442bSMatthias Ringwald				handleHexPacket(fout, timestamp, 0, rest)
100*1ca3442bSMatthias Ringwald				continue
101*1ca3442bSMatthias Ringwald			rest = chop(line,'EVT <= ')
102*1ca3442bSMatthias Ringwald			if rest:
103*1ca3442bSMatthias Ringwald				handleHexPacket(fout, timestamp, 1, rest)
104*1ca3442bSMatthias Ringwald				continue
105*1ca3442bSMatthias Ringwald			rest = chop(line,'ACL => ')
106*1ca3442bSMatthias Ringwald			if rest:
107*1ca3442bSMatthias Ringwald				handleHexPacket(fout, timestamp, 2, rest)
108*1ca3442bSMatthias Ringwald				continue
109*1ca3442bSMatthias Ringwald			rest = chop(line,'ACL <= ')
110*1ca3442bSMatthias Ringwald			if rest:
111*1ca3442bSMatthias Ringwald				handleHexPacket(fout, timestamp, 3, rest)
112*1ca3442bSMatthias Ringwald				continue
113*1ca3442bSMatthias Ringwald			rest = chop(line,'LOG -- ')
114*1ca3442bSMatthias Ringwald			if rest:
115*1ca3442bSMatthias Ringwald				line = rest
116*1ca3442bSMatthias Ringwald			dumpPacket(fout, timestamp, 0xfc, line)
117