• Stars
    star
    340
  • Rank 124,317 (Top 3 %)
  • Language
    C
  • License
    MIT License
  • Created about 8 years ago
  • Updated 8 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

CAN DBC to C (and CSV, JSON and XML) compiler using the mpc parser combinator library

dbcc

DBC converter/compiler

This program turns a DBC file into a number of different formats.

CAN-FD IS CURRENTLY NOT SUPPORTED.

As you can see by the big note above, CAN-FD is currently not supported, and likely will not (for a while). The problem is that CAN-FD allows for messages above 64-bits in length and this project and the code generated from it makes the assumption that 8-bits is all that the Lord (or Satan if your project is dealing with AUTOSAR) intended a CAN message to have in it.

Introduction

dbcc is a program for converting a DBC file primarily into into C code that can serialize and deserialize CAN messages into structures that represent those messages and signals. It is also possible to print out the information contained in a structure.

Building, Licenses and Dependencies

See the license file for details of the license for this program, it is released under the MIT license. Dependencies, if linked against, may have their own license and their own set of restrictions if built against.

The sources file mpc.c and mpc.h originate from a parser combinator written in C called MPC and are licensed under the 3 Clause BSD license.

To build, you only need a C (C99) compiler and Make (probably GNU make, I make no effort to support other Make implementations). The dbcc program itself it written in what should be portable C with the only external dependency being your platforms C library.

You should be able to type:

make

To build, an executable called 'dbcc' is produced. To test run the tests, xmllint is required.

C Coding Standards

  • When in doubt, format with indent with the "-linux" option.
  • Use tabs, not spaces for formatting
  • Use assertions where possible (not for error checking, for checking pre/post conditions and invariants).
  • The tool should run on Windows and Linux with no modification. The project is written in pure C.
  • No external dependencies should brought into the project.

Notes on generated code

  • If you want a specific format in the generated code, integrate indent into you toolchain instead of trying to change the code generator.
  • The output of the generated code is generally not stable, it may change from commit to commit, download and maintain a specific version if you want stability.
  • That said, the -n option can be used to specify the output version which might give you access to previous behaviour if backwards compatibility has been implemented.

Generated output versions

You can specify the version to use on a command line with the -n option. The latest version will be used by default.

Version 1:

Legacy/original behaviour. Note that this still won't provide a stable output, but will have a better chance of not having breaking changes.

Version 2:

  • Latest version

  • Enum names are qualified with the CAN message name

  • encode/decode function names are also qualified with the message name

How to use the generated code

The code generator can make code to unpack a message (turn some bytes into a data structure), decode a message (apply a scaling/offset minimum and maximum values to the values in a data structure), and the inverse can be done (pack/encode).

You can look at the code generated from the DBC files within the project to get an understanding of how it should work.

If you want to process a CAN message that you have received you will need to call the 'unpack_message'. The code generate is agnostic to the CPUs byte order, it takes a 'uint64_t' value containing a single CAN packet (along with the CAN ID and the DLC for the that packet) and unpacks that into a structure it generates. The first byte of the CAN packet should be put in the least significant byte of the 'uint64_t'.

You can use the following functions to convert to/from a CAN message:

static uint64_t u64_from_can_msg(const uint8_t m[8]) {
	return ((uint64_t)m[7] << 56) | ((uint64_t)m[6] << 48) | ((uint64_t)m[5] << 40) | ((uint64_t)m[4] << 32) 
		| ((uint64_t)m[3] << 24) | ((uint64_t)m[2] << 16) | ((uint64_t)m[1] << 8) | ((uint64_t)m[0] << 0);
}

static void u64_to_can_msg(const uint64_t u, uint8_t m[8]) {
	m[7] = u >> 56;
	m[6] = u >> 48;
	m[5] = u >> 40;
	m[4] = u >> 32;
	m[3] = u >> 24;
	m[2] = u >> 16;
	m[1] = u >>  8;
	m[0] = u >>  0;
}

