Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Controller

This section introduces the APIs available in the Controller.

fpga_state

Retrieve the state of the FPGA. Before using this, you need to enable state retrieval with ReadsFPGAState.

use autd3::prelude::*;
#[allow(unused_variables)]
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut autd = Controller::open([AUTD3::default()], autd3::link::Nop::new())?;
autd.send(ReadsFPGAState::new(|_dev| true))?;

let info = autd.fpga_state()?;
Ok(())
}
#include<autd3.hpp>
#include<autd3/link/nop.hpp>
int main() {
using namespace autd3;
auto autd =
Controller::open({AUTD3{}}, link::Nop{});
autd.send(ReadsFPGAState([](const auto&) { return true; }));

const auto info = autd.fpga_state();
return 0; }
using AUTD3Sharp;
using AUTD3Sharp.Link;
using AUTD3Sharp.Utils;
using var autd = Controller.Open([new AUTD3()], new Nop());
autd.Send(new ReadsFPGAState(_ => true));

var info = autd.FPGAState();
from pyautd3 import Controller, AUTD3, ReadsFPGAState
from pyautd3.link.nop import Nop
autd = Controller.open([AUTD3()], Nop())
autd.send(ReadsFPGAState(lambda _: True))

info = autd.fpga_state()

The argument of the ReadsFPGAState constructor is Fn(&Device) -> bool, which specifies whether to enable state retrieval for each device.

fpga_state returns None for devices that are not enabled.

The following information can currently be obtained as the state of the FPGA:

  • is_thermal_assert: Whether the temperature sensor for fan control is asserted
  • current_mod_segment: Current Modulation Segment
  • current_stm_segment: Current FociSTM/GainSTM Segment
  • current_gain_segment: Current Gain Segment
  • is_gain_mode: Whether Gain is currently being used
  • is_stm_mode: Whether FociSTM/GainSTM is currently being used

send

Send data to the device.

Data can be sent either individually or two at a time.

sender

You can specify settings for sending via sender.

use autd3::prelude::*;
use std::time::Duration;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut autd = Controller::open([AUTD3::default()], autd3::link::Nop::new())?;
let mut sender = autd.sender(
    SenderOption {
        send_interval: Some(Duration::from_millis(1)),
        receive_interval: Some(Duration::from_millis(1)),
        timeout: None,
        parallel: ParallelMode::Auto,
    },
);
let d = Null {};
sender.send(d)?;
Ok(())
}
#include<chrono>
#include<autd3.hpp>
#include<autd3/link/nop.hpp>
int main() {
using namespace autd3;
auto autd = Controller::open({AUTD3{}}, link::Nop{});
auto sender =
    autd.sender(SenderOption{.send_interval = std::chrono::milliseconds(1),
                             .receive_interval = std::chrono::milliseconds(1),
                             .timeout = std::nullopt});
const Null d;
sender.send(d);
return 0; }
using AUTD3Sharp;
using AUTD3Sharp.Link;
using AUTD3Sharp.Gain;
using AUTD3Sharp.Utils;
using var autd = Controller.Open([new AUTD3()], new Nop());
var sender = autd.Sender(
    new SenderOption
    {
        SendInterval = Duration.FromMillis(1),
        ReceiveInterval = Duration.FromMillis(1),
        Timeout = null,
    }
);
var d = new Null();
sender.Send(d);
from pyautd3 import AUTD3, Controller, Duration, Null, SenderOption
from pyautd3.link.nop import Nop
autd = Controller.open([AUTD3()], Nop())
sender = autd.sender(
    SenderOption(
        send_interval=Duration.from_millis(1),
        receive_interval=Duration.from_millis(1),
        timeout=None,
    ),
)
d = Null()
sender.send(d)

Here,

  • send_interval: Send interval
  • receive_interval: Receive interval
  • timeout: Timeout duration. See About Ack check for details.
  • parallel: Parallel computation mode. See About Parallel Computation for details.

and the default values are as above.

Note that Controller::send is equivalent to Sender::send with the Controller::default_sender_option (which is configurable).

About ack check

If the timeout value is

  • greater than 0, the send function waits until the sent data is processed by the device or the specified timeout duration elapses. If it cannot confirm that the sent data was processed by the device, it returns an error.
  • 0, the send function does not check whether the sent data was processed by the device.

If you want to ensure that the data is sent, it is recommended to set this to an appropriate value.

If timeout is not specified in SenderOption, the default value () is used.

When sending multiple data at once, the maximum timeout value of each data is used.

About Parallel Computation

Internal calculations for each data can be executed in parallel on a per-device basis.

Specifying ParallelMode::On enables parallel computation, and ParallelMode::Off disables it.

In the case of ParallelMode::Auto, parallel computation is enabled if the number of devices exceeds the parallel computation threshold value for each data as shown below.

Parallel Computation Threshold Value
Clear/GPIOOutputs/
ForceFan/PhaseCorrection/
ReadsFPGAState/SwapSegment/
Silencer/Synchronize/
FociSTM (less than 4000 foci)/
Modulation
18446744073709551615
PulseWidthEncoder/
FociSTM (4000 foci or more)/
/GainSTM/Gain
4

inspect (available only in Rust)

The calculations for Gain, Modulation, GainSTM, and FociSTM are lazy for parallelization and to minimize memory allocation, and the calculation results are constructed directly within the frame. Therefore, it is not possible to directly check these calculation results before sending.

By using Controller::inspect, you can check these calculation results without sending.

use autd3::prelude::*;
#[allow(unused_variables)]
fn main() -> Result<(), Box<dyn std::error::Error>> {
let autd = Controller::open([AUTD3::default()], autd3::link::Nop::new())?;
let r = autd.inspect(Null {})?;
dbg!(&r[0]); // result of device 0
// &r[0] = Some(
//     GainInspectionResult {
//         name: "Null",
//         data: [
//             Drive {
//                 phase: 0x00,
//                 intensity: 0x00,
//             },
//             ︙
//             Drive {
//                 phase: 0x00,
//                 intensity: 0x00,
//             },
//         ],
//         segment: S0,
//         transition_mode: None,
//     },
// )

Ok(())
}