Files
StarPilot/panda/examples/can_bit_transition.py
T
firestar5683 22a8575199 Vendor dependencies and resources for standalone builds
Keep official openpilot ancestry and dependency licenses. Store resources directly in Git, remove LFS setup requirements, and leave the downloadable big model outside the source tree.
2026-10-03 21:01:18 +00:00

112 lines
3.6 KiB
Python
Executable File

#!/usr/bin/env python3
import csv
import sys
CSV_KEYS = {
"logger": {
"time": "Time",
"message_id": "MessageID",
"data": "Message",
"bus": "Bus"
},
"cabana": {
"time": "time",
"message_id": "addr",
"data": "data",
"bus": "bus"
}
}
class Message():
"""Details about a specific message ID."""
def __init__(self, message_id):
self.message_id = message_id
self.ones = [0] * 64 # bit set if 1 is always seen
self.zeros = [0] * 64 # bit set if 0 is always seen
def printBitDiff(self, other):
"""Prints bits that transition from always zero to always 1 and vice versa."""
for i in range(len(self.ones)):
zero_to_one = other.zeros[i] & self.ones[i]
if zero_to_one:
print('id %s 0 -> 1 at byte %d bitmask %d' % (self.message_id, i, zero_to_one))
one_to_zero = other.ones[i] & self.zeros[i]
if one_to_zero:
print('id %s 1 -> 0 at byte %d bitmask %d' % (self.message_id, i, one_to_zero))
class Info():
"""A collection of Messages."""
def __init__(self):
self.messages = {} # keyed by MessageID
def load(self, filename, start, end):
"""Given a CSV file, adds information about message IDs and their values."""
with open(filename, newline='') as inp:
reader = csv.DictReader(inp)
dtype = None
for row in reader:
if not len(row):
continue
if dtype is None:
dtype = "logger" if "Bus" in row else "cabana"
time = float(row[CSV_KEYS[dtype]["time"]])
bus = int(row[CSV_KEYS[dtype]["bus"]])
if time < start or bus > 127:
continue
elif time > end:
break
message_id = row[CSV_KEYS[dtype]["message_id"]]
if message_id.startswith('0x'):
message_id = message_id[2:] # remove leading '0x'
else:
message_id = hex(int(message_id))[2:] # old message IDs are in decimal
message_id = f'{bus}:{message_id}'
data = row[CSV_KEYS[dtype]["data"]]
if data.startswith('0x'):
data = data[2:] # remove leading '0x'
else:
data = data
new_message = False
if message_id not in self.messages:
self.messages[message_id] = Message(message_id)
new_message = True
message = self.messages[message_id]
bts = bytearray.fromhex(data)
for i in range(len(bts)):
ones = int(bts[i])
message.ones[i] = ones if new_message else message.ones[i] & ones
# Inverts the data and masks it to a byte to get the zeros as ones.
zeros = (~int(bts[i])) & 0xff
message.zeros[i] = zeros if new_message else message.zeros[i] & zeros
def PrintUnique(log_file, low_range, high_range):
# find messages with bits that are always low
start, end = list(map(float, low_range.split('-')))
low = Info()
low.load(log_file, start, end)
# find messages with bits that are always high
start, end = list(map(float, high_range.split('-')))
high = Info()
high.load(log_file, start, end)
# print messages that go from low to high
found = False
for message_id in sorted(high.messages, key=lambda x: int(x.split(':')[1], 16)):
if message_id in low.messages:
high.messages[message_id].printBitDiff(low.messages[message_id])
found = True
if not found:
print('No messages that transition from always low to always high found!')
if __name__ == "__main__":
if len(sys.argv) < 4:
print('Usage:\n%s log.csv <low-start>-<low-end> <high-start>-<high-end>' % sys.argv[0])
sys.exit(0)
PrintUnique(sys.argv[1], sys.argv[2], sys.argv[3])