mirror of https://github.com/rusefi/opendbc.git
CANParser: add flag for bus timeout (#586)
* CANParser: add flag for bus timeout * bump to 500ms * 10x most frequent msg * little test * per bus * Update can/parser.cc
This commit is contained in:
parent
eb56fff37a
commit
004db342a8
|
@ -60,7 +60,10 @@ private:
|
|||
|
||||
public:
|
||||
bool can_valid = false;
|
||||
bool bus_timeout = false;
|
||||
uint64_t last_sec = 0;
|
||||
uint64_t last_nonempty_sec = 0;
|
||||
uint64_t bus_timeout_threshold = 0;
|
||||
|
||||
CANParser(int abus, const std::string& dbc_name,
|
||||
const std::vector<MessageParseOptions> &options,
|
||||
|
|
|
@ -74,6 +74,7 @@ cdef extern from "common.h":
|
|||
|
||||
cdef cppclass CANParser:
|
||||
bool can_valid
|
||||
bool bus_timeout
|
||||
CANParser(int, string, vector[MessageParseOptions], vector[SignalParseOptions])
|
||||
void update_string(string, bool)
|
||||
vector[SignalValue] query_latest()
|
||||
|
|
|
@ -108,6 +108,8 @@ CANParser::CANParser(int abus, const std::string& dbc_name,
|
|||
assert(dbc);
|
||||
init_crc_lookup_tables();
|
||||
|
||||
bus_timeout_threshold = std::numeric_limits<uint64_t>::max();
|
||||
|
||||
for (const auto& op : options) {
|
||||
MessageState &state = message_states[op.address];
|
||||
state.address = op.address;
|
||||
|
@ -116,6 +118,9 @@ CANParser::CANParser(int abus, const std::string& dbc_name,
|
|||
// msg is not valid if a message isn't received for 10 consecutive steps
|
||||
if (op.check_frequency > 0) {
|
||||
state.check_threshold = (1000000000ULL / op.check_frequency) * 10;
|
||||
|
||||
// bus timeout threshold should be 10x the fastest msg
|
||||
bus_timeout_threshold = std::min(bus_timeout_threshold, state.check_threshold);
|
||||
}
|
||||
|
||||
const Msg* msg = NULL;
|
||||
|
@ -213,6 +218,8 @@ void CANParser::update_string(const std::string &data, bool sendcan) {
|
|||
void CANParser::UpdateCans(uint64_t sec, const capnp::List<cereal::CanData>::Reader& cans) {
|
||||
//DEBUG("got %d messages\n", cans.size());
|
||||
|
||||
bool bus_empty = true;
|
||||
|
||||
// parse the messages
|
||||
for (int i = 0; i < cans.size(); i++) {
|
||||
auto cmsg = cans[i];
|
||||
|
@ -220,6 +227,8 @@ void CANParser::UpdateCans(uint64_t sec, const capnp::List<cereal::CanData>::Rea
|
|||
// DEBUG("skip %d: wrong bus\n", cmsg.getAddress());
|
||||
continue;
|
||||
}
|
||||
bus_empty = false;
|
||||
|
||||
auto state_it = message_states.find(cmsg.getAddress());
|
||||
if (state_it == message_states.end()) {
|
||||
// DEBUG("skip %d: not specified\n", cmsg.getAddress());
|
||||
|
@ -243,6 +252,12 @@ void CANParser::UpdateCans(uint64_t sec, const capnp::List<cereal::CanData>::Rea
|
|||
memcpy(data.data(), dat.begin(), dat.size());
|
||||
state_it->second.parse(sec, data);
|
||||
}
|
||||
|
||||
// update bus timeout
|
||||
if (!bus_empty) {
|
||||
last_nonempty_sec = sec;
|
||||
}
|
||||
bus_timeout = (sec - last_nonempty_sec) > bus_timeout_threshold;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ cdef class CANParser:
|
|||
dict vl
|
||||
dict vl_all
|
||||
bool can_valid
|
||||
bool bus_timeout
|
||||
string dbc_name
|
||||
int can_invalid_cnt
|
||||
|
||||
|
@ -111,6 +112,7 @@ cdef class CANParser:
|
|||
if self.can.can_valid:
|
||||
self.can_invalid_cnt = 0
|
||||
self.can_valid = self.can_invalid_cnt < CAN_INVALID_CNT
|
||||
self.bus_timeout = self.can.bus_timeout
|
||||
|
||||
new_vals = self.can.query_latest()
|
||||
for cv in new_vals:
|
||||
|
|
|
@ -7,10 +7,13 @@ from opendbc.can.parser import CANParser
|
|||
from opendbc.can.packer import CANPacker
|
||||
|
||||
# Python implementation so we don't have to depend on boardd
|
||||
def can_list_to_can_capnp(can_msgs, msgtype='can'):
|
||||
def can_list_to_can_capnp(can_msgs, msgtype='can', logMonoTime=None):
|
||||
dat = messaging.new_message()
|
||||
dat.init(msgtype, len(can_msgs))
|
||||
|
||||
if logMonoTime is not None:
|
||||
dat.logMonoTime = logMonoTime
|
||||
|
||||
for i, can_msg in enumerate(can_msgs):
|
||||
if msgtype == 'sendcan':
|
||||
cc = dat.sendcan[i]
|
||||
|
@ -149,6 +152,45 @@ class TestCanParserPacker(unittest.TestCase):
|
|||
|
||||
idx += 1
|
||||
|
||||
def test_bus_timeout(self):
|
||||
"""Test CAN bus timeout detection"""
|
||||
dbc_file = "honda_civic_touring_2016_can_generated"
|
||||
|
||||
freq = 100
|
||||
checks = [("VSA_STATUS", freq), ("STEER_MOTOR_TORQUE", freq/2)]
|
||||
|
||||
parser = CANParser(dbc_file, [], checks, 0)
|
||||
packer = CANPacker(dbc_file)
|
||||
|
||||
i = 0
|
||||
def send_msg(blank=False):
|
||||
nonlocal i
|
||||
i += 1
|
||||
t = i*((1 / freq) * 1e9)
|
||||
|
||||
if blank:
|
||||
msgs = []
|
||||
else:
|
||||
msgs = [packer.make_can_msg("VSA_STATUS", 0, {}), ]
|
||||
|
||||
can = can_list_to_can_capnp(msgs, logMonoTime=t)
|
||||
parser.update_strings([can, ])
|
||||
|
||||
# all good, no timeout
|
||||
for _ in range(1000):
|
||||
send_msg()
|
||||
self.assertFalse(parser.bus_timeout, str(_))
|
||||
|
||||
# timeout after 10 blank msgs
|
||||
for n in range(200):
|
||||
send_msg(blank=True)
|
||||
self.assertEqual(n >= 10, parser.bus_timeout)
|
||||
|
||||
# no timeout immediately after seen again
|
||||
send_msg()
|
||||
self.assertFalse(parser.bus_timeout)
|
||||
|
||||
|
||||
def test_updated(self):
|
||||
"""Test updated value dict"""
|
||||
dbc_file = "honda_civic_touring_2016_can_generated"
|
||||
|
|
Loading…
Reference in New Issue