Merge opendbc subtree

Vehicle Researcher 2019-12-13 13:02:48 -08:00
commit 261fb00e11
63 changed files with 2723 additions and 217 deletions

8
opendbc/.gitignore vendored
View File

@ -1,2 +1,10 @@
*.pyc
*.os
*.tmp
.*.swp
can/*.so
can/build/
can/obj/
can/packer_pyx.cpp
can/parser_pyx.cpp
can/packer_impl.cpp

25
opendbc/Dockerfile 100644
View File

@ -0,0 +1,25 @@
from ubuntu:16.04
RUN apt-get update && apt-get install -y libzmq3-dev clang wget git autoconf libtool curl make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev llvm libncurses5-dev libncursesw5-dev xz-utils tk-dev libffi-dev liblzma-dev python-openssl
RUN curl -L https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer | bash
ENV PATH="/root/.pyenv/bin:/root/.pyenv/shims:${PATH}"
RUN pyenv install 3.7.3
RUN pyenv global 3.7.3
RUN pyenv rehash
COPY requirements.txt /tmp/
RUN pip install -r /tmp/requirements.txt
ENV PYTHONPATH=/project
# TODO: Add tag to cereal
RUN git clone https://github.com/commaai/cereal.git /project/cereal
RUN /project/cereal/install_capnp.sh
WORKDIR /project
COPY SConstruct .
COPY . /project/opendbc
RUN scons -c && scons -j$(nproc)

View File

@ -42,7 +42,7 @@ For example:
SG_ VEHICLE_SPEED : 7|15@0+ (0.01,0) [0|250] "kph" PCM
```
- Signal's size: always use the smallest amount of bits possible. For example, let's say I'm reverse engineering the gas pedal position and I've determined that it's in a 3 bytes message. For 0% pedal position I read a message value of `0x00 0x00 0x00`, while for 100% of pedal position I read `0x64 0x00 0x00`: clearly, the gas pedal position is within the first byte of the message and I might be tempted to define the signal `GAS_POS` as:
- Signal size: always use the smallest amount of bits possible. For example, let's say I'm reverse engineering the gas pedal position and I've determined that it's in a 3 bytes message. For 0% pedal position I read a message value of `0x00 0x00 0x00`, while for 100% of pedal position I read `0x64 0x00 0x00`: clearly, the gas pedal position is within the first byte of the message and I might be tempted to define the signal `GAS_POS` as:
```
SG_ GAS_POS : 7|8@0+ (1,0) [0|100] "%" PCM
```

57
opendbc/SConstruct 100644
View File

@ -0,0 +1,57 @@
import os
import subprocess
zmq = 'zmq'
arch = subprocess.check_output(["uname", "-m"], encoding='utf8').rstrip()
cereal_dir = Dir('.')
cpppath = [
'#',
'#cereal',
"#cereal/messaging",
"#opendbc/can",
'/usr/lib/include',
]
AddOption('--test',
action='store_true',
help='build test files')
AddOption('--asan',
action='store_true',
help='turn on ASAN')
ccflags_asan = ["-fsanitize=address", "-fno-omit-frame-pointer"] if GetOption('asan') else []
ldflags_asan = ["-fsanitize=address"] if GetOption('asan') else []
env = Environment(
ENV=os.environ,
CC='clang',
CXX='clang++',
CCFLAGS=[
"-g",
"-fPIC",
"-O2",
"-Werror=implicit-function-declaration",
"-Werror=incompatible-pointer-types",
"-Werror=int-conversion",
"-Werror=return-type",
"-Werror=format-extra-args",
] + ccflags_asan,
LDFLAGS=ldflags_asan,
LINKFLAGS=ldflags_asan,
CFLAGS="-std=gnu11",
CXXFLAGS="-std=c++14",
CPPPATH=cpppath,
)
Export('env', 'zmq', 'arch')
cereal = [File('#cereal/libcereal.a')]
messaging = [File('#cereal/libmessaging.a')]
Export('cereal', 'messaging')
SConscript(['cereal/SConscript'])
SConscript(['opendbc/can/SConscript'])

View File

@ -271,8 +271,8 @@ BO_ 342 STEERING_SENSORS: 6 EPS
SG_ CHECKSUM : 43|4@0+ (1,0) [0|3] "" EON
BO_ 399 STEER_STATUS: 7 EPS
SG_ STEER_TORQUE_SENSOR : 7|16@0- (1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_MOTOR : 23|16@0- (1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_SENSOR : 7|16@0- (-1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_MOTOR : 23|16@0- (-1,0) [-31000|31000] "tbd" EON
SG_ STEER_STATUS : 39|4@0+ (1,0) [0|15] "" EON
SG_ STEER_CONTROL_ACTIVE : 35|1@0+ (1,0) [0|1] "" EON
SG_ COUNTER : 53|2@0+ (1,0) [0|3] "" EON

View File

@ -259,8 +259,8 @@ BO_ 392 GEARBOX: 6 XXX
SG_ GEAR : 36|5@0+ (1,0) [0|31] "" EON
BO_ 399 STEER_STATUS: 6 EPS
SG_ STEER_TORQUE_SENSOR : 7|12@0- (1,0) [-2047.5|2047.5] "tbd" EON
SG_ STEER_TORQUE_MOTOR : 23|16@0- (1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_SENSOR : 7|12@0- (-1,0) [-2047.5|2047.5] "tbd" EON
SG_ STEER_TORQUE_MOTOR : 23|16@0- (-1,0) [-31000|31000] "tbd" EON
SG_ STEER_STATUS : 35|4@0+ (1,0) [0|15] "" EON
SG_ STEER_CONTROL_ACTIVE : 36|1@0+ (1,0) [0|1] "" EON
SG_ COUNTER : 45|2@0+ (1,0) [0|3] "" EON

View File

@ -0,0 +1,16 @@
pr: none
pool:
vmImage: 'ubuntu-16.04'
steps:
- script: |
set -e
docker build -t opendbc .
displayName: 'Build'
- script: |
docker run opendbc bash -c "python -m unittest discover opendbc"
displayName: 'Unit tests'
- script: |
docker run opendbc bash -c "cd opendbc/can/tests/linter_python; PYTHONPATH=/ ./flake8_opendbc.sh"
docker run opendbc bash -c "cd opendbc/can/tests/linter_python; PYTHONPATH=/ ./pylint_opendbc.sh"
displayName: 'Python linter'

View File

@ -0,0 +1,27 @@
Import('env', 'cereal')
import os
from opendbc.can.process_dbc import process
dbcs = []
for x in sorted(os.listdir('../')):
if x.endswith(".dbc"):
def compile_dbc(target, source, env):
process(source[0].path, target[0].path)
in_fn = [os.path.join('../', x), 'dbc_template.cc']
out_fn = os.path.join('dbc_out', x.replace(".dbc", ".cc"))
dbc = env.Command(out_fn, in_fn, compile_dbc)
dbcs.append(dbc)
libdbc = env.SharedLibrary('libdbc', ["dbc.cc", "parser.cc", "packer.cc", "common.cc"]+dbcs, LIBS=["capnp", "kj"])
# packer
env.Command(['packer_pyx.so'],
[libdbc, 'packer_pyx.pyx', 'packer_pyx_setup.py'],
"cd opendbc/can && python3 packer_pyx_setup.py build_ext --inplace")
# parser
env.Command(['parser_pyx.so'],
[libdbc, cereal, 'parser_pyx_setup.py', 'parser_pyx.pyx', 'common.pxd'],
"cd opendbc/can && python3 parser_pyx_setup.py build_ext --inplace")

View File

View File

@ -0,0 +1,2 @@
from opendbc.can.parser_pyx import CANDefine # pylint: disable=no-name-in-module, import-error
assert CANDefine

View File

@ -0,0 +1,165 @@
#include "common.h"
unsigned int honda_checksum(unsigned int address, uint64_t d, int l) {
d >>= ((8-l)*8); // remove padding
d >>= 4; // remove checksum
int s = 0;
while (address) { s += (address & 0xF); address >>= 4; }
while (d) { s += (d & 0xF); d >>= 4; }
s = 8-s;
s &= 0xF;
return s;
}
unsigned int toyota_checksum(unsigned int address, uint64_t d, int l) {
d >>= ((8-l)*8); // remove padding
d >>= 8; // remove checksum
unsigned int s = l;
while (address) { s += address & 0xff; address >>= 8; }
while (d) { s += d & 0xff; d >>= 8; }
return s & 0xFF;
}
// Static lookup table for fast computation of CRC8 poly 0x2F, aka 8H2F/AUTOSAR
uint8_t crc8_lut_8h2f[256];
void gen_crc_lookup_table(uint8_t poly, uint8_t crc_lut[]) {
uint8_t crc;
int i, j;
for (i = 0; i < 256; i++) {
crc = i;
for (j = 0; j < 8; j++) {
if ((crc & 0x80) != 0)
crc = (uint8_t)((crc << 1) ^ poly);
else
crc <<= 1;
}
crc_lut[i] = crc;
}
}
void init_crc_lookup_tables() {
// At init time, set up static lookup tables for fast CRC computation.
gen_crc_lookup_table(0x2F, crc8_lut_8h2f); // CRC-8 8H2F/AUTOSAR for Volkswagen
}
unsigned int volkswagen_crc(unsigned int address, uint64_t d, int l) {
// Volkswagen uses standard CRC8 8H2F/AUTOSAR, but they compute it with
// a magic variable padding byte tacked onto the end of the payload.
// https://www.autosar.org/fileadmin/user_upload/standards/classic/4-3/AUTOSAR_SWS_CRCLibrary.pdf
uint8_t *dat = (uint8_t *)&d;
uint8_t crc = 0xFF; // Standard init value for CRC8 8H2F/AUTOSAR
// CRC the payload first, skipping over the first byte where the CRC lives.
for (int i = 1; i < l; i++) {
crc ^= dat[i];
crc = crc8_lut_8h2f[crc];
}
// Look up and apply the magic final CRC padding byte, which permutes by CAN
// address, and additionally (for SOME addresses) by the message counter.
uint8_t counter = dat[1] & 0x0F;
switch(address) {
case 0x86: // LWI_01 Steering Angle
crc ^= (uint8_t[]){0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86}[counter];
break;
case 0x9F: // EPS_01 Electric Power Steering
crc ^= (uint8_t[]){0xF5,0xF5,0xF5,0xF5,0xF5,0xF5,0xF5,0xF5,0xF5,0xF5,0xF5,0xF5,0xF5,0xF5,0xF5,0xF5}[counter];
break;
case 0xAD: // Getriebe_11 Automatic Gearbox
crc ^= (uint8_t[]){0x3F,0x69,0x39,0xDC,0x94,0xF9,0x14,0x64,0xD8,0x6A,0x34,0xCE,0xA2,0x55,0xB5,0x2C}[counter];
break;
case 0xFD: // ESP_21 Electronic Stability Program
crc ^= (uint8_t[]){0xB4,0xEF,0xF8,0x49,0x1E,0xE5,0xC2,0xC0,0x97,0x19,0x3C,0xC9,0xF1,0x98,0xD6,0x61}[counter];
break;
case 0x106: // ESP_05 Electronic Stability Program
crc ^= (uint8_t[]){0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07}[counter];
break;
case 0x117: // ACC_10 Automatic Cruise Control
crc ^= (uint8_t[]){0xAC,0xAC,0xAC,0xAC,0xAC,0xAC,0xAC,0xAC,0xAC,0xAC,0xAC,0xAC,0xAC,0xAC,0xAC,0xAC}[counter];
break;
case 0x122: // ACC_06 Automatic Cruise Control
crc ^= (uint8_t[]){0x37,0x7D,0xF3,0xA9,0x18,0x46,0x6D,0x4D,0x3D,0x71,0x92,0x9C,0xE5,0x32,0x10,0xB9}[counter];
break;
case 0x126: // HCA_01 Heading Control Assist
crc ^= (uint8_t[]){0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA}[counter];
break;
case 0x12B: // GRA_ACC_01 Steering wheel controls for ACC
crc ^= (uint8_t[]){0x6A,0x38,0xB4,0x27,0x22,0xEF,0xE1,0xBB,0xF8,0x80,0x84,0x49,0xC7,0x9E,0x1E,0x2B}[counter];
break;
case 0x187: // EV_Gearshift "Gear" selection data for EVs with no gearbox
crc ^= (uint8_t[]){0x7F,0xED,0x17,0xC2,0x7C,0xEB,0x44,0x21,0x01,0xFA,0xDB,0x15,0x4A,0x6B,0x23,0x05}[counter];
break;
case 0x30C: // ACC_02 Automatic Cruise Control
crc ^= (uint8_t[]){0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F}[counter];
break;
case 0x3C0: // Klemmen_Status_01 ignition and starting status
crc ^= (uint8_t[]){0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3}[counter];
break;
case 0x65D: // ESP_20 Electronic Stability Program
crc ^= (uint8_t[]){0xAC,0xB3,0xAB,0xEB,0x7A,0xE1,0x3B,0xF7,0x73,0xBA,0x7C,0x9E,0x06,0x5F,0x02,0xD9}[counter];
break;
default: // As-yet undefined CAN message, CRC check expected to fail
printf("Attempt to CRC check undefined Volkswagen message 0x%02X\n", address);
crc ^= (uint8_t[]){0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}[counter];
break;
}
crc = crc8_lut_8h2f[crc];
return crc ^ 0xFF; // Return after standard final XOR for CRC8 8H2F/AUTOSAR
}
unsigned int pedal_checksum(uint64_t d, int l) {
uint8_t crc = 0xFF;
uint8_t poly = 0xD5; // standard crc8
d >>= ((8-l)*8); // remove padding
d >>= 8; // remove checksum
uint8_t *dat = (uint8_t *)&d;
int i, j;
for (i = 0; i < l - 1; i++) {
crc ^= dat[i];
for (j = 0; j < 8; j++) {
if ((crc & 0x80) != 0) {
crc = (uint8_t)((crc << 1) ^ poly);
}
else {
crc <<= 1;
}
}
}
return crc;
}
uint64_t read_u64_be(const uint8_t* v) {
return (((uint64_t)v[0] << 56)
| ((uint64_t)v[1] << 48)
| ((uint64_t)v[2] << 40)
| ((uint64_t)v[3] << 32)
| ((uint64_t)v[4] << 24)
| ((uint64_t)v[5] << 16)
| ((uint64_t)v[6] << 8)
| (uint64_t)v[7]);
}
uint64_t read_u64_le(const uint8_t* v) {
return ((uint64_t)v[0]
| ((uint64_t)v[1] << 8)
| ((uint64_t)v[2] << 16)
| ((uint64_t)v[3] << 24)
| ((uint64_t)v[4] << 32)
| ((uint64_t)v[5] << 40)
| ((uint64_t)v[6] << 48)
| ((uint64_t)v[7] << 56));
}

View File

@ -0,0 +1,70 @@
#pragma once
#include <vector>
#include <map>
#include <unordered_map>
#include "common_dbc.h"
#include <capnp/serialize.h>
#include "cereal/gen/cpp/log.capnp.h"
#define MAX_BAD_COUNTER 5
// Helper functions
unsigned int honda_checksum(unsigned int address, uint64_t d, int l);
unsigned int toyota_checksum(unsigned int address, uint64_t d, int l);
void init_crc_lookup_tables();
unsigned int volkswagen_crc(unsigned int address, uint64_t d, int l);
unsigned int pedal_checksum(uint64_t d, int l);
uint64_t read_u64_be(const uint8_t* v);
uint64_t read_u64_le(const uint8_t* v);
class MessageState {
public:
uint32_t address;
unsigned int size;
std::vector<Signal> parse_sigs;
std::vector<double> vals;
uint16_t ts;
uint64_t seen;
uint64_t check_threshold;
uint8_t counter;
uint8_t counter_fail;
bool parse(uint64_t sec, uint16_t ts_, uint8_t * dat);
bool update_counter_generic(int64_t v, int cnt_size);
};
class CANParser {
private:
const int bus;
const DBC *dbc = NULL;
std::unordered_map<uint32_t, MessageState> message_states;
public:
bool can_valid = false;
uint64_t last_sec = 0;
CANParser(int abus, const std::string& dbc_name,
const std::vector<MessageParseOptions> &options,
const std::vector<SignalParseOptions> &sigoptions);
void UpdateCans(uint64_t sec, const capnp::List<cereal::CanData>::Reader& cans);
void UpdateValid(uint64_t sec);
void update_string(std::string data, bool sendcan);
std::vector<SignalValue> query_latest();
};
class CANPacker {
private:
const DBC *dbc = NULL;
std::map<std::pair<uint32_t, std::string>, Signal> signal_lookup;
std::map<uint32_t, Msg> message_lookup;
public:
CANPacker(const std::string& dbc_name);
uint64_t pack(uint32_t address, const std::vector<SignalPackValue> &signals, int counter);
};

View File

@ -0,0 +1,82 @@
# distutils: language = c++
#cython: language_level=3
from libc.stdint cimport uint32_t, uint64_t, uint16_t
from libcpp.vector cimport vector
from libcpp.map cimport map
from libcpp.string cimport string
from libcpp.unordered_set cimport unordered_set
from libcpp cimport bool
cdef extern from "common_dbc.h":
ctypedef enum SignalType:
DEFAULT,
HONDA_CHECKSUM,
HONDA_COUNTER,
TOYOTA_CHECKSUM,
PEDAL_CHECKSUM,
PEDAL_COUNTER,
VOLKSWAGEN_CHECKSUM,
VOLKSWAGEN_COUNTER
cdef struct Signal:
const char* name
int b1, b2, bo
bool is_signed
double factor, offset
SignalType type
cdef struct Msg:
const char* name
uint32_t address
unsigned int size
size_t num_sigs
const Signal *sigs
cdef struct Val:
const char* name
uint32_t address
const char* def_val
const Signal *sigs
cdef struct DBC:
const char* name
size_t num_msgs
const Msg *msgs
const Val *vals
size_t num_vals
cdef struct SignalParseOptions:
uint32_t address
const char* name
double default_value
cdef struct MessageParseOptions:
uint32_t address
int check_frequency
cdef struct SignalValue:
uint32_t address
uint16_t ts
const char* name
double value
cdef struct SignalPackValue:
const char * name
double value
cdef extern from "common.h":
cdef const DBC* dbc_lookup(const string);
cdef cppclass CANParser:
bool can_valid
CANParser(int, string, vector[MessageParseOptions], vector[SignalParseOptions])
void update_string(string, bool)
vector[SignalValue] query_latest()
cdef cppclass CANPacker:
CANPacker(string)
uint64_t pack(uint32_t, vector[SignalPackValue], int counter)

View File

@ -0,0 +1,82 @@
#pragma once
#include <cstddef>
#include <cstdint>
#include <string>
#define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0]))
struct SignalPackValue {
const char* name;
double value;
};
struct SignalParseOptions {
uint32_t address;
const char* name;
double default_value;
};
struct MessageParseOptions {
uint32_t address;
int check_frequency;
};
struct SignalValue {
uint32_t address;
uint16_t ts;
const char* name;
double value;
};
enum SignalType {
DEFAULT,
HONDA_CHECKSUM,
HONDA_COUNTER,
TOYOTA_CHECKSUM,
PEDAL_CHECKSUM,
PEDAL_COUNTER,
VOLKSWAGEN_CHECKSUM,
VOLKSWAGEN_COUNTER,
};
struct Signal {
const char* name;
int b1, b2, bo;
bool is_signed;
double factor, offset;
bool is_little_endian;
SignalType type;
};
struct Msg {
const char* name;
uint32_t address;
unsigned int size;
size_t num_sigs;
const Signal *sigs;
};
struct Val {
const char* name;
uint32_t address;
const char* def_val;
const Signal *sigs;
};
struct DBC {
const char* name;
size_t num_msgs;
const Msg *msgs;
const Val *vals;
size_t num_vals;
};
const DBC* dbc_lookup(const std::string& dbc_name);
void dbc_register(const DBC* dbc);
#define dbc_init(dbc) \
static void __attribute__((constructor)) do_dbc_init_ ## dbc(void) { \
dbc_register(&dbc); \
}

31
opendbc/can/dbc.cc 100644
View File

@ -0,0 +1,31 @@
#include <vector>
#include "common_dbc.h"
namespace {
std::vector<const DBC*>& get_dbcs() {
static std::vector<const DBC*> vec;
return vec;
}
}
const DBC* dbc_lookup(const std::string& dbc_name) {
for (const auto& dbci : get_dbcs()) {
if (dbc_name == dbci->name) {
return dbci;
}
}
return NULL;
}
void dbc_register(const DBC* dbc) {
get_dbcs().push_back(dbc);
}
extern "C" {
const DBC* dbc_lookup(const char* dbc_name) {
return dbc_lookup(std::string(dbc_name));
}
}

275
opendbc/can/dbc.py 100755
View File

@ -0,0 +1,275 @@
import re
import os
import struct
import sys
import numbers
from collections import namedtuple, defaultdict
def int_or_float(s):
# return number, trying to maintain int format
if s.isdigit():
return int(s, 10)
else:
return float(s)
DBCSignal = namedtuple(
"DBCSignal", ["name", "start_bit", "size", "is_little_endian", "is_signed",
"factor", "offset", "tmin", "tmax", "units"])
class dbc():
def __init__(self, fn):
self.name, _ = os.path.splitext(os.path.basename(fn))
with open(fn, encoding="ascii") as f:
self.txt = f.readlines()
self._warned_addresses = set()
# regexps from https://github.com/ebroecker/canmatrix/blob/master/canmatrix/importdbc.py
bo_regexp = re.compile(r"^BO\_ (\w+) (\w+) *: (\w+) (\w+)")
sg_regexp = re.compile(r"^SG\_ (\w+) : (\d+)\|(\d+)@(\d+)([\+|\-]) \(([0-9.+\-eE]+),([0-9.+\-eE]+)\) \[([0-9.+\-eE]+)\|([0-9.+\-eE]+)\] \"(.*)\" (.*)")
sgm_regexp = re.compile(r"^SG\_ (\w+) (\w+) *: (\d+)\|(\d+)@(\d+)([\+|\-]) \(([0-9.+\-eE]+),([0-9.+\-eE]+)\) \[([0-9.+\-eE]+)\|([0-9.+\-eE]+)\] \"(.*)\" (.*)")
val_regexp = re.compile(r"VAL\_ (\w+) (\w+) (\s*[-+]?[0-9]+\s+\".+?\"[^;]*)")
# A dictionary which maps message ids to tuples ((name, size), signals).
# name is the ASCII name of the message.
# size is the size of the message in bytes.
# signals is a list signals contained in the message.
# signals is a list of DBCSignal in order of increasing start_bit.
self.msgs = {}
# A dictionary which maps message ids to a list of tuples (signal name, definition value pairs)
self.def_vals = defaultdict(list)
# lookup to bit reverse each byte
self.bits_index = [(i & ~0b111) + ((-i-1) & 0b111) for i in range(64)]
for l in self.txt:
l = l.strip()
if l.startswith("BO_ "):
# new group
dat = bo_regexp.match(l)
if dat is None:
print("bad BO {0}".format(l))
name = dat.group(2)
size = int(dat.group(3))
ids = int(dat.group(1), 0) # could be hex
if ids in self.msgs:
sys.exit("Duplicate address detected %d %s" % (ids, self.name))
self.msgs[ids] = ((name, size), [])
if l.startswith("SG_ "):
# new signal
dat = sg_regexp.match(l)
go = 0
if dat is None:
dat = sgm_regexp.match(l)
go = 1
if dat is None:
print("bad SG {0}".format(l))
sgname = dat.group(1)
start_bit = int(dat.group(go+2))
signal_size = int(dat.group(go+3))
is_little_endian = int(dat.group(go+4))==1
is_signed = dat.group(go+5)=='-'
factor = int_or_float(dat.group(go+6))
offset = int_or_float(dat.group(go+7))
tmin = int_or_float(dat.group(go+8))
tmax = int_or_float(dat.group(go+9))
units = dat.group(go+10)
self.msgs[ids][1].append(
DBCSignal(sgname, start_bit, signal_size, is_little_endian,
is_signed, factor, offset, tmin, tmax, units))
if l.startswith("VAL_ "):
# new signal value/definition
dat = val_regexp.match(l)
if dat is None:
print("bad VAL {0}".format(l))
ids = int(dat.group(1), 0) # could be hex
sgname = dat.group(2)
defvals = dat.group(3)
defvals = defvals.replace("?",r"\?") #escape sequence in C++
defvals = defvals.split('"')[:-1]
# convert strings to UPPER_CASE_WITH_UNDERSCORES
defvals[1::2] = [d.strip().upper().replace(" ","_") for d in defvals[1::2]]
defvals = '"'+"".join(str(i) for i in defvals)+'"'
self.def_vals[ids].append((sgname, defvals))
for msg in self.msgs.values():
msg[1].sort(key=lambda x: x.start_bit)
self.msg_name_to_address = {}
for address, m in self.msgs.items():
name = m[0][0]
self.msg_name_to_address[name] = address
def lookup_msg_id(self, msg_id):
if not isinstance(msg_id, numbers.Number):
msg_id = self.msg_name_to_address[msg_id]
return msg_id
def reverse_bytes(self, x):
return ((x & 0xff00000000000000) >> 56) | \
((x & 0x00ff000000000000) >> 40) | \
((x & 0x0000ff0000000000) >> 24) | \
((x & 0x000000ff00000000) >> 8) | \
((x & 0x00000000ff000000) << 8) | \
((x & 0x0000000000ff0000) << 24) | \
((x & 0x000000000000ff00) << 40) | \
((x & 0x00000000000000ff) << 56)
def encode(self, msg_id, dd):
"""Encode a CAN message using the dbc.
Inputs:
msg_id: The message ID.
dd: A dictionary mapping signal name to signal data.
"""
msg_id = self.lookup_msg_id(msg_id)
msg_def = self.msgs[msg_id]
size = msg_def[0][1]
result = 0
for s in msg_def[1]:
ival = dd.get(s.name)
if ival is not None:
ival = (ival / s.factor) - s.offset
ival = int(round(ival))
if s.is_signed and ival < 0:
ival = (1 << s.size) + ival
if s.is_little_endian:
shift = s.start_bit
else:
b1 = (s.start_bit // 8) * 8 + (-s.start_bit - 1) % 8
shift = 64 - (b1 + s.size)
mask = ((1 << s.size) - 1) << shift
dat = (ival & ((1 << s.size) - 1)) << shift
if s.is_little_endian:
mask = self.reverse_bytes(mask)
dat = self.reverse_bytes(dat)
result &= ~mask
result |= dat
result = struct.pack('>Q', result)
return result[:size]
def decode(self, x, arr=None, debug=False):
"""Decode a CAN message using the dbc.
Inputs:
x: A collection with elements (address, time, data), where address is
the CAN address, time is the bus time, and data is the CAN data as a
hex string.
arr: Optional list of signals which should be decoded and returned.
debug: True to print debugging statements.
Returns:
A tuple (name, data), where name is the name of the CAN message and data
is the decoded result. If arr is None, data is a dict of properties.
Otherwise data is a list of the same length as arr.
Returns (None, None) if the message could not be decoded.
"""
if arr is None:
out = {}
else:
out = [None]*len(arr)
msg = self.msgs.get(x[0])
if msg is None:
if x[0] not in self._warned_addresses:
#print("WARNING: Unknown message address {}".format(x[0]))
self._warned_addresses.add(x[0])
return None, None
name = msg[0][0]
if debug:
print(name)
st = x[2].ljust(8, b'\x00')
le, be = None, None
for s in msg[1]:
if arr is not None and s[0] not in arr:
continue
start_bit = s[1]
signal_size = s[2]
little_endian = s[3]
signed = s[4]
factor = s[5]
offset = s[6]
if little_endian:
if le is None:
le = struct.unpack("<Q", st)[0]
tmp = le
shift_amount = start_bit
else:
if be is None:
be = struct.unpack(">Q", st)[0]
tmp = be
b1 = (start_bit // 8) * 8 + (-start_bit - 1) % 8
shift_amount = 64 - (b1 + signal_size)
if shift_amount < 0:
continue
tmp = (tmp >> shift_amount) & ((1 << signal_size) - 1)
if signed and (tmp >> (signal_size - 1)):
tmp -= (1 << signal_size)
tmp = tmp * factor + offset
# if debug:
# print("%40s %2d %2d %7.2f %s" % (s[0], s[1], s[2], tmp, s[-1]))
if arr is None:
out[s[0]] = tmp
else:
out[arr.index(s[0])] = tmp
return name, out
def get_signals(self, msg):
msg = self.lookup_msg_id(msg)
return [sgs.name for sgs in self.msgs[msg][1]]
if __name__ == "__main__":
from opendbc import DBC_PATH
dbc_test = dbc(os.path.join(DBC_PATH, 'toyota_prius_2017_pt_generated.dbc'))
msg = ('STEER_ANGLE_SENSOR', {'STEER_ANGLE': -6.0, 'STEER_RATE': 4, 'STEER_FRACTION': -0.2})
encoded = dbc_test.encode(*msg)
decoded = dbc_test.decode((0x25, 0, encoded))
assert decoded == msg
dbc_test = dbc(os.path.join(DBC_PATH, 'hyundai_santa_fe_2019_ccan.dbc'))
decoded = dbc_test.decode((0x2b0, 0, "\xfa\xfe\x00\x07\x12"))
assert abs(decoded[1]['SAS_Angle'] - (-26.2)) < 0.001
msg = ('SAS11', {'SAS_Stat': 7.0, 'MsgCount': 0.0, 'SAS_Angle': -26.200000000000003, 'SAS_Speed': 0.0, 'CheckSum': 0.0})
encoded = dbc_test.encode(*msg)
decoded = dbc_test.decode((0x2b0, 0, encoded))
assert decoded == msg

2
opendbc/can/dbc_out/.gitignore vendored 100644
View File

@ -0,0 +1,2 @@
*.cc

View File

View File

@ -0,0 +1,81 @@
#include "common_dbc.h"
namespace {
{% for address, msg_name, msg_size, sigs in msgs %}
const Signal sigs_{{address}}[] = {
{% for sig in sigs %}
{
{% if sig.is_little_endian %}
{% set b1 = sig.start_bit %}
{% else %}
{% set b1 = (sig.start_bit//8)*8 + (-sig.start_bit-1) % 8 %}
{% endif %}
.name = "{{sig.name}}",
.b1 = {{b1}},
.b2 = {{sig.size}},
.bo = {{64 - (b1 + sig.size)}},
.is_signed = {{"true" if sig.is_signed else "false"}},
.factor = {{sig.factor}},
.offset = {{sig.offset}},
.is_little_endian = {{"true" if sig.is_little_endian else "false"}},
{% if checksum_type == "honda" and sig.name == "CHECKSUM" %}
.type = SignalType::HONDA_CHECKSUM,
{% elif checksum_type == "honda" and sig.name == "COUNTER" %}
.type = SignalType::HONDA_COUNTER,
{% elif checksum_type == "toyota" and sig.name == "CHECKSUM" %}
.type = SignalType::TOYOTA_CHECKSUM,
{% elif checksum_type == "volkswagen" and sig.name == "CHECKSUM" %}
.type = SignalType::VOLKSWAGEN_CHECKSUM,
{% elif checksum_type == "volkswagen" and sig.name == "COUNTER" %}
.type = SignalType::VOLKSWAGEN_COUNTER,
{% elif address in [512, 513] and sig.name == "CHECKSUM_PEDAL" %}
.type = SignalType::PEDAL_CHECKSUM,
{% elif address in [512, 513] and sig.name == "COUNTER_PEDAL" %}
.type = SignalType::PEDAL_COUNTER,
{% else %}
.type = SignalType::DEFAULT,
{% endif %}
},
{% endfor %}
};
{% endfor %}
const Msg msgs[] = {
{% for address, msg_name, msg_size, sigs in msgs %}
{% set address_hex = "0x%X" % address %}
{
.name = "{{msg_name}}",
.address = {{address_hex}},
.size = {{msg_size}},
.num_sigs = ARRAYSIZE(sigs_{{address}}),
.sigs = sigs_{{address}},
},
{% endfor %}
};
const Val vals[] = {
{% for address, sig in def_vals %}
{% for sg_name, def_val in sig %}
{% set address_hex = "0x%X" % address %}
{
.name = "{{sg_name}}",
.address = {{address_hex}},
.def_val = {{def_val}},
.sigs = sigs_{{address}},
},
{% endfor %}
{% endfor %}
};
}
const DBC {{dbc.name}} = {
.name = "{{dbc.name}}",
.num_msgs = ARRAYSIZE(msgs),
.msgs = msgs,
.vals = vals,
.num_vals = ARRAYSIZE(vals),
};
dbc_init({{dbc.name}})

View File

@ -0,0 +1,108 @@
#include <cassert>
#include <utility>
#include <algorithm>
#include <map>
#include <cmath>
#include "common.h"
#define WARN printf
// this is the same as read_u64_le, but uses uint64_t as in/out
uint64_t ReverseBytes(uint64_t x) {
return ((x & 0xff00000000000000ull) >> 56) |
((x & 0x00ff000000000000ull) >> 40) |
((x & 0x0000ff0000000000ull) >> 24) |
((x & 0x000000ff00000000ull) >> 8) |
((x & 0x00000000ff000000ull) << 8) |
((x & 0x0000000000ff0000ull) << 24) |
((x & 0x000000000000ff00ull) << 40) |
((x & 0x00000000000000ffull) << 56);
}
uint64_t set_value(uint64_t ret, Signal sig, int64_t ival){
int shift = sig.is_little_endian? sig.b1 : sig.bo;
uint64_t mask = ((1ULL << sig.b2)-1) << shift;
uint64_t dat = (ival & ((1ULL << sig.b2)-1)) << shift;
if (sig.is_little_endian) {
dat = ReverseBytes(dat);
mask = ReverseBytes(mask);
}
ret &= ~mask;
ret |= dat;
return ret;
}
CANPacker::CANPacker(const std::string& dbc_name) {
dbc = dbc_lookup(dbc_name);
assert(dbc);
for (int i=0; i<dbc->num_msgs; i++) {
const Msg* msg = &dbc->msgs[i];
message_lookup[msg->address] = *msg;
for (int j=0; j<msg->num_sigs; j++) {
const Signal* sig = &msg->sigs[j];
signal_lookup[std::make_pair(msg->address, std::string(sig->name))] = *sig;
}
}
init_crc_lookup_tables();
}
uint64_t CANPacker::pack(uint32_t address, const std::vector<SignalPackValue> &signals, int counter) {
uint64_t ret = 0;
for (const auto& sigval : signals) {
std::string name = std::string(sigval.name);
double value = sigval.value;
auto sig_it = signal_lookup.find(std::make_pair(address, name));
if (sig_it == signal_lookup.end()) {
WARN("undefined signal %s - %d\n", name.c_str(), address);
continue;
}
auto sig = sig_it->second;
int64_t ival = (int64_t)(round((value - sig.offset) / sig.factor));
if (ival < 0) {
ival = (1ULL << sig.b2) + ival;
}
ret = set_value(ret, sig, ival);
}
if (counter >= 0){
auto sig_it = signal_lookup.find(std::make_pair(address, "COUNTER"));
if (sig_it == signal_lookup.end()) {
WARN("COUNTER not defined\n");
return ret;
}
auto sig = sig_it->second;
if ((sig.type != SignalType::HONDA_COUNTER) && (sig.type != SignalType::VOLKSWAGEN_COUNTER)) {
WARN("COUNTER signal type not valid\n");
}
ret = set_value(ret, sig, counter);
}
auto sig_it_checksum = signal_lookup.find(std::make_pair(address, "CHECKSUM"));
if (sig_it_checksum != signal_lookup.end()) {
auto sig = sig_it_checksum->second;
if (sig.type == SignalType::HONDA_CHECKSUM) {
unsigned int chksm = honda_checksum(address, ret, message_lookup[address].size);
ret = set_value(ret, sig, chksm);
} else if (sig.type == SignalType::TOYOTA_CHECKSUM) {
unsigned int chksm = toyota_checksum(address, ret, message_lookup[address].size);
ret = set_value(ret, sig, chksm);
} else if (sig.type == SignalType::VOLKSWAGEN_CHECKSUM) {
// FIXME: Hackish fix for an endianness issue. The message is in reverse byte order
// until later in the pack process. Checksums can be run backwards, CRCs not so much.
// The correct fix is unclear but this works for the moment.
unsigned int chksm = volkswagen_crc(address, ReverseBytes(ret), message_lookup[address].size);
ret = set_value(ret, sig, chksm);
} else {
//WARN("CHECKSUM signal type not valid\n");
}
}
return ret;
}

View File

@ -0,0 +1,3 @@
# pylint: skip-file
from opendbc.can.packer_pyx import CANPacker
assert CANPacker

View File

@ -0,0 +1,67 @@
# distutils: language = c++
# cython: c_string_encoding=ascii, language_level=3
from libc.stdint cimport uint32_t, uint64_t
from libcpp.vector cimport vector
from libcpp.map cimport map
from libcpp.string cimport string
from libcpp cimport bool
from posix.dlfcn cimport dlopen, dlsym, RTLD_LAZY
from common cimport CANPacker as cpp_CANPacker
from common cimport dbc_lookup, SignalPackValue, DBC
cdef class CANPacker:
cdef:
cpp_CANPacker *packer
const DBC *dbc
map[string, (int, int)] name_to_address_and_size
map[int, int] address_to_size
def __init__(self, dbc_name):
self.packer = new cpp_CANPacker(dbc_name)
self.dbc = dbc_lookup(dbc_name)
num_msgs = self.dbc[0].num_msgs
for i in range(num_msgs):
msg = self.dbc[0].msgs[i]
self.name_to_address_and_size[string(msg.name)] = (msg.address, msg.size)
self.address_to_size[msg.address] = msg.size
cdef uint64_t pack(self, addr, values, counter):
cdef vector[SignalPackValue] values_thing
cdef SignalPackValue spv
names = []
for name, value in values.iteritems():
n = name.encode('utf8')
names.append(n) # TODO: find better way to keep reference to temp string arround
spv.name = n
spv.value = value
values_thing.push_back(spv)
return self.packer.pack(addr, values_thing, counter)
cdef inline uint64_t ReverseBytes(self, uint64_t x):
return (((x & 0xff00000000000000ull) >> 56) |
((x & 0x00ff000000000000ull) >> 40) |
((x & 0x0000ff0000000000ull) >> 24) |
((x & 0x000000ff00000000ull) >> 8) |
((x & 0x00000000ff000000ull) << 8) |
((x & 0x0000000000ff0000ull) << 24) |
((x & 0x000000000000ff00ull) << 40) |
((x & 0x00000000000000ffull) << 56))
cpdef make_can_msg(self, name_or_addr, bus, values, counter=-1):
cdef int addr, size
if type(name_or_addr) == int:
addr = name_or_addr
size = self.address_to_size[name_or_addr]
else:
addr, size = self.name_to_address_and_size[name_or_addr.encode('utf8')]
cdef uint64_t val = self.pack(addr, values, counter)
val = self.ReverseBytes(val)
return [addr, 0, (<char *>&val)[:size], bus]

View File

@ -0,0 +1,60 @@
import os
import sysconfig
import subprocess
from distutils.core import Extension, setup # pylint: disable=import-error,no-name-in-module
from Cython.Build import cythonize
from Cython.Distutils import build_ext
BASEDIR = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), "../../"))
def get_ext_filename_without_platform_suffix(filename):
name, ext = os.path.splitext(filename)
ext_suffix = sysconfig.get_config_var('EXT_SUFFIX')
if ext_suffix == ext:
return filename
ext_suffix = ext_suffix.replace(ext, '')
idx = name.find(ext_suffix)
if idx == -1:
return filename
else:
return name[:idx] + ext
class BuildExtWithoutPlatformSuffix(build_ext):
def get_ext_filename(self, ext_name):
filename = super().get_ext_filename(ext_name)
return get_ext_filename_without_platform_suffix(filename)
sourcefiles = ['packer_pyx.pyx']
extra_compile_args = ["-std=c++11"]
ARCH = subprocess.check_output(["uname", "-m"], encoding='utf8').rstrip() # pylint: disable=unexpected-keyword-arg
if ARCH == "aarch64":
extra_compile_args += ["-Wno-deprecated-register"]
setup(name='CAN packer',
cmdclass={'build_ext': BuildExtWithoutPlatformSuffix},
ext_modules=cythonize(
Extension(
"packer_pyx",
language="c++",
sources=sourcefiles,
extra_compile_args=extra_compile_args,
include_dirs=[
BASEDIR,
os.path.join(BASEDIR, 'phonelibs', 'capnp-cpp/include'),
],
extra_link_args=[
os.path.join(BASEDIR, 'opendbc', 'can', 'libdbc.so'),
],
)
),
nthreads=4,
)

View File

@ -0,0 +1,239 @@
#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::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;
}

View File

@ -0,0 +1,2 @@
from opendbc.can.parser_pyx import CANParser # pylint: disable=no-name-in-module, import-error
assert CANParser

View File

@ -0,0 +1,188 @@
# distutils: language = c++
# cython: c_string_encoding=ascii, language_level=3
from libcpp.string cimport string
from libcpp.vector cimport vector
from libcpp cimport bool
from libcpp.unordered_set cimport unordered_set
from libc.stdint cimport uint32_t, uint64_t, uint16_t
from libcpp.map cimport map
from collections import defaultdict
from common cimport CANParser as cpp_CANParser
from common cimport SignalParseOptions, MessageParseOptions, dbc_lookup, SignalValue, DBC
from libcpp cimport bool
import os
import numbers
cdef int CAN_INVALID_CNT = 5
cdef class CANParser:
cdef:
cpp_CANParser *can
const DBC *dbc
map[string, uint32_t] msg_name_to_address
map[uint32_t, string] address_to_msg_name
vector[SignalValue] can_values
bool test_mode_enabled
cdef public:
string dbc_name
dict vl
dict ts
bool can_valid
int can_invalid_cnt
def __init__(self, dbc_name, signals, checks=None, bus=0):
if checks is None:
checks = []
self.can_valid = True
self.dbc_name = dbc_name
self.dbc = dbc_lookup(dbc_name)
self.vl = {}
self.ts = {}
self.can_invalid_cnt = CAN_INVALID_CNT
num_msgs = self.dbc[0].num_msgs
for i in range(num_msgs):
msg = self.dbc[0].msgs[i]
name = msg.name.decode('utf8')
self.msg_name_to_address[name] = msg.address
self.address_to_msg_name[msg.address] = name
self.vl[msg.address] = {}
self.vl[name] = {}
self.ts[msg.address] = {}
self.ts[name] = {}
# Convert message names into addresses
for i in range(len(signals)):
s = signals[i]
if not isinstance(s[1], numbers.Number):
name = s[1].encode('utf8')
s = (s[0], self.msg_name_to_address[name], s[2])
signals[i] = s
for i in range(len(checks)):
c = checks[i]
if not isinstance(c[0], numbers.Number):
name = c[0].encode('utf8')
c = (self.msg_name_to_address[name], c[1])
checks[i] = c
cdef vector[SignalParseOptions] signal_options_v
cdef SignalParseOptions spo
for sig_name, sig_address, sig_default in signals:
spo.address = sig_address
spo.name = sig_name
spo.default_value = sig_default
signal_options_v.push_back(spo)
message_options = dict((address, 0) for _, address, _ in signals)
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):
cdef string sig_name
cdef unordered_set[uint32_t] updated_val
can_values = self.can.query_latest()
valid = self.can.can_valid
# Update invalid flag
self.can_invalid_cnt += 1
if valid:
self.can_invalid_cnt = 0
self.can_valid = self.can_invalid_cnt < CAN_INVALID_CNT
for cv in can_values:
# Cast char * directly to unicde
name = <unicode>self.address_to_msg_name[cv.address].c_str()
cv_name = <unicode>cv.name
self.vl[cv.address][cv_name] = cv.value
self.ts[cv.address][cv_name] = cv.ts
self.vl[name][cv_name] = cv.value
self.ts[name][cv_name] = cv.ts
updated_val.insert(cv.address)
return updated_val
def update_string(self, dat, sendcan=False):
self.can.update_string(dat, sendcan)
return self.update_vl()
def update_strings(self, strings, sendcan=False):
updated_vals = set()
for s in strings:
updated_val = self.update_string(s, sendcan)
updated_vals.update(updated_val)
return updated_vals
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)
num_vals = self.dbc[0].num_vals
address_to_msg_name = {}
num_msgs = self.dbc[0].num_msgs
for i in range(num_msgs):
msg = self.dbc[0].msgs[i]
name = msg.name.decode('utf8')
address = msg.address
address_to_msg_name[address] = name
dv = defaultdict(dict)
for i in range(num_vals):
val = self.dbc[0].vals[i]
sgname = val.name.decode('utf8')
address = val.address
def_val = val.def_val.decode('utf8')
#separate definition/value pairs
def_val = def_val.split()
values = [int(v) for v in def_val[::2]]
defs = def_val[1::2]
if address not in dv:
dv[address] = {}
msgname = address_to_msg_name[address]
dv[msgname] = {}
# two ways to lookup: address or msg name
dv[address][sgname] = dict(zip(values, defs))
dv[msgname][sgname] = dv[address][sgname]
self.dv = dict(dv)

View File

@ -0,0 +1,59 @@
import os
import subprocess
import sysconfig
from distutils.core import Extension, setup # pylint: disable=import-error,no-name-in-module
from Cython.Build import cythonize
from Cython.Distutils import build_ext
BASEDIR = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), "../../"))
def get_ext_filename_without_platform_suffix(filename):
name, ext = os.path.splitext(filename)
ext_suffix = sysconfig.get_config_var('EXT_SUFFIX')
if ext_suffix == ext:
return filename
ext_suffix = ext_suffix.replace(ext, '')
idx = name.find(ext_suffix)
if idx == -1:
return filename
else:
return name[:idx] + ext
class BuildExtWithoutPlatformSuffix(build_ext):
def get_ext_filename(self, ext_name):
filename = super().get_ext_filename(ext_name)
return get_ext_filename_without_platform_suffix(filename)
sourcefiles = ['parser_pyx.pyx']
extra_compile_args = ["-std=c++11"]
ARCH = subprocess.check_output(["uname", "-m"], encoding='utf8').rstrip() # pylint: disable=unexpected-keyword-arg
if ARCH == "aarch64":
extra_compile_args += ["-Wno-deprecated-register"]
setup(name='CAN parser',
cmdclass={'build_ext': BuildExtWithoutPlatformSuffix},
ext_modules=cythonize(
Extension(
"parser_pyx",
language="c++",
sources=sourcefiles,
extra_compile_args=extra_compile_args,
include_dirs=[
BASEDIR,
os.path.join(BASEDIR, 'phonelibs', 'capnp-cpp/include'),
],
extra_link_args=[
os.path.join(BASEDIR, 'opendbc', 'can', 'libdbc.so'),
],
)
),
nthreads=4,
)

View File

@ -0,0 +1,112 @@
#!/usr/bin/env python3
from __future__ import print_function
import os
import sys
import jinja2
from collections import Counter
from opendbc.can.dbc import dbc
def process(in_fn, out_fn):
dbc_name = os.path.split(out_fn)[-1].replace('.cc', '')
#print("processing %s: %s -> %s" % (dbc_name, in_fn, out_fn))
template_fn = os.path.join(os.path.dirname(__file__), "dbc_template.cc")
with open(template_fn, "r") as template_f:
template = jinja2.Template(template_f.read(), trim_blocks=True, lstrip_blocks=True)
can_dbc = dbc(in_fn)
msgs = [(address, msg_name, msg_size, sorted(msg_sigs, key=lambda s: s.name not in ("COUNTER", "CHECKSUM"))) # process counter and checksums first
for address, ((msg_name, msg_size), msg_sigs) in sorted(can_dbc.msgs.items()) if msg_sigs]
def_vals = {a: sorted(set(b)) for a, b in can_dbc.def_vals.items()} # remove duplicates
def_vals = sorted(def_vals.items())
if can_dbc.name.startswith(("honda_", "acura_")):
checksum_type = "honda"
checksum_size = 4
counter_size = 2
checksum_start_bit = 3
counter_start_bit = 5
little_endian = False
elif can_dbc.name.startswith(("toyota_", "lexus_")):
checksum_type = "toyota"
checksum_size = 8
counter_size = None
checksum_start_bit = 7
counter_start_bit = None
little_endian = False
elif can_dbc.name.startswith(("vw_", "volkswagen_", "audi_", "seat_", "skoda_")):
checksum_type = "volkswagen"
checksum_size = 8
counter_size = 4
checksum_start_bit = 0
counter_start_bit = 0
little_endian = True
else:
checksum_type = None
checksum_size = None
counter_size = None
checksum_start_bit = None
counter_start_bit = None
little_endian = None
# sanity checks on expected COUNTER and CHECKSUM rules, as packer and parser auto-compute those signals
for address, msg_name, msg_size, sigs in msgs:
dbc_msg_name = dbc_name + " " + msg_name
for sig in sigs:
if checksum_type is not None:
# checksum rules
if sig.name == "CHECKSUM":
if sig.size != checksum_size:
sys.exit("%s: CHECKSUM is not %d bits long" % (dbc_msg_name, checksum_size))
if sig.start_bit % 8 != checksum_start_bit:
sys.exit("%s: CHECKSUM starts at wrong bit" % dbc_msg_name)
if little_endian != sig.is_little_endian:
sys.exit("%s: CHECKSUM has wrong endianess" % dbc_msg_name)
# counter rules
if sig.name == "COUNTER":
if counter_size is not None and sig.size != counter_size:
sys.exit("%s: COUNTER is not %d bits long" % (dbc_msg_name, counter_size))
if counter_start_bit is not None and sig.start_bit % 8 != counter_start_bit:
print(counter_start_bit, sig.start_bit)
sys.exit("%s: COUNTER starts at wrong bit" % dbc_msg_name)
if little_endian != sig.is_little_endian:
sys.exit("%s: COUNTER has wrong endianess" % dbc_msg_name)
# pedal rules
if address in [0x200, 0x201]:
if sig.name == "COUNTER_PEDAL" and sig.size != 4:
sys.exit("%s: PEDAL COUNTER is not 4 bits long" % dbc_msg_name)
if sig.name == "CHECKSUM_PEDAL" and sig.size != 8:
sys.exit("%s: PEDAL CHECKSUM is not 8 bits long" % dbc_msg_name)
# Fail on duplicate message names
c = Counter([msg_name for address, msg_name, msg_size, sigs in msgs])
for name, count in c.items():
if count > 1:
sys.exit("%s: Duplicate message name in DBC file %s" % (dbc_name, name))
parser_code = template.render(dbc=can_dbc, checksum_type=checksum_type, msgs=msgs, def_vals=def_vals, len=len)
with open(out_fn, "w") as out_f:
out_f.write(parser_code)
def main():
if len(sys.argv) != 3:
print("usage: %s dbc_directory output_filename" % (sys.argv[0],))
sys.exit(0)
dbc_dir = sys.argv[1]
out_fn = sys.argv[2]
dbc_name = os.path.split(out_fn)[-1].replace('.cc', '')
in_fn = os.path.join(dbc_dir, dbc_name + '.dbc')
process(in_fn, out_fn)
if __name__ == '__main__':
main()

1
opendbc/can/tests/.gitignore vendored 100644
View File

@ -0,0 +1 @@
*.bz2

View File

View File

@ -0,0 +1,585 @@
[MASTER]
# A comma-separated list of package or module names from where C extensions may
# be loaded. Extensions are loading into the active Python interpreter and may
# run arbitrary code
extension-pkg-whitelist=scipy
# Add files or directories to the blacklist. They should be base names, not
# paths.
ignore=CVS
# Add files or directories matching the regex patterns to the blacklist. The
# regex matches against base names, not paths.
ignore-patterns=
# Python code to execute, usually for sys.path manipulation such as
# pygtk.require().
#init-hook=
# Use multiple processes to speed up Pylint.
jobs=4
# List of plugins (as comma separated values of python modules names) to load,
# usually to register additional checkers.
load-plugins=
# Pickle collected data for later comparisons.
persistent=yes
# Specify a configuration file.
#rcfile=
# When enabled, pylint would attempt to guess common misconfiguration and emit
# user-friendly hints instead of false-positive error messages
suggestion-mode=yes
# Allow loading of arbitrary C extensions. Extensions are imported into the
# active Python interpreter and may run arbitrary code.
unsafe-load-any-extension=no
[MESSAGES CONTROL]
# Only show warnings with the listed confidence levels. Leave empty to show
# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED
confidence=
# Disable the message, report, category or checker with the given id(s). You
# can either give multiple identifiers separated by comma (,) or put this
# option multiple times (only on the command line, not in the configuration
# file where it should appear only once).You can also use "--disable=all" to
# disable everything first and then reenable specific checks. For example, if
# you want to run only the similarities checker, you can use "--disable=all
# --enable=similarities". If you want to run only the classes checker, but have
# no Warning level messages displayed, use"--disable=all --enable=classes
# --disable=W"
disable=print-statement,
parameter-unpacking,
unpacking-in-except,
old-raise-syntax,
backtick,
long-suffix,
old-ne-operator,
old-octal-literal,
import-star-module-level,
non-ascii-bytes-literal,
raw-checker-failed,
bad-inline-option,
locally-disabled,
locally-enabled,
file-ignored,
suppressed-message,
useless-suppression,
deprecated-pragma,
apply-builtin,
basestring-builtin,
buffer-builtin,
cmp-builtin,
coerce-builtin,
execfile-builtin,
file-builtin,
long-builtin,
raw_input-builtin,
reduce-builtin,
standarderror-builtin,
unicode-builtin,
xrange-builtin,
coerce-method,
delslice-method,
getslice-method,
setslice-method,
no-absolute-import,
old-division,
dict-iter-method,
dict-view-method,
next-method-called,
metaclass-assignment,
indexing-exception,
raising-string,
reload-builtin,
oct-method,
hex-method,
nonzero-method,
cmp-method,
input-builtin,
round-builtin,
intern-builtin,
unichr-builtin,
map-builtin-not-iterating,
zip-builtin-not-iterating,
range-builtin-not-iterating,
filter-builtin-not-iterating,
using-cmp-argument,
eq-without-hash,
div-method,
idiv-method,
rdiv-method,
exception-message-attribute,
invalid-str-codec,
sys-max-int,
bad-python3-import,
deprecated-string-function,
deprecated-str-translate-call,
deprecated-itertools-function,
deprecated-types-field,
next-method-defined,
dict-items-not-iterating,
dict-keys-not-iterating,
dict-values-not-iterating,
bad-indentation,
line-too-long,
missing-docstring,
multiple-statements,
bad-continuation,
invalid-name,
too-many-arguments,
too-many-locals,
superfluous-parens,
bad-whitespace,
too-many-instance-attributes,
wrong-import-position,
ungrouped-imports,
wrong-import-order,
protected-access,
trailing-whitespace,
too-many-branches,
too-few-public-methods,
too-many-statements,
trailing-newlines,
attribute-defined-outside-init,
too-many-return-statements,
too-many-public-methods,
unused-argument,
old-style-class,
no-init,
len-as-condition,
unneeded-not,
no-self-use,
multiple-imports,
no-else-return,
logging-not-lazy,
fixme,
redefined-outer-name,
unused-variable,
unsubscriptable-object,
expression-not-assigned,
too-many-boolean-expressions,
consider-using-ternary,
invalid-unary-operand-type,
relative-import,
deprecated-lambda
# Enable the message, report, category or checker with the given id(s). You can
# either give multiple identifier separated by comma (,) or put this option
# multiple time (only on the command line, not in the configuration file where
# it should appear only once). See also the "--disable" option for examples.
enable=c-extension-no-member
[REPORTS]
# Python expression which should return a note less than 10 (10 is the highest
# note). You have access to the variables errors warning, statement which
# respectively contain the number of errors / warnings messages and the total
# number of statements analyzed. This is used by the global evaluation report
# (RP0004).
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
# Template used to display messages. This is a python new-style format string
# used to format the message information. See doc for all details
#msg-template=
# Set the output format. Available formats are text, parseable, colorized, json
# and msvs (visual studio).You can also give a reporter class, eg
# mypackage.mymodule.MyReporterClass.
output-format=text
# Tells whether to display a full report or only the messages
reports=no
# Activate the evaluation score.
score=yes
[REFACTORING]
# Maximum number of nested blocks for function / method body
max-nested-blocks=5
# Complete name of functions that never returns. When checking for
# inconsistent-return-statements if a never returning function is called then
# it will be considered as an explicit return statement and no message will be
# printed.
never-returning-functions=optparse.Values,sys.exit
[LOGGING]
# Logging modules to check that the string format arguments are in logging
# function parameter format
logging-modules=logging
[SPELLING]
# Limits count of emitted suggestions for spelling mistakes
max-spelling-suggestions=4
# Spelling dictionary name. Available dictionaries: none. To make it working
# install python-enchant package.
spelling-dict=
# List of comma separated words that should not be checked.
spelling-ignore-words=
# A path to a file that contains private dictionary; one word per line.
spelling-private-dict-file=
# Tells whether to store unknown words to indicated private dictionary in
# --spelling-private-dict-file option instead of raising a message.
spelling-store-unknown-words=no
[MISCELLANEOUS]
# List of note tags to take in consideration, separated by a comma.
notes=FIXME,
XXX,
TODO
[SIMILARITIES]
# Ignore comments when computing similarities.
ignore-comments=yes
# Ignore docstrings when computing similarities.
ignore-docstrings=yes
# Ignore imports when computing similarities.
ignore-imports=no
# Minimum lines number of a similarity.
min-similarity-lines=4
[TYPECHECK]
# List of decorators that produce context managers, such as
# contextlib.contextmanager. Add to this list to register other decorators that
# produce valid context managers.
contextmanager-decorators=contextlib.contextmanager
# List of members which are set dynamically and missed by pylint inference
# system, and so shouldn't trigger E1101 when accessed. Python regular
# expressions are accepted.
generated-members=capnp.* cereal.* pygame.* zmq.* setproctitle.* smbus2.* usb1.* serial.* cv2.*
# Tells whether missing members accessed in mixin class should be ignored. A
# mixin class is detected if its name ends with "mixin" (case insensitive).
ignore-mixin-members=yes
# This flag controls whether pylint should warn about no-member and similar
# checks whenever an opaque object is returned when inferring. The inference
# can return multiple potential results while evaluating a Python object, but
# some branches might not be evaluated, which results in partial inference. In
# that case, it might be useful to still emit no-member and other checks for
# the rest of the inferred objects.
ignore-on-opaque-inference=yes
# List of class names for which member attributes should not be checked (useful
# for classes with dynamically set attributes). This supports the use of
# qualified names.
ignored-classes=optparse.Values,thread._local,_thread._local
# List of module names for which member attributes should not be checked
# (useful for modules/projects where namespaces are manipulated during runtime
# and thus existing member attributes cannot be deduced by static analysis. It
# supports qualified module names, as well as Unix pattern matching.
ignored-modules=flask setproctitle usb1 flask.ext.socketio smbus2 usb1.*
# Show a hint with possible names when a member name was not found. The aspect
# of finding the hint is based on edit distance.
missing-member-hint=yes
# The minimum edit distance a name should have in order to be considered a
# similar match for a missing member name.
missing-member-hint-distance=1
# The total number of similar names that should be taken in consideration when
# showing a hint for a missing member.
missing-member-max-choices=1
[VARIABLES]
# List of additional names supposed to be defined in builtins. Remember that
# you should avoid to define new builtins when possible.
additional-builtins=
# Tells whether unused global variables should be treated as a violation.
allow-global-unused-variables=yes
# List of strings which can identify a callback function by name. A callback
# name must start or end with one of those strings.
callbacks=cb_,
_cb
# A regular expression matching the name of dummy variables (i.e. expectedly
# not used).
dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_
# Argument names that match this expression will be ignored. Default to name
# with leading underscore
ignored-argument-names=_.*|^ignored_|^unused_
# Tells whether we should check for unused import in __init__ files.
init-import=no
# List of qualified module names which can have objects that can redefine
# builtins.
redefining-builtins-modules=six.moves,past.builtins,future.builtins
[FORMAT]
# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
expected-line-ending-format=
# Regexp for a line that is allowed to be longer than the limit.
ignore-long-lines=^\s*(# )?<?https?://\S+>?$
# Number of spaces of indent required inside a hanging or continued line.
indent-after-paren=4
# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
# tab).
indent-string=' '
# Maximum number of characters on a single line.
max-line-length=100
# Maximum number of lines in a module
max-module-lines=1000
# List of optional constructs for which whitespace checking is disabled. `dict-
# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}.
# `trailing-comma` allows a space between comma and closing bracket: (a, ).
# `empty-line` allows space-only lines.
no-space-check=trailing-comma,
dict-separator
# Allow the body of a class to be on the same line as the declaration if body
# contains single statement.
single-line-class-stmt=no
# Allow the body of an if to be on the same line as the test if there is no
# else.
single-line-if-stmt=no
[BASIC]
# Naming style matching correct argument names
argument-naming-style=snake_case
# Regular expression matching correct argument names. Overrides argument-
# naming-style
#argument-rgx=
# Naming style matching correct attribute names
attr-naming-style=snake_case
# Regular expression matching correct attribute names. Overrides attr-naming-
# style
#attr-rgx=
# Bad variable names which should always be refused, separated by a comma
bad-names=foo,
bar,
baz,
toto,
tutu,
tata
# Naming style matching correct class attribute names
class-attribute-naming-style=any
# Regular expression matching correct class attribute names. Overrides class-
# attribute-naming-style
#class-attribute-rgx=
# Naming style matching correct class names
class-naming-style=PascalCase
# Regular expression matching correct class names. Overrides class-naming-style
#class-rgx=
# Naming style matching correct constant names
const-naming-style=UPPER_CASE
# Regular expression matching correct constant names. Overrides const-naming-
# style
#const-rgx=
# Minimum line length for functions/classes that require docstrings, shorter
# ones are exempt.
docstring-min-length=-1
# Naming style matching correct function names
function-naming-style=snake_case
# Regular expression matching correct function names. Overrides function-
# naming-style
#function-rgx=
# Good variable names which should always be accepted, separated by a comma
good-names=i,
j,
k,
ex,
Run,
_
# Include a hint for the correct naming format with invalid-name
include-naming-hint=no
# Naming style matching correct inline iteration names
inlinevar-naming-style=any
# Regular expression matching correct inline iteration names. Overrides
# inlinevar-naming-style
#inlinevar-rgx=
# Naming style matching correct method names
method-naming-style=snake_case
# Regular expression matching correct method names. Overrides method-naming-
# style
#method-rgx=
# Naming style matching correct module names
module-naming-style=snake_case
# Regular expression matching correct module names. Overrides module-naming-
# style
#module-rgx=
# Colon-delimited sets of names that determine each other's naming style when
# the name regexes allow several styles.
name-group=
# Regular expression which should only match function or class names that do
# not require a docstring.
no-docstring-rgx=^_
# List of decorators that produce properties, such as abc.abstractproperty. Add
# to this list to register other decorators that produce valid properties.
property-classes=abc.abstractproperty
# Naming style matching correct variable names
variable-naming-style=snake_case
# Regular expression matching correct variable names. Overrides variable-
# naming-style
#variable-rgx=
[DESIGN]
# Maximum number of arguments for function / method
max-args=5
# Maximum number of attributes for a class (see R0902).
max-attributes=7
# Maximum number of boolean expressions in a if statement
max-bool-expr=5
# Maximum number of branch for function / method body
max-branches=12
# Maximum number of locals for function / method body
max-locals=15
# Maximum number of parents for a class (see R0901).
max-parents=7
# Maximum number of public methods for a class (see R0904).
max-public-methods=20
# Maximum number of return / yield for function / method body
max-returns=6
# Maximum number of statements in function / method body
max-statements=50
# Minimum number of public methods for a class (see R0903).
min-public-methods=2
[CLASSES]
# List of method names used to declare (i.e. assign) instance attributes.
defining-attr-methods=__init__,
__new__,
setUp
# List of member names, which should be excluded from the protected access
# warning.
exclude-protected=_asdict,
_fields,
_replace,
_source,
_make
# List of valid names for the first argument in a class method.
valid-classmethod-first-arg=cls
# List of valid names for the first argument in a metaclass class method.
valid-metaclass-classmethod-first-arg=mcs
[IMPORTS]
# Allow wildcard imports from modules that define __all__.
allow-wildcard-with-all=no
# Analyse import fallback blocks. This can be used to support both Python 2 and
# 3 compatible code, which means that the block might have code that exists
# only in one or another interpreter, leading to false positives when analysed.
analyse-fallback-blocks=no
# Deprecated modules which should not be used, separated by a comma
deprecated-modules=regsub,
TERMIOS,
Bastion,
rexec
# Create a graph of external dependencies in the given file (report RP0402 must
# not be disabled)
ext-import-graph=
# Create a graph of every (i.e. internal and external) dependencies in the
# given file (report RP0402 must not be disabled)
import-graph=
# Create a graph of internal dependencies in the given file (report RP0402 must
# not be disabled)
int-import-graph=
# Force import order to recognize a module as part of the standard
# compatibility libraries.
known-standard-library=
# Force import order to recognize a module as part of a third party library.
known-third-party=enchant
[EXCEPTIONS]
# Exceptions that will emit a warning when being caught. Defaults to
# "Exception"
overgeneral-exceptions=Exception

View File

@ -0,0 +1,8 @@
#!/usr/bin/env bash
RESULT=$(python3 -m flake8 --select=F $(find ../../../ -type f | grep "\.py$"))
if [[ $RESULT ]]; then
echo "Pyflakes found errors in the code. Please fix and try again"
echo "$RESULT"
exit 1
fi

View File

@ -0,0 +1,11 @@
#!/usr/bin/env bash
python3 -m pylint --disable=R,C,W $(find ../../../ -type f | grep "\.py$")
exit_status=$?
(( res = exit_status & 3 ))
if [[ $res != 0 ]]; then
echo "Pylint found errors in the code. Please fix and try again"
exit 1
fi

View File

@ -0,0 +1,27 @@
#!/usr/bin/env python3
import unittest
from opendbc.can.can_define import CANDefine
class TestCADNDefine(unittest.TestCase):
def test_civic(self):
dbc_file = "honda_civic_touring_2016_can_generated"
defs = CANDefine(dbc_file)
self.assertDictEqual(defs.dv[399], defs.dv['STEER_STATUS'])
self.assertDictEqual(defs.dv[399],
{'STEER_STATUS':
{6: 'TMP_FAULT',
5: 'FAULT_1',
4: 'NO_TORQUE_ALERT_2',
3: 'LOW_SPEED_LOCKOUT',
2: 'NO_TORQUE_ALERT_1',
0: 'NORMAL'}
}
)
if __name__ == "__main__":
unittest.main()

View File

@ -0,0 +1,105 @@
#!/usr/bin/env python3
import unittest
from opendbc.can.parser import CANParser
from opendbc.can.packer import CANPacker
import cereal.messaging as messaging
# Python implementation so we don't have to depend on boardd
def can_list_to_can_capnp(can_msgs, msgtype='can'):
dat = messaging.new_message()
dat.init(msgtype, len(can_msgs))
for i, can_msg in enumerate(can_msgs):
if msgtype == 'sendcan':
cc = dat.sendcan[i]
else:
cc = dat.can[i]
cc.address = can_msg[0]
cc.busTime = can_msg[1]
cc.dat = bytes(can_msg[2])
cc.src = can_msg[3]
return dat.to_bytes()
class TestCanParserPacker(unittest.TestCase):
def test_civic(self):
dbc_file = "honda_civic_touring_2016_can_generated"
signals = [
("STEER_TORQUE", "STEERING_CONTROL", 0),
("STEER_TORQUE_REQUEST", "STEERING_CONTROL", 0),
]
checks = []
parser = CANParser(dbc_file, signals, checks, 0)
packer = CANPacker(dbc_file)
idx = 0
for steer in range(-256, 255):
for active in [1, 0]:
values = {
"STEER_TORQUE": steer,
"STEER_TORQUE_REQUEST": active,
}
msgs = packer.make_can_msg("STEERING_CONTROL", 0, values, idx)
bts = can_list_to_can_capnp([msgs])
parser.update_string(bts)
self.assertAlmostEqual(parser.vl["STEERING_CONTROL"]["STEER_TORQUE"], steer)
self.assertAlmostEqual(parser.vl["STEERING_CONTROL"]["STEER_TORQUE_REQUEST"], active)
self.assertAlmostEqual(parser.vl["STEERING_CONTROL"]["COUNTER"], idx % 4)
idx += 1
def test_subaru(self):
# Subuaru is little endian
dbc_file = "subaru_global_2017"
signals = [
("Counter", "ES_LKAS", 0),
("LKAS_Output", "ES_LKAS", 0),
("LKAS_Request", "ES_LKAS", 0),
("SET_1", "ES_LKAS", 0),
]
checks = []
parser = CANParser(dbc_file, signals, checks, 0)
packer = CANPacker(dbc_file)
idx = 0
for steer in range(-256, 255):
for active in [1, 0]:
values = {
"Counter": idx,
"LKAS_Output": steer,
"LKAS_Request": active,
"SET_1": 1
}
msgs = packer.make_can_msg("ES_LKAS", 0, values)
bts = can_list_to_can_capnp([msgs])
parser.update_string(bts)
self.assertAlmostEqual(parser.vl["ES_LKAS"]["LKAS_Output"], steer)
self.assertAlmostEqual(parser.vl["ES_LKAS"]["LKAS_Request"], active)
self.assertAlmostEqual(parser.vl["ES_LKAS"]["SET_1"], 1)
self.assertAlmostEqual(parser.vl["ES_LKAS"]["Counter"], idx % 16)
idx += 1
if __name__ == "__main__":
unittest.main()

View File

@ -91,8 +91,8 @@ BO_ 380 POWERTRAIN_DATA: 8 PCM
SG_ CHECKSUM : 59|4@0+ (1,0) [0|15] "" EON
BO_ 399 STEER_STATUS: 7 EPS
SG_ STEER_TORQUE_SENSOR : 7|16@0- (1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_MOTOR : 23|16@0- (1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_SENSOR : 7|16@0- (-1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_MOTOR : 23|16@0- (-1,0) [-31000|31000] "tbd" EON
SG_ STEER_STATUS : 39|4@0+ (1,0) [0|15] "" EON
SG_ STEER_CONTROL_ACTIVE : 35|1@0+ (1,0) [0|1] "" EON
SG_ COUNTER : 53|2@0+ (1,0) [0|3] "" EON

View File

@ -26,8 +26,8 @@ BO_ 342 STEERING_SENSORS: 6 EPS
SG_ CHECKSUM : 43|4@0+ (1,0) [0|3] "" EON
BO_ 399 STEER_STATUS: 7 EPS
SG_ STEER_TORQUE_SENSOR : 7|16@0- (1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_MOTOR : 23|16@0- (1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_SENSOR : 7|16@0- (-1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_MOTOR : 23|16@0- (-1,0) [-31000|31000] "tbd" EON
SG_ STEER_STATUS : 39|4@0+ (1,0) [0|15] "" EON
SG_ STEER_CONTROL_ACTIVE : 35|1@0+ (1,0) [0|1] "" EON
SG_ COUNTER : 53|2@0+ (1,0) [0|3] "" EON

View File

@ -14,8 +14,8 @@ BO_ 392 GEARBOX: 6 XXX
SG_ GEAR : 36|5@0+ (1,0) [0|31] "" EON
BO_ 399 STEER_STATUS: 6 EPS
SG_ STEER_TORQUE_SENSOR : 7|12@0- (1,0) [-2047.5|2047.5] "tbd" EON
SG_ STEER_TORQUE_MOTOR : 23|16@0- (1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_SENSOR : 7|12@0- (-1,0) [-2047.5|2047.5] "tbd" EON
SG_ STEER_TORQUE_MOTOR : 23|16@0- (-1,0) [-31000|31000] "tbd" EON
SG_ STEER_STATUS : 35|4@0+ (1,0) [0|15] "" EON
SG_ STEER_CONTROL_ACTIVE : 36|1@0+ (1,0) [0|1] "" EON
SG_ COUNTER : 45|2@0+ (1,0) [0|3] "" EON

View File

@ -31,8 +31,8 @@ BO_ 330 STEERING_SENSORS: 8 EPS
SG_ CHECKSUM : 59|4@0+ (1,0) [0|3] "" EON
BO_ 399 STEER_STATUS: 7 EPS
SG_ STEER_TORQUE_SENSOR : 7|16@0- (1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_MOTOR : 23|16@0- (1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_SENSOR : 7|16@0- (-1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_MOTOR : 23|16@0- (-1,0) [-31000|31000] "tbd" EON
SG_ STEER_STATUS : 39|4@0+ (1,0) [0|15] "" EON
SG_ STEER_CONTROL_ACTIVE : 35|1@0+ (1,0) [0|1] "" EON
SG_ COUNTER : 53|2@0+ (1,0) [0|3] "" EON

View File

@ -8,8 +8,8 @@ BO_ 342 STEERING_SENSORS: 6 EPS
SG_ CHECKSUM : 43|4@0+ (1,0) [0|15] "" EON
BO_ 399 STEER_STATUS: 6 EPS
SG_ STEER_TORQUE_SENSOR : 7|12@0- (1,0) [-2047.5|2047.5] "tbd" EON
SG_ STEER_TORQUE_MOTOR : 23|16@0- (1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_SENSOR : 7|12@0- (-1,0) [-2047.5|2047.5] "tbd" EON
SG_ STEER_TORQUE_MOTOR : 23|16@0- (-1,0) [-31000|31000] "tbd" EON
SG_ STEER_CONTROL_ACTIVE : 36|1@0+ (1,0) [0|1] "" EON
SG_ STEER_STATUS : 35|4@0+ (1,0) [0|15] "" EON
SG_ COUNTER : 45|2@0+ (1,0) [0|3] "" EON

View File

@ -26,8 +26,8 @@ BO_ 342 STEERING_SENSORS: 6 EPS
SG_ CHECKSUM : 43|4@0+ (1,0) [0|3] "" EON
BO_ 399 STEER_STATUS: 7 EPS
SG_ STEER_TORQUE_SENSOR : 7|16@0- (1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_MOTOR : 23|16@0- (1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_SENSOR : 7|16@0- (-1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_MOTOR : 23|16@0- (-1,0) [-31000|31000] "tbd" EON
SG_ STEER_STATUS : 39|4@0+ (1,0) [0|15] "" EON
SG_ STEER_CONTROL_ACTIVE : 35|1@0+ (1,0) [0|1] "" EON
SG_ COUNTER : 53|2@0+ (1,0) [0|3] "" EON

View File

@ -26,8 +26,8 @@ BO_ 342 STEERING_SENSORS: 6 EPS
SG_ CHECKSUM : 43|4@0+ (1,0) [0|3] "" EON
BO_ 399 STEER_STATUS: 7 EPS
SG_ STEER_TORQUE_SENSOR : 7|16@0- (1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_MOTOR : 23|16@0- (1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_SENSOR : 7|16@0- (-1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_MOTOR : 23|16@0- (-1,0) [-31000|31000] "tbd" EON
SG_ STEER_STATUS : 39|4@0+ (1,0) [0|15] "" EON
SG_ STEER_CONTROL_ACTIVE : 35|1@0+ (1,0) [0|1] "" EON
SG_ COUNTER : 53|2@0+ (1,0) [0|3] "" EON

View File

@ -18,8 +18,8 @@ BO_ 342 STEERING_SENSORS: 6 EPS
SG_ CHECKSUM : 43|4@0+ (1,0) [0|3] "" EON
BO_ 399 STEER_STATUS: 7 EPS
SG_ STEER_TORQUE_SENSOR : 7|16@0- (1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_MOTOR : 23|16@0- (1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_SENSOR : 7|16@0- (-1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_MOTOR : 23|16@0- (-1,0) [-31000|31000] "tbd" EON
SG_ STEER_STATUS : 39|4@0+ (1,0) [0|15] "" EON
SG_ STEER_CONTROL_ACTIVE : 35|1@0+ (1,0) [0|1] "" EON
SG_ COUNTER : 53|2@0+ (1,0) [0|3] "" EON

View File

@ -11,8 +11,8 @@ BO_ 342 STEERING_SENSORS: 6 EPS
SG_ STEER_ANGLE : 7|16@0- (-0.1,0) [-500|500] "deg" EON
BO_ 399 STEER_STATUS: 7 EPS
SG_ STEER_TORQUE_SENSOR : 7|16@0- (1,0) [-2985|2985] "tbd" EON
SG_ STEER_TORQUE_MOTOR : 23|16@0- (1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_SENSOR : 7|16@0- (-1,0) [-2985|2985] "tbd" EON
SG_ STEER_TORQUE_MOTOR : 23|16@0- (-1,0) [-31000|31000] "tbd" EON
SG_ CHECKSUM : 51|4@0+ (1,0) [0|15] "" EON
SG_ COUNTER : 53|2@0+ (1,0) [0|3] "" EON
SG_ STEER_STATUS : 43|4@0+ (1,0) [0|15] "" EON

View File

@ -26,8 +26,8 @@ BO_ 342 STEERING_SENSORS: 6 EPS
SG_ CHECKSUM : 43|4@0+ (1,0) [0|3] "" EON
BO_ 399 STEER_STATUS: 7 EPS
SG_ STEER_TORQUE_SENSOR : 7|16@0- (1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_MOTOR : 23|16@0- (1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_SENSOR : 7|16@0- (-1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_MOTOR : 23|16@0- (-1,0) [-31000|31000] "tbd" EON
SG_ STEER_STATUS : 39|4@0+ (1,0) [0|15] "" EON
SG_ STEER_CONTROL_ACTIVE : 35|1@0+ (1,0) [0|1] "" EON
SG_ COUNTER : 53|2@0+ (1,0) [0|3] "" EON

View File

@ -21,8 +21,8 @@ BO_ 342 STEERING_SENSORS: 6 EPS
SG_ CHECKSUM : 43|4@0+ (1,0) [0|3] "" EON
BO_ 399 STEER_STATUS: 7 EPS
SG_ STEER_TORQUE_SENSOR : 7|16@0- (1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_MOTOR : 23|16@0- (1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_SENSOR : 7|16@0- (-1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_MOTOR : 23|16@0- (-1,0) [-31000|31000] "tbd" EON
SG_ STEER_STATUS : 39|4@0+ (1,0) [0|15] "" EON
SG_ STEER_CONTROL_ACTIVE : 35|1@0+ (1,0) [0|1] "" EON
SG_ COUNTER : 53|2@0+ (1,0) [0|3] "" EON

View File

@ -95,8 +95,8 @@ BO_ 380 POWERTRAIN_DATA: 8 PCM
SG_ CHECKSUM : 59|4@0+ (1,0) [0|15] "" EON
BO_ 399 STEER_STATUS: 7 EPS
SG_ STEER_TORQUE_SENSOR : 7|16@0- (1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_MOTOR : 23|16@0- (1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_SENSOR : 7|16@0- (-1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_MOTOR : 23|16@0- (-1,0) [-31000|31000] "tbd" EON
SG_ STEER_STATUS : 39|4@0+ (1,0) [0|15] "" EON
SG_ STEER_CONTROL_ACTIVE : 35|1@0+ (1,0) [0|1] "" EON
SG_ COUNTER : 53|2@0+ (1,0) [0|3] "" EON

View File

@ -95,8 +95,8 @@ BO_ 380 POWERTRAIN_DATA: 8 PCM
SG_ CHECKSUM : 59|4@0+ (1,0) [0|15] "" EON
BO_ 399 STEER_STATUS: 7 EPS
SG_ STEER_TORQUE_SENSOR : 7|16@0- (1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_MOTOR : 23|16@0- (1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_SENSOR : 7|16@0- (-1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_MOTOR : 23|16@0- (-1,0) [-31000|31000] "tbd" EON
SG_ STEER_STATUS : 39|4@0+ (1,0) [0|15] "" EON
SG_ STEER_CONTROL_ACTIVE : 35|1@0+ (1,0) [0|1] "" EON
SG_ COUNTER : 53|2@0+ (1,0) [0|3] "" EON

View File

@ -95,8 +95,8 @@ BO_ 380 POWERTRAIN_DATA: 8 PCM
SG_ CHECKSUM : 59|4@0+ (1,0) [0|15] "" EON
BO_ 399 STEER_STATUS: 7 EPS
SG_ STEER_TORQUE_SENSOR : 7|16@0- (1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_MOTOR : 23|16@0- (1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_SENSOR : 7|16@0- (-1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_MOTOR : 23|16@0- (-1,0) [-31000|31000] "tbd" EON
SG_ STEER_STATUS : 39|4@0+ (1,0) [0|15] "" EON
SG_ STEER_CONTROL_ACTIVE : 35|1@0+ (1,0) [0|1] "" EON
SG_ COUNTER : 53|2@0+ (1,0) [0|3] "" EON

View File

@ -164,7 +164,7 @@ BO_ 780 ACC_HUD: 8 ADAS
SG_ BOH : 38|1@0+ (1,0) [0|1] "" BDY
SG_ ACC_PROBLEM : 37|1@0+ (1,0) [0|1] "" BDY
SG_ FCM_OFF : 36|1@0+ (1,0) [0|1] "" BDY
SG_ BOH_2 : 35|1@0+ (1,0) [0|1] "" BDY
SG_ FCM_OFF_2 : 35|1@0+ (1,0) [0|1] "" BDY
SG_ FCM_PROBLEM : 34|1@0+ (1,0) [0|1] "" BDY
SG_ RADAR_OBSTRUCTED : 33|1@0+ (1,0) [0|1] "" BDY
SG_ ENABLE_MINI_CAR : 32|1@0+ (1,0) [0|1] "" BDY
@ -174,10 +174,12 @@ BO_ 780 ACC_HUD: 8 ADAS
SG_ BOH_4 : 42|1@0+ (1,0) [0|3] "" BDY
SG_ BOH_5 : 41|1@0+ (1,0) [0|3] "" BDY
SG_ CRUISE_CONTROL_LABEL : 40|1@0+ (1,0) [0|3] "" BDY
SG_ HUD_DISTANCE_3 : 52|1@0+ (1,0) [0|1] "" BDY
SG_ IMPERIAL_UNIT : 54|1@0+ (1,0) [0|1] "" BDY
SG_ SET_ME_X01_2 : 55|1@0+ (1,0) [0|1] "" BDY
SG_ IMPERIAL_UNIT : 54|1@0+ (1,0) [0|1] "" BDY
SG_ HUD_DISTANCE_3 : 52|1@0+ (1,0) [0|1] "" BDY
SG_ CHIME : 51|3@0+ (1,0) [0|1] "" BDY
SG_ SET_ME_X01 : 48|1@0+ (1,0) [0|1] "" BDY
SG_ ICONS : 63|2@0+ (1,0) [0|1] "" BDY
SG_ COUNTER : 61|2@0+ (1,0) [0|3] "" BDY
SG_ CHECKSUM : 59|4@0+ (1,0) [0|3] "" BDY
@ -276,8 +278,8 @@ BO_ 330 STEERING_SENSORS: 8 EPS
SG_ CHECKSUM : 59|4@0+ (1,0) [0|3] "" EON
BO_ 399 STEER_STATUS: 7 EPS
SG_ STEER_TORQUE_SENSOR : 7|16@0- (1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_MOTOR : 23|16@0- (1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_SENSOR : 7|16@0- (-1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_MOTOR : 23|16@0- (-1,0) [-31000|31000] "tbd" EON
SG_ STEER_STATUS : 39|4@0+ (1,0) [0|15] "" EON
SG_ STEER_CONTROL_ACTIVE : 35|1@0+ (1,0) [0|1] "" EON
SG_ COUNTER : 53|2@0+ (1,0) [0|3] "" EON

View File

@ -91,8 +91,8 @@ BO_ 380 POWERTRAIN_DATA2: 8 PCM
SG_ CHECKSUM : 59|4@0+ (1,0) [0|3] "" NEO
BO_ 399 STEER_STATUS: 7 EPS
SG_ STEER_TORQUE_SENSOR : 7|16@0- (1,0) [-31000|31000] "tbd" NEO
SG_ STEER_TORQUE_MOTOR : 23|16@0- (1,0) [-31000|31000] "tbd" NEO
SG_ STEER_TORQUE_SENSOR : 7|16@0- (-1,0) [-31000|31000] "tbd" NEO
SG_ STEER_TORQUE_MOTOR : 23|16@0- (-1,0) [-31000|31000] "tbd" NEO
SG_ STEER_STATUS : 39|4@0+ (1,0) [0|15] "" NEO
SG_ STEER_CONTROL_ACTIVE : 35|1@0+ (1,0) [0|1] "" NEO
SG_ COUNTER : 53|2@0+ (1,0) [0|3] "" NEO

View File

@ -95,8 +95,8 @@ BO_ 380 POWERTRAIN_DATA: 8 PCM
SG_ CHECKSUM : 59|4@0+ (1,0) [0|15] "" EON
BO_ 399 STEER_STATUS: 7 EPS
SG_ STEER_TORQUE_SENSOR : 7|16@0- (1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_MOTOR : 23|16@0- (1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_SENSOR : 7|16@0- (-1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_MOTOR : 23|16@0- (-1,0) [-31000|31000] "tbd" EON
SG_ STEER_STATUS : 39|4@0+ (1,0) [0|15] "" EON
SG_ STEER_CONTROL_ACTIVE : 35|1@0+ (1,0) [0|1] "" EON
SG_ COUNTER : 53|2@0+ (1,0) [0|3] "" EON

View File

@ -95,8 +95,8 @@ BO_ 380 POWERTRAIN_DATA: 8 PCM
SG_ CHECKSUM : 59|4@0+ (1,0) [0|15] "" EON
BO_ 399 STEER_STATUS: 7 EPS
SG_ STEER_TORQUE_SENSOR : 7|16@0- (1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_MOTOR : 23|16@0- (1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_SENSOR : 7|16@0- (-1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_MOTOR : 23|16@0- (-1,0) [-31000|31000] "tbd" EON
SG_ STEER_STATUS : 39|4@0+ (1,0) [0|15] "" EON
SG_ STEER_CONTROL_ACTIVE : 35|1@0+ (1,0) [0|1] "" EON
SG_ COUNTER : 53|2@0+ (1,0) [0|3] "" EON

View File

@ -253,8 +253,8 @@ BO_ 342 STEERING_SENSORS: 6 EPS
SG_ CHECKSUM : 43|4@0+ (1,0) [0|15] "" EON
BO_ 399 STEER_STATUS: 6 EPS
SG_ STEER_TORQUE_SENSOR : 7|12@0- (1,0) [-2047.5|2047.5] "tbd" EON
SG_ STEER_TORQUE_MOTOR : 23|16@0- (1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_SENSOR : 7|12@0- (-1,0) [-2047.5|2047.5] "tbd" EON
SG_ STEER_TORQUE_MOTOR : 23|16@0- (-1,0) [-31000|31000] "tbd" EON
SG_ STEER_CONTROL_ACTIVE : 36|1@0+ (1,0) [0|1] "" EON
SG_ STEER_STATUS : 35|4@0+ (1,0) [0|15] "" EON
SG_ COUNTER : 45|2@0+ (1,0) [0|3] "" EON

View File

@ -271,8 +271,8 @@ BO_ 342 STEERING_SENSORS: 6 EPS
SG_ CHECKSUM : 43|4@0+ (1,0) [0|3] "" EON
BO_ 399 STEER_STATUS: 7 EPS
SG_ STEER_TORQUE_SENSOR : 7|16@0- (1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_MOTOR : 23|16@0- (1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_SENSOR : 7|16@0- (-1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_MOTOR : 23|16@0- (-1,0) [-31000|31000] "tbd" EON
SG_ STEER_STATUS : 39|4@0+ (1,0) [0|15] "" EON
SG_ STEER_CONTROL_ACTIVE : 35|1@0+ (1,0) [0|1] "" EON
SG_ COUNTER : 53|2@0+ (1,0) [0|3] "" EON

View File

@ -265,8 +265,8 @@ BO_ 342 STEERING_SENSORS: 6 EPS
SG_ CHECKSUM : 43|4@0+ (1,0) [0|3] "" EON
BO_ 399 STEER_STATUS: 7 EPS
SG_ STEER_TORQUE_SENSOR : 7|16@0- (1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_MOTOR : 23|16@0- (1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_SENSOR : 7|16@0- (-1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_MOTOR : 23|16@0- (-1,0) [-31000|31000] "tbd" EON
SG_ STEER_STATUS : 39|4@0+ (1,0) [0|15] "" EON
SG_ STEER_CONTROL_ACTIVE : 35|1@0+ (1,0) [0|1] "" EON
SG_ COUNTER : 53|2@0+ (1,0) [0|3] "" EON

View File

@ -95,8 +95,8 @@ BO_ 380 POWERTRAIN_DATA: 8 PCM
SG_ CHECKSUM : 59|4@0+ (1,0) [0|15] "" EON
BO_ 399 STEER_STATUS: 7 EPS
SG_ STEER_TORQUE_SENSOR : 7|16@0- (1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_MOTOR : 23|16@0- (1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_SENSOR : 7|16@0- (-1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_MOTOR : 23|16@0- (-1,0) [-31000|31000] "tbd" EON
SG_ STEER_STATUS : 39|4@0+ (1,0) [0|15] "" EON
SG_ STEER_CONTROL_ACTIVE : 35|1@0+ (1,0) [0|1] "" EON
SG_ COUNTER : 53|2@0+ (1,0) [0|3] "" EON

View File

@ -263,8 +263,8 @@ BO_ 342 STEERING_SENSORS: 6 EPS
SG_ CHECKSUM : 43|4@0+ (1,0) [0|3] "" EON
BO_ 399 STEER_STATUS: 7 EPS
SG_ STEER_TORQUE_SENSOR : 7|16@0- (1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_MOTOR : 23|16@0- (1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_SENSOR : 7|16@0- (-1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_MOTOR : 23|16@0- (-1,0) [-31000|31000] "tbd" EON
SG_ STEER_STATUS : 39|4@0+ (1,0) [0|15] "" EON
SG_ STEER_CONTROL_ACTIVE : 35|1@0+ (1,0) [0|1] "" EON
SG_ COUNTER : 53|2@0+ (1,0) [0|3] "" EON

View File

@ -256,8 +256,8 @@ BO_ 342 STEERING_SENSORS: 6 EPS
SG_ STEER_ANGLE : 7|16@0- (-0.1,0) [-500|500] "deg" EON
BO_ 399 STEER_STATUS: 7 EPS
SG_ STEER_TORQUE_SENSOR : 7|16@0- (1,0) [-2985|2985] "tbd" EON
SG_ STEER_TORQUE_MOTOR : 23|16@0- (1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_SENSOR : 7|16@0- (-1,0) [-2985|2985] "tbd" EON
SG_ STEER_TORQUE_MOTOR : 23|16@0- (-1,0) [-31000|31000] "tbd" EON
SG_ CHECKSUM : 51|4@0+ (1,0) [0|15] "" EON
SG_ COUNTER : 53|2@0+ (1,0) [0|3] "" EON
SG_ STEER_STATUS : 43|4@0+ (1,0) [0|15] "" EON

View File

@ -271,8 +271,8 @@ BO_ 342 STEERING_SENSORS: 6 EPS
SG_ CHECKSUM : 43|4@0+ (1,0) [0|3] "" EON
BO_ 399 STEER_STATUS: 7 EPS
SG_ STEER_TORQUE_SENSOR : 7|16@0- (1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_MOTOR : 23|16@0- (1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_SENSOR : 7|16@0- (-1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_MOTOR : 23|16@0- (-1,0) [-31000|31000] "tbd" EON
SG_ STEER_STATUS : 39|4@0+ (1,0) [0|15] "" EON
SG_ STEER_CONTROL_ACTIVE : 35|1@0+ (1,0) [0|1] "" EON
SG_ COUNTER : 53|2@0+ (1,0) [0|3] "" EON

View File

@ -266,8 +266,8 @@ BO_ 342 STEERING_SENSORS: 6 EPS
SG_ CHECKSUM : 43|4@0+ (1,0) [0|3] "" EON
BO_ 399 STEER_STATUS: 7 EPS
SG_ STEER_TORQUE_SENSOR : 7|16@0- (1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_MOTOR : 23|16@0- (1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_SENSOR : 7|16@0- (-1,0) [-31000|31000] "tbd" EON
SG_ STEER_TORQUE_MOTOR : 23|16@0- (-1,0) [-31000|31000] "tbd" EON
SG_ STEER_STATUS : 39|4@0+ (1,0) [0|15] "" EON
SG_ STEER_CONTROL_ACTIVE : 35|1@0+ (1,0) [0|1] "" EON
SG_ COUNTER : 53|2@0+ (1,0) [0|3] "" EON

View File

@ -0,0 +1,7 @@
Cython==0.29.14
flake8==3.7.9
Jinja2==2.10.3
pycapnp==0.6.4
pylint==2.4.3
pyyaml==5.1.2
scons==3.1.1

View File

@ -33,47 +33,47 @@ NS_ :
BS_:
BU_: XXX
BU_: XXX 0
BO_ 2 Steering: 8 XXX
SG_ NEW_SIGNAL_1 : 31|4@0- (1,0) [0|65535] "" XXX
SG_ Counter : 25|3@1+ (1,0) [0|15] "" XXX
SG_ Checksum : 32|8@1+ (1,0) [0|255] "" XXX
SG_ NEW_SIGNAL_2 : 22|3@0+ (1,0) [0|7] "" XXX
SG_ NEW_SIGNAL_6 : 24|1@1+ (1,0) [0|3] "" XXX
SG_ Steering_Angle : 7|16@0- (0.1,0) [-500|500] "degree" XXX
SG_ NEW_SIGNAL_6 : 24|1@0+ (1,0) [0|3] "" XXX
SG_ NEW_SIGNAL_2 : 22|3@0+ (1,0) [0|7] "" XXX
SG_ Counter : 27|3@0+ (1,0) [0|15] "" XXX
SG_ NEW_SIGNAL_1 : 31|4@0- (1,0) [0|65535] "" XXX
SG_ Checksum : 39|8@0+ (1,0) [0|255] "" XXX
BO_ 208 G_Sensor: 8 XXX
SG_ NEW_SIGNAL_3 : 32|8@1+ (1,0) [0|255] "" XXX
SG_ Steering_Angle : 0|16@1- (1,0) [0|65535] "" XXX
SG_ NEW_SIGNAL_1 : 47|8@0+ (1,0) [0|255] "" XXX
SG_ _Latitudinal : 16|16@1- (0.0035,1) [0|65535] "" XXX
SG_ _Longitudinal : 48|16@1- (0.000035,0) [0|255] "" XXX
SG_ Steering_Angle : 0|16@1- (1,0) [0|65535] "" XXX
SG_ NEW_SIGNAL_1 : 40|8@1+ (1,0) [0|255] "" XXX
BO_ 209 Brake_Pedal: 8 XXX
SG_ NEW_SIGNAL_1 : 26|1@1+ (1,0) [0|3] "" XXX
SG_ Brake_Pedal : 23|8@0+ (1,0) [0|255] "" XXX
SG_ NEW_SIGNAL_2 : 31|1@1+ (1,0) [0|255] "" XXX
SG_ Brake_Pedal : 16|8@1+ (1,0) [0|255] "" XXX
SG_ Speed : 0|16@1+ (0.05625,0) [0|255] "KPH" XXX
BO_ 210 Brake_2: 8 XXX
SG_ NEW_SIGNAL_1 : 46|1@0+ (1,0) [0|4294967295] "" XXX
SG_ NEW_SIGNAL_2 : 39|3@0+ (1,0) [0|7] "" XXX
SG_ Right_Brake : 48|8@1+ (1,0) [0|255] "" XXX
SG_ Left_Brake : 63|8@0+ (1,0) [0|255] "" XXX
SG_ Brake_Light : 35|1@1+ (1,0) [0|15] "" XXX
SG_ Brake_Related : 36|1@1+ (1,0) [0|255] "" XXX
SG_ Left_Brake : 56|8@1+ (1,0) [0|255] "" XXX
SG_ NEW_SIGNAL_1 : 46|1@1+ (1,0) [0|4294967295] "" XXX
SG_ NEW_SIGNAL_2 : 37|3@1+ (1,0) [0|7] "" XXX
BO_ 211 Brake_Type: 8 XXX
SG_ NEW_SIGNAL_4 : 28|4@1+ (1,0) [0|15] "" XXX
SG_ NEW_SIGNAL_3 : 7|1@0+ (1,0) [0|4294967295] "" XXX
SG_ NEW_SIGNAL_3 : 7|1@1+ (1,0) [0|4294967295] "" XXX
SG_ NEW_SIGNAL_2 : 16|4@1+ (1,0) [0|15] "" XXX
SG_ Speed_Counter : 39|8@0+ (1,0) [0|15] "" XXX
SG_ Counter : 55|8@0+ (1,0) [0|255] "" XXX
SG_ Brake_Light : 21|1@0+ (1,0) [0|3] "" XXX
SG_ Brake_Cruise_On : 42|1@0+ (1,0) [0|3] "" XXX
SG_ Brake_Pedal_On : 46|1@0+ (1,0) [0|3] "" XXX
SG_ Brake_Light : 21|1@1+ (1,0) [0|3] "" XXX
SG_ NEW_SIGNAL_4 : 28|4@1+ (1,0) [0|15] "" XXX
SG_ Speed_Counter : 32|8@1+ (1,0) [0|15] "" XXX
SG_ Brake_Cruise_On : 42|1@1+ (1,0) [0|3] "" XXX
SG_ Brake_Pedal_On : 46|1@1+ (1,0) [0|3] "" XXX
SG_ Counter : 48|8@1+ (1,0) [0|255] "" XXX
BO_ 212 Wheel_Speeds: 8 XXX
SG_ FL : 0|16@1+ (0.0592,0) [2|255] "KPH" XXX
@ -85,72 +85,71 @@ BO_ 320 Throttle: 8 XXX
SG_ Off_Throttle_2 : 56|1@1+ (1,0) [0|3] "" XXX
SG_ Throttle_Combo : 40|8@1+ (1,0) [0|255] "" XXX
SG_ Engine_RPM : 16|14@1+ (1,0) [0|15] "" XXX
SG_ Off_Throttle : 30|1@0+ (1,0) [0|3] "" XXX
SG_ Throttle_Cruise : 39|8@0+ (1,0) [0|255] "" XXX
SG_ Throttle_Body_ : 55|8@0+ (1,0) [0|255] "" XXX
SG_ NEW_SIGNAL_3 : 63|1@0+ (1,0) [0|15] "" XXX
SG_ Not_Full_Throttle : 14|1@0+ (1,0) [0|15] "" XXX
SG_ Counter : 8|4@1+ (1,0) [0|15] "" XXX
SG_ NEW_SIGNAL_3 : 63|1@1+ (1,0) [0|15] "" XXX
SG_ NEW_SIGNAL_1 : 61|1@1+ (1,0) [0|3] "" XXX
SG_ Throttle_Body_ : 48|8@1+ (1,0) [0|255] "" XXX
SG_ Throttle_Cruise : 32|8@1+ (1,0) [0|255] "" XXX
SG_ Off_Throttle : 30|1@1+ (1,0) [0|3] "" XXX
SG_ Throttle_Pedal : 0|8@1+ (0.392157,0) [0|255] "" XXX
SG_ Counter : 8|4@1+ (1,0) [0|15] "" XXX
SG_ Not_Full_Throttle : 14|1@1+ (1,0) [0|15] "" XXX
BO_ 321 undefined: 8 XXX
BO_ 321 Engine: 8 XXX
SG_ NEW_SIGNAL_7 : 59|2@1+ (1,0) [0|63] "" XXX
SG_ NEW_SIGNAL_6 : 46|1@0+ (1,0) [0|3] "" XXX
SG_ NEW_SIGNAL_2 : 47|1@1+ (1,0) [0|15] "" XXX
SG_ NEW_SIGNAL_5 : 48|4@1+ (1,0) [0|15] "" XXX
SG_ NEW_SIGNAL_3 : 54|2@0+ (1,0) [0|255] "" XXX
SG_ NEW_SIGNAL_8 : 31|4@0+ (1,0) [0|15] "" XXX
SG_ Engine_RPM : 32|12@1+ (1,0) [0|8191] "" XXX
SG_ Engine_Torque : 0|15@1+ (1,0) [0|255] "" XXX
SG_ Wheel_Torque : 16|12@1+ (1,0) [0|255] "" XXX
SG_ Engine_Stop : 15|1@0+ (1,0) [0|3] "" XXX
SG_ Engine_RPM : 32|12@1+ (1,0) [0|8191] "" XXX
SG_ NEW_SIGNAL_3 : 53|2@1+ (1,0) [0|255] "" XXX
SG_ NEW_SIGNAL_6 : 46|1@1+ (1,0) [0|3] "" XXX
SG_ NEW_SIGNAL_8 : 28|4@1+ (1,0) [0|15] "" XXX
SG_ Engine_Stop : 15|1@1+ (1,0) [0|3] "" XXX
SG_ Engine_Torque : 0|15@1+ (1,0) [0|255] "" XXX
BO_ 324 CruiseControl: 8 XXX
SG_ Cruise_On : 48|1@0+ (1,0) [0|3] "" XXX
SG_ OnOffButton : 2|1@1+ (1,0) [0|3] "" XXX
SG_ SET_BUTTON : 3|1@0+ (1,0) [0|3] "" XXX
SG_ RES_BUTTON : 4|1@0+ (1,0) [0|3] "" XXX
SG_ NEW_SIGNAL_6 : 50|1@0+ (1,0) [0|3] "" XXX
SG_ NEW_SIGNAL_4 : 28|5@0+ (1,0) [0|16777215] "" XXX
SG_ SET_BUTTON : 3|1@1+ (1,0) [0|3] "" XXX
SG_ RES_BUTTON : 4|1@1+ (1,0) [0|3] "" XXX
SG_ NEW_SIGNAL_2 : 8|1@1+ (1,0) [0|255] "" XXX
SG_ Button : 13|1@1+ (1,0) [0|3] "" XXX
SG_ NEW_SIGNAL_9 : 15|1@1+ (1,0) [0|127] "" XXX
SG_ NEW_SIGNAL_2 : 8|1@0+ (1,0) [0|255] "" XXX
SG_ Cruise_Activated : 49|1@0+ (1,0) [0|7] "" XXX
SG_ Brake_Pedal_On : 51|1@0+ (1,0) [0|3] "" XXX
SG_ NEW_SIGNAL_1 : 23|8@0+ (1,-124) [0|255] "" XXX
SG_ Button : 13|1@0+ (1,0) [0|3] "" XXX
SG_ NEW_SIGNAL_1 : 16|8@1+ (1,-124) [0|255] "" XXX
SG_ NEW_SIGNAL_4 : 24|5@1+ (1,0) [0|16777215] "" XXX
SG_ Cruise_On : 48|1@1+ (1,0) [0|3] "" XXX
SG_ Cruise_Activated : 49|1@1+ (1,0) [0|7] "" XXX
SG_ NEW_SIGNAL_6 : 50|1@1+ (1,0) [0|3] "" XXX
SG_ Brake_Pedal_On : 51|1@1+ (1,0) [0|3] "" XXX
BO_ 328 Transmission: 8 XXX
SG_ Counter : 11|4@0+ (1,0) [0|255] "" XXX
SG_ NEW_SIGNAL_7 : 63|1@0+ (1,0) [0|3] "" XXX
SG_ NEW_SIGNAL_4 : 15|4@0+ (1,0) [0|15] "" XXX
SG_ Paddle_Shift : 60|2@1+ (1,0) [0|255] "" XXX
SG_ NEW_SIGNAL_1 : 31|1@0+ (1,0) [0|3] "" XXX
SG_ Transmission_Engine : 16|15@1+ (1,0) [0|65535] "" XXX
SG_ NEW_SIGNAL_5 : 43|1@0+ (1,0) [0|65535] "" XXX
SG_ Gear : 48|4@1+ (1,0) [0|15] "" XXX
SG_ Gear_2 : 52|4@1+ (1,0) [0|15] "" XXX
SG_ Manual_Gear : 4|4@1+ (1,0) [0|255] "" XXX
SG_ Transmission_Engine : 16|15@1+ (1,0) [0|65535] "" XXX
SG_ NEW_SIGNAL_7 : 63|1@1+ (1,0) [0|3] "" XXX
SG_ NEW_SIGNAL_5 : 43|1@1+ (1,0) [0|65535] "" XXX
SG_ NEW_SIGNAL_1 : 31|1@1+ (1,0) [0|3] "" XXX
SG_ NEW_SIGNAL_4 : 12|4@1+ (1,0) [0|15] "" XXX
SG_ Counter : 8|4@1+ (1,0) [0|255] "" XXX
BO_ 329 CVT_Ratio: 8 XXX
SG_ NEW_SIGNAL_2 : 31|8@0+ (1,0) [0|255] "" XXX
SG_ NEW_SIGNAL_3 : 40|8@1+ (1,0) [0|255] "" XXX
SG_ NEW_SIGNAL_4 : 0|8@1+ (1,0) [0|255] "" XXX
SG_ NEW_SIGNAL_5 : 11|4@0+ (1,0) [0|65535] "" XXX
SG_ NEW_SIGNAL_1 : 39|8@0+ (1,0) [0|255] "" XXX
SG_ NEW_SIGNAL_5 : 8|4@1+ (1,0) [0|65535] "" XXX
SG_ NEW_SIGNAL_2 : 24|8@1+ (1,0) [0|255] "" XXX
SG_ NEW_SIGNAL_1 : 32|8@1+ (1,0) [0|255] "" XXX
SG_ NEW_SIGNAL_3 : 40|8@1+ (1,0) [0|255] "" XXX
BO_ 336 Brake_Pressure: 8 XXX
SG_ Brake_Pressure_Right : 0|8@1+ (1,0) [0|15] "" XXX
SG_ Brake_Pressure_Left : 15|8@0+ (1,0) [0|255] "" XXX
SG_ Brake_Pressure_Left : 8|8@1+ (1,0) [0|255] "" XXX
BO_ 338 Stalk: 8 XXX
SG_ Wiper : 62|1@0+ (1,0) [0|3] "" XXX
SG_ brake_light : 52|1@0+ (1,0) [0|3] "" XXX
SG_ Headlights : 59|1@0+ (1,0) [0|3] "" XXX
SG_ Runlights : 58|1@1+ (1,0) [0|3] "" XXX
SG_ Highbeam : 60|1@0+ (1,0) [0|3] "" XXX
SG_ Counter : 15|4@0+ (1,0) [0|15] "" XXX
BO_ 342 NEW_MSG_2: 8 XXX
SG_ Wiper : 62|1@1+ (1,0) [0|3] "" XXX
SG_ Highbeam : 60|1@1+ (1,0) [0|3] "" XXX
SG_ Headlights : 59|1@1+ (1,0) [0|3] "" XXX
SG_ brake_light : 52|1@1+ (1,0) [0|3] "" XXX
SG_ Counter : 12|4@1+ (1,0) [0|15] "" XXX
BO_ 346 Counter_3: 8 XXX
SG_ Counter : 0|4@1+ (1,0) [0|15] "" XXX
@ -160,36 +159,40 @@ BO_ 346 Counter_3: 8 XXX
BO_ 352 ES_Brake: 8 XXX
SG_ Counter : 48|3@1+ (1,0) [0|7] "" XXX
SG_ Checksum : 56|8@1+ (1,0) [0|7] "" XXX
SG_ Brake_On : 22|1@0+ (1,0) [0|3] "" XXX
SG_ Brake_Light : 20|1@0+ (1,0) [0|2047] "" XXX
SG_ Cruise_Activated : 23|1@0+ (1,0) [0|3] "" XXX
SG_ Brake_Pressure : 0|16@1+ (1,0) [0|255] "" XXX
SG_ ES_Error : 21|1@0+ (1,0) [0|7] "" XXX
SG_ Cruise_Activated : 23|1@1+ (1,0) [0|3] "" XXX
SG_ Brake_On : 22|1@1+ (1,0) [0|3] "" XXX
SG_ ES_Error : 21|1@1+ (1,0) [0|7] "" XXX
SG_ Brake_Light : 20|1@1+ (1,0) [0|2047] "" XXX
BO_ 353 ES_CruiseThrottle: 8 XXX
SG_ Throttle_Cruise : 0|12@1+ (1,0) [0|255] "" XXX
SG_ Counter_1 : 46|3@0+ (1,0) [0|15] "" XXX
SG_ Wheel_stop : 22|1@0+ (1,0) [0|3] "" XXX
SG_ CloseDistance : 24|8@1+ (1,0) [0|255] "" XXX
SG_ Unknown : 18|1@1+ (1,0) [0|7] "" XXX
SG_ Button_Speed_Down : 49|1@1+ (1,0) [0|3] "" XXX
SG_ Button_Resume : 50|1@1+ (1,0) [0|15] "" XXX
SG_ NEW_SIGNAL_3_Blank : 15|4@0+ (1,0) [0|15] "" XXX
SG_ NEW_SIGNAL_2_Blank : 48|1@1+ (1,0) [0|3] "" XXX
SG_ Checksum : 56|8@1+ (1,0) [0|15] "" XXX
SG_ NEW_SIGNAL_9 : 17|1@1+ (1,0) [0|3] "" XXX
SG_ Cruise_Activatedish : 16|1@1+ (1,0) [0|7] "" XXX
SG_ NEW_SIGNAL_6_Blank : 23|1@0+ (1,0) [0|7] "" XXX
SG_ DistanceSwap : 21|1@0+ (1,0) [0|3] "" XXX
SG_ Brake_On : 20|1@0+ (1,0) [0|7] "" XXX
SG_ Button : 48|3@1+ (1,0) [0|3] "" XXX
SG_ ES_Error : 42|1@1+ (1,0) [0|3] "" XXX
SG_ Standstill_2 : 41|1@1+ (1,0) [0|3] "" XXX
SG_ Standstill : 22|1@1+ (1,0) [0|3] "" XXX
SG_ Unknown : 18|1@1+ (1,0) [0|7] "" XXX
SG_ Brake_On : 20|1@1+ (1,0) [0|7] "" XXX
SG_ DistanceSwap : 21|1@1+ (1,0) [0|3] "" XXX
SG_ Counter : 44|3@1+ (1,0) [0|15] "" XXX
SG_ SET_0_1 : 32|9@1+ (1,0) [0|255] "" XXX
SG_ CloseDistance : 24|8@1+ (0.0196,0) [0|255] "m" XXX
SG_ SET_0_2 : 51|5@1+ (1,0) [0|31] "" XXX
SG_ SET_0_3 : 47|1@1+ (1,0) [0|3] "" XXX
SG_ SET_0_4 : 43|1@1+ (1,0) [0|3] "" XXX
SG_ SET_1 : 23|1@1+ (1,0) [0|7] "" XXX
SG_ NEW_SIGNAL_1 : 19|1@1+ (1,0) [0|1] "" XXX
SG_ Throttle_Cruise : 0|12@1+ (1,0) [0|255] "" XXX
SG_ SET_2 : 12|4@1+ (1,0) [0|15] "" XXX
SG_ Cruise_Activatedish : 16|1@1+ (1,0) [0|7] "" XXX
SG_ NEW_SIGNAL_9 : 17|1@1+ (1,0) [0|3] "" XXX
BO_ 354 ES_RPM: 8 XXX
SG_ Counter : 48|3@1+ (1,0) [0|7] "" XXX
SG_ Cruise_Activated : 9|1@0+ (1,0) [0|3] "" XXX
SG_ Checksum : 39|8@0+ (1,0) [0|65535] "" XXX
SG_ RPM : 16|16@1+ (1,0) [0|255] "" XXX
SG_ Brake : 8|1@1+ (1,0) [0|7] "" XXX
SG_ Cruise_Activated : 9|1@1+ (1,0) [0|3] "" XXX
SG_ Checksum : 32|8@1+ (1,0) [0|65535] "" XXX
BO_ 356 ES_LKAS: 8 XXX
SG_ Checksum : 56|8@1+ (1,0) [0|255] "" XXX
@ -198,39 +201,39 @@ BO_ 356 ES_LKAS: 8 XXX
SG_ LKAS_Command : 8|13@1- (-1,0) [-4096|4096] "" XXX
BO_ 358 ES_DashStatus: 8 XXX
SG_ Counter : 39|3@0+ (1,0) [0|7] "" XXX
SG_ Obstacle_Distance : 48|4@1+ (1,0) [0|15] "" XXX
SG_ Cruise_Off : 22|1@0+ (1,0) [0|3] "" XXX
SG_ Car_Follow : 46|1@1+ (1,0) [0|255] "" XXX
SG_ Driver_Input : 20|1@0+ (1,0) [0|15] "" XXX
SG_ WHEELS_MOVING_2015 : 19|1@1+ (1,0) [0|3] "" XXX
SG_ Untitled_Blank : 18|1@0+ (1,0) [0|3] "" XXX
SG_ NEW_SIGNAL_6_Blank : 21|1@0+ (1,0) [0|3] "" XXX
SG_ NEW_SIGNAL_5_Blank : 33|1@1+ (1,0) [0|3] "" XXX
SG_ NEW_SIGNAL_4_Blank : 34|1@1+ (1,0) [0|7] "" XXX
SG_ NEW_SIGNAL_1 : 35|1@0+ (1,0) [0|31] "" XXX
SG_ Steep_Hill_Disengage : 44|1@0+ (1,0) [0|3] "" XXX
SG_ ES_Error : 32|1@1+ (1,0) [0|3] "" XXX
SG_ Cruise_Activated : 17|1@1+ (1,0) [0|3] "" XXX
SG_ Cruise_On : 16|1@1+ (1,0) [0|7] "" XXX
SG_ Disengage_Alert : 15|2@0+ (1,0) [0|3] "" XXX
SG_ 3SecondDisengage : 13|2@0+ (1,0) [0|3] "" XXX
SG_ Not_Ready_Startup : 0|3@1+ (1,0) [0|7] "" XXX
SG_ 3SecondDisengage : 12|2@1+ (1,0) [0|3] "" XXX
SG_ Disengage_Alert : 14|2@1+ (1,0) [0|3] "" XXX
SG_ Cruise_On : 16|1@1+ (1,0) [0|7] "" XXX
SG_ Cruise_Activated : 17|1@1+ (1,0) [0|3] "" XXX
SG_ WHEELS_MOVING_2015 : 19|1@1+ (1,0) [0|3] "" XXX
SG_ Driver_Input : 20|1@1+ (1,0) [0|15] "" XXX
SG_ ES_Error : 32|1@1+ (1,0) [0|3] "" XXX
SG_ NEW_SIGNAL_5_Blank : 33|1@1+ (1,0) [0|3] "" XXX
SG_ Cruise_On_2 : 34|1@1+ (1,0) [0|7] "" XXX
SG_ NEW_SIGNAL_1 : 35|1@1+ (1,0) [0|31] "" XXX
SG_ Counter : 37|3@1+ (1,0) [0|7] "" XXX
SG_ Steep_Hill_Disengage : 44|1@1+ (1,0) [0|3] "" XXX
SG_ Lead_Car : 46|1@1+ (1,0) [0|255] "" XXX
SG_ Cruise_Set_Speed : 24|8@1+ (1,0) [0|255] "" XXX
SG_ Distance_Bars : 21|3@1+ (1,0) [0|3] "" XXX
SG_ Untitled_Blank_2 : 18|1@1+ (1,0) [0|3] "" XXX
SG_ Obstacle_Distance : 48|4@1+ (5,0) [0|15] "m" XXX
BO_ 359 ES_LDW: 8 XXX
SG_ All_depart_2015 : 0|1@1+ (1,0) [0|255] "" XXX
SG_ LKAS_Inactive_2017 : 36|1@1+ (1,0) [0|3] "" XXX
SG_ LKAS_Steer_Active_2017 : 37|1@0+ (1,0) [0|3] "" XXX
SG_ Right_Line_2017 : 24|1@1+ (1,0) [0|7] "" XXX
SG_ Left_Line_2017 : 25|1@1+ (1,0) [0|3] "" XXX
SG_ Sig2All_Depart : 28|1@0+ (1,0) [0|3] "" XXX
SG_ Sig1All_Depart : 31|1@0+ (1,0) [0|15] "" XXX
SG_ Sig1Right_Depart : 48|1@1+ (1,0) [0|3] "" XXX
SG_ Sig1Right_Depart_Front : 49|1@1+ (1,0) [0|3] "" XXX
SG_ Sig2Right_Depart : 50|1@1+ (1,0) [0|7] "" XXX
SG_ Left_Depart_Front : 51|1@0+ (1,0) [0|3] "" XXX
SG_ Sig3All_Depart : 52|1@0+ (1,0) [0|3] "" XXX
SG_ LKAS_Inactive_2017 : 36|1@1+ (1,0) [0|3] "" XXX
SG_ Sig1Right_Depart_Front : 49|1@1+ (1,0) [0|3] "" XXX
SG_ Sig3All_Depart : 52|1@1+ (1,0) [0|3] "" XXX
SG_ Left_Depart_Front : 51|1@1+ (1,0) [0|3] "" XXX
SG_ Alerts : 48|5@1+ (1,0) [0|3] "" XXX
SG_ LKAS_Active : 37|1@1+ (1,0) [0|3] "" XXX
SG_ Sig1All_Depart : 31|1@1+ (1,0) [0|15] "" XXX
SG_ Sig2All_Depart : 28|1@1+ (1,0) [0|3] "" XXX
SG_ Right_Line_2017 : 24|1@1+ (1,0) [0|7] "" XXX
SG_ All_depart_2015 : 0|1@1+ (1,0) [0|255] "" XXX
BO_ 392 Counter_0: 8 XXX
SG_ Counter : 16|4@1+ (1,0) [0|15] "" XXX
@ -238,62 +241,56 @@ BO_ 392 Counter_0: 8 XXX
BO_ 554 NEW_MSG_3: 8 XXX
SG_ Counter : 0|4@1+ (1,0) [0|255] "" XXX
BO_ 604 undefined: 8 XXX
BO_ 640 NEW_MSG_10: 8 XXX
SG_ NEW_SIGNAL_2 : 24|8@1+ (1,0) [0|255] "" XXX
SG_ NEW_SIGNAL_4 : 54|2@0+ (1,0) [0|15] "" XXX
SG_ Counter : 8|4@1+ (1,0) [0|15] "" XXX
SG_ NEW_SIGNAL_3 : 34|2@0+ (1,0) [0|63] "" XXX
SG_ NEW_SIGNAL_1 : 47|8@0+ (1,0) [0|255] "" XXX
SG_ NEW_SIGNAL_5 : 39|1@0+ (1,0) [0|3] "" XXX
SG_ NEW_SIGNAL_6 : 0|1@1+ (1,0) [0|7] "" XXX
SG_ NEW_SIGNAL_7 : 38|1@0+ (1,0) [0|3] "" XXX
SG_ Counter : 8|4@1+ (1,0) [0|15] "" XXX
SG_ NEW_SIGNAL_2 : 24|8@1+ (1,0) [0|255] "" XXX
SG_ NEW_SIGNAL_3 : 33|2@1+ (1,0) [0|63] "" XXX
SG_ NEW_SIGNAL_7 : 38|1@1+ (1,0) [0|3] "" XXX
SG_ NEW_SIGNAL_5 : 39|1@1+ (1,0) [0|3] "" XXX
SG_ NEW_SIGNAL_1 : 40|8@1+ (1,0) [0|255] "" XXX
SG_ NEW_SIGNAL_4 : 53|2@1+ (1,0) [0|15] "" XXX
BO_ 642 Dashlights: 8 XXX
SG_ NEW_SIGNAL_2 : 32|1@1+ (1,0) [0|15] "" XXX
SG_ Counter : 15|4@0+ (1,0) [0|15] "" XXX
SG_ NEW_SIGNAL_1 : 0|12@1+ (1,0) [0|255] "" XXX
SG_ NEW_SIGNAL_3 : 34|2@1+ (1,0) [0|3] "" XXX
SG_ LEFT_BLINKER : 44|1@0+ (1,0) [0|3] "" XXX
SG_ RIGHT_BLINKER : 45|1@0+ (1,0) [0|3] "" XXX
SG_ NEW_SIGNAL_1 : 0|12@1+ (1,0) [0|255] "" XXX
SG_ Counter : 12|4@1+ (1,0) [0|15] "" XXX
SG_ RIGHT_BLINKER : 45|1@1+ (1,0) [0|3] "" XXX
SG_ LEFT_BLINKER : 44|1@1+ (1,0) [0|3] "" XXX
SG_ SEATBELT_FL : 40|1@1+ (1,0) [0|3] "" XXX
BO_ 644 NEW_MSG_8: 8 XXX
SG_ Counter : 8|4@1+ (1,0) [0|15] "" XXX
BO_ 805 undefined: 8 XXX
BO_ 880 Steer_Torque_2: 8 XXX
SG_ Steering_Voltage_Flat : 0|8@1+ (1,0) [0|255] "" XXX
SG_ NEW_SIGNAL_1 : 8|1@1+ (1,0) [0|255] "" XXX
SG_ NEW_SIGNAL_2 : 30|1@1+ (1,0) [0|3] "" XXX
SG_ Steer_Torque_Sensor : 32|8@1- (-1,0) [0|255] "" XXX
SG_ Counter : 40|4@1+ (1,0) [0|15] "" XXX
SG_ NEW_SIGNAL_3 : 48|4@1- (1,0) [0|15] "" XXX
SG_ Steering_Voltage_Flat : 7|8@0+ (1,0) [0|255] "" XXX
SG_ NEW_SIGNAL_1 : 8|1@0+ (1,0) [0|255] "" XXX
SG_ NEW_SIGNAL_2 : 30|1@0+ (1,0) [0|3] "" XXX
SG_ NEW_SIGNAL_4_2017 : 52|1@0+ (1,0) [0|3] "" XXX
SG_ NEW_SIGNAL_5_2017 : 54|1@0+ (1,0) [0|3] "" XXX
SG_ Steer_Torque_Sensor : 32|8@1- (-1,0) [0|255] "" XXX
SG_ NEW_SIGNAL_4_2017 : 52|1@1+ (1,0) [0|3] "" XXX
SG_ NEW_SIGNAL_5_2017 : 54|1@1+ (1,0) [0|3] "" XXX
BO_ 881 Steering_Torque: 8 XXX
SG_ Steering_Motor_Flat : 0|10@1+ (32,0) [0|16500] "" XXX
SG_ Steer_Torque_Output : 16|11@1- (-32,0) [-16500|16500] "" XXX
SG_ Steer_Torque_Sensor : 29|11@1- (8,0) [-8500|-8500] "" XXX
SG_ Steering_Angle : 40|16@1- (-0.026,0) [-600|600] "" XXX
SG_ LKA_Lockout : 27|1@1+ (1,0) [0|1] "" XXX
SG_ Steer_Torque_Sensor : 29|11@1- (8,0) [-8500|-8500] "" XXX
SG_ Steering_Angle : 40|16@1- (-0.033,0) [-600|600] "" XXX
BO_ 882 Counter: 8 XXX
SG_ Counter : 15|4@0+ (1,0) [0|31] "" XXX
SG_ Something : 16|2@1+ (1,0) [0|255] "" XXX
SG_ Counter : 12|4@1+ (1,0) [0|31] "" XXX
BO_ 884 BodyInfo: 8 XXX
SG_ DOOR_OPEN_FR : 24|1@0+ (1,0) [0|1] "" XXX
SG_ DOOR_OPEN_FL : 25|1@0+ (1,0) [0|1] "" XXX
SG_ DOOR_OPEN_RL : 26|1@0+ (1,0) [0|1] "" XXX
SG_ DOOR_OPEN_RR : 27|1@0+ (1,0) [0|1] "" XXX
SG_ DOOR_OPEN_Hatch : 28|1@0+ (1,0) [0|1] "" XXX
SG_ _UNKNOWN : 2|3@0+ (1,0) [0|1] "" XXX
BO_ 886 undefined: 8 XXX
SG_ DOOR_OPEN_Hatch : 28|1@1+ (1,0) [0|1] "" XXX
SG_ DOOR_OPEN_RR : 27|1@1+ (1,0) [0|1] "" XXX
SG_ DOOR_OPEN_RL : 26|1@1+ (1,0) [0|1] "" XXX
SG_ DOOR_OPEN_FL : 25|1@1+ (1,0) [0|1] "" XXX
SG_ DOOR_OPEN_FR : 24|1@1+ (1,0) [0|1] "" XXX
SG_ _UNKNOWN : 0|3@1+ (1,0) [0|1] "" XXX
BO_ 864 Engine_Temp: 8 XXX
SG_ NEW_SIGNAL_1 : 32|8@1+ (1,0) [0|255] "" XXX
@ -309,22 +306,22 @@ BO_ 865 NEW_MSG_16: 8 XXX
SG_ NEW_SIGNAL_2 : 12|1@1+ (1,0) [0|255] "" XXX
BO_ 866 Fuel__: 8 XXX
SG_ NEW_SIGNAL_2 : 55|8@0+ (1,0) [0|16777215] "" XXX
SG_ NEW_SIGNAL_3 : 35|4@0+ (1,0) [0|255] "" XXX
SG_ NEW_SIGNAL_4 : 47|8@0+ (1,0) [0|1] "" XXX
SG_ NEW_SIGNAL_1 : 0|16@1+ (1,0) [0|255] "" XXX
SG_ NEW_SIGNAL_5 : 24|1@0+ (1,0) [0|32767] "" XXX
SG_ NEW_SIGNAL_5 : 24|1@1+ (1,0) [0|32767] "" XXX
SG_ NEW_SIGNAL_3 : 32|4@1+ (1,0) [0|255] "" XXX
SG_ NEW_SIGNAL_4 : 40|8@1+ (1,0) [0|1] "" XXX
SG_ NEW_SIGNAL_2 : 48|8@1+ (1,0) [0|16777215] "" XXX
BO_ 872 NEW_MSG_15: 8 XXX
SG_ NEW_SIGNAL_1 : 31|8@0+ (1,0) [0|65535] "" XXX
SG_ NEW_SIGNAL_1 : 24|8@1+ (1,0) [0|65535] "" XXX
BO_ 977 NEW_MSG_12: 8 XXX
SG_ NEW_SIGNAL_1 : 0|8@1+ (1,0) [0|255] "" XXX
SG_ NEW_SIGNAL_2 : 16|12@1+ (1,0) [0|255] "" XXX
BO_ 1632 Huge_Counter: 8 XXX
SG_ NEW_SIGNAL_1 : 31|8@0+ (1,0) [0|255] "" XXX
SG_ Counter : 55|16@0+ (1,0) [0|255] "" XXX
SG_ NEW_SIGNAL_1 : 31|8@0+ (1,0) [0|255] "" XXX
BO_ 1745 NEW_MSG_11: 8 XXX
SG_ NEW_SIGNAL_1 : 24|6@1+ (1,0) [0|255] "" XXX
@ -332,8 +329,8 @@ BO_ 1745 NEW_MSG_11: 8 XXX
SG_ NEW_SIGNAL_3 : 0|8@1+ (1,0) [0|255] "" XXX
BO_ 1786 NEW_MSG_9: 8 XXX
SG_ Counter : 3|4@0+ (1,0) [0|255] "" XXX
SG_ NEW_SIGNAL_2 : 8|16@1+ (1,0) [0|15] "" XXX
SG_ Counter : 0|4@1+ (1,0) [0|255] "" XXX
@ -346,26 +343,28 @@ CM_ SG_ 320 Off_Throttle_2 "Less sensitive";
CM_ SG_ 320 Throttle_Body_ "Throttle related";
CM_ SG_ 328 Gear "15 = P, 14 = R, 0 = N, 1-6=gear";
CM_ SG_ 328 Gear_2 "15 = P, 14 = R, 0 = N, 1-6=gear";
CM_ SG_ 353 NEW_SIGNAL_3_Blank "always 2";
CM_ SG_ 353 NEW_SIGNAL_2_Blank "0";
CM_ SG_ 353 NEW_SIGNAL_9 "flipped around quick engagement";
CM_ SG_ 353 NEW_SIGNAL_6_Blank "always 1";
CM_ SG_ 353 Button "1 = main, 2 = set shallow, 3 = set deep, 4 = resume shallow, 5 resume deep";
CM_ SG_ 353 Brake_On "long activatedish";
CM_ SG_ 353 SET_1 "always 1";
CM_ SG_ 353 SET_2 "";
CM_ SG_ 353 NEW_SIGNAL_9 "flipped around quick engagement";
CM_ SG_ 354 RPM "20hz version of Transmission_Engine under Transmission";
CM_ SG_ 358 Car_Follow "front car detected";
CM_ SG_ 358 ES_Error "No engagement until restart";
CM_ SG_ 358 Cruise_Activated "is 1 when cruise is able to go";
CM_ SG_ 358 Disengage_Alert "seatbelt and steep hill disengage";
CM_ SG_ 358 3SecondDisengage "seatbelt disengage";
CM_ SG_ 359 All_depart_2015 "always 1 on 2017";
CM_ SG_ 359 LKAS_Inactive_2017 "1 when not steering, 0 when lkas steering";
CM_ SG_ 359 Sig2All_Depart "Left and right depart";
CM_ SG_ 359 Sig1All_Depart "Left and right depart";
CM_ SG_ 358 Disengage_Alert "seatbelt and steep hill disengage";
CM_ SG_ 358 Cruise_Activated "is 1 when cruise is able to go";
CM_ SG_ 358 ES_Error "No engagement until restart";
CM_ SG_ 358 Lead_Car "front car detected";
CM_ SG_ 359 Sig1Right_Depart "right depart, hill steep and seatbelt disengage";
CM_ SG_ 359 LKAS_Inactive_2017 "1 when not steering, 0 when lkas steering";
CM_ SG_ 359 Sig1Right_Depart_Front "object in front, right depart, hill steep and seatbelt disengage alert ";
CM_ SG_ 359 Left_Depart_Front "warning after acceleration into car in front and left depart";
CM_ SG_ 359 Alerts "2 = lead beep";
CM_ SG_ 359 Sig1All_Depart "Left and right depart";
CM_ SG_ 359 Sig2All_Depart "Left and right depart";
CM_ SG_ 359 All_depart_2015 "always 1 on 2017";
CM_ SG_ 642 Counter "Affected by signals";
CM_ SG_ 642 RIGHT_BLINKER "0 off, 2 right, 1 left";
CM_ SG_ 642 SEATBELT_FL "";
CM_ SG_ 880 Steering_Voltage_Flat "receives later than 371";
CM_ SG_ 880 NEW_SIGNAL_1 "0 in 2017";
CM_ SG_ 880 NEW_SIGNAL_4_2017 "1 in 2017";