Skip to main content

SocketCan

Struct SocketCan 

Source
pub struct SocketCan { /* private fields */ }
Expand description

A CANopen transport over a Linux SocketCAN interface.

Implementations§

Source§

impl SocketCan

Source

pub fn open(interface: &str) -> Result<Self>

Open the named CAN interface (e.g. "can0" or "vcan0").

Examples found in repository?
examples/vcan_loopback.rs (line 69)
60    pub fn run() -> Result<(), Box<dyn Error>> {
61        let (ready_tx, ready_rx) = mpsc::channel::<()>();
62        thread::spawn(move || {
63            if let Err(e) = serve(ready_tx) {
64                eprintln!("server thread error: {e}");
65            }
66        });
67        ready_rx.recv().map_err(|_| "server failed to start")?;
68
69        let bus = SocketCan::open(IFACE)?;
70        bus.set_read_timeout(Duration::from_secs(2))?;
71
72        // --- 1. LSS: assign the unconfigured node its id (0x10), then reset. ---
73        bus.send(lss::LSS_MASTER_COB_ID, &encode_switch_global(true))?;
74        bus.send(lss::LSS_MASTER_COB_ID, &encode_configure_node_id(0x10))?;
75        let cfg = recv_cob(&bus, lss::LSS_SLAVE_COB_ID)?;
76        assert_eq!(&cfg.data()[..2], &[0x11, 0x00]); // configure success
77        bus.send(lss::LSS_MASTER_COB_ID, &encode_store())?;
78        recv_cob(&bus, lss::LSS_SLAVE_COB_ID)?; // store response
79        bus.send(lss::LSS_MASTER_COB_ID, &encode_switch_global(false))?;
80        bus.send_nmt(NmtCommand::ResetCommunication, NodeId::BROADCAST)?;
81        let bootup = recv_cob(&bus, 0x700 + 0x10)?; // node boots on 0x710
82        println!(
83            "LSS: assigned node-id 0x10; node booted (bootup {:02X?})",
84            bootup.data()
85        );
86
87        let node = NodeId::new(0x10)?;
88
89        // --- 2. SDO: expedited and segmented. ---
90        let device_type = bus.sdo_read(node, Address::new(0x1000, 0), DataType::Unsigned32)?;
91        println!("SDO: read 0x1000 device type   = {device_type:?}");
92        assert_eq!(device_type, Value::Unsigned32(0x0004_0192));
93        bus.sdo_write(node, Address::new(0x1017, 0), Value::Unsigned16(2500))?;
94        assert_eq!(
95            bus.sdo_read(node, Address::new(0x1017, 0), DataType::Unsigned16)?,
96            Value::Unsigned16(2500)
97        );
98        let big = Value::Unsigned64(0x0102_0304_0506_0708);
99        bus.sdo_write(node, Address::new(0x2000, 0), big)?; // segmented
100        assert_eq!(
101            bus.sdo_read(node, Address::new(0x2000, 0), DataType::Unsigned64)?,
102            big
103        );
104        println!("SDO: expedited + segmented read/write OK");
105
106        // --- 3+4. NMT start, then RPDO in -> SYNC -> TPDO out. ---
107        bus.send_nmt(NmtCommand::StartRemoteNode, node)?;
108        bus.send(0x200 + 0x10, &[0xCD, 0xAB])?; // RPDO1 -> 0x6000/1 = 0xABCD
109        bus.send(SYNC_COB_ID, &[])?;
110        let tpdo = recv_cob(&bus, 0x180 + 0x10)?;
111        assert_eq!(tpdo.data(), &[0xCD, 0xAB]);
112        println!(
113            "NMT+PDO: RPDO in 0xABCD -> SYNC -> TPDO out {:02X?}",
114            tpdo.data()
115        );
116
117        // --- 5. Block transfer: stream 50 bytes, server CRC-verifies. ---
118        let payload: [u8; 50] = core::array::from_fn(|i| i as u8);
119        bus.send(
120            BLOCK_REQ,
121            &encode_download_initiate(Address::new(0x3000, 0), Some(payload.len() as u32), true),
122        )?;
123        let mut writer = BlockWriter::new(&payload, block::MAX_BLKSIZE);
124        while let Some(segment) = writer.next_segment() {
125            bus.send(BLOCK_REQ, &segment)?;
126        }
127        bus.send(BLOCK_REQ, &writer.end_frame(true))?;
128        let confirm = recv_cob(&bus, BLOCK_RESP)?;
129        assert_eq!(confirm.data(), &[1], "server CRC-verified the block");
130        println!(
131            "BLOCK: downloaded {} bytes -> server CRC-verified",
132            payload.len()
133        );
134
135        println!("\nvcan0 loopback OK — LSS, SDO, NMT, PDO, and block transfer all round-tripped.");
136        Ok(())
137    }
138
139    /// Receive frames until one arrives on `cob_id`.
140    fn recv_cob(bus: &SocketCan, cob_id: u16) -> Result<Received, Box<dyn Error>> {
141        loop {
142            let frame = bus.recv()?;
143            if frame.cob_id == cob_id {
144                return Ok(frame);
145            }
146        }
147    }
148
149    /// The device node: unconfigured until LSS assigns an id, then a full node.
150    fn serve(ready: mpsc::Sender<()>) -> Result<(), Box<dyn Error>> {
151        let bus = SocketCan::open(IFACE)?;
152        bus.set_read_timeout(Duration::from_secs(3))?;
153
154        let mut od = ObjectDictionary::<8>::new();
155        od.insert(
156            Address::new(0x1000, 0),
157            Entry::constant(Value::Unsigned32(0x0004_0192)),
158        )?;
159        od.insert(Address::new(0x1017, 0), Entry::rw(Value::Unsigned16(1000)))?;
160        od.insert(Address::new(0x2000, 0), Entry::rw(Value::Unsigned64(0)))?;
161        od.insert(Address::new(0x6000, 1), Entry::rw(Value::Unsigned16(0)))?;
162
163        // Provisional id 1 while unconfigured; LSS assigns the real one.
164        let mut node = Node::new(NodeId::new(1)?, od);
165        node.enable_lss(LssAddress {
166            vendor_id: 0x1F,
167            product_code: 0x2A,
168            revision_number: 1,
169            serial_number: 0x99,
170        });
171        ready.send(()).map_err(|_| "client went away")?;
172
173        let mut block_rx = BlockReceiver::<256>::new();
174        let mut booted = false;
175
176        while let Ok(frame) = bus.recv() {
177            if frame.cob_id == BLOCK_REQ {
178                handle_block(&bus, &mut block_rx, &frame)?;
179                continue;
180            }
181            if let Some(tx) = node.on_frame(frame.cob_id, frame.data()) {
182                bus.send(tx.cob_id, tx.data())?;
183            }
184            // The reset that follows LSS configuration: adopt the id and boot.
185            if !booted && frame.cob_id == NMT_COMMAND_COB_ID {
186                node.apply_lss_node_id();
187                let id = node.node_id().raw() as u16;
188                node.add_rpdo(0x200 + id, single_map(0x6000, 1, 16))?;
189                node.add_tpdo(
190                    0x180 + id,
191                    single_map(0x6000, 1, 16),
192                    TransmissionType::SynchronousAcyclic,
193                )?;
194                let boot = node.boot();
195                bus.send(boot.cob_id, boot.data())?;
196                booted = true;
197            }
198            if frame.cob_id == SYNC_COB_ID {
199                for tx in node.sync_tpdos() {
200                    bus.send(tx.cob_id, tx.data())?;
201                }
202            }
203        }
204        Ok(())
205    }
Source

