文章目录

  • 测试环境
  • RUST 安装
  • VSCode 配置
  • 新工程
  • args 命令行参数传入
  • 多文件 mod 和 include
  • 多bin 与 workspace
  • println
  • thread
  • 多生产-单消费
  • UDP
  • 库引入
  • UART serial
  • UART serial2
  • SocketCAN
  • CAN
  • CANFD
  • Github

测试环境

WSL2
Ubuntu 22.04
Kernel 5.15.57.1
cargo  1.63.0 (不定期更新)

RUST 安装

# 安装
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh# 版本检查
# 第一句可以放到 ~/.bashrc里面
source "$HOME/.cargo/env"
cargo --version
rustc --version# 更新
rustup update

VSCode 配置

插件:

  • rust-analyzer
  • Error Lens

新工程

cargo new playground
cd playground
cargo run

可执行文件的路径为

playground/target/debug/playground# 查看文件大小发现有3.xM, 应该是打包进了rust的运行时之类的
$ ls -lh target/debug/playground# 编译release版本, 会小一点
$ cargo build --release
$ ls -lh target/release/playground# 还有其它减少体积的方式, 可自行搜索# 清理
$ cargo clean

args 命令行参数传入

C语言编程时, 经常可以看到main函数

int main(int argc, char *argv[])

这里argc是参数个数, argv[]是参数的字符串数组, argv[0], argv[1]… 这些就是通过命令行传入的参数.

rust 中也有类似的, 如 std::env::args, 用法举例

use std::env;
fn main() {let args: Vec<String> = env::args().collect();println!("{:?}", args);
}

测试

$ cargo run 1 a 127.0.0.1Compiling playground v0.1.0 (/home/karoto/git/rust_note/playground)Finished dev [unoptimized + debuginfo] target(s) in 0.31sRunning `target/debug/playground 1 a 127.0.0.1`
["target/debug/playground", "1", "a", "127.0.0.1"]

或者是for循环的方式, 一个一个打出来

    for i in env::args() {println!("{}", i);}

参考 args in std::env - Rust (rust-lang.org)

多文件 mod 和 include

现在有两个文件

$ tree src
src
├── main.rs
└── test_args.rs# test_args 中要被调用的函数前面加上pub
# 这里main改成其它名字比较好
$ cat src/test_args.rs
use std::env;
pub fn main() {let args: Vec<String> = env::args().collect();println!("{:?}", args);
}# 用mod把文件引入, mod是modules缩写, 可以把一个文件看成一个module
$ cat src/main.rs
mod test_args;
fn main() {test_args::main();
}# 运行
$ cargo run 1 a Compiling playground v0.1.0 (/home/karoto/git/rust_note/playground)Finished dev [unoptimized + debuginfo] target(s) in 0.30sRunning `target/debug/playground 1 a`
["target/debug/playground", "1", "a"]

还有一种 include 的方式

# test_args 中的main要改成其它名字
$ cat src/test_args.rs
use std::env;
pub fn print_args() {let args: Vec<String> = env::args().collect();println!("{:?}", args);
}# include 引入文件/文件夹, 直接用里面pub过的fn
$ cat src/main.rs
include!("../src/test_args.rs");
fn main() {print_args();
}

参考 rust多文件/文件夹及模块管理 - 简书 (jianshu.com)

多bin 与 workspace

比如server/client, pub/sub… 参考 关于rust:如何使用Cargo构建多个二进制文件:

  • Cargo.toml文件中指定多个 [[bin]]
  • 或者 [workspace] 搭配多个工程, 每个工程都有一个 Cargo.toml

个人开发怎么都行, 多人开发第二种应该会好一点, 或者两种组合使用

第一种方式举例

