You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
			
				
					92 lines
				
				3.1 KiB
			
		
		
			
		
	
	
					92 lines
				
				3.1 KiB
			| 
								 
											8 years ago
										 
									 | 
							
								#!/usr/bin/env python
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# Given an interesting CSV file of CAN messages and a list of background CAN
							 | 
						||
| 
								 | 
							
								# messages, print which bits in the interesting file have never appeared
							 | 
						||
| 
								 | 
							
								# in the background files.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# Expects the CSV file to be in the format from can_logger.py
							 | 
						||
| 
								 | 
							
								# Bus,MessageID,Message,MessageLength
							 | 
						||
| 
								 | 
							
								# 0,0x292,0x040000001068,6
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# The old can_logger.py format is also supported:
							 | 
						||
| 
								 | 
							
								# Bus,MessageID,Message
							 | 
						||
| 
								 | 
							
								# 0,344,c000c00000000000
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import binascii
							 | 
						||
| 
								 | 
							
								import csv
							 | 
						||
| 
								 | 
							
								import sys
							 | 
						||
| 
								 | 
							
								from panda import Panda
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class Message():
							 | 
						||
| 
								 | 
							
								  """Details about a specific message ID."""
							 | 
						||
| 
								 | 
							
								  def __init__(self, message_id):
							 | 
						||
| 
								 | 
							
								    self.message_id = message_id
							 | 
						||
| 
								 | 
							
								    self.data = {}  # keyed by hex string encoded message data
							 | 
						||
| 
								 | 
							
								    self.ones = [0] * 8   # bit set if 1 is seen
							 | 
						||
| 
								 | 
							
								    self.zeros = [0] * 8  # bit set if 0 has been seen
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  def printBitDiff(self, other):
							 | 
						||
| 
								 | 
							
								    """Prints bits that are set or cleared compared to other background."""
							 | 
						||
| 
								 | 
							
								    for i in xrange(len(self.ones)):
							 | 
						||
| 
								 | 
							
								      new_ones = ((~other.ones[i]) & 0xff) & self.ones[i]
							 | 
						||
| 
								 | 
							
								      if new_ones:
							 | 
						||
| 
								 | 
							
								        print 'id %s new one  at byte %d bitmask %d' % (
							 | 
						||
| 
								 | 
							
								            self.message_id, i, new_ones)
							 | 
						||
| 
								 | 
							
								      new_zeros = ((~other.zeros[i]) & 0xff) & self.zeros[i]
							 | 
						||
| 
								 | 
							
								      if new_zeros:
							 | 
						||
| 
								 | 
							
								        print 'id %s new zero at byte %d bitmask %d' % (
							 | 
						||
| 
								 | 
							
								            self.message_id, i, new_zeros)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class Info():
							 | 
						||
| 
								 | 
							
								  """A collection of Messages."""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  def __init__(self):
							 | 
						||
| 
								 | 
							
								    self.messages = {}  # keyed by MessageID
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  def load(self, filename):
							 | 
						||
| 
								 | 
							
								    """Given a CSV file, adds information about message IDs and their values."""
							 | 
						||
| 
								 | 
							
								    with open(filename, 'rb') as input:
							 | 
						||
| 
								 | 
							
								      reader = csv.reader(input)
							 | 
						||
| 
								 | 
							
								      next(reader, None)  # skip the CSV header
							 | 
						||
| 
								 | 
							
								      for row in reader:
							 | 
						||
| 
								 | 
							
								        if row[1].startswith('0x'):
							 | 
						||
| 
								 | 
							
								          message_id = row[1][2:]  # remove leading '0x'
							 | 
						||
| 
								 | 
							
								        else:
							 | 
						||
| 
								 | 
							
								          message_id = hex(int(row[1]))[2:]  # old message IDs are in decimal
							 | 
						||
| 
								 | 
							
								        if row[1].startswith('0x'):
							 | 
						||
| 
								 | 
							
								          data = row[2][2:]  # remove leading '0x'
							 | 
						||
| 
								 | 
							
								        else:
							 | 
						||
| 
								 | 
							
								          data = row[2]
							 | 
						||
| 
								 | 
							
								        if message_id not in self.messages:
							 | 
						||
| 
								 | 
							
								          self.messages[message_id] = Message(message_id)
							 | 
						||
| 
								 | 
							
								        message = self.messages[message_id]
							 | 
						||
| 
								 | 
							
								        if data not in self.messages[message_id].data:
							 | 
						||
| 
								 | 
							
								          message.data[data] = True
							 | 
						||
| 
								 | 
							
								        bytes = bytearray.fromhex(data)
							 | 
						||
| 
								 | 
							
								        for i in xrange(len(bytes)):
							 | 
						||
| 
								 | 
							
								          message.ones[i] = message.ones[i] | int(bytes[i])
							 | 
						||
| 
								 | 
							
								          # Inverts the data and masks it to a byte to get the zeros as ones.
							 | 
						||
| 
								 | 
							
								          message.zeros[i] = message.zeros[i] | ( (~int(bytes[i])) & 0xff)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def PrintUnique(interesting_file, background_files):
							 | 
						||
| 
								 | 
							
								  background = Info()
							 | 
						||
| 
								 | 
							
								  for background_file in background_files:
							 | 
						||
| 
								 | 
							
								    background.load(background_file)
							 | 
						||
| 
								 | 
							
								  interesting = Info()
							 | 
						||
| 
								 | 
							
								  interesting.load(interesting_file)
							 | 
						||
| 
								 | 
							
								  for message_id in interesting.messages:
							 | 
						||
| 
								 | 
							
								    if message_id not in background.messages:
							 | 
						||
| 
								 | 
							
								      print 'New message_id: %s' % message_id
							 | 
						||
| 
								 | 
							
								    else:
							 | 
						||
| 
								 | 
							
								      interesting.messages[message_id].printBitDiff(
							 | 
						||
| 
								 | 
							
								          background.messages[message_id])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								if __name__ == "__main__":
							 | 
						||
| 
								 | 
							
								  if len(sys.argv) < 3:
							 | 
						||
| 
								 | 
							
								    print 'Usage:\n%s interesting.csv background*.csv' % sys.argv[0]
							 | 
						||
| 
								 | 
							
								    sys.exit(0)
							 | 
						||
| 
								 | 
							
								  PrintUnique(sys.argv[1], sys.argv[2:])
							 |