Skip to main content

Port

Struct Port 

Source
pub struct Port<'a, B, H = LocalHandlers<'a>> { /* private fields */ }
Available on crate feature 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:

  1. B: the type of Backend used to send/receive data.
    • Use the convenience methods open_serial and open_tcp to 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 the OpenSerialOptions and OpenTcpOptions builder types.
  2. 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 Send and one that does not (the default). To convert a port into a type that implements Send, use the try_into_send method.

Implementations§

Source§

impl<'a> Port<'a, Serial>

Source

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")?;
Source

pub fn open_serial_options() -> OpenSerialOptions

Get an OpenSerialOptions to customize how a serial port is opened.

Source§

impl<'a> Port<'a, TcpStream>

Source

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")?;
Source

pub fn open_tcp_options() -> OpenTcpOptions

Get an OpenTcpOptions to customize how a TCP port is opened.

Source§

impl<'a> Port<'a, Mock>

Source

pub fn open_mock() -> Port<'a, Mock>

Available on crate feature 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,

Source

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>
where B: Backend, H: Handlers, H::PacketHandler: FnMut(&[u8], Message, Direction) + 'a,

Source

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();
}
Source

pub fn tx_recv<M>( &mut self, message: M, ) -> Result<Message<M::Response>, BinaryError>

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()?;
Source

pub fn tx_recv_n<M>( &mut self, message: M, n: usize, ) -> Result<Vec<Message<M::Response>>, BinaryError>

Transmit a message and then receive n responses.

See tx_recv for more details.

Source

pub fn tx_recv_until_timeout<M>( &mut self, message: M, ) -> Result<Vec<Message<M::Response>>, BinaryError>

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.

Source

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.

Source

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)?;
Source

pub fn recv_any(&mut self) -> Result<Message, BinaryError>

Receive a message containing any command.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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
)?;
Source

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.

Source

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

pub fn message_ids(&self) -> bool

Return whether message IDs will be transmitted and parsed.

Source

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.

Source

pub fn read_timeout(&self) -> Result<Option<Duration>, Error>

Get the read timeout.

If it is None, reads will block indefinitely.

Source

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.

Source

pub fn backend(&self) -> &B

Get a referenced to the backend.

Source

pub fn backend_mut(&mut self) -> &mut B

Get a mutable reference to the backend.

Source

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.

Source

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:?}");
}
Source

pub fn clear_packet_handler(&mut self) -> Option<H::PacketHandler>

Clear any callback registered via set_packet_handler and return it.

Source

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()?;

Trait Implementations§

Source§

impl<B: Backend, H> Debug for Port<'_, B, H>

Source§

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

Formats the value using the given formatter. Read more
Source§

impl<B: Backend, H> Port<B> for Port<'_, B, H>

Auto Trait Implementations§

§

impl<'a, B, H = LocalHandlers<'a>> !RefUnwindSafe for Port<'a, B, H>

§

impl<'a, B, H = LocalHandlers<'a>> !UnwindSafe for Port<'a, B, H>

§

impl<'a, B, H> Freeze for Port<'a, B, H>
where B: Freeze, H: Freeze,

§

impl<'a, B, H> Send for Port<'a, B, H>
where B: Send, H: Send,

§

impl<'a, B, H> Sync for Port<'a, B, H>
where B: Sync, H: Sync,

§

impl<'a, B, H> Unpin for Port<'a, B, H>
where B: Unpin, H: Unpin,

§

impl<'a, B, H> UnsafeUnpin for Port<'a, B, H>
where B: UnsafeUnpin, H: UnsafeUnpin,

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, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

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

fn try_from(value: U) -> Result<T, !>

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.