$ tree
.
├── Cargo.toml
└── src├── play_args│   ├── main.rs│   └── test_args.rs└── play_hello└── main.rs# 在toml里面写两个[[bin]], 填入可执行文件名字和路径
$ cat Cargo.toml
[package]
name = "playground"
version = "0.1.0"
edition = "2021"[dependencies][[bin]]
name = "play_hello"
path = "src/play_hello/main.rs"[[bin]]
name = "play_args"
path = "src/play_args/main.rs"$ cargo build
$ ./target/debug/play_args  1 2 3
["./target/debug/play_args", "1", "2", "3"]
$ ./target/debug/play_hello
Hello, world!

第二种方式举例

# play_args 和 play_hello 是直接 cargo new 出来的
$ tree
.
├── Cargo.toml
├── play_args
│   ├── Cargo.toml
│   └── src
│       ├── main.rs
│       └── test_args.rs
└── play_hello├── Cargo.toml└── src└── main.rs# 顶层手写一个Cargo.toml, 内容如下
$ cat Cargo.toml
[workspace]
members = ["play_args", "play_hello"]$ cargo buildCompiling play_args v0.1.0 (/home/karoto/git/rust_note/playground/play_args)Compiling play_hello v0.1.0 (/home/karoto/git/rust_note/playground/play_hello)Finished dev [unoptimized + debuginfo] target(s) in 0.52s
$ ./target/debug/play_args 1 a
["./target/debug/play_args", "1", "a"]
$ ./target/debug/play_hello
Hello, world!

println

println in std - Rust (rust-lang.org)

fn add(x: i32, y: i32) -> i32 {x + y
}fn main() {// 整数let a = 1;println!("{}", a);// 字符let b = 'a';println!("{}", b);// 字符串let s = "hello";println!("{}", s);// 布尔值let b = true;println!("{}", b);// 浮点数let f = 3.1415926;println!("{}", f);// 数组let arr = [10, 11, 13, 24, 50];println!("{:?}", arr);// 元组let tup = (1, "hello", true);println!("{:?}", tup);// 函数let f = add;println!("11 + 22 = {}", f(11, 22));// =================let c = {let a = 1;let b = 2;a + b};println!("{}", c);// lambda表达式let lambda = |x: i32, y: i32| x + y;println!("{}", lambda(3, 4));// 打印匿名函数let anon = |x: i32, y: i32| x + y;println!("{:?}", anon(5, 6));// 匿名函数作为参数传递let add_one = |x: i32| x + 1;println!("{}", add_one(9));// 匿名函数作为返回值let f = || {println!("hi");};f();// 打印十六进制, 不够2位补0let hex = |x: i32| -> String {format!("{:02x}", x)};println!("{}", hex(255));// 遍历数组, 打印十六进制for i in arr.iter() {println!("{}", hex(*i));}// 排序let mut v = vec![10, 30, 11, 20, 4, 330, 21, 110, 5, 10, 1];v.sort();println!("{:?}", v);
}

运行结果

1
a
hello
true
3.1415926
[10, 11, 13, 24, 50]
(1, "hello", true)
11 + 22 = 33
3
7
11
10
hi
ff
0a
0b
0d
18
32
[1, 4, 5, 10, 10, 11, 20, 21, 30, 110, 330]

thread

std::thread - Rust (rust-lang.org)

use std::{thread, time};fn main() {// 线程1let handle = thread::spawn(|| {for i in 1..10 {println!("hi number {} from the spawned thread!", i);thread::sleep(time::Duration::from_millis(100));}});// 主线程for i in 1..5 {println!("hi number {} from the main thread!", i);thread::sleep(time::Duration::from_millis(100));}// 等待线程1结束handle.join().unwrap();
}

运行结果

$ ./target/debug/play_thread
hi number 1 from the main thread!
hi number 1 from the spawned thread!
hi number 2 from the main thread!
hi number 2 from the spawned thread!
hi number 3 from the main thread!
hi number 3 from the spawned thread!
hi number 4 from the spawned thread!
hi number 4 from the main thread!
hi number 5 from the spawned thread!
hi number 6 from the spawned thread!
hi number 7 from the spawned thread!
hi number 8 from the spawned thread!
hi number 9 from the spawned thread!

