#!/usr/bin/env python3 # BlueKitchen GmbH (c) 2014 # convert log output to PacketLogger format # can be viewed with Wireshark # APPLE PacketLogger # typedef struct { # uint32_t len; # uint32_t ts_sec; # uint32_t ts_usec; # uint8_t type; // 0xfc for note # } import re import sys import time import os default_date="2001-01-01" default_hours = 12 packet_counter = 0 last_time = default_date + " " + str(default_hours) + ":00:00.000" def chop(line, prefix): if line.startswith(prefix): return line[len(prefix):] return None def str2hex(value): if value: return int(value, 16) return None def arrayForNet32(value): return bytearray([value >> 24, (value >> 16) & 0xff, (value >> 8) & 0xff, value & 0xff]) def generateTimestamp(t): global last_time global packet_counter # use last_time if time missing for this entry if not t: t = last_time if t: last_time = t # check for date parts = t.split(' ') have_date = True if len(parts) == 1: # only time, prepend fixed date have_date = False t = "2000-01-01 " + t; # handle ms try: (t1, t2) = t.split('.') if t1 and t2: t_obj = time.strptime(t1, "%Y-%m-%d %H:%M:%S") tv_sec = int(time.mktime(t_obj)) if not have_date: # start at 12:00 tv_sec += 12*60*60 tv_usec = int(t2) * 1000 return (tv_sec, tv_usec) except ValueError: # print 'Cannot parse time', t pass packet_counter += 1 return (packet_counter, 0) def dumpPacket(fout, timestamp, type, data): length = 9 + len(data) (tv_sec, tv_usec) = generateTimestamp(timestamp) fout.write(arrayForNet32(length)) fout.write(arrayForNet32(tv_sec)) fout.write(arrayForNet32(tv_usec)) fout.write(bytearray([type])) fout.write(data) def handleHexPacket(fout, timestamp, type, text): try: data = bytearray(list(map(str2hex, text.strip().split()))) dumpPacket(fout, timestamp, type, data) except TypeError: print('Cannot parse hexdump', text.strip()) if len(sys.argv) == 1: print('BTstack Console to PacketLogger converter') print('Copyright 2014, BlueKitchen GmbH') print('') print('Usage: ', sys.argv[0], 'ascii-log-file.txt [hci_dump.pklg]') print('Converted hci_dump.pklg can be viewed with Wireshark and OS X PacketLogger') exit(0) infile = sys.argv[1] outfile = os.path.splitext(infile)[0] + ".pklg" if len(sys.argv) > 2: outfile = sys.argv[2] # with open(outfile, 'w') as fout: with open (outfile, 'wb') as fout: with open (infile, 'rt') as fin: packet_counter = 0 line_conter = 0 for line in fin: try: # try to deal with windows 16-bit unicode by dropping \0 characters line = ''.join([c for c in line if c != '\0']) # drop Segger RTT console prefix if line.startswith('00> '): line = line[4:] line_conter += 1 timestamp = None # strip newlines line = line.strip("\n\r") # skip empty lines if len(line) == 0: continue parts = re.match('\[(.*)\] (.*)', line) if parts and len(parts.groups()) == 2: (timestamp, line) = parts.groups() rest = chop(line,'CMD => ') if rest: handleHexPacket(fout, timestamp, 0, rest) continue rest = chop(line,'EVT <= ') if rest: handleHexPacket(fout, timestamp, 1, rest) continue rest = chop(line,'ACL => ') if rest: handleHexPacket(fout, timestamp, 2, rest) continue rest = chop(line,'ACL <= ') if rest: handleHexPacket(fout, timestamp, 3, rest) continue rest = chop(line,'SCO => ') if rest: handleHexPacket(fout, timestamp, 8, rest) continue rest = chop(line,'SCO <= ') if rest: handleHexPacket(fout, timestamp, 9, rest) continue rest = chop(line,'ISO => ') if rest: handleHexPacket(fout, timestamp, 0x0c, rest) continue rest = chop(line,'ISO <= ') if rest: handleHexPacket(fout, timestamp, 0x0d, rest) continue rest = chop(line,'LOG -- ') if rest: line = rest dumpPacket(fout, timestamp, 0xfc, line.encode('ascii')) except: print("Error in line %u: '%s'" % (line_conter, line)) print("\nPacket Log: %s" % outfile)