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