pub fn set_read_timeout(&self, timeout: Duration) -> Result<()>

Set a read timeout, so SocketCan::recv (and the SDO helpers) fail with a timeout error rather than blocking forever.

Examples found in repository?
examples/vcan_loopback.rs (line 70)
60    pub fn run() -> Result<(), Box<dyn Error>> {
61        let (ready_tx, ready_rx) = mpsc::channel::<()>();
62        thread::spawn(move || {
63            if let Err(e) = serve(ready_tx) {
64                eprintln!("server thread error: {e}");
65            }
66        });
67        ready_rx.recv().map_err(|_| "server failed to start")?;
68
69        let bus = SocketCan::open(IFACE)?;
70        bus.set_read_timeout(Duration::from_secs(2))?;
71
72        // --- 1. LSS: assign the unconfigured node its id (0x10), then reset. ---
73        bus.send(lss::LSS_MASTER_COB_ID, &encode_switch_global(true))?;
74        bus.send(lss::LSS_MASTER_COB_ID, &encode_configure_node_id(0x10))?;
75        let cfg = recv_cob(&bus, lss::LSS_SLAVE_COB_ID)?;
76        assert_eq!(&cfg.data()[..2], &[0x11, 0x00]); // configure success
77        bus.send(lss::LSS_MASTER_COB_ID, &encode_store())?;
78        recv_cob(&bus, lss::LSS_SLAVE_COB_ID)?; // store response
79        bus.send(lss::LSS_MASTER_COB_ID, &encode_switch_global(false))?;
80        bus.send_nmt(NmtCommand::ResetCommunication, NodeId::BROADCAST)?;
81        let bootup = recv_cob(&bus, 0x700 + 0x10)?; // node boots on 0x710
82        println!(
83            "LSS: assigned node-id 0x10; node booted (bootup {:02X?})",
84            bootup.data()
85        );
86
87        let node = NodeId::new(0x10)?;
88
89        // --- 2. SDO: expedited and segmented. ---
90        let device_type = bus.sdo_read(node, Address::new(0x1000, 0), DataType::Unsigned32)?;
91        println!("SDO: read 0x1000 device type   = {device_type:?}");
92        assert_eq!(device_type, Value::Unsigned32(0x0004_0192));
93        bus.sdo_write(node, Address::new(0x1017, 0), Value::Unsigned16(2500))?;
94        assert_eq!(
95            bus.sdo_read(node, Address::new(0x1017, 0), DataType::Unsigned16)?,
96            Value::Unsigned16(2500)
97        );
98        let big = Value::Unsigned64(0x0102_0304_0506_0708);
99        bus.sdo_write(node, Address::new(0x2000, 0), big)?; // segmented
100        assert_eq!(
101            bus.sdo_read(node, Address::new(0x2000, 0), DataType::Unsigned64)?,
102            big
103        );
104        println!("SDO: expedited + segmented read/write OK");
105
106        // --- 3+4. NMT start, then RPDO in -> SYNC -> TPDO out. ---
107        bus.send_nmt(NmtCommand::StartRemoteNode, node)?;
108        bus.send(0x200 + 0x10, &[0xCD, 0xAB])?; // RPDO1 -> 0x6000/1 = 0xABCD
109        bus.send(SYNC_COB_ID, &[])?;
110        let tpdo = recv_cob(&bus, 0x180 + 0x10)?;
111        assert_eq!(tpdo.data(), &[0xCD, 0xAB]);
112        println!(
113            "NMT+PDO: RPDO in 0xABCD -> SYNC -> TPDO out {:02X?}",
114            tpdo.data()
115        );
116
117        // --- 5. Block transfer: stream 50 bytes, server CRC-verifies. ---
118        let payload: [u8; 50] = core::array::from_fn(|i| i as u8);
119        bus.send(
120            BLOCK_REQ,
121            &encode_download_initiate(Address::new(0x3000, 0), Some(payload.len() as u32), true),
122        )?;
123        let mut writer = BlockWriter::new(&payload, block::MAX_BLKSIZE);
124        while let Some(segment) = writer.next_segment() {
125            bus.send(BLOCK_REQ, &segment)?;
126        }
127        bus.send(BLOCK_REQ, &writer.end_frame(true))?;
128        let confirm = recv_cob(&bus, BLOCK_RESP)?;
129        assert_eq!(confirm.data(), &[1], "server CRC-verified the block");
130        println!(
131            "BLOCK: downloaded {} bytes -> server CRC-verified",
132            payload.len()
133        );
134
135        println!("\nvcan0 loopback OK — LSS, SDO, NMT, PDO, and block transfer all round-tripped.");
136        Ok(())
137    }
138
139    /// Receive frames until one arrives on `cob_id`.
140    fn recv_cob(bus: &SocketCan, cob_id: u16) -> Result<Received, Box<dyn Error>> {
141        loop {
142            let frame = bus.recv()?;
143            if frame.cob_id == cob_id {
144                return Ok(frame);
145            }
146        }
147    }
148
149    /// The device node: unconfigured until LSS assigns an id, then a full node.
150    fn serve(ready: mpsc::Sender<()>) -> Result<(), Box<dyn Error>> {
151        let bus = SocketCan::open(IFACE)?;
152        bus.set_read_timeout(Duration::from_secs(3))?;
153
154        let mut od = ObjectDictionary::<8>::new();
155        od.insert(
156            Address::new(0x1000, 0),
157            Entry::constant(Value::Unsigned32(0x0004_0192)),
158        )?;
159        od.insert(Address::new(0x1017, 0), Entry::rw(Value::Unsigned16(1000)))?;
160        od.insert(Address::new(0x2000, 0), Entry::rw(Value::Unsigned64(0)))?;
161        od.insert(Address::new(0x6000, 1), Entry::rw(Value::Unsigned16(0)))?;
162
163        // Provisional id 1 while unconfigured; LSS assigns the real one.
164        let mut node = Node::new(NodeId::new(1)?, od);
165        node.enable_lss(LssAddress {
166            vendor_id: 0x1F,
167            product_code: 0x2A,
168            revision_number: 1,
169            serial_number: 0x99,
170        });
171        ready.send(()).map_err(|_| "client went away")?;
172
173        let mut block_rx = BlockReceiver::<256>::new();
174        let mut booted = false;
175
176        while let Ok(frame) = bus.recv() {
177            if frame.cob_id == BLOCK_REQ {
178                handle_block(&bus, &mut block_rx, &frame)?;
179                continue;
180            }
181            if let Some(tx) = node.on_frame(frame.cob_id, frame.data()) {
182                bus.send(tx.cob_id, tx.data())?;
183            }
184            // The reset that follows LSS configuration: adopt the id and boot.
185            if !booted && frame.cob_id == NMT_COMMAND_COB_ID {
186                node.apply_lss_node_id();
187                let id = node.node_id().raw() as u16;
188                node.add_rpdo(0x200 + id, single_map(0x6000, 1, 16))?;
189                node.add_tpdo(
190                    0x180 + id,
191                    single_map(0x6000, 1, 16),
192                    TransmissionType::SynchronousAcyclic,
193                )?;
194                let boot = node.boot();
195                bus.send(boot.cob_id, boot.data())?;
196                booted = true;
197            }
198            if frame.cob_id == SYNC_COB_ID {
199                for tx in node.sync_tpdos() {
200                    bus.send(tx.cob_id, tx.data())?;
201                }
202            }
203        }
204        Ok(())
205    }
Source

