2019-11-22 21:46:33 -08:00
|
|
|
# distutils: language = c++
|
|
|
|
# cython: c_string_encoding=ascii, language_level=3
|
|
|
|
|
|
|
|
from libcpp.string cimport string
|
|
|
|
from libcpp.vector cimport vector
|
|
|
|
from libcpp.unordered_set cimport unordered_set
|
|
|
|
from libc.stdint cimport uint32_t, uint64_t, uint16_t
|
2020-08-02 13:02:07 -07:00
|
|
|
from libcpp cimport bool
|
2022-02-10 13:01:30 -08:00
|
|
|
from libcpp.map cimport map
|
2019-12-03 09:13:37 -08:00
|
|
|
|
2020-11-26 16:11:23 -08:00
|
|
|
from .common cimport CANParser as cpp_CANParser
|
|
|
|
from .common cimport SignalParseOptions, MessageParseOptions, dbc_lookup, SignalValue, DBC
|
2019-11-22 21:46:33 -08:00
|
|
|
|
|
|
|
import os
|
|
|
|
import numbers
|
2020-08-02 13:02:07 -07:00
|
|
|
from collections import defaultdict
|
2019-11-22 21:46:33 -08:00
|
|
|
|
2022-02-10 13:01:30 -08:00
|
|
|
|
2019-11-22 21:46:33 -08:00
|
|
|
cdef class CANParser:
|
|
|
|
cdef:
|
|
|
|
cpp_CANParser *can
|
|
|
|
const DBC *dbc
|
|
|
|
map[uint32_t, string] address_to_msg_name
|
|
|
|
vector[SignalValue] can_values
|
|
|
|
|
2020-08-02 13:02:07 -07:00
|
|
|
cdef readonly:
|
2019-11-22 21:46:33 -08:00
|
|
|
dict vl
|
2022-02-10 13:01:30 -08:00
|
|
|
dict vl_all
|
2023-02-07 23:00:22 -08:00
|
|
|
dict ts_nanos
|
2022-02-09 22:46:28 -08:00
|
|
|
string dbc_name
|
2019-11-22 21:46:33 -08:00
|
|
|
|
2021-04-24 23:09:56 -07:00
|
|
|
def __init__(self, dbc_name, signals, checks=None, bus=0, enforce_checks=True):
|
2019-11-22 21:46:33 -08:00
|
|
|
if checks is None:
|
|
|
|
checks = []
|
2022-02-09 22:46:28 -08:00
|
|
|
|
2019-11-22 21:46:33 -08:00
|
|
|
self.dbc_name = dbc_name
|
|
|
|
self.dbc = dbc_lookup(dbc_name)
|
2020-09-10 06:01:34 -07:00
|
|
|
if not self.dbc:
|
2021-04-24 23:09:56 -07:00
|
|
|
raise RuntimeError(f"Can't find DBC: {dbc_name}")
|
2019-11-22 21:46:33 -08:00
|
|
|
|
2022-02-09 22:46:28 -08:00
|
|
|
self.vl = {}
|
2022-02-10 13:01:30 -08:00
|
|
|
self.vl_all = {}
|
2023-02-07 23:00:22 -08:00
|
|
|
self.ts_nanos = {}
|
2022-08-08 18:58:35 -07:00
|
|
|
msg_name_to_address = {}
|
2019-11-22 21:46:33 -08:00
|
|
|
|
2022-05-12 17:59:33 -07:00
|
|
|
for i in range(self.dbc[0].msgs.size()):
|
2019-11-22 21:46:33 -08:00
|
|
|
msg = self.dbc[0].msgs[i]
|
|
|
|
name = msg.name.decode('utf8')
|
|
|
|
|
2022-08-08 18:58:35 -07:00
|
|
|
msg_name_to_address[name] = msg.address
|
2019-11-22 21:46:33 -08:00
|
|
|
self.address_to_msg_name[msg.address] = name
|
|
|
|
self.vl[msg.address] = {}
|
2022-02-09 22:46:28 -08:00
|
|
|
self.vl[name] = self.vl[msg.address]
|
2022-02-10 13:01:30 -08:00
|
|
|
self.vl_all[msg.address] = defaultdict(list)
|
|
|
|
self.vl_all[name] = self.vl_all[msg.address]
|
2023-02-07 23:00:22 -08:00
|
|
|
self.ts_nanos[msg.address] = {}
|
|
|
|
self.ts_nanos[name] = self.ts_nanos[msg.address]
|
2019-11-22 21:46:33 -08:00
|
|
|
|
|
|
|
# Convert message names into addresses
|
|
|
|
for i in range(len(signals)):
|
|
|
|
s = signals[i]
|
|
|
|
if not isinstance(s[1], numbers.Number):
|
2022-08-08 18:58:35 -07:00
|
|
|
if name not in msg_name_to_address:
|
2022-08-08 19:08:04 -07:00
|
|
|
print(msg_name_to_address)
|
2022-08-08 18:58:35 -07:00
|
|
|
raise RuntimeError(f"could not find message {repr(name)} in DBC {self.dbc_name}")
|
2022-08-08 19:08:04 -07:00
|
|
|
s = (s[0], msg_name_to_address[s[1]])
|
2019-11-22 21:46:33 -08:00
|
|
|
signals[i] = s
|
|
|
|
|
|
|
|
for i in range(len(checks)):
|
|
|
|
c = checks[i]
|
|
|
|
if not isinstance(c[0], numbers.Number):
|
2022-08-08 19:08:04 -07:00
|
|
|
if c[0] not in msg_name_to_address:
|
|
|
|
print(msg_name_to_address)
|
2022-08-08 18:58:35 -07:00
|
|
|
raise RuntimeError(f"could not find message {repr(name)} in DBC {self.dbc_name}")
|
2022-08-08 19:08:04 -07:00
|
|
|
c = (msg_name_to_address[c[0]], c[1])
|
2019-11-22 21:46:33 -08:00
|
|
|
checks[i] = c
|
|
|
|
|
2021-04-24 23:09:56 -07:00
|
|
|
if enforce_checks:
|
|
|
|
checked_addrs = {c[0] for c in checks}
|
|
|
|
signal_addrs = {s[1] for s in signals}
|
|
|
|
unchecked = signal_addrs - checked_addrs
|
|
|
|
if len(unchecked):
|
|
|
|
err_msg = ', '.join(f"{self.address_to_msg_name[addr].decode()} ({hex(addr)})" for addr in unchecked)
|
|
|
|
raise RuntimeError(f"Unchecked addrs: {err_msg}")
|
|
|
|
|
2019-11-22 21:46:33 -08:00
|
|
|
cdef vector[SignalParseOptions] signal_options_v
|
|
|
|
cdef SignalParseOptions spo
|
2022-01-27 17:02:12 -08:00
|
|
|
for sig_name, sig_address in signals:
|
2019-11-22 21:46:33 -08:00
|
|
|
spo.address = sig_address
|
|
|
|
spo.name = sig_name
|
|
|
|
signal_options_v.push_back(spo)
|
|
|
|
|
2022-01-27 17:02:12 -08:00
|
|
|
message_options = dict((address, 0) for _, address in signals)
|
2019-11-22 21:46:33 -08:00
|
|
|
message_options.update(dict(checks))
|
|
|
|
|
|
|
|
cdef vector[MessageParseOptions] message_options_v
|
|
|
|
cdef MessageParseOptions mpo
|
|
|
|
for msg_address, freq in message_options.items():
|
|
|
|
mpo.address = msg_address
|
|
|
|
mpo.check_frequency = freq
|
|
|
|
message_options_v.push_back(mpo)
|
|
|
|
|
|
|
|
self.can = new cpp_CANParser(bus, dbc_name, message_options_v, signal_options_v)
|
|
|
|
self.update_vl()
|
|
|
|
|
|
|
|
cdef unordered_set[uint32_t] update_vl(self):
|
2022-02-10 13:01:30 -08:00
|
|
|
cdef unordered_set[uint32_t] updated_addrs
|
2019-11-22 21:46:33 -08:00
|
|
|
|
2022-02-10 13:01:30 -08:00
|
|
|
new_vals = self.can.query_latest()
|
|
|
|
for cv in new_vals:
|
2020-09-29 11:59:26 -07:00
|
|
|
# Cast char * directly to unicode
|
2019-11-22 21:46:33 -08:00
|
|
|
cv_name = <unicode>cv.name
|
|
|
|
self.vl[cv.address][cv_name] = cv.value
|
2022-02-10 13:01:30 -08:00
|
|
|
self.vl_all[cv.address][cv_name].extend(cv.all_values)
|
2023-02-07 23:00:22 -08:00
|
|
|
self.ts_nanos[cv.address][cv_name] = cv.ts_nanos
|
2022-02-10 13:01:30 -08:00
|
|
|
updated_addrs.insert(cv.address)
|
2019-11-22 21:46:33 -08:00
|
|
|
|
2022-02-10 13:01:30 -08:00
|
|
|
return updated_addrs
|
2019-11-22 21:46:33 -08:00
|
|
|
|
|
|
|
def update_string(self, dat, sendcan=False):
|
2022-02-10 13:01:30 -08:00
|
|
|
for v in self.vl_all.values():
|
|
|
|
v.clear()
|
|
|
|
|
2019-11-22 21:46:33 -08:00
|
|
|
self.can.update_string(dat, sendcan)
|
|
|
|
return self.update_vl()
|
|
|
|
|
|
|
|
def update_strings(self, strings, sendcan=False):
|
2022-02-10 13:01:30 -08:00
|
|
|
for v in self.vl_all.values():
|
|
|
|
v.clear()
|
2022-02-09 22:01:25 -08:00
|
|
|
|
2022-02-10 13:01:30 -08:00
|
|
|
updated_addrs = set()
|
2019-11-22 21:46:33 -08:00
|
|
|
for s in strings:
|
2022-02-10 14:40:15 -08:00
|
|
|
self.can.update_string(s, sendcan)
|
|
|
|
updated_addrs.update(self.update_vl())
|
2022-02-10 13:01:30 -08:00
|
|
|
return updated_addrs
|
2019-11-22 21:46:33 -08:00
|
|
|
|
2022-08-19 16:19:36 -07:00
|
|
|
@property
|
|
|
|
def can_valid(self):
|
|
|
|
return self.can.can_valid
|
|
|
|
|
|
|
|
@property
|
|
|
|
def bus_timeout(self):
|
|
|
|
return self.can.bus_timeout
|
|
|
|
|
2019-12-03 09:13:37 -08:00
|
|
|
|
|
|
|
cdef class CANDefine():
|
|
|
|
cdef:
|
|
|
|
const DBC *dbc
|
|
|
|
|
|
|
|
cdef public:
|
|
|
|
dict dv
|
|
|
|
string dbc_name
|
|
|
|
|
|
|
|
def __init__(self, dbc_name):
|
|
|
|
self.dbc_name = dbc_name
|
|
|
|
self.dbc = dbc_lookup(dbc_name)
|
2020-09-10 06:01:34 -07:00
|
|
|
if not self.dbc:
|
2021-04-24 23:09:56 -07:00
|
|
|
raise RuntimeError(f"Can't find DBC: '{dbc_name}'")
|
|
|
|
|
2019-12-03 09:13:37 -08:00
|
|
|
address_to_msg_name = {}
|
|
|
|
|
2022-05-12 17:59:33 -07:00
|
|
|
for i in range(self.dbc[0].msgs.size()):
|
2019-12-03 09:13:37 -08:00
|
|
|
msg = self.dbc[0].msgs[i]
|
|
|
|
name = msg.name.decode('utf8')
|
|
|
|
address = msg.address
|
|
|
|
address_to_msg_name[address] = name
|
|
|
|
|
|
|
|
dv = defaultdict(dict)
|
|
|
|
|
2022-05-12 17:59:33 -07:00
|
|
|
for i in range(self.dbc[0].vals.size()):
|
2019-12-03 09:13:37 -08:00
|
|
|
val = self.dbc[0].vals[i]
|
|
|
|
|
|
|
|
sgname = val.name.decode('utf8')
|
|
|
|
def_val = val.def_val.decode('utf8')
|
2021-09-02 13:53:06 -07:00
|
|
|
address = val.address
|
|
|
|
msgname = address_to_msg_name[address]
|
2019-12-03 09:13:37 -08:00
|
|
|
|
2021-09-02 13:53:06 -07:00
|
|
|
# separate definition/value pairs
|
2019-12-03 09:13:37 -08:00
|
|
|
def_val = def_val.split()
|
|
|
|
values = [int(v) for v in def_val[::2]]
|
|
|
|
defs = def_val[1::2]
|
|
|
|
|
|
|
|
# two ways to lookup: address or msg name
|
|
|
|
dv[address][sgname] = dict(zip(values, defs))
|
|
|
|
dv[msgname][sgname] = dv[address][sgname]
|
|
|
|
|
2022-01-24 15:46:00 -08:00
|
|
|
self.dv = dict(dv)
|