|
| 1 | +#!/usr/bin/env python |
| 2 | + |
| 3 | +import binascii |
| 4 | +import csv |
| 5 | +import sys |
| 6 | + |
| 7 | +class Message(): |
| 8 | + """Details about a specific message ID.""" |
| 9 | + def __init__(self, message_id): |
| 10 | + self.message_id = message_id |
| 11 | + self.ones = [0] * 8 # bit set if 1 is always seen |
| 12 | + self.zeros = [0] * 8 # bit set if 0 is always seen |
| 13 | + |
| 14 | + def printBitDiff(self, other): |
| 15 | + """Prints bits that transition from always zero to always 1 and vice versa.""" |
| 16 | + for i in xrange(len(self.ones)): |
| 17 | + zero_to_one = other.zeros[i] & self.ones[i] |
| 18 | + if zero_to_one: |
| 19 | + print 'id %s 0 -> 1 at byte %d bitmask %d' % (self.message_id, i, zero_to_one) |
| 20 | + one_to_zero = other.ones[i] & self.zeros[i] |
| 21 | + if one_to_zero: |
| 22 | + print 'id %s 1 -> 0 at byte %d bitmask %d' % (self.message_id, i, one_to_zero) |
| 23 | + |
| 24 | + |
| 25 | +class Info(): |
| 26 | + """A collection of Messages.""" |
| 27 | + |
| 28 | + def __init__(self): |
| 29 | + self.messages = {} # keyed by MessageID |
| 30 | + |
| 31 | + def load(self, filename, start, end): |
| 32 | + """Given a CSV file, adds information about message IDs and their values.""" |
| 33 | + with open(filename, 'rb') as input: |
| 34 | + reader = csv.reader(input) |
| 35 | + next(reader, None) # skip the CSV header |
| 36 | + for row in reader: |
| 37 | + if not len(row): continue |
| 38 | + time = float(row[0]) |
| 39 | + bus = int(row[2]) |
| 40 | + if time < start or bus > 127: |
| 41 | + continue |
| 42 | + elif time > end: |
| 43 | + break |
| 44 | + if row[1].startswith('0x'): |
| 45 | + message_id = row[1][2:] # remove leading '0x' |
| 46 | + else: |
| 47 | + message_id = hex(int(row[1]))[2:] # old message IDs are in decimal |
| 48 | + |
| 49 | + if row[3].startswith('0x'): |
| 50 | + data = row[3][2:] # remove leading '0x' |
| 51 | + else: |
| 52 | + data = row[3] |
| 53 | + new_message = False |
| 54 | + if message_id not in self.messages: |
| 55 | + self.messages[message_id] = Message(message_id) |
| 56 | + new_message = True |
| 57 | + message = self.messages[message_id] |
| 58 | + bytes = bytearray.fromhex(data) |
| 59 | + for i in xrange(len(bytes)): |
| 60 | + ones = int(bytes[i]) |
| 61 | + message.ones[i] = ones if new_message else message.ones[i] & ones |
| 62 | + # Inverts the data and masks it to a byte to get the zeros as ones. |
| 63 | + zeros = (~int(bytes[i])) & 0xff |
| 64 | + message.zeros[i] = zeros if new_message else message.zeros[i] & zeros |
| 65 | + |
| 66 | +def PrintUnique(log_file, low_range, high_range): |
| 67 | + # find messages with bits that are always low |
| 68 | + start, end = map(float, low_range.split('-')) |
| 69 | + low = Info() |
| 70 | + low.load(log_file, start, end) |
| 71 | + # find messages with bits that are always high |
| 72 | + start, end = map(float, high_range.split('-')) |
| 73 | + high = Info() |
| 74 | + high.load(log_file, start, end) |
| 75 | + # print messages that go from low to high |
| 76 | + found = False |
| 77 | + for message_id in high.messages: |
| 78 | + if message_id in low.messages: |
| 79 | + high.messages[message_id].printBitDiff(low.messages[message_id]) |
| 80 | + found = True |
| 81 | + if not found: print 'No messages that transition from always low to always high found!' |
| 82 | + |
| 83 | +if __name__ == "__main__": |
| 84 | + if len(sys.argv) < 4: |
| 85 | + print 'Usage:\n%s log.csv <low-start>-<low-end> <high-start>-<high-end>' % sys.argv[0] |
| 86 | + sys.exit(0) |
| 87 | + PrintUnique(sys.argv[1], sys.argv[2], sys.argv[3]) |
0 commit comments