A lightweight DBC file parser and C code generator for CAN bus message decoding. Vera automates the conversion of CAN message definitions into efficient C code, providing both direct decoding support and native SDK integrations.
Vera exists to simplify the workflow of working with CAN networks by providing:
- Generated API from DBC files: Parse any CAN database (DBC) file and automatically generate typed C code for encoding/decoding messages
- SDK-specific adapters: Pre-built HAL integrations for popular embedded platforms (ESP-IDF, STM32 HAL, AutoDevKit)
- Type safety: Strongly-typed structures for messages and signals, eliminating manual bit manipulation
- Minimal runtime: Generated code is self-contained and has no external dependencies beyond the C standard library
The generated code provides:
- Signal decoding from raw CAN frames with automatic scaling/offset conversion
- Signal encoding for creating CAN frames
- MQTT topic mapping via TP_ instructions, to integrate in MQTT networks and pipelines
- Validation for out-of-bounds values
- Go 1.25.1 or later
- C compiler (for building binaries)
# Clone the repository
git clone https://github.com/ApexCorse/vera.git
cd vera
# Install the CLI tool
go install ./cmd/veraYou can also find pre-built binaries in the releases page.
# Generate C code from a DBC file
vera -f network.dbc ./output
# This creates:
# - output/vera.h (header file with type definitions and function declarations)
# - output/vera.c (source file with decoding/encoding implementations)To use with a specific SDK:
# ESP-IDF integration
vera -f network.dbc -sdk espidf ./output
# STM32 HAL integration
vera -f network.dbc -sdk stm32hal ./output
# AutoDevKit integration
vera -f network.dbc -sdk autodevkit ./outputvera/
├── cmd/vera/ # CLI entry point
├── codegen/ # C code generation package
│ ├── codegen.go # Generic C code generation logic
│ ├── templates.go # Header and source templates
│ ├── espidf/ # ESP-IDF-specific adapter generation
│ ├── stm32hal/ # STM32 HAL-specific adapter generation
│ └── autodevkit/ # AutoDevKit-specific adapter generation
└── internal/ # Core parsing and validation (main package files below)
The main package (vera/) contains the core functionality:
| File | Description |
|---|---|
parser.go |
Parses DBC files and returns a Config structure |
message.go |
Message struct with validation and line parsing |
signal.go |
Signal struct with validation and detailed parsing |
types.go |
Shared types (Config, Node, Endianness, SignalTopic) |
validator.go |
Validation of DBC content (signal placement, duplicate topics, etc.) |
errors.go |
Error construction with line number context |
The codegen/ package handles C code generation:
| File | Description |
|---|---|
vera.{h,c}.tmpl |
Source and header file templates (used via text/template) |
codegen.go |
Function for generating standard vera.h and vera.c |
espidf/ |
ESP-IDF HAL adapter (decodes ESP's native twai_frame_t type) |
stm32hal/ |
STM32 HAL adapter (decodes CAN_RxHeaderTypeDef and CAN_TxHeaderTypeDef) |
autodevkit/ |
AutoDevKit adapter (decodes CANTxFrame type) |
# Basic usage
vera [options] <build_path>
# Options
-f <file> DBC file path (default: config.dbc)
-sdk <sdk> Target SDK: espidf, stm32hal, autodevkit
-v Print version (from VERA_VERSION env var)#include "vera.h"
int main() {
// Initialize a CAN frame with data
vera_can_rx_frame_t frame = {
.id = 0x7B,
.dlc = 6,
.data = {0x10, 0x20, 0x30, 0x40, 0x50, 0x60}
};
// Decode the message
vera_decoding_result_t result = {0};
vera_err_t err = vera_decode_can_frame(&frame, &result);
if (err == vera_err_ok) {
for (uint8_t i = 0; i < result.n_signals; i++) {
printf("Signal: %s = %.2f %s\n",
result.decoded_signals[i].name,
result.decoded_signals[i].value,
result.decoded_signals[i].unit);
}
free(result.decoded_signals);
}
return 0;
}With espidf:
#include "vera_espidf.h"
void process_can_message(const twai_frame_t* esp_frame) {
vera_decoding_result_t result = {0};
vera_err_t err = vera_decode_espidf_rx_frame(esp_frame, &result);
if (err == vera_err_ok) {
// Process decoded signals...
free(result.decoded_signals);
}
}With stm32hal:
#include "vera_stm32hal.h"
void process_can_message(CAN_RxHeaderTypeDef* can_header, uint8_t* data) {
vera_decoding_result_t result = {0};
vera_err_t err = vera_decode_stm32hal_rx_frame(can_header, data, &result);
if (err == vera_err_ok) {
// Process decoded signals...
free(result.decoded_signals);
}
}Vera expects DBC files with the following format:
BO_ <message_id> <message_name>: <dlc> <transmitter>
SG_ <signal_name> : <start_bit>|<length>@<endianness><sign> (<factor>,<offset>) [<min>|<max>] "<unit>" <receivers>
TP_ <signal_name> <mqtt_topic>
Important notes:
- Start bit and length are in bits, DLC is in bytes
- Receivers are parsed if present, but not used in code generation
- Only little-endian (endiananness
1) is currently supported - TP_ instructions are placed at the same level as BO_ instructions (not indented), and refer to the signals, not the messages
BO_ 123 EngineSpeed: 6 Engine
SG_ EngineSpeed : 0|32@1+ (0.1,0) [0|8000] "RPM" DriverGateway
SG_ BatteryTemperature : 32|16@1+(12,4) (1,0) [0|8000] "ºC" DriverGateway
TP_ EngineSpeed vehicle/engine/speed
TP_ BatteryTemperature vehicle/battery/temperature
# Run all tests
go test ./...
# Run tests with verbose output
go test -v ./...
# Run specific test file
go test ./parser_test.go
# Run tests with coverage
go test -cover ./...
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out# Build the CLI tool
go build ./cmd/vera
# Install for local use
go install ./cmd/veraReleases are automatically created when you push a git tag:
# Create and push a version tag
git tag -a v1.0.0 -m "Release v1.0.0"
git push origin v1.0.0The GitHub Actions workflow handles:
- Building binaries for Linux (amd64), Windows (amd64), macOS Intel (amd64), and macOS Apple Silicon (arm64)
- Creating a GitHub release with auto-generated notes
- Uploading platform binaries as release assets
.
├── cmd/vera/ # CLI entry point (main.go)
├── codegen/ # C code generation
│ ├── codegen.go # Generic code generation
│ ├── vera.c.tmpl # Source file template
│ ├── vera.h.tmpl # Header file template
│ ├── espidf/ # ESP-IDF HAL adapter
│ ├── stm32hal/ # STM32 HAL adapter
│ └── autodevkit/ # AutoDevKit adapter
├── gentest/ # Test infrastructure
│ ├── CMakeLists.txt # CMake build config
│ ├── config-test.dbc # Test DBC file
│ ├── test.c # Test application
│ ├── test.sh # Test runner script
│ └── unity/ # Unity test framework
├── vera/ # Main package (core functionality)
│ ├── parser.go # DBC parser
│ ├── message.go # Message parsing/validation
│ ├── signal.go # Signal parsing/validation
│ ├── types.go # Shared types
│ ├── validator.go # DBC validation
│ ├── errors.go # Error types
│ ├── message_test.go # Message tests
│ ├── parser_test.go # Parser tests
│ ├── signal_test.go # Signal tests
│ └── validator_test.go # Validator tests
├── go.mod
├── go.sum
└── README.md
When contributing to Vera:
- Write tests for new features or bug fixes
- Update documentation as needed
- Follow the existing code style
- All tests should pass before submitting a pull request
This project is part of the ApexCorse organization.