多生产-单消费

use std::{sync::mpsc, thread, time};fn main() {// 多生产者-单消费者let (tx, rx) = mpsc::channel();for i in 0..10 {let tx = tx.clone();thread::spawn(move|| {tx.send(i).unwrap();thread::sleep(time::Duration::from_millis(1000-i*100));tx.send(i+100).unwrap();});}for _ in 0..20 {let j = rx.recv().unwrap();println!("Got: {}", j);}
}

运行

$ ./target/debug/play_mpsc
Got: 0
Got: 2
Got: 3
Got: 1
Got: 4
Got: 5
Got: 6
Got: 7
Got: 9
Got: 8
Got: 109
Got: 108
Got: 107
Got: 106
Got: 105
Got: 104
Got: 103
Got: 102
Got: 101
Got: 100

关于 多生产者、单消费者FIFO队列通信, 参考:

  • std::sync::mpsc - Rust (rust-lang.org)

UDP

UdpSocket in std::net - Rust (rust-lang.org)

下面的例子就不区分server和client了

$ cargo new play_udp# play_udp/Cargo.toml 最下面添加
[[bin]]
name = "play_udp_server"
path = "src/play_udp_server/main.rs"[[bin]]
name = "play_udp_client"
path = "src/play_udp_client/main.rs"$ tree play_udp/
play_udp/
├── Cargo.toml
└── src├── play_udp_client│   └── main.rs└── play_udp_server└── main.rs

7878端口