pub fn set_nonblocking(&self, nonblocking: bool) -> Result<()>

Put the socket into (non-)blocking mode.

Source

pub fn send(&self, cob_id: u16, data: &[u8]) -> Result<()>

Transmit data on COB-ID cob_id as a standard data frame.

Examples found in repository?
examples/vcan_loopback.rs (line 73)
60    pub fn run() -> Result<(), Box<dyn Error>> {
61        let (ready_tx, ready_rx) = mpsc::channel::<()>();
62        thread::spawn(move || {
63            if let Err(e) = serve(ready_tx) {
64                eprintln!("server thread error: {e}");
65            }
66        });
67        ready_rx.recv().map_err(|_| "server failed to start")?;
68
69        let bus = SocketCan::open(IFACE)?;
70        bus.set_read_timeout(Duration::from_secs(2))?;
71
72        // --- 1. LSS: assign the unconfigured node its id (0x10), then reset. ---
73        bus.send(lss::LSS_MASTER_COB_ID, &encode_switch_global(true))?;
74        bus.send(lss::LSS_MASTER_COB_ID, &encode_configure_node_id(0x10))?;
75        let cfg = recv_cob(&bus, lss::LSS_SLAVE_COB_ID)?;
76        assert_eq!(&cfg.data()[..2], &[0x11, 0x00]); // configure success
77        bus.send(lss::LSS_MASTER_COB_ID, &encode_store())?;
78        recv_cob(&bus, lss::LSS_SLAVE_COB_ID)?; // store response
79        bus.send(lss::LSS_MASTER_COB_ID, &encode_switch_global(false))?;
80        bus.send_nmt(NmtCommand::ResetCommunication, NodeId::BROADCAST)?;
81        let bootup = recv_cob(&bus, 0x700 + 0x10)?; // node boots on 0x710
82        println!(
83            "LSS: assigned node-id 0x10; node booted (bootup {:02X?})",
84            bootup.data()
85        );
86
87        let node = NodeId::new(0x10)?;
88
89        // --- 2. SDO: expedited and segmented. ---
90        let device_type = bus.sdo_read(node, Address::new(0x1000, 0), DataType::Unsigned32)?;
91        println!("SDO: read 0x1000 device type   = {device_type:?}");
92        assert_eq!(device_type, Value::Unsigned32(0x0004_0192));
93        bus.sdo_write(node, Address::new(0x1017, 0), Value::Unsigned16(2500))?;
94        assert_eq!(
95            bus.sdo_read(node, Address::new(0x1017, 0), DataType::Unsigned16)?,
96            Value::Unsigned16(2500)
97        );
98        let big = Value::Unsigned64(0x0102_0304_0506_0708);
99        bus.sdo_write(node, Address::new(0x2000, 0), big)?; // segmented
100        assert_eq!(
101            bus.sdo_read(node, Address::new(0x2000, 0), DataType::Unsigned64)?,
102            big
103        );
104        println!("SDO: expedited + segmented read/write OK");
105
106        // --- 3+4. NMT start, then RPDO in -> SYNC -> TPDO out. ---
107        bus.send_nmt(NmtCommand::StartRemoteNode, node)?;
108        bus.send(0x200 + 0x10, &[0xCD, 0xAB])?; // RPDO1 -> 0x6000/1 = 0xABCD
109        bus.send(SYNC_COB_ID, &[])?;
110        let tpdo = recv_cob(&bus, 0x180 + 0x10)?;
111        assert_eq!(tpdo.data(), &[0xCD, 0xAB]);
112        println!(
113            "NMT+PDO: RPDO in 0xABCD -> SYNC -> TPDO out {:02X?}",
114            tpdo.data()
115        );
116
117        // --- 5. Block transfer: stream 50 bytes, server CRC-verifies. ---
118        let payload: [u8; 50] = core::array::from_fn(|i| i as u8);
119        bus.send(
120            BLOCK_REQ,
121            &encode_download_initiate(Address::new(0x3000, 0), Some(payload.len() as u32), true),
122        )?;
123        let mut writer = BlockWriter::new(&payload, block::MAX_BLKSIZE);
124        while let Some(segment) = writer.next_segment() {
125            bus.send(BLOCK_REQ, &segment)?;
126        }
127        bus.send(BLOCK_REQ, &writer.end_frame(true))?;
128        let confirm = recv_cob(&bus, BLOCK_RESP)?;
129        assert_eq!(confirm.data(), &[1], "server CRC-verified the block");
130        println!(
131            "BLOCK: downloaded {} bytes -> server CRC-verified",
132            payload.len()
133        );
134
135        println!("\nvcan0 loopback OK — LSS, SDO, NMT, PDO, and block transfer all round-tripped.");
136        Ok(())
137    }
138
139    /// Receive frames until one arrives on `cob_id`.
140    fn recv_cob(bus: &SocketCan, cob_id: u16) -> Result<Received, Box<dyn Error>> {
141        loop {
142            let frame = bus.recv()?;
143            if frame.cob_id == cob_id {
144                return Ok(frame);
145            }
146        }
147    }
148
149    /// The device node: unconfigured until LSS assigns an id, then a full node.
150    fn serve(ready: mpsc::Sender<()>) -> Result<(), Box<dyn Error>> {
151        let bus = SocketCan::open(IFACE)?;
152        bus.set_read_timeout(Duration::from_secs(3))?;
153
154        let mut od = ObjectDictionary::<8>::new();
155        od.insert(
156            Address::new(0x1000, 0),
157            Entry::constant(Value::Unsigned32(0x0004_0192)),
158        )?;
159        od.insert(Address::new(0x1017, 0), Entry::rw(Value::Unsigned16(1000)))?;
160        od.insert(Address::new(0x2000, 0), Entry::rw(Value::Unsigned64(0)))?;
161        od.insert(Address::new(0x6000, 1), Entry::rw(Value::Unsigned16(0)))?;
162
163        // Provisional id 1 while unconfigured; LSS assigns the real one.
164        let mut node = Node::new(NodeId::new(1)?, od);
165        node.enable_lss(LssAddress {
166            vendor_id: 0x1F,
167            product_code: 0x2A,
168            revision_number: 1,
169            serial_number: 0x99,
170        });
171        ready.send(()).map_err(|_| "client went away")?;
172
173        let mut block_rx = BlockReceiver::<256>::new();
174        let mut booted = false;
175
176        while let Ok(frame) = bus.recv() {
177            if frame.cob_id == BLOCK_REQ {
178                handle_block(&bus, &mut block_rx, &frame)?;
179                continue;
180            }
181            if let Some(tx) = node.on_frame(frame.cob_id, frame.data()) {
182                bus.send(tx.cob_id, tx.data())?;
183            }
184            // The reset that follows LSS configuration: adopt the id and boot.
185            if !booted && frame.cob_id == NMT_COMMAND_COB_ID {
186                node.apply_lss_node_id();
187                let id = node.node_id().raw() as u16;
188                node.add_rpdo(0x200 + id, single_map(0x6000, 1, 16))?;
189                node.add_tpdo(
190                    0x180 + id,
191                    single_map(0x6000, 1, 16),
192                    TransmissionType::SynchronousAcyclic,
193                )?;
194                let boot = node.boot();
195                bus.send(boot.cob_id, boot.data())?;
196                booted = true;
197            }
198            if frame.cob_id == SYNC_COB_ID {
199                for tx in node.sync_tpdos() {
200                    bus.send(tx.cob_id, tx.data())?;
201                }
202            }
203        }
204        Ok(())
205    }
206
207    /// Reassemble a streamed block download and CRC-verify it on the end frame.
208    fn handle_block(
209        bus: &SocketCan,
210        rx: &mut BlockReceiver<256>,
211        frame: &Received,
212    ) -> Result<(), Box<dyn Error>> {
213        let p = pad8(frame.data());
214        let cmd = p[0];
215        if cmd & 0xE0 == 0xC0 && cmd & 0x01 == 0 {
216            *rx = BlockReceiver::new(); // initiate: start fresh
217        } else if cmd & 0xE0 == 0xC0 && cmd & 0x01 == 1 {
218            let (unused, crc) = decode_end(&p)?;
219            let ok = rx.finish(unused, crc, true).is_ok();
220            bus.send(BLOCK_RESP, &[ok as u8])?; // one confirmation frame
221        } else {
222            rx.push(&decode_sub_segment(&p))?; // a sub-block segment
223        }
224        Ok(())
225    }
Source

