Files
dragonpilot/can/parser.cc
T
Vehicle Researcher e0ab166ed3 Squashed 'opendbc/' changes from a62d5dd84..f1e69a6cf
f1e69a6cf Fix wrong message size in Chrysler
54482cfb0 Fix GM message signal sizes
4e796e06d Fix wrong message sizes in Nissan
fb6c1ee2b Better GEAR signal tracking the gear stick rather than the gear box (#257)
d7a2efbbd Raw angle signal data for easy checksum calc, and one less gear bit (#254)
7456061a7 add checksum check to can parser for subaru
7f3b1774d Chrysler: calculate checksum in can packer/parser (#255)
0c0215516 Rename BYTE_ to SET_ME_X (#253)
1efe437cf Add values for a static 0xe5 (honda bosch) (#250)
7dffe0bd9 Create DBC for HRV (#248)
b69398525 Add LFAHDA message to hyundai
a57e7ddbd CANPacker: Subaru checksum support  (#241)
36c471e59 Fixed signals order and added new signals for subaru global (#221)
7b5a1fcc1 BMW 2008-2013 (#230)
cc09af763 Add RPM signal (#216)
47db9238f Add SWA_01 message detail and CRC support for VW MQB (#236)
c98fe2ab9 Fixed signal unknown1 overlapping the button bits (#239)
572261ee3 Rear Cross Traffic Alert
044730aeb Speed limit signs
87b1a21fb Pedals/gear, gas pedal scale value
ce78044d8 Tracking the steer angle with LKAS signal
7f19ab415 Introduce the new  mazda 3  2019/2020 dbc
e58520619 traffic sign speed limit
00bad5ee7 Speed Auto High Beam Traffic signs
9d080ea42 Nissan leaf (#238)
50fbbe739 nissan x trail cleanup (#237)

git-subtree-dir: opendbc
git-subtree-split: f1e69a6cf91cdaf1b8008d73f6fbb6634fbbeb42
2020-05-09 13:01:32 -07:00

250 lines
6.8 KiB
C++

#include <cassert>
#include <cstring>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <algorithm>
#include "common.h"
#define DEBUG(...)
// #define DEBUG printf
#define INFO printf
bool MessageState::parse(uint64_t sec, uint16_t ts_, uint8_t * dat) {
uint64_t dat_le = read_u64_le(dat);
uint64_t dat_be = read_u64_be(dat);
for (int i=0; i < parse_sigs.size(); i++) {
auto& sig = parse_sigs[i];
int64_t tmp;
if (sig.is_little_endian){
tmp = (dat_le >> sig.b1) & ((1ULL << sig.b2)-1);
} else {
tmp = (dat_be >> sig.bo) & ((1ULL << sig.b2)-1);
}
if (sig.is_signed) {
tmp -= (tmp >> (sig.b2-1)) ? (1ULL << sig.b2) : 0; //signed
}
DEBUG("parse 0x%X %s -> %lld\n", address, sig.name, tmp);
if (sig.type == SignalType::HONDA_CHECKSUM) {
if (honda_checksum(address, dat_be, size) != tmp) {
INFO("0x%X CHECKSUM FAIL\n", address);
return false;
}
} else if (sig.type == SignalType::HONDA_COUNTER) {
if (!update_counter_generic(tmp, sig.b2)) {
return false;
}
} else if (sig.type == SignalType::TOYOTA_CHECKSUM) {
if (toyota_checksum(address, dat_be, size) != tmp) {
INFO("0x%X CHECKSUM FAIL\n", address);
return false;
}
} else if (sig.type == SignalType::VOLKSWAGEN_CHECKSUM) {
if (volkswagen_crc(address, dat_le, size) != tmp) {
INFO("0x%X CRC FAIL\n", address);
return false;
}
} else if (sig.type == SignalType::VOLKSWAGEN_COUNTER) {
if (!update_counter_generic(tmp, sig.b2)) {
return false;
}
} else if (sig.type == SignalType::SUBARU_CHECKSUM) {
if (subaru_checksum(address, dat_be, size) != tmp) {
INFO("0x%X CHECKSUM FAIL\n", address);
return false;
}
} else if (sig.type == SignalType::CHRYSLER_CHECKSUM) {
if (chrysler_checksum(address, dat_le, size) != tmp) {
INFO("0x%X CHECKSUM FAIL\n", address);
return false;
}
} else if (sig.type == SignalType::PEDAL_CHECKSUM) {
if (pedal_checksum(dat_be, size) != tmp) {
INFO("0x%X PEDAL CHECKSUM FAIL\n", address);
return false;
}
} else if (sig.type == SignalType::PEDAL_COUNTER) {
if (!update_counter_generic(tmp, sig.b2)) {
return false;
}
}
vals[i] = tmp * sig.factor + sig.offset;
}
ts = ts_;
seen = sec;
return true;
}
bool MessageState::update_counter_generic(int64_t v, int cnt_size) {
uint8_t old_counter = counter;
counter = v;
if (((old_counter+1) & ((1 << cnt_size) -1)) != v) {
counter_fail += 1;
if (counter_fail > 1) {
INFO("0x%X COUNTER FAIL %d -- %d vs %d\n", address, counter_fail, old_counter, (int)v);
}
if (counter_fail >= MAX_BAD_COUNTER) {
return false;
}
} else if (counter_fail > 0) {
counter_fail--;
}
return true;
}
CANParser::CANParser(int abus, const std::string& dbc_name,
const std::vector<MessageParseOptions> &options,
const std::vector<SignalParseOptions> &sigoptions)
: bus(abus) {
dbc = dbc_lookup(dbc_name);
assert(dbc);
init_crc_lookup_tables();
for (const auto& op : options) {
MessageState state = {
.address = op.address,
// .check_frequency = op.check_frequency,
};
// 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;
}
const Msg* msg = NULL;
for (int i=0; i<dbc->num_msgs; i++) {
if (dbc->msgs[i].address == op.address) {
msg = &dbc->msgs[i];
break;
}
}
if (!msg) {
fprintf(stderr, "CANParser: could not find message 0x%X in DBC %s\n", op.address, dbc_name.c_str());
assert(false);
}
state.size = msg->size;
// track checksums and counters for this message
for (int i=0; i<msg->num_sigs; i++) {
const Signal *sig = &msg->sigs[i];
if (sig->type != SignalType::DEFAULT) {
state.parse_sigs.push_back(*sig);
state.vals.push_back(0);
}
}
// track requested signals for this message
for (const auto& sigop : sigoptions) {
if (sigop.address != op.address) continue;
for (int i=0; i<msg->num_sigs; i++) {
const Signal *sig = &msg->sigs[i];
if (strcmp(sig->name, sigop.name) == 0
&& sig->type == SignalType::DEFAULT) {
state.parse_sigs.push_back(*sig);
state.vals.push_back(sigop.default_value);
break;
}
}
}
message_states[state.address] = state;
}
}
void CANParser::UpdateCans(uint64_t sec, const capnp::List<cereal::CanData>::Reader& cans) {
int msg_count = cans.size();
uint64_t p;
DEBUG("got %d messages\n", msg_count);
// parse the messages
for (int i = 0; i < msg_count; i++) {
auto cmsg = cans[i];
if (cmsg.getSrc() != bus) {
// DEBUG("skip %d: wrong bus\n", cmsg.getAddress());
continue;
}
auto state_it = message_states.find(cmsg.getAddress());
if (state_it == message_states.end()) {
// DEBUG("skip %d: not specified\n", cmsg.getAddress());
continue;
}
if (cmsg.getDat().size() > 8) continue; //shouldnt ever happen
uint8_t dat[8] = {0};
memcpy(dat, cmsg.getDat().begin(), cmsg.getDat().size());
state_it->second.parse(sec, cmsg.getBusTime(), dat);
}
}
void CANParser::UpdateValid(uint64_t sec) {
can_valid = true;
for (const auto& kv : message_states) {
const auto& state = kv.second;
if (state.check_threshold > 0 && (sec - state.seen) > state.check_threshold) {
if (state.seen > 0) {
DEBUG("0x%X TIMEOUT\n", state.address);
}
can_valid = false;
}
}
}
void CANParser::update_string(std::string data, bool sendcan) {
// format for board, make copy due to alignment issues, will be freed on out of scope
auto amsg = kj::heapArray<capnp::word>((data.length() / sizeof(capnp::word)) + 1);
memcpy(amsg.begin(), data.data(), data.length());
// extract the messages
capnp::FlatArrayMessageReader cmsg(amsg);
cereal::Event::Reader event = cmsg.getRoot<cereal::Event>();
last_sec = event.getLogMonoTime();
auto cans = sendcan? event.getSendcan() : event.getCan();
UpdateCans(last_sec, cans);
UpdateValid(last_sec);
}
std::vector<SignalValue> CANParser::query_latest() {
std::vector<SignalValue> ret;
for (const auto& kv : message_states) {
const auto& state = kv.second;
if (last_sec != 0 && state.seen != last_sec) continue;
for (int i=0; i<state.parse_sigs.size(); i++) {
const Signal &sig = state.parse_sigs[i];
ret.push_back((SignalValue){
.address = state.address,
.ts = state.ts,
.name = sig.name,
.value = state.vals[i],
});
}
}
return ret;
}