pub struct Port<'a, B, H = LocalHandlers<'a>> { /* private fields */ }binary only.Expand description
A Port for transmitting and receiving Zaber Binary protocol messages.
See the binary module documentation for details on how to use a Port.
A port is parameterized by two types:
B: the type ofBackendused to send/receive data.- Use the convenience methods
open_serialandopen_tcpto construct a serial port (Port<Serial>) and a TCP port (Port<TcpStream>). To customize the construction of these types, or to construct a port with a dynamic backend, use theOpenSerialOptionsandOpenTcpOptionsbuilder types.
- Use the convenience methods
H: the type of event handlers.- This has a default and can be ignored in single-threaded contexts. There
are two types for event handlers: on that implements
Sendand one that does not (the default). To convert a port into a type that implementsSend, use thetry_into_sendmethod.
- This has a default and can be ignored in single-threaded contexts. There
are two types for event handlers: on that implements
Implementations§
Source§impl<'a> Port<'a, Serial>
impl<'a> Port<'a, Serial>
Sourcepub fn open_serial(path: &str) -> Result<Port<'a, Serial>, BinaryError>
pub fn open_serial(path: &str) -> Result<Port<'a, Serial>, BinaryError>
Open the serial port at the specified path using the default options.
Alternatively, use Port::open_serial_options to customize how the port is opened.
§Example
let mut port = Port::open_serial("/dev/ttyUSB0")?;Sourcepub fn open_serial_options() -> OpenSerialOptions
pub fn open_serial_options() -> OpenSerialOptions
Get an OpenSerialOptions to customize how a serial port is opened.
Source§impl<'a> Port<'a, TcpStream>
impl<'a> Port<'a, TcpStream>
Sourcepub fn open_tcp<A: ToSocketAddrs>(
address: A,
) -> Result<Port<'a, TcpStream>, Error>
pub fn open_tcp<A: ToSocketAddrs>( address: A, ) -> Result<Port<'a, TcpStream>, Error>
Open the TCP port at the specified address using the default options.
Alternatively, use Port::open_tcp_options to customize how the port is opened.
§Example
let mut port = Port::open_tcp("/dev/ttyUSB0")?;Sourcepub fn open_tcp_options() -> OpenTcpOptions
pub fn open_tcp_options() -> OpenTcpOptions
Get an OpenTcpOptions to customize how a TCP port is opened.
Source§impl<'a> Port<'a, Mock>
impl<'a> Port<'a, Mock>
Sourcepub fn open_mock() -> Port<'a, Mock>
Available on crate feature mock only.
pub fn open_mock() -> Port<'a, Mock>
mock only.Open a Port with a Mock Backend.
This is useful for writing unit/integration tests when an actual device is not available.
See the Mock’s documentation for more details on its behaviour.
§Example
use zproto::binary::command::HOME;
let mut port = Port::open_mock();
port.backend_mut().push([1, 1, 0, 0, 0, 0]);
let reply = port.tx_recv((0, HOME)).unwrap();
assert_eq!(reply.command(), HOME);Source§impl<'a, B> Port<'a, B>where
B: Backend,
impl<'a, B> Port<'a, B>where
B: Backend,
Sourcepub fn open_general(backend: B) -> Port<'a, B>
pub fn open_general(backend: B) -> Port<'a, B>
Open a port with the specified backend.
For Serial or TcpStream backends, use Port::open_serial and Port::open_tcp
instead. Those methods make configuring those backends easier.
Source§impl<'a, B, H> Port<'a, B, H>
impl<'a, B, H> Port<'a, B, H>
Sourcepub fn try_into_send(self) -> Result<SendPort<'a, B>, TryIntoSendError>where
B: Send,
pub fn try_into_send(self) -> Result<SendPort<'a, B>, TryIntoSendError>where
B: Send,
Convert this port into one that implements Send and can therefore be sent
to another thread.
Returns an error if Send bounds could not be added. In particular if
an event handler is currently set. As such, it is recommended to call
Port::try_into_send before setting a callback if you need to do both.
The Port::set_packet_handler on the new port will have an additional
Send bound on any function used as a callback.
§Example
use std::sync::{Arc, Mutex};
let port = Port::open_serial("...")?
.try_into_send() // Required in order to send the port to another thread.
.unwrap();
let port = Arc::new(Mutex::new(port));
let mut handles = vec![];
for i in 0..10 {
let port = port.clone();
let handle = std::thread::spawn(move || {
let mut guard = port.lock().unwrap();
// do something with the port ...
});
handles.push(handle);
}
for handle in handles {
let _ = handle.join();
}Sourcepub fn tx_recv<M>(
&mut self,
message: M,
) -> Result<Message<M::Response>, BinaryError>where
M: TxMessage + ElicitsResponse,
pub fn tx_recv<M>(
&mut self,
message: M,
) -> Result<Message<M::Response>, BinaryError>where
M: TxMessage + ElicitsResponse,
Transmit a message and then receive a response.
§Errors
An error is returned if the ERROR is received, the
command code is unexpected, the device address is unexpected, or, if
message IDs are enabled, the message ID doesn’t match the command.
Note: sending messages to a device alias other than 0 (all devices)
will result in an BinaryUnexpected*.
§Example
use zproto::binary::command::*;
let reply = port.tx_recv((0, RETURN_SETTING, SET_TARGET_SPEED))?;
let value = reply.data()?;Sourcepub fn tx_recv_n<M>(
&mut self,
message: M,
n: usize,
) -> Result<Vec<Message<M::Response>>, BinaryError>where
M: TxMessage + ElicitsResponse,
pub fn tx_recv_n<M>(
&mut self,
message: M,
n: usize,
) -> Result<Vec<Message<M::Response>>, BinaryError>where
M: TxMessage + ElicitsResponse,
Transmit a message and then receive n responses.
See tx_recv for more details.
Sourcepub fn tx_recv_until_timeout<M>(
&mut self,
message: M,
) -> Result<Vec<Message<M::Response>>, BinaryError>where
M: TxMessage + ElicitsResponse,
pub fn tx_recv_until_timeout<M>(
&mut self,
message: M,
) -> Result<Vec<Message<M::Response>>, BinaryError>where
M: TxMessage + ElicitsResponse,
Transmit a message and then receive messages until the port times out.
This useful for sending messages to all devices on the chain and collecting
all of their responses. See tx_recv for more details.
Sourcepub fn tx<M: TxMessage>(
&mut self,
message: M,
) -> Result<Option<u8>, BinaryError>
pub fn tx<M: TxMessage>( &mut self, message: M, ) -> Result<Option<u8>, BinaryError>
Transmit a message.
On success the generated message ID (if any) is returned.
Sourcepub fn recv<C: Command>(
&mut self,
expected: C,
) -> Result<Message<C>, BinaryError>
pub fn recv<C: Command>( &mut self, expected: C, ) -> Result<Message<C>, BinaryError>
Receive a message.
If the received command does not match expected an error is returned.
§Example
use zproto::binary::command::*;
let reply = port.recv(MANUAL_MOVE_TRACKING)?;Sourcepub fn recv_any(&mut self) -> Result<Message, BinaryError>
pub fn recv_any(&mut self) -> Result<Message, BinaryError>
Receive a message containing any command.
Sourcepub fn recv_n<C: Command>(
&mut self,
expected: C,
n: usize,
) -> Result<Vec<Message<C>>, BinaryError>
pub fn recv_n<C: Command>( &mut self, expected: C, n: usize, ) -> Result<Vec<Message<C>>, BinaryError>
Receive n messages.
If any of the received messages have a command that does not match
expected an error is returned and no further messages are received.
Sourcepub fn recv_any_n(&mut self, n: usize) -> Result<Vec<Message>, BinaryError>
pub fn recv_any_n(&mut self, n: usize) -> Result<Vec<Message>, BinaryError>
Receive n messages containing any command.
Each message may contain a different command.
Sourcepub fn recv_until_timeout<C>(
&mut self,
expected: C,
) -> Result<Vec<Message<C>>, BinaryError>where
C: Command,
pub fn recv_until_timeout<C>(
&mut self,
expected: C,
) -> Result<Vec<Message<C>>, BinaryError>where
C: Command,
Receive messages until the port times out.
If any of the received messages have a command that does not match
expected an error is returned and no further messages are received.
Sourcepub fn recv_any_until_timeout(&mut self) -> Result<Vec<Message>, BinaryError>
pub fn recv_any_until_timeout(&mut self) -> Result<Vec<Message>, BinaryError>
Receive messages containing any command until the port times out.
Each message may contain a different command.
Sourcepub fn poll_until<M, F>(
&mut self,
message: M,
predicate: F,
) -> Result<Message<M::Response>, BinaryError>
pub fn poll_until<M, F>( &mut self, message: M, predicate: F, ) -> Result<Message<M::Response>, BinaryError>
Transmit the specified message repeatedly until the predicate returns true for a response.
The reply that first passes the predicate is returned.
§Example
use zproto::binary::command::*;
// Wait until device 1 has passed position 10000.
let last_reply = port.poll_until(
(1, RETURN_CURRENT_POSITION),
|response| response.data().unwrap() > 10000
)?;Sourcepub fn poll_until_idle(
&mut self,
target: u8,
) -> Result<Message<ReturnStatus>, BinaryError>
pub fn poll_until_idle( &mut self, target: u8, ) -> Result<Message<ReturnStatus>, BinaryError>
Transmit the RETURN_STATUS command until the
specified target reports that it is idle.
Sourcepub fn set_message_ids(&mut self, enable: bool) -> Result<bool, BinaryError>
pub fn set_message_ids(&mut self, enable: bool) -> Result<bool, BinaryError>
Enable/disable transmission and parsing of message IDs.
Returns the previous value.
This will configure all devices on the port with the
SET_MESSAGE_ID_MODE command and
configure the port to generate, transmit and parse (or not) message IDs
for all future messages.
By default message ids are not enabled as it consumes one of the 4 data bytes in a message, potentially truncating larger data values.
On success, whether message IDs were previously enabled is returned.
§Example
port.set_message_ids(true)?;
// Message Ids will be used in all future messages.Sourcepub fn message_ids(&self) -> bool
pub fn message_ids(&self) -> bool
Return whether message IDs will be transmitted and parsed.
Sourcepub fn set_read_timeout(
&mut self,
timeout: Option<Duration>,
) -> Result<Option<Duration>, Error>
pub fn set_read_timeout( &mut self, timeout: Option<Duration>, ) -> Result<Option<Duration>, Error>
Set the read timeout and return the old timeout.
If timeout is None, reads will block indefinitely.
Sourcepub fn read_timeout(&self) -> Result<Option<Duration>, Error>
pub fn read_timeout(&self) -> Result<Option<Duration>, Error>
Get the read timeout.
If it is None, reads will block indefinitely.
Sourcepub fn name(&self) -> Option<String>
pub fn name(&self) -> Option<String>
Get the “name” of the port’s backend.
This is often the “name” passed to Port::open_serial or Port::open_tcp.
Sourcepub fn backend_mut(&mut self) -> &mut B
pub fn backend_mut(&mut self) -> &mut B
Get a mutable reference to the backend.
Sourcepub fn into_backend(self) -> B
pub fn into_backend(self) -> B
Consume the port and return the underlying backend.
Note that any data the port has buffered will be lost. Callers should ensure that all expected data has been sent and received.
Sourcepub fn set_packet_handler<F>(&mut self, callback: F) -> Option<H::PacketHandler>where
H::PacketHandler: From<F>,
pub fn set_packet_handler<F>(&mut self, callback: F) -> Option<H::PacketHandler>where
H::PacketHandler: From<F>,
Set a callback that will be called immediately after any Binary packet is sent or received.
If a previous callback was set, it is returned.
To clear a previously registered callback use clear_packet_handler.
The callback will be passed the packet bytes, the parsed version of the bytes, and the direction of the packet.
Note, the Port already logs packets (along with other metadata) via the
log crate, so logging is best handled via a log handler, such as
simple_logger, rather than
a packet callback. However, there are instances when you need access to
the packets directly (for instance, to show them in an application),
which is when a packet callback is most useful.
§Examples
Any closure can be used as a callback.
port.set_packet_handler(|bytes, message, dir| {
println!("{bytes:?} {message:?} {dir:?}");
});However, if the closure captures any variables those variables must
either be moved into the closure with the move keyword (e.g., move |bytes, message, dir| {...})
or live at least as long as the Port instance. Additionally, if those
variables are mutated but also accessed outside of the closure, then a
RefCell/Mutex should be
used to facilitate the sharing.
let packet_list = RefCell::new(Vec::new());
let mut port = Port::open_serial("...")?;
port.set_packet_handler(|_bytes, message, _dir| {
if let Ok(mut packets) = packet_list.try_borrow_mut() {
packets.push(message);
}
});
port.tx_recv((1, command::HOME));
for packet in packet_list.borrow().iter() {
println!("{packet:?}");
}Sourcepub fn clear_packet_handler(&mut self) -> Option<H::PacketHandler>
pub fn clear_packet_handler(&mut self) -> Option<H::PacketHandler>
Clear any callback registered via set_packet_handler and return it.
Sourcepub fn timeout_guard(
&mut self,
timeout: Option<Duration>,
) -> Result<TimeoutGuard<'_, B, Self>, Error>
pub fn timeout_guard( &mut self, timeout: Option<Duration>, ) -> Result<TimeoutGuard<'_, B, Self>, Error>
Set the port timeout and return a “scope guard” that will reset the timeout when it goes out of scope.
While the guard is in scope, the port can only be accessed through the
guard. However, because the guard implements Deref
and DerefMut callers can treat the guard as the
port.
§Example
use zproto::binary::command::*;
{
let mut guard = port.timeout_guard(Some(Duration::from_secs(25)))?;
// All commands within this scope will use a 25 second timeout
guard.tx_recv((1, MOVE_ABSOLUTE, 10000))?;
} // The guard is dropped and the timeout is reset.
// This transaction uses the original timeout
let speed = port.tx_recv((1, RETURN_SETTING, SET_TARGET_SPEED))?.data()?;