pub fn recv(&self) -> Result<Received>

Receive the next CANopen data frame, skipping remote and error frames and any frame with a 29-bit extended identifier.

Examples found in repository?
examples/vcan_loopback.rs (line 142)
140    fn recv_cob(bus: &SocketCan, cob_id: u16) -> Result<Received, Box<dyn Error>> {
141        loop {
142            let frame = bus.recv()?;
143            if frame.cob_id == cob_id {
144                return Ok(frame);
145            }
146        }
147    }
148
149    /// The device node: unconfigured until LSS assigns an id, then a full node.
150    fn serve(ready: mpsc::Sender<()>) -> Result<(), Box<dyn Error>> {
151        let bus = SocketCan::open(IFACE)?;
152        bus.set_read_timeout(Duration::from_secs(3))?;
153
154        let mut od = ObjectDictionary::<8>::new();
155        od.insert(
156            Address::new(0x1000, 0),
157            Entry::constant(Value::Unsigned32(0x0004_0192)),
158        )?;
159        od.insert(Address::new(0x1017, 0), Entry::rw(Value::Unsigned16(1000)))?;
160        od.insert(Address::new(0x2000, 0), Entry::rw(Value::Unsigned64(0)))?;
161        od.insert(Address::new(0x6000, 1), Entry::rw(Value::Unsigned16(0)))?;
162
163        // Provisional id 1 while unconfigured; LSS assigns the real one.
164        let mut node = Node::new(NodeId::new(1)?, od);
165        node.enable_lss(LssAddress {
166            vendor_id: 0x1F,
167            product_code: 0x2A,
168            revision_number: 1,
169            serial_number: 0x99,
170        });
171        ready.send(()).map_err(|_| "client went away")?;
172
173        let mut block_rx = BlockReceiver::<256>::new();
174        let mut booted = false;
175
176        while let Ok(frame) = bus.recv() {
177            if frame.cob_id == BLOCK_REQ {
178                handle_block(&bus, &mut block_rx, &frame)?;
179                continue;
180            }
181            if let Some(tx) = node.on_frame(frame.cob_id, frame.data()) {
182                bus.send(tx.cob_id, tx.data())?;
183            }
184            // The reset that follows LSS configuration: adopt the id and boot.
185            if !booted && frame.cob_id == NMT_COMMAND_COB_ID {
186                node.apply_lss_node_id();
187                let id = node.node_id().raw() as u16;
188                node.add_rpdo(0x200 + id, single_map(0x6000, 1, 16))?;
189                node.add_tpdo(
190                    0x180 + id,
191                    single_map(0x6000, 1, 16),
192                    TransmissionType::SynchronousAcyclic,
193                )?;
194                let boot = node.boot();
195                bus.send(boot.cob_id, boot.data())?;
196                booted = true;
197            }
198            if frame.cob_id == SYNC_COB_ID {
199                for tx in node.sync_tpdos() {
200                    bus.send(tx.cob_id, tx.data())?;
201                }
202            }
203        }
204        Ok(())
205    }
Source

