Legacy Firmware
This SDK is incompatible with the old autd3 SDK, and its communication protocol is a new design.
Therefore, the regular Client cannot drive devices running the legacy firmware.
LegacyClient is a compatibility client for driving devices running the legacy firmware v12.1.0.
Enabling
Section titled “Enabling”In Rust, it is enabled by the legacy feature of autd3-rs (disabled by default).
autd3-rs = { version = "0.4", features = ["legacy"] }The Python and C# bindings require no extra setup.
They are available as autd3.LegacyClient and the AUTD3.Legacy namespace respectively.
User code has the same shape as with the current SDK.
Only replace Client with LegacyClient and ClientConfig with LegacyClientConfig.
All the current Links can be used as they are.
let client = LegacyClient::open( &geometry, EchocatLinkOption::default(), LegacyClientConfig::default(),).await?;client = await LegacyClient.open( geometry, echocat.EchocatLinkOption(), LegacyClientConfig(),)using var client = await LegacyClient.OpenAsync( geometry, new EchocatLinkOption(), new LegacyClientConfig());LegacyClientConfig only holds timeout_cycles (default 2000) and the RT thread tuning (rt_priority / rt_policy / rt_affinity).
The latter have the same types and the same defaults as the current ClientConfig (TimeCritical on Windows, unset elsewhere).
Reading the firmware version is also the same as with the current client.
for (i, version) in client.read_firmware_version().await?.iter().enumerate() { println!("device[{i}] firmware version: {version}");}for i, version in enumerate(await client.read_firmware_version()): print(f"device[{i}] firmware version: {version}")var versions = await client.ReadFirmwareVersionAsync();for (var i = 0; i < versions.Count; i++){ Console.WriteLine($"device[{i}] firmware version: {versions[i]}");}Assembling commands is the same as well (the type is LegacyDatagramBuilder instead of DatagramBuilder).
The compute helpers for Emission patterns and AM waveforms are shared too.
let mut builder = client.datagram_builder();builder .push(SetSilencer::default()) .push(Pattern::new(&emissions)) .push(Modulation::new(SamplingConfig::FREQ_4K, &modulation));let frames = builder.build()?;for frame in &frames { client.send_checked(frame).await?;}builder = client.datagram_builder()builder.push(SetSilencer())builder.push(Pattern(emissions))builder.push(Modulation(SamplingConfig.FREQ_4K, mod_buf))frames = builder.build()for i in range(len(frames)): await client.send_checked(frames[i])using var builder = client.DatagramBuilder();builder .Push(new SetSilencer()) .Push(new Pattern(emissions)) .Push(new Modulation(SamplingConfig.Freq4k, modulation));using var frames = builder.Build();foreach (var frame in frames){ await client.SendCheckedAsync(frame);}push_each, which assigns a command per device, works the same way too.
Shutdown is the same as well.
client.stop().await?;client.close().await?;await client.stop()await client.close()await client.StopAsync();await client.CloseAsync();Differences from the current Client
Section titled “Differences from the current Client”| Item | Client |
LegacyClient |
|---|---|---|
| Send model | Pipelined / stop-and-wait | Stop-and-wait only |
| Reading error details | read_error_detail() |
Not supported (only the ack error code) |
| Reading telemetry counters | read_telemetry() |
Not supported |
The pipelined send of the current client cannot be used with the legacy firmware. Throughput is therefore substantially lower than with the current client.
Supported Commands
Section titled “Supported Commands”The following commands are available.
ClearForceFanSetSilencerPatternModulationChangeModulationBankFociStmPatternStmSetOutputMaskSetPhaseCorrectionSetPulseWidthTableSetGpioOutEmulateGpioIn
The following are unavailable.
WritePatternBufferWriteModulationBufferWriteFociBufferWritePatternCompressedConfigPatternConfigModulationConfigFociStmChangePatternBank(see below)
Switching the Pattern Bank
Section titled “Switching the Pattern Bank”Instead of ChangePatternBank, use the legacy-specific LegacyChangePatternBank.
Choose pattern / foci_stm / pattern_stm according to what is being switched.
let mut builder = client.datagram_builder();builder.push(Pattern::with_bank(PatternBank::B1, &emissions));for frame in &builder.build()? { client.send_checked(frame).await?;}
let mut builder = client.datagram_builder();builder.push(LegacyChangePatternBank::pattern(PatternBank::B0));for frame in &builder.build()? { client.send_checked(frame).await?;}builder = client.datagram_builder()builder.push(Pattern(emissions, PatternBank.B1))frames = builder.build()for i in range(len(frames)): await client.send_checked(frames[i])
builder = client.datagram_builder()builder.push(LegacyChangePatternBank.pattern(PatternBank.B0))frames = builder.build()for i in range(len(frames)): await client.send_checked(frames[i])using (var bankBuilder = client.DatagramBuilder()){ bankBuilder.Push(new Pattern(PatternBank.B1, emissions)); using var bankFrames = bankBuilder.Build(); foreach (var frame in bankFrames) { await client.SendCheckedAsync(frame); }}
using (var bankBuilder = client.DatagramBuilder()){ bankBuilder.Push(LegacyChangePatternBank.Pattern(PatternBank.B0)); using var bankFrames = bankBuilder.Build(); foreach (var frame in bankFrames) { await client.SendCheckedAsync(frame); }}