The code generator will make a structure based on the file name of the DBC file, so for the example DBC file 'ex1.dbc' a data structure called 'can_obj_ex1_h_t' is made. This structure contains all of the CAN message structures, which in turn contain all of the signals. Having all of the messages/signals in one structure has advantages and disadvantages, one of the things it makes easier is defining the data structures needed.

/* reminder of the 'unpack_message' prototype */
int unpack_message(can_obj_ex1_h_t *o, const unsigned long id, uint64_t data, uint8_t dlc);

static can_obj_ex1_h_t ex1;

uint8_t can_message_raw[8];
unsigned long id = 0;
uint8_t dlc = 0;
your_function_to_receive_a_can_message(can_message_raw, &id, &dlc);
if (unpack_message(&ex1, id, can_message_u64, dlc) < 0) {
	// Error Condition; something went wrong
	return -1;
}

'unpack_message' calls the correct unpack function for that ID, as an example for ID '0x020':

case 0x020: return unpack_can_0x020_MagicCanNode1RBootloaderAddress(&o->can_0x020_MagicCanNode1RBootloaderAddress, data, dlc);

The unpack function populates the message object in the 'can_obj_ex1_h_t' structure for that ID. The individual signals can then be decoded with the appropriate functions for that signal. For example:

uint16_t b = 0;
if (decode_can_0x020_MagicNode1R_BLAddy(o, &b)) {
	/* error */
}

To transmit a message, each signal has to be encoded, then the pack function will return a packed message.

Some other notes:

  • Asserts can be disabled with a command line option
  • An option to force the encode/decode function to only use the double width floating point type has been added, so different function types do not have to be dealt with by the programmer.
  • You can remove the message number from the functions and values generated, which is useful if your message numbers are changing a lot, however the names for each message and signal must then be unique.

DBC file specification

For a specification, as I understand it, of the DBC file format, see dbc.md. This is a work in progress.

DBC VIM syntax file

There is a Vim syntax file for DBC files in the project, called dbc.vim

XML Generation

As well as C, XML can be generated, the project contains an XSD and XSLT file for the generated XML.

BSM (beSTORM Module) Generation

An XML based file that can be imported into Beyond Security's beSTORM and used to test CAN BUS infrastructure.

  • Note: May be replaced with an XSLT in the future, deriving from the XML output. The BSM output is itself and XML file.

CSV Generation

A flat CSV file can be generated, which is easier to import into Excel.

JSON Generation

A JSON file can be generated, which is what all the cool kids use nowadays.

Operation

Consult the manual page for more information about the precise operation of the program.

Bugs / To Do

  • Generated manual page from this markdown "readme.md" file.
  • For versions going forward, especially versions that break the generated C code, it might be nice to have an option to generate previous versions of the code.
  • Support CAN-FD (big task).
  • Make definitions for message-ids and Data-Length-Codes so the user does not have to make them as either an enumeration or a define.
  • Make the bit-fields more useful
  • The floating point conversion routines assume your platform is using IEEE-754 floats. If it does not, then tough.
  • A lot of the DBC file format is not dealt with:
    • Special values
    • Timeouts
    • Error frames
    • ...
  • The generated code is not MISRA C compliant.
  • Integers that cannot be represented in a double width floating point number should be packed/unpacked correctly, however the encode/decode and printing functions will not as they use doubles for calculations (pack/unpack do not). This affects numbers larger than 2^53.
  • FYI AUTOSAR sucks. See this message for a perfect description as to why: https://old.reddit.com/r/embedded/comments/leq366/how_much_of_a_modern_carbuilt_from_the_year_2000/gmiq6d0/, I wish I had wrote it.
  • There are two pieces of information that are useful to any CAN stack for received messages; the time stamp of the received message, and the status (error CRC/timeout, message okay, or message never set). This information could be included in the generated C code.
  • Enumeration values could be checked for and only correct values should be decoded, and encoded. There is more stuff that can be done with the enumeration values, along with command line options to enumeration generation.
  • A mechanism for callbacks for custom code for floating point encoding and decoding, and other callbacks in general, could be added. Packing and unpacking floats is done in what should be a portable, but not fast, way.
  • A mechanism and system for error handling should be added, that is, a simple communications manager that does the following:
    • Each signal should have three values associated with it; Unknown (the signal has never been set), Valid, and Error (for any error).
    • If the time out for a message goes out, or a CRC check fails, then all of the messages child messages should get invalidated and set the error state.
    • If the signal contains an invalid value, it gets set to an Error state.
    • All signal access functions should check the Unknown/Error value, returning success only on a Valid signal. There are a few other details that would need to be sorted out, like how CRC and time outs could be calculated.
  • The code generator makes code for packing/encoding and unpacking/decoding, this could be done in one step to simplify the code and data structures, it means decoded/encoded values do not need to recalculated.