pub fn send_nmt(&self, command: NmtCommand, target: NodeId) -> Result<()>

Send an NMT node-control command to target on COB-ID 0x000.

Use NodeId::BROADCAST to address every node at once — e.g. send_nmt(NmtCommand::StartRemoteNode, NodeId::BROADCAST).

Examples found in repository?
examples/vcan_loopback.rs (line 80)
60    pub fn run() -> Result<(), Box<dyn Error>> {
61        let (ready_tx, ready_rx) = mpsc::channel::<()>();
62        thread::spawn(move || {
63            if let Err(e) = serve(ready_tx) {
64                eprintln!("server thread error: {e}");
65            }
66        });
67        ready_rx.recv().map_err(|_| "server failed to start")?;
68
69        let bus = SocketCan::open(IFACE)?;
70        bus.set_read_timeout(Duration::from_secs(2))?;
71
72        // --- 1. LSS: assign the unconfigured node its id (0x10), then reset. ---
73        bus.send(lss::LSS_MASTER_COB_ID, &encode_switch_global(true))?;
74        bus.send(lss::LSS_MASTER_COB_ID, &encode_configure_node_id(0x10))?;
75        let cfg = recv_cob(&bus, lss::LSS_SLAVE_COB_ID)?;
76        assert_eq!(&cfg.data()[..2], &[0x11, 0x00]); // configure success
77        bus.send(lss::LSS_MASTER_COB_ID, &encode_store())?;
78        recv_cob(&bus, lss::LSS_SLAVE_COB_ID)?; // store response
79        bus.send(lss::LSS_MASTER_COB_ID, &encode_switch_global(false))?;
80        bus.send_nmt(NmtCommand::ResetCommunication, NodeId::BROADCAST)?;
81        let bootup = recv_cob(&bus, 0x700 + 0x10)?; // node boots on 0x710
82        println!(
83            "LSS: assigned node-id 0x10; node booted (bootup {:02X?})",
84            bootup.data()
85        );
86
87        let node = NodeId::new(0x10)?;
88
89        // --- 2. SDO: expedited and segmented. ---
90        let device_type = bus.sdo_read(node, Address::new(0x1000, 0), DataType::Unsigned32)?;
91        println!("SDO: read 0x1000 device type   = {device_type:?}");
92        assert_eq!(device_type, Value::Unsigned32(0x0004_0192));
93        bus.sdo_write(node, Address::new(0x1017, 0), Value::Unsigned16(2500))?;
94        assert_eq!(
95            bus.sdo_read(node, Address::new(0x1017, 0), DataType::Unsigned16)?,
96            Value::Unsigned16(2500)
97        );
98        let big = Value::Unsigned64(0x0102_0304_0506_0708);
99        bus.sdo_write(node, Address::new(0x2000, 0), big)?; // segmented
100        assert_eq!(
101            bus.sdo_read(node, Address::new(0x2000, 0), DataType::Unsigned64)?,
102            big
103        );
104        println!("SDO: expedited + segmented read/write OK");
105
106        // --- 3+4. NMT start, then RPDO in -> SYNC -> TPDO out. ---
107        bus.send_nmt(NmtCommand::StartRemoteNode, node)?;
108        bus.send(0x200 + 0x10, &[0xCD, 0xAB])?; // RPDO1 -> 0x6000/1 = 0xABCD
109        bus.send(SYNC_COB_ID, &[])?;
110        let tpdo = recv_cob(&bus, 0x180 + 0x10)?;
111        assert_eq!(tpdo.data(), &[0xCD, 0xAB]);
112        println!(
113            "NMT+PDO: RPDO in 0xABCD -> SYNC -> TPDO out {:02X?}",
114            tpdo.data()
115        );
116
117        // --- 5. Block transfer: stream 50 bytes, server CRC-verifies. ---
118        let payload: [u8; 50] = core::array::from_fn(|i| i as u8);
119        bus.send(
120            BLOCK_REQ,
121            &encode_download_initiate(Address::new(0x3000, 0), Some(payload.len() as u32), true),
122        )?;
123        let mut writer = BlockWriter::new(&payload, block::MAX_BLKSIZE);
124        while let Some(segment) = writer.next_segment() {
125            bus.send(BLOCK_REQ, &segment)?;
126        }
127        bus.send(BLOCK_REQ, &writer.end_frame(true))?;
128        let confirm = recv_cob(&bus, BLOCK_RESP)?;
129        assert_eq!(confirm.data(), &[1], "server CRC-verified the block");
130        println!(
131            "BLOCK: downloaded {} bytes -> server CRC-verified",
132            payload.len()
133        );
134
135        println!("\nvcan0 loopback OK — LSS, SDO, NMT, PDO, and block transfer all round-tripped.");
136        Ok(())
137    }
Source

