1use futures::Stream;
31use tracing::{debug, error};
32
33use machine_vision_formats as formats;
34
35use ci2::{DynamicFrameWithInfo, Result};
36use parking_lot::Mutex;
37use std::sync::Arc;
38
39pub enum FrameResult {
40 Frame(DynamicFrameWithInfo),
41 SingleFrameError(String),
42}
43
44pub trait AsyncCamera {
46 fn frames(
48 &mut self,
49 bufsize: usize,
50 ) -> Result<Box<dyn Stream<Item = FrameResult> + Send + Unpin>>;
51}
52
53pub struct ThreadedAsyncCamera<C> {
54 camera: Arc<Mutex<C>>,
55 name: String,
56 serial: String,
57 model: String,
58 vendor: String,
59 control_and_join_handle: Option<(thread_control::Control, std::thread::JoinHandle<()>)>,
61}
62
63fn _test_camera_is_send() {
64 fn implements<T: Send>() {}
66 implements::<ThreadedAsyncCamera<i8>>();
67}
68
69pub struct ThreadedAsyncCameraModule<M, C, G>
70where
71 M: Send,
72 G: Send,
73{
74 cam_module: M,
75 name: String,
76 camera_type: std::marker::PhantomData<C>,
77 guard_type: std::marker::PhantomData<G>,
78}
79
80impl<C: 'static> ThreadedAsyncCamera<C>
81where
82 C: ci2::Camera + Send,
83{
84 pub fn control_and_join_handle(
85 self,
86 ) -> Option<(thread_control::Control, std::thread::JoinHandle<()>)> {
87 self.control_and_join_handle
88 }
89}
90
91impl<C> AsyncCamera for ThreadedAsyncCamera<C>
92where
93 C: 'static + ci2::Camera + Send,
94{
95 fn frames(
96 &mut self,
97 bufsize: usize,
98 ) -> Result<Box<dyn Stream<Item = FrameResult> + Send + Unpin>> {
99 if self.control_and_join_handle.is_some() {
100 return Err(ci2::Error::from("already launched thread"));
101 }
102
103 let (mut tx, rx) = futures::channel::mpsc::channel(bufsize);
104
105 let (flag, control) = thread_control::make_pair();
106
107 let thread_builder =
108 std::thread::Builder::new().name(format!("ThreadedAsyncCamera-{}", self.name));
109 let cam_arc = self.camera.clone();
110 let join_handle: std::thread::JoinHandle<()> = thread_builder.spawn(move || {
111 while flag.is_alive() {
112 {
115 let mut cam = cam_arc.lock();
116 let msg = match cam.next_frame() {
117 Ok(frame) => FrameResult::Frame(frame),
118 Err(ci2::Error::SingleFrameError(s)) => FrameResult::SingleFrameError(s),
119 Err(e) => {
120 error!(
121 "fatal error acquiring frames: {} {:?} {}:{}",
122 e,
123 e,
124 file!(),
125 line!()
126 );
127 return;
128 }
129 };
130
131 match tx.try_send(msg) {
132 Ok(()) => {} Err(e) => {
134 if e.is_full() {
135 error!("dropping message due to backpressure");
137 }
138 if e.is_disconnected() {
139 debug!("ThreadedAsyncCamera listener disconnected");
140 return;
141 }
142 }
143 };
144 }
145 }
146 debug!(
147 "closing thread {:?} ({:?}) in {}:{}",
148 std::thread::current().name(),
149 std::thread::current().id(),
150 file!(),
151 line!()
152 );
153 })?;
154
155 self.control_and_join_handle = Some((control, join_handle));
156
157 Ok(Box::new(rx))
158 }
159}
160
161impl<M, C, G> ThreadedAsyncCameraModule<M, C, G>
162where
163 M: ci2::CameraModule<CameraType = C, Guard = G>,
164 C: ci2::Camera,
165 G: Send,
166{
167 pub fn threaded_async_camera(&mut self, name: &str) -> Result<ThreadedAsyncCamera<C>> {
168 let camera = self.cam_module.camera(name)?;
169 let name = camera.name().into();
170 let model = camera.name().into();
171 let serial = camera.serial().into();
172 let vendor = camera.vendor().into();
173
174 Ok(ThreadedAsyncCamera {
175 camera: Arc::new(Mutex::new(camera)),
176 name,
177 model,
178 vendor,
179 serial,
180 control_and_join_handle: None,
181 })
182 }
183}
184
185pub fn into_threaded_async<M, C, G>(cam_module: M, _guard: &G) -> ThreadedAsyncCameraModule<M, C, G>
186where
187 M: ci2::CameraModule<CameraType = C, Guard = G>,
188 C: ci2::Camera,
189 G: Send,
190{
191 let name = format!("async-{}", cam_module.name());
192
193 ThreadedAsyncCameraModule {
194 cam_module,
195 name,
196 camera_type: std::marker::PhantomData,
197 guard_type: std::marker::PhantomData,
198 }
199}
200
201impl<C> ci2::CameraInfo for ThreadedAsyncCamera<C>
204where
205 C: ci2::CameraInfo,
206{
207 fn name(&self) -> &str {
208 &self.name
209 }
210 fn serial(&self) -> &str {
211 &self.serial
212 }
213 fn model(&self) -> &str {
214 &self.model
215 }
216 fn vendor(&self) -> &str {
217 &self.vendor
218 }
219}
220
221impl<C> ci2::Camera for ThreadedAsyncCamera<C>
222where
223 C: ci2::Camera,
224{
225 fn command_execute(&self, name: &str, verify: bool) -> ci2::Result<()> {
233 let c = self.camera.lock();
234 c.command_execute(name, verify)
235 }
236
237 fn feature_bool(&self, name: &str) -> ci2::Result<bool> {
238 let c = self.camera.lock();
239 c.feature_bool(name)
240 }
241
242 fn feature_bool_set(&self, name: &str, value: bool) -> ci2::Result<()> {
243 let c = self.camera.lock();
244 c.feature_bool_set(name, value)
245 }
246
247 fn feature_enum(&self, name: &str) -> ci2::Result<String> {
248 let c = self.camera.lock();
249 c.feature_enum(name)
250 }
251
252 fn feature_enum_set(&self, name: &str, value: &str) -> ci2::Result<()> {
253 let c = self.camera.lock();
254 c.feature_enum_set(name, value)
255 }
256
257 fn feature_float(&self, name: &str) -> ci2::Result<f64> {
258 let c = self.camera.lock();
259 c.feature_float(name)
260 }
261
262 fn feature_float_set(&self, name: &str, value: f64) -> ci2::Result<()> {
263 let c = self.camera.lock();
264 c.feature_float_set(name, value)
265 }
266
267 fn feature_int(&self, name: &str) -> ci2::Result<i64> {
268 let c = self.camera.lock();
269 c.feature_int(name)
270 }
271
272 fn feature_int_set(&self, name: &str, value: i64) -> ci2::Result<()> {
273 let c = self.camera.lock();
274 c.feature_int_set(name, value)
275 }
276
277 fn node_map_load(&self, settings: &str) -> Result<()> {
280 let c = self.camera.lock();
281 c.node_map_load(settings)
282 }
283 fn node_map_save(&self) -> Result<String> {
284 let c = self.camera.lock();
285 c.node_map_save()
286 }
287
288 fn width(&self) -> ci2::Result<u32> {
289 let c = self.camera.lock();
290 c.width()
291 }
292 fn height(&self) -> ci2::Result<u32> {
293 let c = self.camera.lock();
294 c.height()
295 }
296 fn pixel_format(&self) -> ci2::Result<formats::PixFmt> {
297 let c = self.camera.lock();
298 c.pixel_format()
299 }
300 fn possible_pixel_formats(&self) -> ci2::Result<Vec<formats::PixFmt>> {
301 let c = self.camera.lock();
302 c.possible_pixel_formats()
303 }
304 fn set_pixel_format(&mut self, pixel_format: formats::PixFmt) -> ci2::Result<()> {
305 let mut c = self.camera.lock();
306 c.set_pixel_format(pixel_format)
307 }
308 fn exposure_time(&self) -> ci2::Result<f64> {
309 let c = self.camera.lock();
310 c.exposure_time()
311 }
312 fn exposure_time_range(&self) -> ci2::Result<(f64, f64)> {
313 let c = self.camera.lock();
314 c.exposure_time_range()
315 }
316 fn set_exposure_time(&mut self, value: f64) -> ci2::Result<()> {
317 let mut c = self.camera.lock();
318 c.set_exposure_time(value)
319 }
320 fn gain(&self) -> ci2::Result<f64> {
321 let c = self.camera.lock();
322 c.gain()
323 }
324 fn gain_range(&self) -> ci2::Result<(f64, f64)> {
325 let c = self.camera.lock();
326 c.gain_range()
327 }
328 fn set_gain(&mut self, value: f64) -> ci2::Result<()> {
329 let mut c = self.camera.lock();
330 c.set_gain(value)
331 }
332 fn exposure_auto(&self) -> ci2::Result<ci2::AutoMode> {
333 let c = self.camera.lock();
334 c.exposure_auto()
335 }
336 fn set_exposure_auto(&mut self, value: ci2::AutoMode) -> ci2::Result<()> {
337 let mut c = self.camera.lock();
338 c.set_exposure_auto(value)
339 }
340 fn gain_auto(&self) -> ci2::Result<ci2::AutoMode> {
341 let c = self.camera.lock();
342 c.gain_auto()
343 }
344 fn set_gain_auto(&mut self, value: ci2::AutoMode) -> ci2::Result<()> {
345 let mut c = self.camera.lock();
346 c.set_gain_auto(value)
347 }
348
349 fn start_default_external_triggering(&mut self) -> ci2::Result<()> {
350 let mut c = self.camera.lock();
351 c.start_default_external_triggering()
352 }
353
354 fn set_software_frame_rate_limit(&mut self, fps_limit: f64) -> ci2::Result<()> {
355 let mut c = self.camera.lock();
356 c.set_software_frame_rate_limit(fps_limit)
357 }
358
359 fn trigger_mode(&self) -> ci2::Result<ci2::TriggerMode> {
360 let c = self.camera.lock();
361 c.trigger_mode()
362 }
363 fn set_trigger_mode(&mut self, value: ci2::TriggerMode) -> ci2::Result<()> {
364 let mut c = self.camera.lock();
365 c.set_trigger_mode(value)
366 }
367
368 fn acquisition_frame_rate_enable(&self) -> ci2::Result<bool> {
369 let c = self.camera.lock();
370 c.acquisition_frame_rate_enable()
371 }
372 fn set_acquisition_frame_rate_enable(&mut self, value: bool) -> ci2::Result<()> {
373 let mut c = self.camera.lock();
374 c.set_acquisition_frame_rate_enable(value)
375 }
376
377 fn acquisition_frame_rate(&self) -> ci2::Result<f64> {
378 let c = self.camera.lock();
379 c.acquisition_frame_rate()
380 }
381 fn acquisition_frame_rate_range(&self) -> ci2::Result<(f64, f64)> {
382 let c = self.camera.lock();
383 c.acquisition_frame_rate_range()
384 }
385 fn set_acquisition_frame_rate(&mut self, value: f64) -> ci2::Result<()> {
386 let mut c = self.camera.lock();
387 c.set_acquisition_frame_rate(value)
388 }
389
390 fn trigger_selector(&self) -> ci2::Result<ci2::TriggerSelector> {
391 let c = self.camera.lock();
392 c.trigger_selector()
393 }
394 fn set_trigger_selector(&mut self, value: ci2::TriggerSelector) -> ci2::Result<()> {
395 let mut c = self.camera.lock();
396 c.set_trigger_selector(value)
397 }
398
399 fn acquisition_mode(&self) -> ci2::Result<ci2::AcquisitionMode> {
400 let c = self.camera.lock();
401 c.acquisition_mode()
402 }
403 fn set_acquisition_mode(&mut self, value: ci2::AcquisitionMode) -> ci2::Result<()> {
404 let mut c = self.camera.lock();
405 c.set_acquisition_mode(value)
406 }
407
408 fn acquisition_start(&mut self) -> ci2::Result<()> {
409 let mut c = self.camera.lock();
410 c.acquisition_start()
411 }
412 fn acquisition_stop(&mut self) -> ci2::Result<()> {
413 let mut c = self.camera.lock();
414 c.acquisition_stop()
415 }
416
417 fn next_frame(&mut self) -> ci2::Result<DynamicFrameWithInfo> {
419 let mut c = self.camera.lock();
420 c.next_frame()
421 }
422}
423
424impl<M, C, G> ci2::CameraModule for ThreadedAsyncCameraModule<M, C, G>
425where
426 M: ci2::CameraModule<CameraType = C, Guard = G>,
427 C: ci2::Camera,
428 G: Send,
429{
430 type CameraType = C;
431 type Guard = G;
432
433 fn name(&self) -> &str {
434 self.name.as_ref()
435 }
436 fn camera_infos(&self) -> Result<Vec<Box<dyn ci2::CameraInfo>>> {
437 self.cam_module.camera_infos()
438 }
439 fn camera(&mut self, name: &str) -> Result<C> {
440 self.cam_module.camera(name)
441 }
442
443 fn settings_file_extension(&self) -> &str {
444 self.cam_module.settings_file_extension()
445 }
446}