openpilot is an open source driver assistance system. openpilot performs the functions of Automated Lane Centering and Adaptive Cruise Control for over 200 supported car makes and models.
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.
 
 
 
 
 
 

67 lines
2.3 KiB

import math
from opendbc.can.dbc import DBC, Signal, SignalType
class CANPacker:
def __init__(self, dbc_name: str):
self.dbc = DBC(dbc_name)
self.counters: dict[int, int] = {}
def pack(self, address: int, values: dict[str, float]) -> bytearray:
msg = self.dbc.addr_to_msg.get(address)
if msg is None:
return bytearray()
dat = bytearray(msg.size)
counter_set = False
for name, value in values.items():
sig = msg.sigs.get(name)
if sig is None:
continue
ival = int(math.floor((value - sig.offset) / sig.factor + 0.5))
if ival < 0:
ival = (1 << sig.size) + ival
set_value(dat, sig, ival)
if sig.type == SignalType.COUNTER or sig.name == "COUNTER":
self.counters[address] = int(value)
counter_set = True
sig_counter = next((s for s in msg.sigs.values() if s.type == SignalType.COUNTER or s.name == "COUNTER"), None)
if sig_counter and not counter_set:
if address not in self.counters:
self.counters[address] = 0
set_value(dat, sig_counter, self.counters[address])
self.counters[address] = (self.counters[address] + 1) % (1 << sig_counter.size)
sig_checksum = next((s for s in msg.sigs.values() if s.type > SignalType.COUNTER), None)
if sig_checksum and sig_checksum.calc_checksum:
checksum = sig_checksum.calc_checksum(address, sig_checksum, dat)
set_value(dat, sig_checksum, checksum)
return dat
def make_can_msg(self, name_or_addr, bus: int, values: dict[str, float]):
if isinstance(name_or_addr, int):
addr = name_or_addr
else:
msg = self.dbc.name_to_msg.get(name_or_addr)
if msg is None:
return 0, b'', bus
addr = msg.address
dat = self.pack(addr, values)
if len(dat) == 0:
return 0, b'', bus
return addr, bytes(dat), bus
def set_value(msg: bytearray, sig: Signal, ival: int) -> None:
i = sig.lsb // 8
bits = sig.size
if sig.size < 64:
ival &= (1 << sig.size) - 1
while 0 <= i < len(msg) and bits > 0:
shift = sig.lsb % 8 if (sig.lsb // 8) == i else 0
size = min(bits, 8 - shift)
mask = ((1 << size) - 1) << shift
msg[i] &= ~mask
msg[i] |= (ival & ((1 << size) - 1)) << shift
bits -= size
ival >>= size
i = i + 1 if sig.is_little_endian else i - 1