feat: 初始化
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "can-link"
|
||||
description = "CAN 传输抽象:帧与链路通道(无协议知识)"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
rust-version.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
tokio = { workspace = true }
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
@@ -0,0 +1,75 @@
|
||||
//! CAN 传输抽象:帧与链路通道。
|
||||
//!
|
||||
//! 本 crate **不含任何协议知识**(无 DJI ID 常量):只定义经典 CAN 数据帧
|
||||
//! 与一对 tokio 通道构成的链路端点。协议族(`dji-esc` / 未来 `dji-gm6020`)
|
||||
//! 与总线后端(SocketCAN 桥、仿真器)共享此类型,互不依赖。
|
||||
#![cfg_attr(test, allow(clippy::unwrap_used, clippy::expect_used))]
|
||||
|
||||
use tokio::sync::mpsc;
|
||||
|
||||
/// 经典 CAN 数据帧(数据长度固定 8 字节)。
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct CanFrame {
|
||||
/// 11 位标准 ID。
|
||||
pub id: u32,
|
||||
/// 数据域。
|
||||
pub data: [u8; 8],
|
||||
}
|
||||
|
||||
impl CanFrame {
|
||||
/// 构造一帧。
|
||||
#[must_use]
|
||||
pub const fn new(id: u32, data: [u8; 8]) -> Self {
|
||||
Self { id, data }
|
||||
}
|
||||
}
|
||||
|
||||
/// CAN 链路端点。
|
||||
///
|
||||
/// - `outgoing_tx`:本端发往总线的帧;
|
||||
/// - `incoming_rx`:本端从总线收到的帧。
|
||||
///
|
||||
/// 一条链路由两个端点构成(见 [`CanLink::pair`])。持有本端、把对端交给
|
||||
/// 对侧(SocketCAN 桥、仿真器)即可通信。
|
||||
#[derive(Debug)]
|
||||
pub struct CanLink {
|
||||
/// 发往总线。
|
||||
pub outgoing_tx: mpsc::Sender<CanFrame>,
|
||||
/// 来自总线。
|
||||
pub incoming_rx: mpsc::Receiver<CanFrame>,
|
||||
}
|
||||
|
||||
impl CanLink {
|
||||
/// 由已有通道组装端点。
|
||||
#[must_use]
|
||||
pub const fn new(
|
||||
outgoing_tx: mpsc::Sender<CanFrame>,
|
||||
incoming_rx: mpsc::Receiver<CanFrame>,
|
||||
) -> Self {
|
||||
Self { outgoing_tx, incoming_rx }
|
||||
}
|
||||
|
||||
/// 创建一对互联端点:`a` 发出的帧会被 `b` 收到,反之亦然。
|
||||
///
|
||||
/// `bound` 为每方向缓冲帧数(建议 ≥ 64,1kHz 收发下留足余量)。
|
||||
#[must_use]
|
||||
pub fn pair(bound: usize) -> (Self, Self) {
|
||||
let (tx_a_to_b, rx_at_b) = mpsc::channel(bound);
|
||||
let (tx_b_to_a, rx_at_a) = mpsc::channel(bound);
|
||||
(Self::new(tx_a_to_b, rx_at_a), Self::new(tx_b_to_a, rx_at_b))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[tokio::test]
|
||||
async fn pair_loops_both_directions() {
|
||||
let (mut a, mut b) = CanLink::pair(8);
|
||||
a.outgoing_tx.send(CanFrame::new(0x200, [1, 0, 0, 0, 0, 0, 0, 0])).await.unwrap();
|
||||
b.outgoing_tx.send(CanFrame::new(0x201, [2, 0, 0, 0, 0, 0, 0, 0])).await.unwrap();
|
||||
assert_eq!(b.incoming_rx.recv().await.unwrap().id, 0x200);
|
||||
assert_eq!(a.incoming_rx.recv().await.unwrap().id, 0x201);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user