build message lookup table in DBC (#942)
* build message lookup table in dbc * constify it * no need to make this more dense * Return empty values and log an error for invalid addresses. log error for undefined signal add comment use LOGE * save one map lookup * only try what is to be traught * rename back * from merge * show addr --------- Co-authored-by: Shane Smiskol <shane@smiskol.com>
This commit is contained in:
parent
8c46e7b603
commit
b4842fd3c5
|
@ -93,11 +93,10 @@ class CANPacker {
|
||||||
private:
|
private:
|
||||||
const DBC *dbc = NULL;
|
const DBC *dbc = NULL;
|
||||||
std::map<std::pair<uint32_t, std::string>, Signal> signal_lookup;
|
std::map<std::pair<uint32_t, std::string>, Signal> signal_lookup;
|
||||||
std::map<uint32_t, Msg> message_lookup;
|
|
||||||
std::map<uint32_t, uint32_t> counters;
|
std::map<uint32_t, uint32_t> counters;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CANPacker(const std::string& dbc_name);
|
CANPacker(const std::string& dbc_name);
|
||||||
std::vector<uint8_t> pack(uint32_t address, const std::vector<SignalPackValue> &values);
|
std::vector<uint8_t> pack(uint32_t address, const std::vector<SignalPackValue> &values);
|
||||||
Msg* lookup_message(uint32_t address);
|
const Msg* lookup_message(uint32_t address);
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,6 +6,7 @@ from libcpp cimport bool
|
||||||
from libcpp.pair cimport pair
|
from libcpp.pair cimport pair
|
||||||
from libcpp.string cimport string
|
from libcpp.string cimport string
|
||||||
from libcpp.vector cimport vector
|
from libcpp.vector cimport vector
|
||||||
|
from libcpp.unordered_map cimport unordered_map
|
||||||
|
|
||||||
|
|
||||||
ctypedef unsigned int (*calc_checksum_type)(uint32_t, const Signal&, const vector[uint8_t] &)
|
ctypedef unsigned int (*calc_checksum_type)(uint32_t, const Signal&, const vector[uint8_t] &)
|
||||||
|
@ -48,6 +49,8 @@ cdef extern from "common_dbc.h":
|
||||||
string name
|
string name
|
||||||
vector[Msg] msgs
|
vector[Msg] msgs
|
||||||
vector[Val] vals
|
vector[Val] vals
|
||||||
|
unordered_map[uint32_t, const Msg*] addr_to_msg
|
||||||
|
unordered_map[string, const Msg*] name_to_msg
|
||||||
|
|
||||||
cdef struct SignalValue:
|
cdef struct SignalValue:
|
||||||
uint32_t address
|
uint32_t address
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cstddef>
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
struct SignalPackValue {
|
struct SignalPackValue {
|
||||||
|
@ -59,6 +59,8 @@ struct DBC {
|
||||||
std::string name;
|
std::string name;
|
||||||
std::vector<Msg> msgs;
|
std::vector<Msg> msgs;
|
||||||
std::vector<Val> vals;
|
std::vector<Val> vals;
|
||||||
|
std::unordered_map<uint32_t, const Msg*> addr_to_msg;
|
||||||
|
std::unordered_map<std::string, const Msg*> name_to_msg;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct ChecksumState {
|
typedef struct ChecksumState {
|
||||||
|
|
|
@ -200,6 +200,8 @@ DBC* dbc_parse_from_stream(const std::string &dbc_name, std::istream &stream, Ch
|
||||||
|
|
||||||
for (auto& m : dbc->msgs) {
|
for (auto& m : dbc->msgs) {
|
||||||
m.sigs = signals[m.address];
|
m.sigs = signals[m.address];
|
||||||
|
dbc->addr_to_msg[m.address] = &m;
|
||||||
|
dbc->name_to_msg[m.name] = &m;
|
||||||
}
|
}
|
||||||
for (auto& v : dbc->vals) {
|
for (auto& v : dbc->vals) {
|
||||||
v.sigs = signals[v.address];
|
v.sigs = signals[v.address];
|
||||||
|
|
|
@ -33,7 +33,6 @@ CANPacker::CANPacker(const std::string& dbc_name) {
|
||||||
assert(dbc);
|
assert(dbc);
|
||||||
|
|
||||||
for (const auto& msg : dbc->msgs) {
|
for (const auto& msg : dbc->msgs) {
|
||||||
message_lookup[msg.address] = msg;
|
|
||||||
for (const auto& sig : msg.sigs) {
|
for (const auto& sig : msg.sigs) {
|
||||||
signal_lookup[std::make_pair(msg.address, sig.name)] = sig;
|
signal_lookup[std::make_pair(msg.address, sig.name)] = sig;
|
||||||
}
|
}
|
||||||
|
@ -42,13 +41,13 @@ CANPacker::CANPacker(const std::string& dbc_name) {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<uint8_t> CANPacker::pack(uint32_t address, const std::vector<SignalPackValue> &signals) {
|
std::vector<uint8_t> CANPacker::pack(uint32_t address, const std::vector<SignalPackValue> &signals) {
|
||||||
auto msg_it = message_lookup.find(address);
|
auto msg_it = dbc->addr_to_msg.find(address);
|
||||||
if (msg_it == message_lookup.end()) {
|
if (msg_it == dbc->addr_to_msg.end()) {
|
||||||
LOGE("undefined address %d", address);
|
LOGE("undefined address %d", address);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<uint8_t> ret(msg_it->second.size, 0);
|
std::vector<uint8_t> ret(msg_it->second->size, 0);
|
||||||
|
|
||||||
// set all values for all given signal/value pairs
|
// set all values for all given signal/value pairs
|
||||||
bool counter_set = false;
|
bool counter_set = false;
|
||||||
|
@ -99,6 +98,6 @@ std::vector<uint8_t> CANPacker::pack(uint32_t address, const std::vector<SignalP
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function has a definition in common.h and is used in PlotJuggler
|
// This function has a definition in common.h and is used in PlotJuggler
|
||||||
Msg* CANPacker::lookup_message(uint32_t address) {
|
const Msg* CANPacker::lookup_message(uint32_t address) {
|
||||||
return &message_lookup[address];
|
return dbc->addr_to_msg.at(address);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +1,17 @@
|
||||||
# distutils: language = c++
|
# distutils: language = c++
|
||||||
# cython: c_string_encoding=ascii, language_level=3
|
# cython: c_string_encoding=ascii, language_level=3
|
||||||
|
|
||||||
from libc.stdint cimport uint8_t
|
from libc.stdint cimport uint8_t, uint32_t
|
||||||
from libcpp.vector cimport vector
|
from libcpp.vector cimport vector
|
||||||
from libcpp.map cimport map
|
|
||||||
from libcpp.string cimport string
|
|
||||||
|
|
||||||
from .common cimport CANPacker as cpp_CANPacker
|
from .common cimport CANPacker as cpp_CANPacker
|
||||||
from .common cimport dbc_lookup, SignalPackValue, DBC
|
from .common cimport dbc_lookup, SignalPackValue, DBC, Msg
|
||||||
|
|
||||||
|
|
||||||
cdef class CANPacker:
|
cdef class CANPacker:
|
||||||
cdef:
|
cdef:
|
||||||
cpp_CANPacker *packer
|
cpp_CANPacker *packer
|
||||||
const DBC *dbc
|
const DBC *dbc
|
||||||
map[string, int] name_to_address
|
|
||||||
|
|
||||||
def __init__(self, dbc_name):
|
def __init__(self, dbc_name):
|
||||||
self.dbc = dbc_lookup(dbc_name)
|
self.dbc = dbc_lookup(dbc_name)
|
||||||
|
@ -22,9 +19,6 @@ cdef class CANPacker:
|
||||||
raise RuntimeError(f"Can't lookup {dbc_name}")
|
raise RuntimeError(f"Can't lookup {dbc_name}")
|
||||||
|
|
||||||
self.packer = new cpp_CANPacker(dbc_name)
|
self.packer = new cpp_CANPacker(dbc_name)
|
||||||
for i in range(self.dbc[0].msgs.size()):
|
|
||||||
msg = self.dbc[0].msgs[i]
|
|
||||||
self.name_to_address[string(msg.name)] = msg.address
|
|
||||||
|
|
||||||
def __dealloc__(self):
|
def __dealloc__(self):
|
||||||
if self.packer:
|
if self.packer:
|
||||||
|
@ -43,11 +37,17 @@ cdef class CANPacker:
|
||||||
return self.packer.pack(addr, values_thing)
|
return self.packer.pack(addr, values_thing)
|
||||||
|
|
||||||
cpdef make_can_msg(self, name_or_addr, bus, values):
|
cpdef make_can_msg(self, name_or_addr, bus, values):
|
||||||
cdef int addr
|
cdef uint32_t addr = 0
|
||||||
|
cdef const Msg* m
|
||||||
if isinstance(name_or_addr, int):
|
if isinstance(name_or_addr, int):
|
||||||
addr = name_or_addr
|
addr = name_or_addr
|
||||||
else:
|
else:
|
||||||
addr = self.name_to_address[name_or_addr.encode("utf8")]
|
try:
|
||||||
|
m = self.dbc.name_to_msg.at(name_or_addr.encode("utf8"))
|
||||||
|
addr = m.address
|
||||||
|
except IndexError:
|
||||||
|
# The C++ pack function will log an error message for invalid addresses
|
||||||
|
pass
|
||||||
|
|
||||||
cdef vector[uint8_t] val = self.pack(addr, values)
|
cdef vector[uint8_t] val = self.pack(addr, values)
|
||||||
return [addr, 0, (<char *>&val[0])[:val.size()], bus]
|
return [addr, 0, (<char *>&val[0])[:val.size()], bus]
|
||||||
|
|
|
@ -120,18 +120,7 @@ CANParser::CANParser(int abus, const std::string& dbc_name, const std::vector<st
|
||||||
bus_timeout_threshold = std::min(bus_timeout_threshold, state.check_threshold);
|
bus_timeout_threshold = std::min(bus_timeout_threshold, state.check_threshold);
|
||||||
}
|
}
|
||||||
|
|
||||||
const Msg* msg = NULL;
|
const Msg *msg = dbc->addr_to_msg.at(address);
|
||||||
for (const auto& m : dbc->msgs) {
|
|
||||||
if (m.address == address) {
|
|
||||||
msg = &m;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!msg) {
|
|
||||||
fprintf(stderr, "CANParser: could not find message 0x%X in DBC %s\n", address, dbc_name.c_str());
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
state.name = msg->name;
|
state.name = msg->name;
|
||||||
state.size = msg->size;
|
state.size = msg->size;
|
||||||
assert(state.size <= 64); // max signal size is 64 bytes
|
assert(state.size <= 64); // max signal size is 64 bytes
|
||||||
|
|
|
@ -36,27 +36,21 @@ cdef class CANParser:
|
||||||
self.vl = {}
|
self.vl = {}
|
||||||
self.vl_all = {}
|
self.vl_all = {}
|
||||||
self.ts_nanos = {}
|
self.ts_nanos = {}
|
||||||
msg_name_to_address = {}
|
|
||||||
address_to_msg_name = {}
|
|
||||||
|
|
||||||
for i in range(self.dbc[0].msgs.size()):
|
|
||||||
msg = self.dbc[0].msgs[i]
|
|
||||||
name = msg.name.decode("utf8")
|
|
||||||
|
|
||||||
msg_name_to_address[name] = msg.address
|
|
||||||
address_to_msg_name[msg.address] = name
|
|
||||||
|
|
||||||
# Convert message names into addresses and check existence in DBC
|
# Convert message names into addresses and check existence in DBC
|
||||||
cdef vector[pair[uint32_t, int]] message_v
|
cdef vector[pair[uint32_t, int]] message_v
|
||||||
for i in range(len(messages)):
|
for i in range(len(messages)):
|
||||||
c = messages[i]
|
c = messages[i]
|
||||||
address = c[0] if isinstance(c[0], numbers.Number) else msg_name_to_address.get(c[0])
|
try:
|
||||||
if address not in address_to_msg_name:
|
m = self.dbc.addr_to_msg.at(c[0]) if isinstance(c[0], numbers.Number) else self.dbc.name_to_msg.at(c[0])
|
||||||
|
except IndexError:
|
||||||
raise RuntimeError(f"could not find message {repr(c[0])} in DBC {self.dbc_name}")
|
raise RuntimeError(f"could not find message {repr(c[0])} in DBC {self.dbc_name}")
|
||||||
|
|
||||||
|
address = m.address
|
||||||
message_v.push_back((address, c[1]))
|
message_v.push_back((address, c[1]))
|
||||||
self.addresses.push_back(address)
|
self.addresses.push_back(address)
|
||||||
|
|
||||||
name = address_to_msg_name[address]
|
name = m.name.decode("utf8")
|
||||||
self.vl[address] = {}
|
self.vl[address] = {}
|
||||||
self.vl[name] = self.vl[address]
|
self.vl[name] = self.vl[address]
|
||||||
self.vl_all[address] = defaultdict(list)
|
self.vl_all[address] = defaultdict(list)
|
||||||
|
@ -128,14 +122,6 @@ cdef class CANDefine():
|
||||||
if not self.dbc:
|
if not self.dbc:
|
||||||
raise RuntimeError(f"Can't find DBC: '{dbc_name}'")
|
raise RuntimeError(f"Can't find DBC: '{dbc_name}'")
|
||||||
|
|
||||||
address_to_msg_name = {}
|
|
||||||
|
|
||||||
for i in range(self.dbc[0].msgs.size()):
|
|
||||||
msg = self.dbc[0].msgs[i]
|
|
||||||
name = msg.name.decode("utf8")
|
|
||||||
address = msg.address
|
|
||||||
address_to_msg_name[address] = name
|
|
||||||
|
|
||||||
dv = defaultdict(dict)
|
dv = defaultdict(dict)
|
||||||
|
|
||||||
for i in range(self.dbc[0].vals.size()):
|
for i in range(self.dbc[0].vals.size()):
|
||||||
|
@ -144,7 +130,11 @@ cdef class CANDefine():
|
||||||
sgname = val.name.decode("utf8")
|
sgname = val.name.decode("utf8")
|
||||||
def_val = val.def_val.decode("utf8")
|
def_val = val.def_val.decode("utf8")
|
||||||
address = val.address
|
address = val.address
|
||||||
msgname = address_to_msg_name[address]
|
try:
|
||||||
|
m = self.dbc.addr_to_msg.at(address)
|
||||||
|
except IndexError:
|
||||||
|
raise KeyError(address)
|
||||||
|
msgname = m.name.decode("utf-8")
|
||||||
|
|
||||||
# separate definition/value pairs
|
# separate definition/value pairs
|
||||||
def_val = def_val.split()
|
def_val = def_val.split()
|
||||||
|
|
Loading…
Reference in New Issue