pub fn sdo_read( &self, node: NodeId, addr: Address, data_type: DataType, ) -> Result<Value, SdoError>

Read object addr from node, interpreting the result as data_type.

Runs the full SDO upload transaction (expedited or segmented) and returns the value, or an SdoError on abort or I/O failure. Set a read timeout first so an unresponsive node cannot block forever.

Examples found in repository?
examples/vcan_loopback.rs (line 90)
60    pub fn run() -> Result<(), Box<dyn Error>> {
61        let (ready_tx, ready_rx) = mpsc::channel::<()>();
62        thread::spawn(move || {
63            if let Err(e) = serve(ready_tx) {
64                eprintln!("server thread error: {e}");
65            }
66        });
67        ready_rx.recv().map_err(|_| "server failed to start")?;
68
69        let bus = SocketCan::open(IFACE)?;
70        bus.set_read_timeout(Duration::from_secs(2))?;
71
72        // --- 1. LSS: assign the unconfigured node its id (0x10), then reset. ---
73        bus.send(lss::LSS_MASTER_COB_ID, &encode_switch_global(true))?;
74        bus.send(lss::LSS_MASTER_COB_ID, &encode_configure_node_id(0x10))?;
75        let cfg = recv_cob(&bus, lss::LSS_SLAVE_COB_ID)?;
76        assert_eq!(&cfg.data()[..2], &[0x11, 0x00]); // configure success
77        bus.send(lss::LSS_MASTER_COB_ID, &encode_store())?;
78        recv_cob(&bus, lss::LSS_SLAVE_COB_ID)?; // store response
79        bus.send(lss::LSS_MASTER_COB_ID, &encode_switch_global(false))?;
80        bus.send_nmt(NmtCommand::ResetCommunication, NodeId::BROADCAST)?;
81        let bootup = recv_cob(&bus, 0x700 + 0x10)?; // node boots on 0x710
82        println!(
83            "LSS: assigned node-id 0x10; node booted (bootup {:02X?})",
84            bootup.data()
85        );
86
87        let node = NodeId::new(0x10)?;
88
89        // --- 2. SDO: expedited and segmented. ---
90        let device_type = bus.sdo_read(node, Address::new(0x1000, 0), DataType::Unsigned32)?;
91        println!("SDO: read 0x1000 device type   = {device_type:?}");
92        assert_eq!(device_type, Value::Unsigned32(0x0004_0192));
93        bus.sdo_write(node, Address::new(0x1017, 0), Value::Unsigned16(2500))?;
94        assert_eq!(
95            bus.sdo_read(node, Address::new(0x1017, 0), DataType::Unsigned16)?,
96            Value::Unsigned16(2500)
97        );
98        let big = Value::Unsigned64(0x0102_0304_0506_0708);
99        bus.sdo_write(node, Address::new(0x2000, 0), big)?; // segmented
100        assert_eq!(
101            bus.sdo_read(node, Address::new(0x2000, 0), DataType::Unsigned64)?,
102            big
103        );
104        println!("SDO: expedited + segmented read/write OK");
105
106        // --- 3+4. NMT start, then RPDO in -> SYNC -> TPDO out. ---
107        bus.send_nmt(NmtCommand::StartRemoteNode, node)?;
108        bus.send(0x200 + 0x10, &[0xCD, 0xAB])?; // RPDO1 -> 0x6000/1 = 0xABCD
109        bus.send(SYNC_COB_ID, &[])?;
110        let tpdo = recv_cob(&bus, 0x180 + 0x10)?;
111        assert_eq!(tpdo.data(), &[0xCD, 0xAB]);
112        println!(
113            "NMT+PDO: RPDO in 0xABCD -> SYNC -> TPDO out {:02X?}",
114            tpdo.data()
115        );
116
117        // --- 5. Block transfer: stream 50 bytes, server CRC-verifies. ---
118        let payload: [u8; 50] = core::array::from_fn(|i| i as u8);
119        bus.send(
120            BLOCK_REQ,
121            &encode_download_initiate(Address::new(0x3000, 0), Some(payload.len() as u32), true),
122        )?;
123        let mut writer = BlockWriter::new(&payload, block::MAX_BLKSIZE);
124        while let Some(segment) = writer.next_segment() {
125            bus.send(BLOCK_REQ, &segment)?;
126        }
127        bus.send(BLOCK_REQ, &writer.end_frame(true))?;
128        let confirm = recv_cob(&bus, BLOCK_RESP)?;
129        assert_eq!(confirm.data(), &[1], "server CRC-verified the block");
130        println!(
131            "BLOCK: downloaded {} bytes -> server CRC-verified",
132            payload.len()
133        );
134
135        println!("\nvcan0 loopback OK — LSS, SDO, NMT, PDO, and block transfer all round-tripped.");
136        Ok(())
137    }
Source

