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 assertedcurrent_mod_segment
: Current Modulation Segmentcurrent_stm_segment
: Current FociSTM/GainSTM Segmentcurrent_gain_segment
: Current Gain Segmentis_gain_mode
: Whether Gain is currently being usedis_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: Duration::from_millis(1),
receive_interval: Duration::from_millis(1),
timeout: None,
parallel: ParallelMode::Auto,
strict: true
},
FixedSchedule::default(),
);
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,
.parallel = ParallelMode::Auto,
.strict = true},
FixedSchedule{});
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,
Parallel = ParallelMode.Auto,
Strict = true,
},
new FixedSchedule()
);
var d = new Null();
sender.Send(d);
from pyautd3 import AUTD3, Controller, Duration, Null, SenderOption, FixedSchedule, ParallelMode
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,
parallel=ParallelMode.Auto,
strict=True
),
FixedSchedule(),
)
d = Null()
sender.send(d)
Here,
send_interval
: Send intervalreceive_interval
: Receive intervaltimeout
: Timeout duration. See About Ack check for details.parallel
: Parallel computation mode. See About Parallel Computation for details.strict
: Whether to strictly check the data to be sent. See About Ack check for details.
and the default values are as above.
The second argument is a structure to adjust send/receive intervals, and you can choose from the following:
FixedSchedule
: Starts the next send at the specified interval from the start time of the previous send, regardless of the time taken for the send process.FixedDelay
: Starts the next send after the specified interval from the completion of the send process.
これらの構造体は, どのようにスレッドをスリープさせるかを指定する以下の構造体を持つ. These structures have the following structures that specify how to put the thread to sleep:
SpinSleeper
: Usesspin_sleep
StdSleeper
: Usesstd::thread::sleep
SpinWait
: Uses busy-waiting
Note that Controller::send
and Controller::group_send
are equivalent to Sender::send
and Sender::group_send
with the Controller::default_sender_option
(which is configurable) and default SpinSleeper
.
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(())
}