binary
only.Expand description
Types and traits for communicating with Zaber products with Zaber’s Binary protocol.
The binary protocol is deprecated and Zaber recommends the ascii
protocol instead.
§Communicating with a Device
All communication with Zaber products starts with a Port
, which can be either a serial or TCP port:
let mut port = Port::open_serial("/dev/ttyUSB0")?;
// OR
let mut port = Port::open_tcp("192.168.0.1:55550")?;
You can then transmit a command to and receive a reply from devices
connected to that port with the tx_recv
method, or any of the
other tx_recv*
methods. Commands are constructed as tuples:
- Commands that do not require data take the form
(u8, Command)
, where
// Send the Home command to all devices (address 0)
use zproto::binary::command::HOME;
let reply = port.tx_recv((0, HOME))?;
- Commands that do require data take a form similar to above,
(u8, Command, Data)
, whereu8
andCommand
are the same andData
is some type that implementsData
. This includes types likei32
,bool
,command
, and other types.
// Move device 1 to the absolute position 10,000.
use zproto::binary::command::*;
let reply = port.tx_recv((1, MOVE_ABSOLUTE, 10000))?;
// OR
let reply = port.tx_recv((0, RETURN_SETTING, SET_TARGET_SPEED))?;
If the response is an ERROR
or is otherwise unexpected
(e.g., from a different device) an error will be returned.
NOTE: Address aliases other than 0 (all devices) are presently not
supported. Responses to such messages will be treated as unexpected by the
tx_recv*
methods.
§Other Port
Methods
tx_recv
works great when you need to send one command and
receive one response. But, when you have a chain of devices, you may need to
read a response from all devices in the chain. When you know the number of
devices in the chain, you can use tx_recv_n
to read n
responses to a command. If you don’t know the number of devices in the chain
you can use tx_recv_until_timeout
to read as
many responses as possible.
Sometimes you only want to transmit or receive data, but not both. In those
cases the tx
, recv
, recv_n
,
and recv_until_timeout
are very helpful.
Finally, a common pattern is to poll a device until it is in a desired
state, which you can do with the poll_until
and
poll_until_idle
methods.
§Reading Data
Reading data from a response is as simple as calling data()
on the response. If the command was sent using the strongly typed commands
in the command
module, the library will pick the correct type conversion
for you at compile time.
use zproto::binary::command::*;
let reply = port.tx_recv((0, RETURN_SETTING, SET_TARGET_SPEED))?;
let speed = reply.data()?; // `speed` is an `i32`
let reply = port.tx_recv((0, RETURN_SETTING, SET_HOME_STATUS))?;
let homed = reply.data()?; // `homed` is a `bool`.
§Sending a Port between threads
By default a Port
does not implement Send
, so cannot be sent to another
thread. If you’re application requires this, use the Port::try_into_send
method to convert it to one that can be. Doing so places Send
bounds on
any packet handlers.
let sendable_port = Port::open_serial("...")?
.try_into_send()
.unwrap();
§Type Safety
The library uses Rust’s type system and the strongly-typed commands in the
command
module to help enforce proper message structure and avoid
run-time bugs. For instance, not passing data to commands that require data,
or passing the wrong data type, will result in a compile time error.
use zproto::binary::command::*;
let reply = port.tx_recv((0, MOVE_ABSOLUTE))?; // ERROR: the data field is missing!
let reply = port.tx_recv((0, MOVE_ABSOLUTE, true))?; // ERROR: the data has the incorrect type!
let reply = port.tx_recv((0, RESET)); // ERROR: Devices do not respond to the RESET command!
To do this, each command in the command
module is given a unique type
that implement a set of traits
. These tell the compiler what kind of
data the command takes, what kind of data it returns, and if it returns a
response at all. However, this means that the commands cannot be swapped out
for one another at run time or stored in a collection.
// This will not compile because SET_TARGET_SPEED and SET_ACCELERATION
// are different types.
use zproto::binary::command::*;
let commands = [(0, SET_TARGET_SPEED, 10000), (0, SET_ACCELERATION, 5000)];
To accommodate situations like this, the library provides “untyped” versions
of the command in the command::untyped
module. The commands in that
module are simply u8
s and can be used anywhere their strongly-typed
counterparts can.
// This works now.
use zproto::binary::command::untyped::*;
let commands = [(0, SET_TARGET_SPEED, 10000), (0, SET_ACCELERATION, 5000)];
However, you will not have any of the nice compile time type safety or automatic type conversion – you will have to pick the types yourself.
use zproto::binary::command::untyped::*;
let reply = port.tx_recv((0, RETURN_SETTING, SET_TARGET_SPEED))?;
let speed: i32 = reply.data()?; // Notice that the type must be specified.
// The compiler cannot tell if you have picked the wrong type so this will
// compile, but the data conversion will fail at run time.
let speed: bool = reply.data()?;
§Handling Compile-time Errors
The traits in this crate are named so that their meaning is hopefully clear, but, nevertheless, the compiler errors can sometimes be confusing. Here are some errors that you might see and suggestions for correcting them.
§TakesData
is not Satisfied
the trait `TakesData<{integer}>` is not implemented for ...
There are two reasons for this error:
- The command does not take any data argument. Try restructuring the message from
(address, command, data)
to(address, command)
. - The command requires a data argument with a different type. Consult the
documentation for the command
and use the data type listed there.
§TakesNoData
is not Satisfied
the trait `TakesNoData` is not implemented for ...
The command likely requires a data argument. Try restructuring the message from (address, command)
to (address, command, data)
.
§ElicitsResponse
is not Satisfied
the trait `ElicitsResponse` is not implemented for ...
This means the command does not elicit a response from a device and the
Port::tx_recv
family of functions would eventually time out waiting for
one. Try transmitting the command without reading a reply with
tx
instead.
Modules§
- command
- Binary commands.
- handlers
- Event handlers for ports.
- traits
- Traits encoding information about Binary commands/messages and the types that can generate them.
Structs§
- IoStates
- The state of multiple digital I/O channels.
- Message
- A Binary Protocol message.
- Open
Serial Options - Options for configuring and opening a serial port.
- Open
TcpOptions - Options for configuring and opening a TCP port.
- Port
- A Port for transmitting and receiving Zaber Binary protocol messages.
- Version
- Represents a version of firmware.