autd3_link_simulator/
lib.rs1#![cfg_attr(docsrs, feature(doc_cfg))]
2#![warn(missing_docs)]
3#![warn(rustdoc::missing_crate_level_docs)]
4#![warn(rustdoc::unescaped_backticks)]
5
6use 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
103pub 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 #[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}