pub fn sdo_write( &self, node: NodeId, addr: Address, value: Value, ) -> Result<(), SdoError>

Write value to object addr on node.

Runs the full SDO download transaction (expedited or segmented), choosing the transfer type from the value’s size.

Examples found in repository?
examples/vcan_loopback.rs (line 93)
60    pub fn run() -> Result<(), Box<dyn Error>> {
61        let (ready_tx, ready_rx) = mpsc::channel::<()>();
62        thread::spawn(move || {
63            if let Err(e) = serve(ready_tx) {
64                eprintln!("server thread error: {e}");
65            }
66        });
67        ready_rx.recv().map_err(|_| "server failed to start")?;
68
69        let bus = SocketCan::open(IFACE)?;
70        bus.set_read_timeout(Duration::from_secs(2))?;
71
72        // --- 1. LSS: assign the unconfigured node its id (0x10), then reset. ---
73        bus.send(lss::LSS_MASTER_COB_ID, &encode_switch_global(true))?;
74        bus.send(lss::LSS_MASTER_COB_ID, &encode_configure_node_id(0x10))?;
75        let cfg = recv_cob(&bus, lss::LSS_SLAVE_COB_ID)?;
76        assert_eq!(&cfg.data()[..2], &[0x11, 0x00]); // configure success
77        bus.send(lss::LSS_MASTER_COB_ID, &encode_store())?;
78        recv_cob(&bus, lss::LSS_SLAVE_COB_ID)?; // store response
79        bus.send(lss::LSS_MASTER_COB_ID, &encode_switch_global(false))?;
80        bus.send_nmt(NmtCommand::ResetCommunication, NodeId::BROADCAST)?;
81        let bootup = recv_cob(&bus, 0x700 + 0x10)?; // node boots on 0x710
82        println!(
83            "LSS: assigned node-id 0x10; node booted (bootup {:02X?})",
84            bootup.data()
85        );
86
87        let node = NodeId::new(0x10)?;
88
89        // --- 2. SDO: expedited and segmented. ---
90        let device_type = bus.sdo_read(node, Address::new(0x1000, 0), DataType::Unsigned32)?;
91        println!("SDO: read 0x1000 device type   = {device_type:?}");
92        assert_eq!(device_type, Value::Unsigned32(0x0004_0192));
93        bus.sdo_write(node, Address::new(0x1017, 0), Value::Unsigned16(2500))?;
94        assert_eq!(
95            bus.sdo_read(node, Address::new(0x1017, 0), DataType::Unsigned16)?,
96            Value::Unsigned16(2500)
97        );
98        let big = Value::Unsigned64(0x0102_0304_0506_0708);
99        bus.sdo_write(node, Address::new(0x2000, 0), big)?; // segmented
100        assert_eq!(
101            bus.sdo_read(node, Address::new(0x2000, 0), DataType::Unsigned64)?,
102            big
103        );
104        println!("SDO: expedited + segmented read/write OK");
105
106        // --- 3+4. NMT start, then RPDO in -> SYNC -> TPDO out. ---
107        bus.send_nmt(NmtCommand::StartRemoteNode, node)?;
108        bus.send(0x200 + 0x10, &[0xCD, 0xAB])?; // RPDO1 -> 0x6000/1 = 0xABCD
109        bus.send(SYNC_COB_ID, &[])?;
110        let tpdo = recv_cob(&bus, 0x180 + 0x10)?;
111        assert_eq!(tpdo.data(), &[0xCD, 0xAB]);
112        println!(
113            "NMT+PDO: RPDO in 0xABCD -> SYNC -> TPDO out {:02X?}",
114            tpdo.data()
115        );
116
117        // --- 5. Block transfer: stream 50 bytes, server CRC-verifies. ---
118        let payload: [u8; 50] = core::array::from_fn(|i| i as u8);
119        bus.send(
120            BLOCK_REQ,
121            &encode_download_initiate(Address::new(0x3000, 0), Some(payload.len() as u32), true),
122        )?;
123        let mut writer = BlockWriter::new(&payload, block::MAX_BLKSIZE);
124        while let Some(segment) = writer.next_segment() {
125            bus.send(BLOCK_REQ, &segment)?;
126        }
127        bus.send(BLOCK_REQ, &writer.end_frame(true))?;
128        let confirm = recv_cob(&bus, BLOCK_RESP)?;
129        assert_eq!(confirm.data(), &[1], "server CRC-verified the block");
130        println!(
131            "BLOCK: downloaded {} bytes -> server CRC-verified",
132            payload.len()
133        );
134
135        println!("\nvcan0 loopback OK — LSS, SDO, NMT, PDO, and block transfer all round-tripped.");
136        Ok(())
137    }

Trait Implementations§

Source§

impl Debug for SocketCan

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

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
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.