pub struct SocketCan { /* private fields */ }Expand description
A CANopen transport over a Linux SocketCAN interface.
Implementations§
Source§impl SocketCan
impl SocketCan
Sourcepub fn open(interface: &str) -> Result<Self>
pub fn open(interface: &str) -> Result<Self>
Open the named CAN interface (e.g. "can0" or "vcan0").
Examples found in repository?
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 }Sourcepub fn set_read_timeout(&self, timeout: Duration) -> Result<()>
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?
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 }Sourcepub fn set_nonblocking(&self, nonblocking: bool) -> Result<()>
pub fn set_nonblocking(&self, nonblocking: bool) -> Result<()>
Put the socket into (non-)blocking mode.
Sourcepub fn send(&self, cob_id: u16, data: &[u8]) -> Result<()>
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?
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 }Sourcepub fn recv(&self) -> Result<Received>
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?
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 }Sourcepub fn send_nmt(&self, command: NmtCommand, target: NodeId) -> Result<()>
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?
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 }Sourcepub fn sdo_read(
&self,
node: NodeId,
addr: Address,
data_type: DataType,
) -> Result<Value, SdoError>
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?
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 }Sourcepub fn sdo_write(
&self,
node: NodeId,
addr: Address,
value: Value,
) -> Result<(), SdoError>
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?
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§
Auto Trait Implementations§
impl Freeze for SocketCan
impl RefUnwindSafe for SocketCan
impl Send for SocketCan
impl Sync for SocketCan
impl Unpin for SocketCan
impl UnsafeUnpin for SocketCan
impl UnwindSafe for SocketCan
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
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>
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>
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