#[cfg(feature = "with-serde")]
extern crate serde;
#[cfg(feature = "with-serde")]
#[macro_use]
extern crate serde_derive;
use derive_getters::Getters;
use nom::types::CompleteByteSlice;
use nom::*;
pub mod parser;
#[cfg(test)]
mod tests {
use super::*;
use std::str;
const SAMPLE_DBC: &'static [u8] = b"
VERSION \"0.1\"
NS_ :
NS_DESC_
CM_
BA_DEF_
BA_
VAL_
CAT_DEF_
CAT_
FILTER
BA_DEF_DEF_
EV_DATA_
ENVVAR_DATA_
SGTYPE_
SGTYPE_VAL_
BA_DEF_SGTYPE_
BA_SGTYPE_
SIG_TYPE_REF_
VAL_TABLE_
SIG_GROUP_
SIG_VALTYPE_
SIGTYPE_VALTYPE_
BO_TX_BU_
BA_DEF_REL_
BA_REL_
BA_DEF_DEF_REL_
BU_SG_REL_
BU_EV_REL_
BU_BO_REL_
SG_MUL_VAL_
BS_:
BU_: PC
BO_ 2000 WebData_2000: 4 Vector__XXX
SG_ Signal_8 : 24|8@1+ (1,0) [0|255] \"\" Vector__XXX
SG_ Signal_7 : 16|8@1+ (1,0) [0|255] \"\" Vector__XXX
SG_ Signal_6 : 8|8@1+ (1,0) [0|255] \"\" Vector__XXX
SG_ Signal_5 : 0|8@1+ (1,0) [0|255] \"\" Vector__XXX
BO_ 1840 WebData_1840: 4 PC
SG_ Signal_4 : 24|8@1+ (1,0) [0|255] \"\" Vector__XXX
SG_ Signal_3 : 16|8@1+ (1,0) [0|255] \"\" Vector__XXX
SG_ Signal_2 : 8|8@1+ (1,0) [0|255] \"\" Vector__XXX
SG_ Signal_1 : 0|8@1+ (1,0) [0|0] \"\" Vector__XXX
EV_ Environment1: 0 [0|220] \"\" 0 6 DUMMY_NODE_VECTOR0 DUMMY_NODE_VECTOR2;
EV_ Environment2: 0 [0|177] \"\" 0 7 DUMMY_NODE_VECTOR1 DUMMY_NODE_VECTOR2;
ENVVAR_DATA_ SomeEnvVarData: 399;
CM_ BO_ 1840 \"Some Message comment\";
CM_ SG_ 1840 Signal_4 \"asaklfjlsdfjlsdfgls
HH?=(%)/&KKDKFSDKFKDFKSDFKSDFNKCnvsdcvsvxkcv\";
CM_ SG_ 5 TestSigLittleUnsigned1 \"asaklfjlsdfjlsdfgls
=0943503450KFSDKFKDFKSDFKSDFNKCnvsdcvsvxkcv\";
BA_DEF_DEF_ \"BusType\" \"AS\";
BA_ \"Attr\" BO_ 4358435 283;
BA_ \"Attr\" BO_ 56949545 344;
VAL_ 2000 Signal_3 255 \"NOP\";
SIG_VALTYPE_ 2000 Signal_8 : 1;
";
#[test]
fn dbc_definition_test() {
match DBC::from_slice(SAMPLE_DBC) {
Ok(dbc_content) => println!("DBC Content{:#?}", dbc_content),
Err(e) => {
match e {
Error::NomError(nom::Err::Incomplete(needed)) => {
eprintln!("Error incomplete input, needed: {:?}", needed)
}
Error::NomError(nom::Err::Error(ctx)) => match ctx {
verbose_errors::Context::Code(i, kind) => eprintln!(
"Error Kind: {:?}, Code: {:?}",
kind,
str::from_utf8(i.as_bytes())
),
verbose_errors::Context::List(l) => eprintln!("Error List: {:?}", l),
},
Error::NomError(nom::Err::Failure(ctx)) => eprintln!("Failure {:?}", ctx),
Error::Incomplete(dbc, remaining) => eprintln!(
"Not all data in buffer was read {:#?}, remaining unparsed: {}",
dbc,
String::from_utf8(remaining).unwrap()
),
}
panic!("Failed to read DBC");
}
}
}
#[test]
fn lookup_signal_comment() {
let dbc_content = DBC::from_slice(SAMPLE_DBC).expect("Failed to parse DBC");
let comment = dbc_content
.signal_comment(&MessageId(1840), "Signal_4")
.expect("Signal comment missing");
assert_eq!(
"asaklfjlsdfjlsdfgls\nHH?=(%)/&KKDKFSDKFKDFKSDFKSDFNKCnvsdcvsvxkcv",
comment
);
}
#[test]
fn lookup_signal_comment_none_when_missing() {
let dbc_content = DBC::from_slice(SAMPLE_DBC).expect("Failed to parse DBC");
let comment = dbc_content.signal_comment(&MessageId(1840), "Signal_2");
assert_eq!(None, comment);
}
#[test]
fn lookup_message_comment() {
let dbc_content = DBC::from_slice(SAMPLE_DBC).expect("Failed to parse DBC");
let comment = dbc_content
.message_comment(&MessageId(1840))
.expect("Message comment missing");
assert_eq!("Some Message comment", comment);
}
#[test]
fn lookup_message_comment_none_when_missing() {
let dbc_content = DBC::from_slice(SAMPLE_DBC).expect("Failed to parse DBC");
let comment = dbc_content.message_comment(&MessageId(2000));
assert_eq!(None, comment);
}
#[test]
fn lookup_value_descriptions_for_signal() {
let dbc_content = DBC::from_slice(SAMPLE_DBC).expect("Failed to parse DBC");
let val_descriptions = dbc_content
.value_descriptions_for_signal(&MessageId(2000), "Signal_3")
.expect("Message comment missing");
let exp = vec![ValDescription {
a: 255.0,
b: "NOP".to_string(),
}];
assert_eq!(exp, val_descriptions);
}
#[test]
fn lookup_value_descriptions_for_signal_none_when_missing() {
let dbc_content = DBC::from_slice(SAMPLE_DBC).expect("Failed to parse DBC");
let val_descriptions =
dbc_content.value_descriptions_for_signal(&MessageId(2000), "Signal_2");
assert_eq!(None, val_descriptions);
}
#[test]
fn lookup_extended_value_type_for_signal() {
let dbc_content = DBC::from_slice(SAMPLE_DBC).expect("Failed to parse DBC");
let extended_value_type =
dbc_content.extended_value_type_for_signal(&MessageId(2000), "Signal_8");
assert_eq!(
extended_value_type,
Some(&SignalExtendedValueType::IEEEfloat32Bit)
);
}
#[test]
fn lookup_extended_value_type_for_signal_none_when_missing() {
let dbc_content = DBC::from_slice(SAMPLE_DBC).expect("Failed to parse DBC");
let extended_value_type =
dbc_content.extended_value_type_for_signal(&MessageId(2000), "Signal_1");
assert_eq!(extended_value_type, None);
}
}
#[derive(Debug)]
pub enum Error<'a> {
Incomplete(DBC, Vec<u8>),
NomError(nom::Err<nom::types::CompleteByteSlice<'a>, u32>),
}
#[derive(Copy, Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize))]
pub struct Baudrate(u64);
#[derive(Clone, Debug, PartialEq, Getters)]
#[cfg_attr(feature = "serde", derive(Serialize))]
pub struct Signal {
name: String,
multiplexer_indicator: MultiplexIndicator,
pub start_bit: u64,
pub signal_size: u64,
byte_order: ByteOrder,
value_type: ValueType,
pub factor: f64,
pub offset: f64,
pub min: f64,
pub max: f64,
unit: String,
receivers: Vec<String>,
}
#[derive(Copy, Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize))]
pub struct MessageId(pub u32);
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize))]
pub enum Transmitter {
NodeName(String),
VectorXXX,
}
#[derive(Clone, Debug, PartialEq, Getters)]
#[cfg_attr(feature = "serde", derive(Serialize))]
pub struct MessageTransmitter {
message_id: MessageId,
transmitter: Vec<Transmitter>,
}
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize))]
pub struct Version(String);
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize))]
pub struct Symbol(String);
#[derive(Copy, Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize))]
pub enum MultiplexIndicator {
Multiplexor,
MultiplexedSignal(u64),
Plain,
}
#[derive(Copy, Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize))]
pub enum ByteOrder {
LittleEndian,
BigEndian,
}
#[derive(Copy, Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize))]
pub enum ValueType {
Signed,
Unsigned,
}
#[derive(Copy, Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize))]
pub enum EnvType {
EnvTypeFloat,
EnvTypeu64,
EnvTypeData,
}
#[derive(Clone, Debug, PartialEq, Getters)]
#[cfg_attr(feature = "serde", derive(Serialize))]
pub struct SignalType {
signal_type_name: String,
signal_size: u64,
byte_order: ByteOrder,
value_type: ValueType,
factor: f64,
offset: f64,
min: f64,
max: f64,
unit: String,
default_value: f64,
value_table: String,
}
#[derive(Copy, Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize))]
pub enum AccessType {
DummyNodeVector0,
DummyNodeVector1,
DummyNodeVector2,
DummyNodeVector3,
}
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize))]
pub enum AccessNode {
AccessNodeVectorXXX,
AccessNodeName(String),
}
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize))]
pub enum SignalAttributeValue {
Text(String),
Int(i64),
}
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize))]
pub enum AttributeValuedForObjectType {
RawAttributeValue(AttributeValue),
NetworkNodeAttributeValue(String, AttributeValue),
MessageDefinitionAttributeValue(MessageId, Option<AttributeValue>),
SignalAttributeValue(MessageId, String, AttributeValue),
EnvVariableAttributeValue(String, AttributeValue),
}
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize))]
pub enum AttributeValueType {
AttributeValueTypeInt(i64, i64),
AttributeValueTypeHex(i64, i64),
AttributeValueTypeFloat(f64, f64),
AttributeValueTypeString,
AttributeValueTypeEnum(Vec<String>),
}
#[derive(Clone, Debug, PartialEq, Getters)]
#[cfg_attr(feature = "serde", derive(Serialize))]
pub struct ValDescription {
a: f64,
b: String,
}
#[derive(Clone, Debug, PartialEq, Getters)]
#[cfg_attr(feature = "serde", derive(Serialize))]
pub struct AttrDefault {
name: String,
value: AttributeValue,
}
#[cfg_attr(feature = "serde", derive(Serialize))]
#[derive(Clone, Debug, PartialEq)]
pub enum AttributeValue {
AttributeValueU64(u64),
AttributeValueI64(i64),
AttributeValueF64(f64),
AttributeValueCharString(String),
}
#[derive(Clone, Debug, PartialEq, Getters)]
#[cfg_attr(feature = "serde", derive(Serialize))]
pub struct ValueTable {
value_table_name: String,
value_descriptions: Vec<ValDescription>,
}
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize))]
pub enum Comment {
Node {
node_name: String,
comment: String,
},
Message {
message_id: MessageId,
comment: String,
},
Signal {
message_id: MessageId,
signal_name: String,
comment: String,
},
EnvVar {
env_var_name: String,
comment: String,
},
Plain {
comment: String,
},
}
#[derive(Clone, Debug, PartialEq, Getters)]
#[cfg_attr(feature = "serde", derive(Serialize))]
pub struct Message {
message_id: MessageId,
message_name: String,
message_size: u64,
transmitter: Transmitter,
signals: Vec<Signal>,
}
#[derive(Clone, Debug, PartialEq, Getters)]
#[cfg_attr(feature = "serde", derive(Serialize))]
pub struct EnvironmentVariable {
env_var_name: String,
env_var_type: EnvType,
min: i64,
max: i64,
unit: String,
initial_value: f64,
ev_id: i64,
access_type: AccessType,
access_nodes: Vec<AccessNode>,
}
#[derive(Clone, Debug, PartialEq, Getters)]
#[cfg_attr(feature = "serde", derive(Serialize))]
pub struct EnvironmentVariableData {
env_var_name: String,
data_size: u64,
}
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize))]
pub struct Node(Vec<String>);
#[derive(Clone, Debug, PartialEq, Getters)]
#[cfg_attr(feature = "serde", derive(Serialize))]
pub struct AttributeDefault {
attribute_name: String,
attribute_value: AttributeValue,
}
#[derive(Clone, Debug, PartialEq, Getters)]
#[cfg_attr(feature = "serde", derive(Serialize))]
pub struct AttributeValueForObject {
attribute_name: String,
attribute_value: AttributeValuedForObjectType,
}
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize))]
pub enum AttributeDefinition {
Message(String),
Node(String),
Signal(String),
EnvironmentVariable(String),
Plain(String),
}
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize))]
pub enum ValueDescription {
Signal {
message_id: MessageId,
signal_name: String,
value_descriptions: Vec<ValDescription>,
},
EnvironmentVariable {
env_var_name: String,
value_descriptions: Vec<ValDescription>,
},
}
#[derive(Clone, Debug, PartialEq, Getters)]
#[cfg_attr(feature = "serde", derive(Serialize))]
pub struct SignalTypeRef {
message_id: MessageId,
signal_name: String,
signal_type_name: String,
}
#[derive(Clone, Debug, PartialEq, Getters)]
#[cfg_attr(feature = "serde", derive(Serialize))]
pub struct SignalGroups {
message_id: MessageId,
signal_group_name: String,
repetitions: u64,
signal_names: Vec<String>,
}
#[derive(Copy, Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize))]
pub enum SignalExtendedValueType {
SignedOrUnsignedInteger,
IEEEfloat32Bit,
IEEEdouble64bit,
}
#[derive(Clone, Debug, PartialEq, Getters)]
#[cfg_attr(feature = "serde", derive(Serialize))]
pub struct SignalExtendedValueTypeList {
message_id: MessageId,
signal_name: String,
signal_extended_value_type: SignalExtendedValueType,
}
#[derive(Clone, Debug, PartialEq, Getters)]
#[cfg_attr(feature = "serde", derive(Serialize))]
pub struct DBC {
version: Version,
new_symbols: Vec<Symbol>,
bit_timing: Option<Vec<Baudrate>>,
nodes: Vec<Node>,
value_tables: Vec<ValueTable>,
messages: Vec<Message>,
message_transmitters: Vec<MessageTransmitter>,
environment_variables: Vec<EnvironmentVariable>,
environment_variable_data: Vec<EnvironmentVariableData>,
signal_types: Vec<SignalType>,
comments: Vec<Comment>,
attribute_definitions: Vec<AttributeDefinition>,
attribute_defaults: Vec<AttributeDefault>,
attribute_values: Vec<AttributeValueForObject>,
value_descriptions: Vec<ValueDescription>,
signal_type_refs: Vec<SignalTypeRef>,
signal_groups: Vec<SignalGroups>,
signal_extended_value_type_list: Vec<SignalExtendedValueTypeList>,
}
impl DBC {
pub fn from_slice(buffer: &[u8]) -> Result<DBC, Error> {
match parser::dbc(CompleteByteSlice(buffer)) {
Ok((remaining, dbc)) => {
if !remaining.is_empty() {
return Err(Error::Incomplete(dbc, remaining.as_bytes().to_vec()));
}
Ok(dbc)
}
Err(e) => Err(Error::NomError(e)),
}
}
pub fn message_comment(&self, message_id: &MessageId) -> Option<&str> {
self.comments
.iter()
.filter_map(|x| match x {
Comment::Message {
message_id: ref x_message_id,
ref comment,
} => {
if x_message_id == message_id {
Some(comment.as_str())
} else {
None
}
}
_ => None,
})
.next()
}
pub fn signal_comment(&self, message_id: &MessageId, signal_name: &str) -> Option<&str> {
self.comments
.iter()
.filter_map(|x| match x {
Comment::Signal {
message_id: ref x_message_id,
signal_name: ref x_signal_name,
comment,
} => {
if x_message_id == message_id && x_signal_name == signal_name {
Some(comment.as_str())
} else {
None
}
}
_ => None,
})
.next()
}
pub fn value_descriptions_for_signal(
&self,
message_id: &MessageId,
signal_name: &str,
) -> Option<&[ValDescription]> {
self.value_descriptions
.iter()
.filter_map(|x| match x {
ValueDescription::Signal {
message_id: ref x_message_id,
signal_name: ref x_signal_name,
ref value_descriptions,
} => {
if x_message_id == message_id && x_signal_name == signal_name {
Some(value_descriptions.as_slice())
} else {
None
}
}
_ => None,
})
.next()
}
pub fn extended_value_type_for_signal(
&self,
message_id: &MessageId,
signal_name: &str,
) -> Option<&SignalExtendedValueType> {
self.signal_extended_value_type_list
.iter()
.filter_map(|x| match x {
SignalExtendedValueTypeList {
message_id: ref x_message_id,
signal_name: ref x_signal_name,
ref signal_extended_value_type,
} => {
if x_message_id == message_id && x_signal_name == signal_name {
Some(signal_extended_value_type)
} else {
None
}
}
_ => None,
})
.next()
}
}