Skip to main content

autd3_link_simulator/
lib.rs

1#![cfg_attr(docsrs, feature(doc_cfg))]
2#![warn(missing_docs)]
3#![warn(rustdoc::missing_crate_level_docs)]
4#![warn(rustdoc::unescaped_backticks)]
5
6//! This crate provides a link for [`AUTD3 Simulator`].
7//!
8//! [`AUTD3 Simulator`]: https://github.com/shinolab/autd3-server
9
10use autd3_core::link::{AsyncLink, LinkError, RxMessage, TxBufferPoolSync, TxMessage};
11
12use autd3_protobuf::*;
13
14use std::net::SocketAddr;
15
16struct SimulatorInner {
17    client: simulator_client::SimulatorClient<tonic::transport::Channel>,
18    last_geometry_version: usize,
19    buffer_pool: TxBufferPoolSync,
20}
21
22impl SimulatorInner {
23    async fn open(
24        addr: &SocketAddr,
25        geometry: &autd3_core::geometry::Geometry,
26    ) -> Result<SimulatorInner, LinkError> {
27        let conn = tonic::transport::Endpoint::new(format!("http://{addr}"))
28            .map_err(AUTDProtoBufError::from)?
29            .connect()
30            .await
31            .map_err(AUTDProtoBufError::from)?;
32        let mut client = simulator_client::SimulatorClient::new(conn);
33
34        client
35            .config_geometry(Geometry::from(geometry))
36            .await
37            .map_err(|e| {
38                AUTDProtoBufError::SendError(format!("Failed to initialize simulator: {e}"))
39            })?;
40
41        let mut buffer_pool = TxBufferPoolSync::default();
42        buffer_pool.init(geometry);
43
44        Ok(Self {
45            client,
46            last_geometry_version: geometry.version(),
47            buffer_pool,
48        })
49    }
50
51    async fn close(&mut self) -> Result<(), LinkError> {
52        self.client
53            .close(CloseRequest {})
54            .await
55            .map_err(AUTDProtoBufError::from)?;
56
57        Ok(())
58    }
59
60    async fn update(&mut self, geometry: &autd3_core::geometry::Geometry) -> Result<(), LinkError> {
61        if self.last_geometry_version == geometry.version() {
62            return Ok(());
63        }
64        self.last_geometry_version = geometry.version();
65        self.client
66            .update_geometry(Geometry::from(geometry))
67            .await
68            .map_err(|e| AUTDProtoBufError::SendError(format!("Failed to update geometry: {e}")))?;
69        Ok(())
70    }
71
72    fn alloc_tx_buffer(&mut self) -> Vec<TxMessage> {
73        self.buffer_pool.borrow()
74    }
75
76    async fn send(&mut self, tx: Vec<TxMessage>) -> Result<(), LinkError> {
77        let tx_data = TxRawData::from(tx.as_slice());
78        self.buffer_pool.return_buffer(tx);
79        self.client
80            .send_data(tx_data)
81            .await
82            .map_err(AUTDProtoBufError::from)?;
83        Ok(())
84    }
85
86    async fn receive(&mut self, rx: &mut [RxMessage]) -> Result<bool, LinkError> {
87        let rx_ = Vec::<RxMessage>::from_msg(
88            self.client
89                .read_data(ReadRequest {})
90                .await
91                .map_err(AUTDProtoBufError::from)?
92                .into_inner(),
93        )?;
94        if rx.len() == rx_.len() {
95            rx.copy_from_slice(&rx_);
96            Ok(true)
97        } else {
98            Ok(false)
99        }
100    }
101}
102
103/// A [`AsyncLink`] for [`AUTD3 Simulator`].
104///
105/// [`AUTD3 Simulator`]: https://github.com/shinolab/autd3-server
106pub struct Simulator {
107    num_devices: usize,
108    addr: SocketAddr,
109    inner: Option<SimulatorInner>,
110    #[cfg(feature = "blocking")]
111    runtime: Option<tokio::runtime::Runtime>,
112}
113
114impl Simulator {
115    /// Creates a new [`Simulator`].
116    #[must_use]
117    pub const fn new(addr: SocketAddr) -> Simulator {
118        Simulator {
119            num_devices: 0,
120            addr,
121            inner: None,
122            #[cfg(feature = "blocking")]
123            runtime: None,
124        }
125    }
126}
127
128impl AsyncLink for Simulator {
129    async fn open(&mut self, geometry: &autd3_core::geometry::Geometry) -> Result<(), LinkError> {
130        self.inner = Some(SimulatorInner::open(&self.addr, geometry).await?);
131        self.num_devices = geometry.len();
132        Ok(())
133    }
134
135    async fn close(&mut self) -> Result<(), LinkError> {
136        if let Some(mut inner) = self.inner.take() {
137            inner.close().await?;
138        }
139        Ok(())
140    }
141
142    async fn update(&mut self, geometry: &autd3_core::geometry::Geometry) -> Result<(), LinkError> {
143        if let Some(inner) = self.inner.as_mut() {
144            inner.update(geometry).await?;
145            Ok(())
146        } else {
147            Err(LinkError::closed())
148        }
149    }
150
151    async fn alloc_tx_buffer(&mut self) -> Result<Vec<TxMessage>, LinkError> {
152        if let Some(inner) = self.inner.as_mut() {
153            Ok(inner.alloc_tx_buffer())
154        } else {
155            Err(LinkError::closed())
156        }
157    }
158
159    async fn send(&mut self, tx: Vec<TxMessage>) -> Result<(), LinkError> {
160        if let Some(inner) = self.inner.as_mut() {
161            inner.send(tx).await?;
162            Ok(())
163        } else {
164            Err(LinkError::closed())
165        }
166    }
167
168    async fn receive(&mut self, rx: &mut [RxMessage]) -> Result<(), LinkError> {
169        if let Some(inner) = self.inner.as_mut() {
170            inner.receive(rx).await?;
171            Ok(())
172        } else {
173            Err(LinkError::closed())
174        }
175    }
176
177    fn is_open(&self) -> bool {
178        self.inner.is_some()
179    }
180}
181
182#[cfg(feature = "blocking")]
183use autd3_core::link::Link;
184
185#[cfg_attr(docsrs, doc(cfg(feature = "blocking")))]
186#[cfg(feature = "blocking")]
187impl Link for Simulator {
188    fn open(&mut self, geometry: &autd3_core::geometry::Geometry) -> Result<(), LinkError> {
189        let runtime = tokio::runtime::Builder::new_multi_thread()
190            .enable_all()
191            .build()
192            .expect("Failed to create runtime");
193        runtime.block_on(<Self as AsyncLink>::open(self, geometry))?;
194        self.runtime = Some(runtime);
195        Ok(())
196    }
197
198    fn close(&mut self) -> Result<(), LinkError> {
199        self.runtime
200            .as_ref()
201            .map_or(Err(LinkError::closed()), |runtime| {
202                runtime.block_on(async {
203                    if let Some(mut inner) = self.inner.take() {
204                        inner.close().await?;
205                    }
206                    Ok(())
207                })
208            })
209    }
210
211    fn update(&mut self, geometry: &autd3_core::geometry::Geometry) -> Result<(), LinkError> {
212        self.runtime
213            .as_ref()
214            .map_or(Err(LinkError::closed()), |runtime| {
215                runtime.block_on(async {
216                    if let Some(inner) = self.inner.as_mut() {
217                        inner.update(geometry).await?;
218                    }
219                    Ok(())
220                })
221            })
222    }
223
224    fn alloc_tx_buffer(&mut self) -> Result<Vec<TxMessage>, LinkError> {
225        self.runtime
226            .as_ref()
227            .map_or(Err(LinkError::closed()), |runtime| {
228                runtime.block_on(async {
229                    if let Some(inner) = self.inner.as_mut() {
230                        Ok(inner.alloc_tx_buffer())
231                    } else {
232                        Err(LinkError::closed())
233                    }
234                })
235            })
236    }
237
238    fn send(&mut self, tx: Vec<TxMessage>) -> Result<(), LinkError> {
239        self.runtime
240            .as_ref()
241            .map_or(Err(LinkError::closed()), |runtime| {
242                runtime.block_on(async {
243                    if let Some(inner) = self.inner.as_mut() {
244                        inner.send(tx).await?;
245                        Ok(())
246                    } else {
247                        Err(LinkError::closed())
248                    }
249                })
250            })
251    }
252
253    fn receive(&mut self, rx: &mut [RxMessage]) -> Result<(), LinkError> {
254        self.runtime
255            .as_ref()
256            .map_or(Err(LinkError::closed()), |runtime| {
257                runtime.block_on(async {
258                    if let Some(inner) = self.inner.as_mut() {
259                        inner.receive(rx).await?;
260                        Ok(())
261                    } else {
262                        Err(LinkError::closed())
263                    }
264                })
265            })
266    }
267
268    fn is_open(&self) -> bool {
269        self.runtime.is_some() && self.inner.is_some()
270    }
271}