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