xref: /btstack/tool/create_packet_log.py (revision ced70f9bfeafe291ec597a3a9cc862e39e0da3ce)
1#!/usr/bin/env python3
2# BlueKitchen GmbH (c) 2014
3
4# convert log output to PacketLogger format
5# can be viewed with Wireshark
6
7# APPLE PacketLogger
8# typedef struct {
9# 	uint32_t	len;
10# 	uint32_t	ts_sec;
11# 	uint32_t	ts_usec;
12# 	uint8_t		type;   // 0xfc for note
13# }
14
15import re
16import sys
17import time
18import os
19
20default_date="2001-01-01"
21default_hours = 12
22packet_counter = 0
23last_time = default_date + " " + str(default_hours) + ":00:00.000"
24
25def chop(line, prefix):
26	if line.startswith(prefix):
27		return line[len(prefix):]
28	return None
29
30def str2hex(value):
31	if value:
32		return int(value, 16)
33	return None
34
35def arrayForNet32(value):
36	return bytearray([value >> 24, (value >> 16) & 0xff, (value >> 8) & 0xff, value & 0xff])
37
38def generateTimestamp(t):
39	global last_time
40	global packet_counter
41
42	# use last_time if time missing for this entry
43	if not t:
44		t = last_time
45	if t:
46		last_time = t
47
48		# check for date
49		parts = t.split(' ')
50		have_date = True
51		if len(parts) == 1:
52			# only time, prepend fixed date
53			have_date = False
54			t = "2000-01-01 " + t;
55
56		# handle ms
57		try:
58			(t1, t2) = t.split('.')
59			if t1 and t2:
60				t_obj   = time.strptime(t1, "%Y-%m-%d %H:%M:%S")
61				tv_sec  = int(time.mktime(t_obj))
62				if not have_date:
63					# start at 12:00
64					tv_sec += 12*60*60
65				tv_usec = int(t2) * 1000
66				return (tv_sec, tv_usec)
67		except ValueError:
68			# print 'Cannot parse time', t
69			pass
70
71	packet_counter += 1
72	return (packet_counter, 0)
73
74def dumpPacket(fout, timestamp, type, data):
75	length = 9 + len(data)
76	(tv_sec, tv_usec) = generateTimestamp(timestamp)
77	fout.write(arrayForNet32(length))
78	fout.write(arrayForNet32(tv_sec))
79	fout.write(arrayForNet32(tv_usec))
80	fout.write(bytearray([type]))
81	fout.write(data)
82
83def handleHexPacket(fout, timestamp, type, text):
84	try:
85		data = bytearray(list(map(str2hex, text.strip().split())))
86		dumpPacket(fout, timestamp, type, data)
87	except TypeError:
88		print('Cannot parse hexdump', text.strip())
89
90if len(sys.argv) == 1:
91	print('BTstack Console to PacketLogger converter')
92	print('Copyright 2014, BlueKitchen GmbH')
93	print('')
94	print('Usage: ', sys.argv[0], 'ascii-log-file.txt [hci_dump.pklg]')
95	print('Converted hci_dump.pklg can be viewed with Wireshark and OS X PacketLogger')
96	exit(0)
97
98infile = sys.argv[1]
99outfile = os.path.splitext(infile)[0] + ".pklg"
100if len(sys.argv) > 2:
101	outfile = sys.argv[2]
102
103# with open(outfile, 'w') as fout:
104with open (outfile, 'wb') as fout:
105	with open (infile, 'rt') as fin:
106		packet_counter = 0
107		line_conter = 0
108		for line in fin:
109			try:
110				# try to deal with windows 16-bit unicode by dropping \0 characters
111				line = ''.join([c for c in line if c != '\0'])
112				# drop Segger RTT console prefix
113				if line.startswith('00> '):
114					line = line[4:]
115				line_conter += 1
116				timestamp = None
117				# strip newlines
118				line = line.strip("\n\r")
119				# skip empty lines
120				if len(line) == 0:
121					continue
122				parts = re.match('\[(.*)\] (.*)', line)
123				if parts and len(parts.groups()) == 2:
124					(timestamp, line) = parts.groups()
125				rest = chop(line,'CMD => ')
126				if rest:
127					handleHexPacket(fout, timestamp, 0, rest)
128					continue
129				rest = chop(line,'EVT <= ')
130				if rest:
131					handleHexPacket(fout, timestamp, 1, rest)
132					continue
133				rest = chop(line,'ACL => ')
134				if rest:
135					handleHexPacket(fout, timestamp, 2, rest)
136					continue
137				rest = chop(line,'ACL <= ')
138				if rest:
139					handleHexPacket(fout, timestamp, 3, rest)
140					continue
141				rest = chop(line,'SCO => ')
142				if rest:
143					handleHexPacket(fout, timestamp, 8, rest)
144					continue
145				rest = chop(line,'SCO <= ')
146				if rest:
147					handleHexPacket(fout, timestamp, 9, rest)
148					continue
149				rest = chop(line,'LOG -- ')
150				if rest:
151					line = rest
152				dumpPacket(fout, timestamp, 0xfc, line.encode('ascii'))
153			except:
154				print("Error in line %u: '%s'" % (line_conter, line))
155
156print("\nPacket Log: %s" % outfile)
157