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?
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 }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?
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 }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?
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 }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?
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 }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?
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 }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?
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 }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?
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 }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