mirror of
https://github.com/dragonpilot/dragonpilot.git
synced 2026-07-07 22:12:05 +08:00
e0ab166ed3
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
250 lines
6.8 KiB
C++
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;
|
|
}
|