Skip to content
This is the development version of the documentation. It may change before the next release. See 0.14.x for the latest release.

Failsafe

The devices have a failsafe feature that stops their output by themselves when communication with the host is lost or when they lose the PTP lock. Both are disabled by default and can be enabled with SetCpuConfig.

Communication-loss failsafe and liveness check

Section titled “Communication-loss failsafe and liveness check”

If failsafe_timeout is set, a device stops its output when communication from the host has been cut off for that long. The default is None (disabled), and the devices do not stop the ultrasound even if communication is cut off by a host crash or a broken cable.

By default, Client sends nothing to the devices by itself while there is nothing to send. Therefore, when failsafe_timeout is set, set heartbeat_interval in TransportOption so that liveness checks are sent periodically. The interval must be sufficiently shorter than failsafe_timeout (aim for less than half).

The following is an example that sets failsafe_timeout to 100 ms and sends a liveness check every 10 ms.

let option = TransportOption {
heartbeat_interval: Some(Duration::from_millis(10)),
..Default::default()
};
let mut client = Client::open(&geometry, &option).await?;
client
.send(SetCpuConfig::new(CpuConfig {
failsafe_timeout: Some(Duration::from_millis(100)),
..Default::default()
}))
.await?;

An output stopped by the failsafe does not come back automatically. Whether it is stopped can be checked with failsafe_active of the DeviceStatus that device_status() of a reply (Response) returns, and sending ReleaseFailsafe resumes it (Clear also works, but it resets every state).

If ptp_unlock_failsafe_timeout is set with SetCpuConfig, a device that has stayed without the PTP lock for the given time stops its output.

The following is an example that sends ReleaseFailsafe to the devices that have failsafe_active set and have relocked (ptp_locked is set).

let status = client.read_state().await?.device_status();
let releasable = |s: &DeviceStatus| s.failsafe_active && s.ptp_locked;
if status.iter().any(releasable) {
client
.send(each(|device| {
releasable(&status[device.idx()]).then_some(ReleaseFailsafe)
}))
.await?;
}

Sending ReleaseFailsafe to a device that is still without the lock returns an error, and its output stays stopped.