// 导入UdpSocket
use std::net::UdpSocket;
fn main() {let addr = "127.0.0.1:7878";let socket = UdpSocket::bind(addr).unwrap();let mut buf = [0; 1024];let mut count = 0;loop {let (amt, src) = socket.recv_from(&mut buf).unwrap();println!("Received {} bytes from {}: {:?}, {}",amt,src,&buf[..amt],String::from_utf8_lossy(&buf[..amt]));// buf扩展countbuf[amt] = count + '0' as u8;socket.send_to(&buf[..amt + 1], src).unwrap();count += 1;if count == 10 {break;}}
}

8888端口

use std::net::UdpSocket;
fn main() {let addr = "127.0.0.1:8888";let socket = UdpSocket::bind(addr).unwrap();let mut buf = [0; 1024];let mut count = 0;// 向7878端口发送数据, 引信socket.send_to(b"hello", "127.0.0.1:7878").unwrap();loop {let (amt, src) = socket.recv_from(&mut buf).unwrap();println!("Received {} bytes from {}: {}",amt,src,String::from_utf8_lossy(&buf[..amt]));socket.send_to(&buf[..amt], src).unwrap();count += 1;if count == 10 {break;}}
}

运行

$ cargo build# 先运行server, 再运行client
$ ./target/debug/play_udp_server
$ ./target/debug/play_udp_client

(半)链式反应

库引入

三种库:

  • crates.io: Rust Package Registry, RUST的官方仓库, 如 rand = "0.3"
  • Git仓库, 如 color = { git = "https://github.com/bjz/color-rs" }
  • 绝对/相对路径, 如 geometry = { path = "crates/geometry" }

如果一直卡顿或报错

# 引入库报
# Blocking waiting for file lock on package cache
rm -rf ~/.cargo/.package-cache

UART serial

serial - Rust (docs.rs)

用python生成一对虚拟串口(尽量不要同时读写)

#!/usr/bin/python3import pty
import os
import selectdef mkpty():#  Open the pseudo terminalmaster1, slave = pty.openpty()slaveName1 = os.ttyname(slave)master2, slave = pty.openpty()slaveName2 = os.ttyname(slave)print('slave device names: ', slaveName1, slaveName2)return master1, master2if __name__ == "__main__":master1, master2 = mkpty()while True:rl, wl, el = select.select([master1,master2], [], [], 1)for master in rl:data = os.read(master, 128)print("read %d data." % len(data) )if master==master1:os.write(master2, data)else:os.write(master1, data)

运行, 打印出的 /dev/pts/31, /dev/pts/32 就是一对虚拟串口

$ python3 vcom.py
slave device names:  /dev/pts/6 /dev/pts/7

rust工程引入serial, 在Cargo.toml

[dependencies]
serial = "0.4.0"

类似上面的udp

$ cargo new play_serial# play_serial/Cargo.toml 引入serial, 添加bin
[dependencies]
serial = "0.4.0"[[bin]]
name = "play_serial_server"
path = "src/play_serial_server/main.rs"[[bin]]
name = "play_serial_client"
path = "src/play_serial_client/main.rs"$ tree play_serial/
play_serial/
├── Cargo.toml
└── src├── play_serial_client│   └── main.rs├── play_serial_server│   └── main.rs└── vcom.py

server

extern crate serial;use serial::prelude::*;
use std::io::prelude::*;
use std::time::Duration;const SETTINGS: serial::PortSettings = serial::PortSettings {baud_rate: serial::Baud115200,char_size: serial::Bits8,parity: serial::ParityNone,stop_bits: serial::Stop1,flow_control: serial::FlowNone,
};fn main() {let mut serial = serial::open("/dev/pts/6").unwrap();serial.configure(&SETTINGS).unwrap();serial.set_timeout(Duration::from_secs(1_000_000_000)).unwrap();let mut buf = [0; 1024];let mut count = 0;loop {let amt = serial.read(&mut buf[..]).unwrap();println!("Received {} bytes: {:?}, {}",amt,&buf[..amt],String::from_utf8_lossy(&buf[..amt]));// buf扩展countbuf[amt] = count + '0' as u8;serial.write(&buf[..amt + 1]).unwrap();count += 1;if count == 10 {break;}}
}

client

extern crate serial;use serial::prelude::*;
use std::io::prelude::*;
use std::time::Duration;const SETTINGS: serial::PortSettings = serial::PortSettings {baud_rate: serial::Baud115200,char_size: serial::Bits8,parity: serial::ParityNone,stop_bits: serial::Stop1,flow_control: serial::FlowNone,
};fn main() {let mut serial = serial::open("/dev/pts/7").unwrap();serial.configure(&SETTINGS).unwrap();serial.set_timeout(Duration::from_secs(1_000_000_000)).unwrap();let mut buf = [0; 1024];let mut count = 0;// 发送数据, 引信serial.write(b"hello").unwrap();loop {let amt = serial.read(&mut buf[..]).unwrap();println!("Received {} bytes: {:?}, {}",amt,&buf[..amt],String::from_utf8_lossy(&buf[..amt]));serial.write(&buf[..amt]).unwrap();count += 1;if count == 10 {break;}}
}

运行

$ cargo build
# Blocking waiting for file lock on package cache
# 如果一直卡在上面这句, 就运行下面的命令
# rm -rf ~/.cargo/.package-cache # 串口操作可能需要加 sudo
$ ./target/debug/play_serial_server
$ ./target/debug/play_serial_client

UART serial2

上面的 dcuddeback/serial-rs: Rust library for interacting with serial ports. (github.com) 可以看到已经停止维护5年了, 最近有个 de-vri-es/serial2-rs: Cross platform serial ports for Rust (github.com), 先不谈性能如何, 先用用看(当然, 如果对所有的都不满意, 可以自己写一个, 或者FFI套C)

serial2 - Rust (docs.rs), examples中可以列出可用串口, 多线程, 多串口操作等

$ cargo new play_serial2# play_serial/Cargo.toml 引入serial, 添加bin
[dependencies]
serial2 = "0.1.6"[[bin]]
name = "play_serial2_server"
path = "src/play_serial2_server/main.rs"[[bin]]
name = "play_serial2_client"
path = "src/play_serial2_client/main.rs"$ tree play_serial2/
play_serial2
├── Cargo.toml
└── src├── play_serial2_client│   └── main.rs└── play_serial2_server└── main.rs

Server

extern crate serial2;use serial2::SerialPort;
use std::time::Duration;fn main() {let mut port = SerialPort::open("/dev/pts/6", 115200).unwrap();SerialPort::set_read_timeout(&mut port, Duration::from_millis(10000)).unwrap();// SerialPort::discard_buffers(&mut port).unwrap();SerialPort::discard_input_buffer(&mut port).unwrap();SerialPort::discard_output_buffer(&mut port).unwrap();let mut buf = [0; 1024];let mut count = 0;loop {let amt = port.read(&mut buf[..]).unwrap();println!("Received {} bytes: {:?}, {}",amt,&buf[..amt],String::from_utf8_lossy(&buf[..amt]));// buf扩展countbuf[amt] = count + '0' as u8;port.write(&buf[..amt + 1]).unwrap();count += 1;if count == 10 {break;}}
}

Client

extern crate serial2;use serial2::SerialPort;
use std::time::Duration;fn main() {let mut port = SerialPort::open("/dev/pts/7", 115200).unwrap();SerialPort::set_read_timeout(&mut port, Duration::from_millis(10000)).unwrap();// SerialPort::discard_buffers(&mut port).unwrap();SerialPort::discard_input_buffer(&mut port).unwrap();SerialPort::discard_output_buffer(&mut port).unwrap();let mut buf = [0; 1024];let mut count = 0;// 发送数据, 引信port.write(b"hello").unwrap();loop {let amt = port.read(&mut buf[..]).unwrap();println!("Received {} bytes: {:?}, {}",amt,&buf[..amt],String::from_utf8_lossy(&buf[..amt]));port.write(&buf[..amt]).unwrap();count += 1;if count == 10 {break;}}
}

测试结果类似上小节, 过程略

SocketCAN

在Ubuntu虚拟出一对CAN, vxcan.sh

#!/bin/sh
sudo modprobe can_raw
sudo modprobe vxcan# 如果 ip link 中存在 vcan0, 就删除 vcan0
if ip link show can0 > /dev/null 2>&1; thensudo ip link set dev can0 downsudo ip link set dev vxcan0 downsudo ip link delete dev can0 type vxcan
fisudo ip link add dev can0 type vxcan
sudo ip link set up can0
sudo ip link set dev vxcan0  up

Search Results for ‘can’ - crates.io: Rust Package Registry 可以找找更多的封装can的, 还有很多新特性支持, 如异步, 多线程等, 但似乎没有找到太好用的

Cargo.toml 中引入socketcan

[dependencies]
socketcan = "1.7.0"

测试代码

extern crate socketcan;fn main() {println!("Hello, world!");// 创建一个socketcan的客户端let socket = socketcan::CANSocket::open("can0").unwrap();// 创建一个帧, id, data, rtr, errlet mut frame = socketcan::CANFrame::new(0x123, &[1, 3, 5, 7, 9, 11, 13, 15], false, false).unwrap();// 发送帧socket.write_frame(&frame).unwrap();// 修改idframe = socketcan::CANFrame::new(0x1FFFFFFF, &[1, 3, 5, 7, 9, 11, 13, 15], false, false).unwrap();// 发送帧socket.write_frame(&frame).unwrap();// 接收帧frame = socket.read_frame().unwrap();// 打印帧println!("{:?}", frame);
}

测试结果

这个毕竟年代久远了, frame中的id, data之类的不是pub, 性能一般, 也不支持CANFD…

其实不如直接完全照搬SocketCAN的C接口, 这样可以无缝理解, 下面用 libc 重写一下.

CAN

libc - Rust (docs.rs)

$ cargo new play_can# play_can/Cargo.toml
[dependencies]
libc = "0.2.132"
ifstructs = "0.1.1"
iptool = "0.1.0"

下面就把C代码逐行翻译成rust, 参考 main.rs

extern crate ifstructs;
extern crate iptool;
extern crate libc;use std::ffi::CString;// can_id: 32 bit, CAN_ID + EFF/RTR/ERR flags
struct CanFrame {can_id: u32,can_dlc: u8,__pad: u8,__res0: u8,__res1: u8,data: [u8; 8],
}fn canopen(ifname: &str) -> i32 {let ifname = CString::new(ifname).unwrap();unsafe {let fd: libc::c_int = libc::socket(libc::AF_CAN, libc::SOCK_RAW, libc::CAN_RAW);if fd < 0 {println!("socket error");std::process::exit(1);}let mut ifr: ifstructs::ifreq = std::mem::zeroed();for i in 0..ifname.as_bytes().len() {ifr.ifr_name[i] = ifname.as_bytes()[i];}libc::ioctl(fd, iptool::SIOCGIFINDEX as libc::c_ulong, &mut ifr);let mut addr: libc::sockaddr_can = std::mem::zeroed();addr.can_family = libc::AF_CAN as libc::sa_family_t;addr.can_ifindex = ifr.ifr_ifru.ifr_ifindex;let ret = libc::bind(fd,&addr as *const libc::sockaddr_can as *const libc::sockaddr,std::mem::size_of::<libc::sockaddr_can>() as libc::socklen_t,);if ret < 0 {println!("bind error");std::process::exit(1);}return fd as i32;}
}fn canclose(fd: i32) -> i32 {unsafe {return libc::close(fd as libc::c_int);}
}fn canwrite(fd: i32, frame: &mut CanFrame) -> i32 {unsafe {let ret = libc::write(fd as libc::c_int,frame as *mut CanFrame as *const libc::c_void,std::mem::size_of::<CanFrame>() as libc::size_t,);return ret as i32;}
}fn canread(fd: i32, frame: &mut CanFrame) -> i32 {unsafe {let ret = libc::read(fd as libc::c_int,frame as *mut CanFrame as *mut libc::c_void,std::mem::size_of::<CanFrame>() as libc::size_t,);return ret as i32;}
}fn main() {let fd = canopen("can0");let mut frame = CanFrame {can_id: 0x123,can_dlc: 8,__pad: 0,__res0: 0,__res1: 0,data: [0; 8],};canwrite(fd, &mut frame);canread(fd, &mut frame);println!("can_id: {:08x}, can_dlc: {}, __pad: {}, __res0: {}, __res1: {}, data: {:02x?}",frame.can_id, frame.can_dlc, frame.__pad, frame.__res0, frame.__res1, frame.data);canclose(fd);
}// $ cansend vxcan0 12345678#11.22
// can_id: 92345678, can_dlc: 2, __pad: 0, __res0: 0, __res1: 0, data: [11, 22, 00, 00, 00, 00, 00, 00]

测试

$ candump -td -x any$ cargo build
$ ./target/debug/play_can$ cansend vxcan0 12345678#11.22
# 因为是扩展帧, can_id 最高位置1, 所以can_id是92345678

如图

CANFD

$ cargo new play_canfd# play_canfd/Cargo.toml
[dependencies]
libc = "0.2.132"
ifstructs = "0.1.1"
iptool = "0.1.0"

把C代码逐行翻译成rust, 参考 canfd.rs

extern crate ifstructs;
extern crate iptool;
extern crate libc;use std::ffi::CString;pub struct CanfdFrame {can_id: u32,len: u8,flags: u8,__res0: u8,__res1: u8,data: [u8; 64],
}pub fn open(ifname: &str) -> i32 {let ifname = CString::new(ifname).unwrap();unsafe {let fd: libc::c_int = libc::socket(libc::AF_CAN, libc::SOCK_RAW, libc::CAN_RAW);if fd < 0 {println!("socket error");std::process::exit(1);}let mut ifr: ifstructs::ifreq = std::mem::zeroed();for i in 0..ifname.as_bytes().len() {ifr.ifr_name[i] = ifname.as_bytes()[i];}libc::ioctl(fd, iptool::SIOCGIFINDEX as libc::c_ulong, &mut ifr);let mut addr: libc::sockaddr_can = std::mem::zeroed();addr.can_family = libc::AF_CAN as libc::sa_family_t;addr.can_ifindex = ifr.ifr_ifru.ifr_ifindex;// canfd supportlet mut canfd_on: libc::c_int = 1;libc::setsockopt(fd,libc::SOL_CAN_RAW,libc::CAN_RAW_FD_FRAMES,&mut canfd_on as *mut libc::c_int as *mut libc::c_void,std::mem::size_of::<libc::c_int>() as libc::socklen_t,);let ret = libc::bind(fd,&addr as *const libc::sockaddr_can as *const libc::sockaddr,std::mem::size_of::<libc::sockaddr_can>() as libc::socklen_t,);if ret < 0 {println!("bind error");std::process::exit(1);}return fd as i32;}
}pub fn close(fd: i32) -> i32 {unsafe {return libc::close(fd as libc::c_int);}
}pub fn write(fd: i32, frame: &mut CanfdFrame) -> i32 {unsafe {let ret = libc::write(fd as libc::c_int,frame as *mut CanfdFrame as *const libc::c_void,std::mem::size_of::<CanfdFrame>() as libc::size_t,);return ret as i32;}
}pub fn read(fd: i32, frame: &mut CanfdFrame) -> i32 {unsafe {let ret = libc::read(fd as libc::c_int,frame as *mut CanfdFrame as *mut libc::c_void,std::mem::size_of::<CanfdFrame>() as libc::size_t,);return ret as i32;}
}pub fn test() {let fd = open("can0");let mut frame = CanfdFrame {can_id: 0x123,len: 64,flags: 0,__res0: 0,__res1: 0,data: [0; 64],};write(fd, &mut frame);read(fd, &mut frame);println!("can_id: {:08x}, can_dlc: {}, __pad: {}, __res0: {}, __res1: {}, data: {:02x?}",frame.can_id, frame.len, frame.flags, frame.__res0, frame.__res1, frame.data);close(fd);
}

然后是 main.rs

mod canfd;fn main() {canfd::test();
}

测试

$ candump -td -x any$ cargo build
$ ./target/debug/play_canfd$ cansend vxcan0 12345678##3.11.22.33.44.55.66.77.88.99.AA.BB.CC.DD.EE.FF
# 因为是扩展帧, can_id 最高位置1, 所以can_id是92345678
# B, BRS
# E, ESI
# 15字节自动扩充到canfd的16字节

如图

除了直接翻译C以外, 另一种流行的思路是既然C底层受众广, 很多也比较稳, 那就直接FFI的方式, 让rust用C的头文件和编译好的静态库好了, 如用 bindgen, 完成了很多自动化的工作, 简单粗暴又高效.

Github

rust_note/playground at main · weifengdq/rust_note (github.com)

欢迎扫描二维码关注微信公众号, 及时获取最新文章:

RUST 环境 UDP UART CANFD相关推荐

  1. C语言实现linux环境UDP协议接收发送数据

    C语言实现linux环境UDP协议接收发送数据 说明 上代码 运行结果 说明 闲来无事,写了个C语言的UDP小程序,程序新建了两个线程,分别用来实现UDP数据到发送和接收.需要的直接拿去用. 上代码 ...

  2. non-Boost Asio 笔记: UDP UART SocketCAN Multicast UDS

    文章目录 关于 第一个程序 环境 文件目录 CMakeLists.txt first.cpp 编译运行 封装一下 UDP Shell 收发UDP数据流 CMakeLists.txt udpc.cpp ...

  3. Rust学习教程03 - 安装Rust环境

    本文节选自<<Rust语言圣经>>一书 欢迎大家加入Rust编程学院,一起学习交流: QQ群:1009730433 安装Rust 强烈建议使用rustup来安装Rust,当然如 ...

  4. vsual studio 2013环境 Udp组播

    前言` MFC(Microsoft Foundation Classes)是微软基础类库的简称,是微软公司实现的一个c++类库,主要封装了大部分的windows API函数,vc++是微软公司开发的c ...

  5. 【配置rust环境】windows+vscode

    文章目录 配置流程 1. 下载和安装rust安装包 2. 配置vscode 3. 测试环境 rustlings基础知识学习环境 1. 安装rustup rustlings答案及分析 参考博客

  6. [RUST]linux docker安装rust环境

    下载安装rust镜像: docker search rust 获取官方版本的rust镜像,如果网卡,设置一下docker源 apt-get update 安装vim(可选,主要用于编辑一些配置文件) ...

  7. rust开发环境_Rust 环境搭建

    Rust 环境搭建 Rust 支持很多的集成开发环境(IDE)或开发专用的文本编辑器. 本教程将使用 Visual Studio Code 作为我们的开发环境(Eclipse 有专用于 Rust 开发 ...

  8. rust外服靶场怎么进_rust 学习之旅一, rust编程环境相关

    Mac rust环境 rust安装: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh rust更新: rustup upd ...

  9. Rust初学者环境搭建(非Viatual Studio ,自定义安装目录)

    一.资源准备 1.1 Rust安装器下载 官网地址:Rust 程序设计语言 (rust-lang.org) 下载文件:rustup-init.exe(别急着运行) 1.2 汉化学习文档 学习文档地址: ...

最新文章

  1. 卡巴循环30天不限次数循环试用工具
  2. ashx页面中context.Session[xxx]获取不到值的解决办法
  3. JS循环绑定对象或变量
  4. 802.11ac/ax (wifi6)中的Beamforming技术介绍
  5. 算法练习day10——190328(二叉树的先序、 中序、 后序遍历, 包括递归方式和非递归方式、找到一个节点的后继节点、二叉树的序列化和反序列化)
  6. For the king:出色的冒险,失败的角色扮演
  7. 【Nginx】Nginx概述
  8. Slog45_项目上线之域名的购买
  9. 一个人幸运的前提,是他有能力改变自己
  10. SpringBoot—自定义线程池及并发定时任务模板
  11. 如何实现响应式布局?
  12. 【kafka】 Error when handling request Name: FetchRequest cannot compare its segment info since it only
  13. IoT:大端与小端字节数据详解
  14. [转载] Python Numpy基础总结
  15. VS2005 My.Computer.Registry 对象 操作注册表 简单示例
  16. swift中闭包的循环引用
  17. 直播防盗链,域名设置
  18. 微信小程序创建项目后无法显示内容
  19. 台式计算机怎样能搜无线连接,台式机怎样能够连入wifi呢
  20. OA是什么意思?什么是OA? OA系统是什么?

热门文章

  1. ThinkPad黑将S笔记本进bios设置u盘启动教程
  2. java程序的开发步骤,全套教学资料
  3. Kappa Statistic
  4. Android 截屏(Screenshot)代码流程小结
  5. k8s挂载目录_Kubernetes 挂载文件到pod里面
  6. 武林外传服务器位置,《武林外传手游》数据互通规则 合区详情
  7. 电路图:TDA1521低音炮电路图以及音箱图纸
  8. 中国科学院843遥感概论-目录
  9. 【精】LintCode领扣算法问题答案:316. 组合集
  10. java中object类怎么赋值_Java面向对象之Object类