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