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?
42 pub fn run() -> Result<(), Box<dyn Error>> {
43 let node = NodeId::new(0x10)?;
44
45 // --- Server node: serve an object dictionary on vcan0 in a thread. ---
46 let (ready_tx, ready_rx) = mpsc::channel::<()>();
47 thread::spawn(move || {
48 if let Err(e) = serve(node, ready_tx) {
49 eprintln!("server thread error: {e}");
50 }
51 });
52 // Wait until the server socket is open and listening.
53 ready_rx.recv().map_err(|_| "server failed to start")?;
54
55 // --- Client: talk to the node over vcan0. ---
56 let bus = SocketCan::open(IFACE)?;
57 bus.set_read_timeout(Duration::from_secs(2))?;
58
59 // Expedited read (4-byte object).
60 let device_type = bus.sdo_read(node, Address::new(0x1000, 0), DataType::Unsigned32)?;
61 println!("read 0x1000 device type = {device_type:?}");
62 assert_eq!(device_type, Value::Unsigned32(0x0004_0192));
63
64 // Expedited write then read-back (2-byte object).
65 bus.sdo_write(node, Address::new(0x1017, 0), Value::Unsigned16(2500))?;
66 let heartbeat = bus.sdo_read(node, Address::new(0x1017, 0), DataType::Unsigned16)?;
67 println!("write 0x1017 heartbeat -> read = {heartbeat:?}");
68 assert_eq!(heartbeat, Value::Unsigned16(2500));
69
70 // 8-byte object forces SEGMENTED transfer over the real bus.
71 let big = Value::Unsigned64(0x0102_0304_0506_0708);
72 bus.sdo_write(node, Address::new(0x2000, 0), big)?;
73 let back = bus.sdo_read(node, Address::new(0x2000, 0), DataType::Unsigned64)?;
74 println!("write 0x2000 (segmented) -> read = {back:?}");
75 assert_eq!(back, big);
76
77 println!("\nvcan0 loopback OK — expedited and segmented SDO round-trips succeeded.");
78 Ok(())
79 }
80
81 /// A minimal device node: build an OD and answer SDO requests addressed to
82 /// this node until the bus goes quiet.
83 fn serve(node: NodeId, ready: mpsc::Sender<()>) -> Result<(), Box<dyn Error>> {
84 let bus = SocketCan::open(IFACE)?;
85 bus.set_read_timeout(Duration::from_secs(3))?;
86
87 let mut od = ObjectDictionary::<8>::new();
88 od.insert(
89 Address::new(0x1000, 0),
90 Entry::constant(Value::Unsigned32(0x0004_0192)),
91 )?;
92 od.insert(Address::new(0x1017, 0), Entry::rw(Value::Unsigned16(1000)))?;
93 od.insert(Address::new(0x2000, 0), Entry::rw(Value::Unsigned64(0)))?;
94
95 let mut server = SdoServer::new(node);
96 ready.send(()).map_err(|_| "client went away")?;
97
98 // Serve until a read times out (the client is done and the bus is idle).
99 while let Ok(frame) = bus.recv() {
100 if frame.cob_id != server.request_cob_id() {
101 continue;
102 }
103 if let Some(response) = server.handle(&mut od, frame.payload()) {
104 bus.send(server.response_cob_id(), &response)?;
105 }
106 }
107 Ok(())
108 }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?
42 pub fn run() -> Result<(), Box<dyn Error>> {
43 let node = NodeId::new(0x10)?;
44
45 // --- Server node: serve an object dictionary on vcan0 in a thread. ---
46 let (ready_tx, ready_rx) = mpsc::channel::<()>();
47 thread::spawn(move || {
48 if let Err(e) = serve(node, ready_tx) {
49 eprintln!("server thread error: {e}");
50 }
51 });
52 // Wait until the server socket is open and listening.
53 ready_rx.recv().map_err(|_| "server failed to start")?;
54
55 // --- Client: talk to the node over vcan0. ---
56 let bus = SocketCan::open(IFACE)?;
57 bus.set_read_timeout(Duration::from_secs(2))?;
58
59 // Expedited read (4-byte object).
60 let device_type = bus.sdo_read(node, Address::new(0x1000, 0), DataType::Unsigned32)?;
61 println!("read 0x1000 device type = {device_type:?}");
62 assert_eq!(device_type, Value::Unsigned32(0x0004_0192));
63
64 // Expedited write then read-back (2-byte object).
65 bus.sdo_write(node, Address::new(0x1017, 0), Value::Unsigned16(2500))?;
66 let heartbeat = bus.sdo_read(node, Address::new(0x1017, 0), DataType::Unsigned16)?;
67 println!("write 0x1017 heartbeat -> read = {heartbeat:?}");
68 assert_eq!(heartbeat, Value::Unsigned16(2500));
69
70 // 8-byte object forces SEGMENTED transfer over the real bus.
71 let big = Value::Unsigned64(0x0102_0304_0506_0708);
72 bus.sdo_write(node, Address::new(0x2000, 0), big)?;
73 let back = bus.sdo_read(node, Address::new(0x2000, 0), DataType::Unsigned64)?;
74 println!("write 0x2000 (segmented) -> read = {back:?}");
75 assert_eq!(back, big);
76
77 println!("\nvcan0 loopback OK — expedited and segmented SDO round-trips succeeded.");
78 Ok(())
79 }
80
81 /// A minimal device node: build an OD and answer SDO requests addressed to
82 /// this node until the bus goes quiet.
83 fn serve(node: NodeId, ready: mpsc::Sender<()>) -> Result<(), Box<dyn Error>> {
84 let bus = SocketCan::open(IFACE)?;
85 bus.set_read_timeout(Duration::from_secs(3))?;
86
87 let mut od = ObjectDictionary::<8>::new();
88 od.insert(
89 Address::new(0x1000, 0),
90 Entry::constant(Value::Unsigned32(0x0004_0192)),
91 )?;
92 od.insert(Address::new(0x1017, 0), Entry::rw(Value::Unsigned16(1000)))?;
93 od.insert(Address::new(0x2000, 0), Entry::rw(Value::Unsigned64(0)))?;
94
95 let mut server = SdoServer::new(node);
96 ready.send(()).map_err(|_| "client went away")?;
97
98 // Serve until a read times out (the client is done and the bus is idle).
99 while let Ok(frame) = bus.recv() {
100 if frame.cob_id != server.request_cob_id() {
101 continue;
102 }
103 if let Some(response) = server.handle(&mut od, frame.payload()) {
104 bus.send(server.response_cob_id(), &response)?;
105 }
106 }
107 Ok(())
108 }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?
83 fn serve(node: NodeId, ready: mpsc::Sender<()>) -> Result<(), Box<dyn Error>> {
84 let bus = SocketCan::open(IFACE)?;
85 bus.set_read_timeout(Duration::from_secs(3))?;
86
87 let mut od = ObjectDictionary::<8>::new();
88 od.insert(
89 Address::new(0x1000, 0),
90 Entry::constant(Value::Unsigned32(0x0004_0192)),
91 )?;
92 od.insert(Address::new(0x1017, 0), Entry::rw(Value::Unsigned16(1000)))?;
93 od.insert(Address::new(0x2000, 0), Entry::rw(Value::Unsigned64(0)))?;
94
95 let mut server = SdoServer::new(node);
96 ready.send(()).map_err(|_| "client went away")?;
97
98 // Serve until a read times out (the client is done and the bus is idle).
99 while let Ok(frame) = bus.recv() {
100 if frame.cob_id != server.request_cob_id() {
101 continue;
102 }
103 if let Some(response) = server.handle(&mut od, frame.payload()) {
104 bus.send(server.response_cob_id(), &response)?;
105 }
106 }
107 Ok(())
108 }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?
83 fn serve(node: NodeId, ready: mpsc::Sender<()>) -> Result<(), Box<dyn Error>> {
84 let bus = SocketCan::open(IFACE)?;
85 bus.set_read_timeout(Duration::from_secs(3))?;
86
87 let mut od = ObjectDictionary::<8>::new();
88 od.insert(
89 Address::new(0x1000, 0),
90 Entry::constant(Value::Unsigned32(0x0004_0192)),
91 )?;
92 od.insert(Address::new(0x1017, 0), Entry::rw(Value::Unsigned16(1000)))?;
93 od.insert(Address::new(0x2000, 0), Entry::rw(Value::Unsigned64(0)))?;
94
95 let mut server = SdoServer::new(node);
96 ready.send(()).map_err(|_| "client went away")?;
97
98 // Serve until a read times out (the client is done and the bus is idle).
99 while let Ok(frame) = bus.recv() {
100 if frame.cob_id != server.request_cob_id() {
101 continue;
102 }
103 if let Some(response) = server.handle(&mut od, frame.payload()) {
104 bus.send(server.response_cob_id(), &response)?;
105 }
106 }
107 Ok(())
108 }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?
42 pub fn run() -> Result<(), Box<dyn Error>> {
43 let node = NodeId::new(0x10)?;
44
45 // --- Server node: serve an object dictionary on vcan0 in a thread. ---
46 let (ready_tx, ready_rx) = mpsc::channel::<()>();
47 thread::spawn(move || {
48 if let Err(e) = serve(node, ready_tx) {
49 eprintln!("server thread error: {e}");
50 }
51 });
52 // Wait until the server socket is open and listening.
53 ready_rx.recv().map_err(|_| "server failed to start")?;
54
55 // --- Client: talk to the node over vcan0. ---
56 let bus = SocketCan::open(IFACE)?;
57 bus.set_read_timeout(Duration::from_secs(2))?;
58
59 // Expedited read (4-byte object).
60 let device_type = bus.sdo_read(node, Address::new(0x1000, 0), DataType::Unsigned32)?;
61 println!("read 0x1000 device type = {device_type:?}");
62 assert_eq!(device_type, Value::Unsigned32(0x0004_0192));
63
64 // Expedited write then read-back (2-byte object).
65 bus.sdo_write(node, Address::new(0x1017, 0), Value::Unsigned16(2500))?;
66 let heartbeat = bus.sdo_read(node, Address::new(0x1017, 0), DataType::Unsigned16)?;
67 println!("write 0x1017 heartbeat -> read = {heartbeat:?}");
68 assert_eq!(heartbeat, Value::Unsigned16(2500));
69
70 // 8-byte object forces SEGMENTED transfer over the real bus.
71 let big = Value::Unsigned64(0x0102_0304_0506_0708);
72 bus.sdo_write(node, Address::new(0x2000, 0), big)?;
73 let back = bus.sdo_read(node, Address::new(0x2000, 0), DataType::Unsigned64)?;
74 println!("write 0x2000 (segmented) -> read = {back:?}");
75 assert_eq!(back, big);
76
77 println!("\nvcan0 loopback OK — expedited and segmented SDO round-trips succeeded.");
78 Ok(())
79 }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?
42 pub fn run() -> Result<(), Box<dyn Error>> {
43 let node = NodeId::new(0x10)?;
44
45 // --- Server node: serve an object dictionary on vcan0 in a thread. ---
46 let (ready_tx, ready_rx) = mpsc::channel::<()>();
47 thread::spawn(move || {
48 if let Err(e) = serve(node, ready_tx) {
49 eprintln!("server thread error: {e}");
50 }
51 });
52 // Wait until the server socket is open and listening.
53 ready_rx.recv().map_err(|_| "server failed to start")?;
54
55 // --- Client: talk to the node over vcan0. ---
56 let bus = SocketCan::open(IFACE)?;
57 bus.set_read_timeout(Duration::from_secs(2))?;
58
59 // Expedited read (4-byte object).
60 let device_type = bus.sdo_read(node, Address::new(0x1000, 0), DataType::Unsigned32)?;
61 println!("read 0x1000 device type = {device_type:?}");
62 assert_eq!(device_type, Value::Unsigned32(0x0004_0192));
63
64 // Expedited write then read-back (2-byte object).
65 bus.sdo_write(node, Address::new(0x1017, 0), Value::Unsigned16(2500))?;
66 let heartbeat = bus.sdo_read(node, Address::new(0x1017, 0), DataType::Unsigned16)?;
67 println!("write 0x1017 heartbeat -> read = {heartbeat:?}");
68 assert_eq!(heartbeat, Value::Unsigned16(2500));
69
70 // 8-byte object forces SEGMENTED transfer over the real bus.
71 let big = Value::Unsigned64(0x0102_0304_0506_0708);
72 bus.sdo_write(node, Address::new(0x2000, 0), big)?;
73 let back = bus.sdo_read(node, Address::new(0x2000, 0), DataType::Unsigned64)?;
74 println!("write 0x2000 (segmented) -> read = {back:?}");
75 assert_eq!(back, big);
76
77 println!("\nvcan0 loopback OK — expedited and segmented SDO round-trips succeeded.");
78 Ok(())
79 }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