It would be possible to generate nice (ASCII ART) images that show how a message is structured, which helps in understanding the message in question, and is useful for documentation purposes, for example, something like:

Message Name: Example-1
Message ID: 0x10, 16
DLC: 1 (8-bits)
+-----+-----.-----.-----.-----+-----.-----+-----+
|     |                       |           |     |
|     |                       |           |     |
+-----+-----.-----.-----.-----+-----.-----+-----+
   0     1     2     3     4     5     6     7
Bit     0: Signal-Name-1, 1 bit signal, scalar 1.0, offset 0
Bits  1-2: Signal-Name-2, 4 bit signal, signed, Motorola, ...
... etcetera ...

Or something similar. This would be another output module.

<style type="text/css"> body { margin:40px auto;max-width:850px;line-height:1.6;font-size:16px;color:#444;padding:0 10px } h1,h2,h3 { line-height:1.2 } </style>

More Repositories

1

forth-cpu

A Forth CPU and System on a Chip, based on the J1, written in VHDL
VHDL
320
star
2

libforth

libforth: A small Forth interpreter that can be used as a library written in c99
C
176
star
3

bit-serial

A bit-serial CPU written in VHDL, with a simulator written in C.
VHDL
110
star
4

embed

An embeddable, tiny Forth interpreter with metacompiler.
Forth
91
star
5

subleq

16-bit SUBLEQ CPU running eForth - just for fun
Forth
52
star
6

q

A fixed point library (Signed Q16.16) for embedded systems.
C
36
star
7

pickle

Improvements to picol: A TCL like interpreter suitable as an shell in an embedded system
C
23
star
8

shrink

LZSS/RLE compression library - for making big things small and then back again, or big things slightly bigger...
C
17
star
9

httpc

HTTP client for embedded use - supports redirects and resume.
C
14
star
10

cdb

Constant Database Clone
C
12
star
11

utf8

UTF-8 library functions
C
7
star
12

liblisp

liblisp; a lisp interpreter that can be used as a library written in c99
C
7
star
13

rust-embed-forth

A small eForth VM and image in rust
Rust
7
star
14

os

VM/OS/Language work in progress
C
7
star
15

edlin

Line Editor Library for constrained systems (that also have a command line and file system...)
C
7
star
16

subleq-js

SUBLEQ eForth website and interactive interpreter.
HTML
6
star
17

lzss-forth

LZSS compression in Forth
Forth
6
star
18

forth2c

Forth 2 C compiler
Python
4
star
19

ledcom

Using an LED for light sensing and two way communication
C
4
star
20

muxleq

A two instruction set computer that greatly speeds things up over SUBLEQ
Forth
4
star
21

nackle

Crypto tools and protocols
C
3
star
22

ngram

Print out a list of ngrams for a file; works on binary data as well as text
C
3
star
23

third

Cleaned up source for a Forth like interpreter from a 1992 IOCCC winner called 'buzzard'
C
3
star
24

ebnf

EBNF compiler compiler - second attempt!
C
3
star
25

nvram

Non-volatile variables in C
Perl
3
star
26

subleq-nodejs

NPM package for SUBLEQ VM
JavaScript
2
star
27

junk

A junk yard of code
C
2
star
28

arduino

Miscellaneous Arduino Projects: FORTH, Morse Code and LED communications
C
2
star
29

unit

Tiny Unit Test "Framework" in C
C
2
star
30

snake

snake in forth
Forth
2
star
31

mod-pickle

Modules for the pickle interpreter
C
2
star
32

allocator

library to allocate from a pool, written in C, which should integrate with some of my other libraries
C
2
star
33

ascii

Just making an experimental VM that uses only ASCII printable characters for instruction ops, might port into to an FPGA
C
2
star
34

tga

netpbm to tga file
C
2
star
35

uart

General Purpose UART in VHDL
VHDL
2
star
36

morse

Simple Morse code encoding and decoding in a header only library
C
2
star
37

gladiators

Evolve tiny agents that attack each other and find food
C
2
star
38

eweb

An embeddable webserver (originally from dweb)
C
2
star
39

sntp

bare bone sntp implementation
C
2
star
40

subleq-perl

Perl N-Bit SUBLEQ interpreter with an eForth image
Perl
2
star
41

localely

Unflipping the <ctype.h> functions
C
2
star
42

hexy

Portable hexdumping routines with all the bells and whistles
C
2
star
43

subleq-vhdl

SUBLEQ computer written in VHDL for an FPGA that runs Forth
VHDL
2
star
44

ansi

ANSI terminal functions for the Pickle Interpreter
Tcl
1
star
45

forth.vim

Modified version of the Forth syntax rules for Vim
Vim Script
1
star
46

note

CLI Note taking application
C
1
star
47

fuzzy

Fuzzy string matching in perl
Perl
1
star
48

subleq-rust

SUBLEQ VM for rust with an eForth image
Rust
1
star
49

scrape

Messing around with python modules and web scraping, nothing special
Python
1
star
50

web.anapnea

My website hosted at anapnea.
HTML
1
star
51

monte-pl

A silly Monte Carlo method script to calculate Pi in Perl
Perl
1
star
52

subleq-forth

A Forth implementation of the SUBLEQ virtual machine.
Forth
1
star
53

fifo

A simple FIFO written in C
C
1
star
54

subleq-python

Python N-Bit SUBLEQ Interpreter with eForth image
Python
1
star
55

crud

A python web based CRUD application; sort of a skeleton and proof of concept project
Python
1
star
56

lisp

A small (~1000LoC) embeddable LISP interpreter
C
1
star
57

tkfind

GUI file finding utility in perl
Perl
1
star
58

howerj.github.io

website for howerj
HTML
1
star
59

tftp

Portable TFTP client and server
C
1
star
60

cdbdbs

Example databases for 32-bit version of CDB
1
star
61

dxsde

auto-generate configuration editor (experimental)
C#
1
star
62

poly

Generate list of a polynomials and some info about them for a Linear Feedback Shift Register (LFSR)
C
1
star
63

jiggle

A small auto-hotkey script to jiggle the mouse to stop screen savers from locking the screen on Windows
AutoHotkey
1
star
64

diff

A small diff utility
C
1
star
65

ffs

Forth File System using the BLOCK word-set
Forth
1
star
66

lfsr-vhdl

An implementation of a CPU that uses a Linear Feedback Shift Register as a Program Counter instead of a normal one
VHDL
1
star
67

tile

Stupid maze generator
C
1
star
68

digits-nodejs

In the spirit of making pointless little libraries for NPM I'm making one that calculates the number of digits required to represent a number in a given radix.
JavaScript
1
star
69

lfsr

A VM that uses LFSR instead of a normal program counter
Forth
1
star