pub struct Received {
pub cob_id: u16,
/* private fields */
}Expand description
A CANopen frame received from the bus: its COB-ID and up to eight bytes.
Fields§
§cob_id: u16The frame’s COB-ID (11-bit standard identifier).
Implementations§
Source§impl Received
impl Received
Sourcepub fn data(&self) -> &[u8] ⓘ
pub fn data(&self) -> &[u8] ⓘ
The received bytes, trimmed to the frame’s data length.
Examples found in repository?
examples/vcan_loopback.rs (line 91)
46 pub fn run() -> Result<(), Box<dyn Error>> {
47 let node = NodeId::new(0x10)?;
48
49 // --- Server node: serve an object dictionary on vcan0 in a thread. ---
50 let (ready_tx, ready_rx) = mpsc::channel::<()>();
51 thread::spawn(move || {
52 if let Err(e) = serve(node, ready_tx) {
53 eprintln!("server thread error: {e}");
54 }
55 });
56 // Wait until the server socket is open and listening.
57 ready_rx.recv().map_err(|_| "server failed to start")?;
58
59 // --- Client: talk to the node over vcan0. ---
60 let bus = SocketCan::open(IFACE)?;
61 bus.set_read_timeout(Duration::from_secs(2))?;
62
63 // Expedited read (4-byte object).
64 let device_type = bus.sdo_read(node, Address::new(0x1000, 0), DataType::Unsigned32)?;
65 println!("read 0x1000 device type = {device_type:?}");
66 assert_eq!(device_type, Value::Unsigned32(0x0004_0192));
67
68 // Expedited write then read-back (2-byte object).
69 bus.sdo_write(node, Address::new(0x1017, 0), Value::Unsigned16(2500))?;
70 let heartbeat = bus.sdo_read(node, Address::new(0x1017, 0), DataType::Unsigned16)?;
71 println!("write 0x1017 heartbeat -> read = {heartbeat:?}");
72 assert_eq!(heartbeat, Value::Unsigned16(2500));
73
74 // 8-byte object forces SEGMENTED transfer over the real bus.
75 let big = Value::Unsigned64(0x0102_0304_0506_0708);
76 bus.sdo_write(node, Address::new(0x2000, 0), big)?;
77 let back = bus.sdo_read(node, Address::new(0x2000, 0), DataType::Unsigned64)?;
78 println!("write 0x2000 (segmented) -> read = {back:?}");
79 assert_eq!(back, big);
80
81 // --- PDO: go operational, drive an RPDO in and a SYNC-triggered TPDO
82 // out. RPDO1 (0x200+node) writes 0x6000/1; TPDO1 (0x180+node) maps
83 // the same object, so a SYNC echoes back what the RPDO wrote. ---
84 let rpdo1 = 0x200 + node.raw() as u16;
85 let tpdo1 = 0x180 + node.raw() as u16;
86 bus.send_nmt(NmtCommand::StartRemoteNode, node)?; // -> operational
87 bus.send(rpdo1, &[0xCD, 0xAB])?; // RPDO1: 0x6000/1 <- 0xABCD
88 bus.send(SYNC_COB_ID, &[])?; // SYNC: node emits synchronous TPDOs
89
90 let tpdo = recv_cob(&bus, tpdo1)?;
91 println!("RPDO in 0xABCD -> SYNC -> TPDO out = {:02X?}", tpdo.data());
92 assert_eq!(tpdo.data(), &[0xCD, 0xAB]);
93
94 println!(
95 "\nvcan0 loopback OK — SDO (expedited + segmented), NMT, and PDO all round-tripped."
96 );
97 Ok(())
98 }
99
100 /// Receive frames until one arrives on `cob_id`.
101 fn recv_cob(bus: &SocketCan, cob_id: u16) -> Result<Received, Box<dyn Error>> {
102 loop {
103 let frame = bus.recv()?;
104 if frame.cob_id == cob_id {
105 return Ok(frame);
106 }
107 }
108 }
109
110 /// A device node: build an OD, configure a PDO pair, boot, and serve frames
111 /// (SDO, NMT, RPDO) plus SYNC-triggered TPDOs until the bus goes quiet.
112 fn serve(node_id: NodeId, ready: mpsc::Sender<()>) -> Result<(), Box<dyn Error>> {
113 let bus = SocketCan::open(IFACE)?;
114 bus.set_read_timeout(Duration::from_secs(3))?;
115
116 let mut od = ObjectDictionary::<8>::new();
117 od.insert(
118 Address::new(0x1000, 0),
119 Entry::constant(Value::Unsigned32(0x0004_0192)),
120 )?;
121 od.insert(Address::new(0x1017, 0), Entry::rw(Value::Unsigned16(1000)))?;
122 od.insert(Address::new(0x2000, 0), Entry::rw(Value::Unsigned64(0)))?;
123 od.insert(Address::new(0x6000, 1), Entry::rw(Value::Unsigned16(0)))?;
124
125 let mut node = Node::new(node_id, od);
126 // RPDO1 receives into 0x6000/1; TPDO1 transmits it back on SYNC.
127 node.add_rpdo(0x200 + node_id.raw() as u16, mapping(0x6000, 1, 16))?;
128 node.add_tpdo(
129 0x180 + node_id.raw() as u16,
130 mapping(0x6000, 1, 16),
131 TransmissionType::SynchronousAcyclic,
132 )?;
133 node.boot(); // enter pre-operational so SDO is served
134 ready.send(()).map_err(|_| "client went away")?;
135
136 // Serve until a read times out (the client is done and the bus is idle).
137 while let Ok(frame) = bus.recv() {
138 if let Some(tx) = node.on_frame(frame.cob_id, frame.data()) {
139 bus.send(tx.cob_id, tx.data())?;
140 }
141 if frame.cob_id == SYNC_COB_ID {
142 for tx in node.sync_tpdos() {
143 bus.send(tx.cob_id, tx.data())?;
144 }
145 }
146 }
147 Ok(())
148 }Trait Implementations§
Auto Trait Implementations§
impl Freeze for Received
impl RefUnwindSafe for Received
impl Send for Received
impl Sync for Received
impl Unpin for Received
impl UnsafeUnpin for Received
impl UnwindSafe for Received
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
Converts
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
Converts
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more