# dbc-data

[![GitHub repo](https://img.shields.io/badge/github-oxibus/dbc--data-8da0cb?logo=github)](https://github.com/oxibus/dbc-data)
[![crates.io version](https://img.shields.io/crates/v/dbc-data)](https://crates.io/crates/dbc-data)
[![crate usage](https://img.shields.io/crates/d/dbc-data)](https://crates.io/crates/dbc-data)
[![docs.rs status](https://img.shields.io/docsrs/dbc-data)](https://docs.rs/dbc-data)
[![crates.io license](https://img.shields.io/crates/l/dbc-data)](https://github.com/oxibus/dbc-data)
[![CI build status](https://github.com/oxibus/dbc-data/actions/workflows/ci.yml/badge.svg)](https://github.com/oxibus/dbc-data/actions)
[![Codecov](https://img.shields.io/codecov/c/github/oxibus/dbc-data)](https://app.codecov.io/gh/oxibus/dbc-data)

A derive-macro which produces code to access signals within CAN
messages, as described by a `.dbc` file.  The generated code has
very few dependencies: just core primitives and `[u8]` slices, and
is `#[no_std]` compatible.

## Changelog

[CHANGELOG.md](./CHANGELOG.md)

## Example

Given a `.dbc` file containing:

```text
BO_ 1023 SomeMessage: 4 Ecu1
 SG_ Unsigned16 : 16|16@0+ (1,0) [0|0] "" Vector__XXX
 SG_ Unsigned8 : 8|8@1+ (1,0) [0|0] "" Vector__XXX
 SG_ Signed8 : 0|8@1- (1,0) [0|0] "" Vector__XXX
```

The following code can be written to access the fields of the
message:

```rust
pub use dbc_data::*;

#[derive(DbcData, Default)]
#[dbc_file = "tests/example.dbc"]
struct TestData {
    some_message: SomeMessage,
}

fn test() {
    let mut t = TestData::default();

    assert_eq!(SomeMessage::ID, 1023);
    assert_eq!(SomeMessage::DLC, 4);
    assert!(t.some_message.decode(&[0xFE, 0x34, 0x56, 0x78]));
    assert_eq!(t.some_message.Signed8, -2);
    assert_eq!(t.some_message.Unsigned8, 0x34);
    assert_eq!(t.some_message.Unsigned16, 0x5678); // big-endian
}
```

An `enum` can also be used to derive the types for signals
and messages.

See the test cases in this crate for examples of usage.

## Code Generation

This crate is aimed at embedded systems where typically some
subset of the messages and signals defined in the `.dbc` file are
of interest, and the rest can be ignored for a minimal footprint.
If you need to decode the entire DBC into rich (possibly
`std`-dependent) types to run on a host system, there are other
crates for that such as `dbc_codegen`.

### Messages

As `.dbc` files typically contain multiple messages, each of these
can be brought into scope by referencing their name as a type
(e.g. `SomeMessage` as shown above) and this determines what code
is generated.  Messages not referenced will not generate any code.

When a range of message IDs contain the same signals, such as a
series of readings which do not fit into a single message, then
declaring an array will allow that type to be used for all of
them.

## Signals

For cases where only certain signals within a message are needed,
the `#[dbc_signals]` attribute lets you specify which ones are
used.

### Types

Single-bit signals generate `bool` types, and signals with a scale
factor generate `f32` types.  All other signals generate signed or
unsigned native types which are large enough to fit the contained
values, e.g.  13-bit signals will be stored in a `u16` and 17-bit
signals will be stored in a `u32`.

## Additional `#[derive(...)]`s
To specify additional traits derived for the generated types, use
the `#[dbc_derive(...)]` attribute with a comma-separated list of
trait names.  The `Default`, `Copy`, and `Clone` traits are derived
by default.

## Usage

As DBC message names tend to follow different conventions from Rust
code, it can be helpful to wrap them in `newtype` declarations.
Additionally, it is often desirable to scope these identifiers away
from application code by using a private module:

```rust,no_run
mod private {
    use dbc_data::DbcData;
    #[derive(DbcData)]
    // (struct with DBC messages, e.g. some_Message_NAME)
}

pub type SomeMessageName = private::some_Message_NAME;
```

The application uses this wrapped type without exposure to the
DBC-centric naming.  The wrapped types can have their own `impl`
block(s) to extend functionality, if desired.  Functions which
perform operations on signals, define new constants, etc. can be
added in such blocks.  The application can access signal fields
directly from the underlying type and/or use the wrapped
interfaces.

## Functionality

* Decode signals from PDU into native types
  * const definitions for `ID: u32`, `DLC: u8`, `EXTENDED: bool`,
    and `CYCLE_TIME: usize` when present
* Encode signal into PDU (except unaligned BE)

## TODO

* Encode unaligned BE signals
* Generate dispatcher for decoding based on ID (including ranges)
* Enforce that arrays of messages contain the same signals
* Support multiplexed signals
* Emit `enum`s for value-tables, with optional type association

## Development

* This project is easier to develop with [just](https://github.com/casey/just#readme), a modern alternative to `make`.
  Install it with `cargo install just`.
* To get a list of available commands, run `just`.
* To run tests, use `just test`.

## License

Licensed under either of

* Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or <https://www.apache.org/licenses/LICENSE-2.0>)
* MIT license ([LICENSE-MIT](LICENSE-MIT) or <https://opensource.org/licenses/MIT>)
  at your option.

### Contribution

Unless you explicitly state otherwise, any contribution intentionally
submitted for inclusion in the work by you, as defined in the
Apache-2.0 license, shall be dual-licensed as above, without any
additional terms or conditions.
