#socket-can #automotive #dbc #can #ecu #database

bin+lib dbcc

数据基础 CAN (dbc) 文件编译成 Rust 代码

17 个版本 (8 个稳定版)

2.2.1 2020 年 11 月 5 日
2.2.0 2020 年 10 月 23 日
2.1.2 2020 年 9 月 23 日
2.1.0 2020 年 7 月 22 日
1.0.1 2019 年 4 月 10 日

数据库实现 中排名 98

每月 46 次下载

MIT 许可证

295KB
519

dbcc 构建状态

=============

dbcc 可以将 数据基础 CAN 文件转换为 Rust 代码。生成的代码可以通过例如与信号值枚举类型匹配等方式以类型安全的方式与 CAN 信号进行交互。此外,它还提供了一种方便的方式使用 SocketCAN BCM Sockets,通过 tokio 流来过滤指定的消息。

功能

  • 生成消息、信号解码器代码
  • 生成消息 ID 常量
  • 生成用于匹配信号值的枚举
  • 生成用于 CAN 消息的 tokio 流
  • 生成消息、信号编码器

选项 1 - 运行 CLI

安装

cargo install dbcc

使用 CLI 生成代码。

dbcc --input dbcc --with-tokio -i examples/j1939.dbc > examples/gen/j1939.rs

生成运行时警告,请使用

RUST_LOG=info dbcc --with-tokio -i examples/j1939.dbc > examples/gen/j1939.rs

选项 2 - build.rs

在构建时生成代码。将以下内容添加到您的 build.rs。根据您的需要调整 dbc 输入路径和目标路径。

use dbcc::{DbccOpt, can_code_gen};
use can_dbc;

use std::fs::File;
use std::io::prelude::*;
use std::path::Path;

fn main() -> std::io::Result<()> {
    let dbcs = &[
        ("./dbcs/j1939.dbc", "./src/lib.rs"),
    ];
    generate_code_for_dbc(dbcs)?;
    Ok(())
}

fn generate_code_for_dbc<P: AsRef<Path>>(input_output: &[(P, P)]) -> std::io::Result<()> {

    for (input_path, output_path) in input_output {
        let mut f = File::open(input_path).expect("Failed to open input file");
        let mut buffer = Vec::new();
        f.read_to_end(&mut buffer).expect("Failed to read file");

        let opt = DbccOpt {
            with_tokio: true,
        };

        let dbc_content = can_dbc::DBC::from_slice(&buffer).expect("Failed to read DBC file");
        let code = can_code_gen(&opt, &dbc_content).expect("Failed to generate rust code");

        let mut f = File::create(output_path)?;
        f.write_all(&code.to_string().into_bytes())?;
    }

    Ok(())
}

包含

  • 将生成的 Rust 文件移动到您的项目的 src/ 文件夹。
  • 将以下依赖项添加到您的项目的 Cargo.toml
[dependencies]
byteorder = "1.2"

使用

/// If you are using Rust 2018 no `external crate byteorder;` is necessary
/// Generated module
mod j1939;

fn main() {
    // J1939 - Operators External Light Controls Message Id
    let can_message_id = 2365443326u32;
    // can frame data field (0-8 bytes)
    let can_frame_data: Vec<u8> = vec![0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];

    // CAN Message ID constant from generated code
    if can_message_id == j1939::MESSAGE_ID_OEL {
        // J1939 - Operators External Light Controls Message
        let oel = j1939::Oel::new(can_frame_data);

        // Signal indicate the selected position of the operator's hazard light switch.
        match oel.hazardlightswitch() {
            j1939::HazardLightSwitch2365443326::HazardLampsToBeFlashing => println!("Hazard Lamps To Be Flashing"),
            j1939::HazardLightSwitch2365443326::HazardLampsToBeOff => println!("Hazard Lamps To Be Off"),
            j1939::HazardLightSwitch2365443326::NotAvailable => println!("Not available"),
            j1939::HazardLightSwitch2365443326::Error => println!("Error"),
            j1939::HazardLightSwitch2365443326::XValue(_) => unreachable!(),
        }
    }
}

包含 SocketCAN 流

  • 在调用 dbcc 时确保传递 --with-tokio 标志。
  • 将生成的 Rust 文件移动到您的项目的 src/ 文件夹。
  • 将以下依赖项添加到您的项目的 Cargo.toml
[dependencies]
byteorder = "1.3"
futures = "0.3"
tokio = "0.3"
tokio-socketcan-bcm = "1.0"
mod j1939;

use futures::future::Future;
use futures::stream::Stream;
use std::io;
use std::time::Duration;
use tokio;

fn main() -> io::Result<()> {
    let ival = Duration::from_secs(0);

    let f = j1939::Oel::stream("vcan0", &ival, &ival)?
        .for_each(|oel| {
            // Signal indicates the selected position of the operator's hazard light switch.
            match oel.hazardlightswitch() {
                j1939::HazardLightSwitch2365443326::HazardLampsToBeFlashing => {
                    println!("Hazard Lamps To Be Flashing")
                }
                j1939::HazardLightSwitch2365443326::HazardLampsToBeOff => {
                    println!("Hazard Lamps To Be Off")
                }
                j1939::HazardLightSwitch2365443326::NotAvailable => println!("Not available"),
                j1939::HazardLightSwitch2365443326::Error => println!("Error"),
                j1939::HazardLightSwitch2365443326::XValue(_) => unreachable!(),
            }
            Ok(())
        });

    tokio::run(f.map_err(|_| ()));

    Ok(())
}

命名

建议:值描述,即 VAL_ ... 应仅包含字母数字字符或下划线,并且应以字母字符开头。例如,VAL_ 100 "111 Wunderschön Inc" 255 应为 VAL_ 100 " Wunderschoen Inc 111" 255

  • 枚举:如果名称不以字母字符开头,则生成的名称前缀为 X
  • 枚举:非字母数字字符或_将被替换为X
  • 枚举:为每个枚举添加一个XValue(f64)变体,因为值描述通常无法涵盖所有可能性。

依赖关系

~8–18MB
~228K SLoC