1use std::collections::VecDeque;
2use std::sync::Arc;
3
4use ad_core_rs::ndarray::NDArray;
5use ad_core_rs::ndarray_pool::NDArrayPool;
6use ad_core_rs::plugin::runtime::{NDPluginProcess, ProcessResult};
7use epics_base_rs::calc;
8
9#[derive(Debug, Clone)]
18pub struct CalcExpression {
19 compiled: calc::CompiledExpr,
20}
21
22impl CalcExpression {
23 pub fn parse(expr: &str) -> Option<CalcExpression> {
27 calc::compile(expr)
28 .ok()
29 .map(|compiled| CalcExpression { compiled })
30 }
31
32 pub fn evaluate(&self, a: f64, b: f64) -> f64 {
35 let mut inputs = calc::NumericInputs::new();
36 inputs.vars[0] = a; inputs.vars[1] = b; calc::eval(&self.compiled, &mut inputs).unwrap_or(0.0)
39 }
40
41 pub fn evaluate_vars(&self, vars: &[f64; 16]) -> f64 {
45 let mut inputs = calc::NumericInputs::with_vars(*vars);
46 calc::eval(&self.compiled, &mut inputs).unwrap_or(0.0)
47 }
48}
49
50#[derive(Debug, Clone)]
52pub enum TriggerCondition {
53 AttributeThreshold { name: String, threshold: f64 },
55 External,
57 Calc {
62 attr_a: String,
63 attr_b: String,
64 expression: CalcExpression,
65 },
66}
67
68#[derive(Debug, Clone, Copy, PartialEq, Eq)]
70pub enum BufferStatus {
71 Idle,
72 BufferFilling,
73 Flushing,
74 AcquisitionCompleted,
75}
76
77pub struct CircularBuffer {
79 pub(crate) pre_count: usize,
80 pub(crate) post_count: usize,
81 buffer: VecDeque<Arc<NDArray>>,
82 pub(crate) trigger_condition: TriggerCondition,
83 triggered: bool,
84 post_remaining: usize,
85 captured: Vec<Arc<NDArray>>,
86 preset_trigger_count: usize,
88 trigger_count: usize,
90 flush_on_soft_trigger: bool,
92 pub(crate) status: BufferStatus,
94}
95
96impl CircularBuffer {
97 pub fn new(pre_count: usize, post_count: usize, condition: TriggerCondition) -> Self {
98 Self {
99 pre_count,
100 post_count,
101 buffer: VecDeque::with_capacity(pre_count + 1),
102 trigger_condition: condition,
103 triggered: false,
104 post_remaining: 0,
105 captured: Vec::new(),
106 preset_trigger_count: 0,
107 trigger_count: 0,
108 flush_on_soft_trigger: false,
109 status: BufferStatus::Idle,
110 }
111 }
112
113 pub fn set_preset_trigger_count(&mut self, count: usize) {
115 self.preset_trigger_count = count;
116 }
117
118 pub fn trigger_count(&self) -> usize {
120 self.trigger_count
121 }
122
123 pub fn status(&self) -> BufferStatus {
125 self.status
126 }
127
128 pub fn set_flush_on_soft_trigger(&mut self, flush: bool) {
130 self.flush_on_soft_trigger = flush;
131 }
132
133 pub fn push(&mut self, array: Arc<NDArray>) -> bool {
136 if self.status == BufferStatus::AcquisitionCompleted {
138 return false;
139 }
140
141 if self.status == BufferStatus::Idle {
143 self.status = BufferStatus::BufferFilling;
144 }
145
146 if self.triggered {
147 self.captured.push(array);
149 self.post_remaining -= 1;
150 if self.post_remaining == 0 {
151 self.triggered = false;
152 if self.preset_trigger_count > 0 && self.trigger_count >= self.preset_trigger_count
154 {
155 self.status = BufferStatus::AcquisitionCompleted;
156 } else {
157 self.status = BufferStatus::BufferFilling;
158 }
159 return true;
160 }
161 return false;
162 }
163
164 let trigger = match &self.trigger_condition {
167 TriggerCondition::AttributeThreshold { name, threshold } => array
168 .attributes
169 .get(name)
170 .and_then(|a| a.value.as_f64())
171 .map(|v| v >= *threshold)
172 .unwrap_or(false),
173 TriggerCondition::External => false,
174 TriggerCondition::Calc {
175 attr_a,
176 attr_b,
177 expression,
178 } => {
179 let a = array
180 .attributes
181 .get(attr_a)
182 .and_then(|a| a.value.as_f64())
183 .unwrap_or(f64::NAN);
184 let b = array
185 .attributes
186 .get(attr_b)
187 .and_then(|a| a.value.as_f64())
188 .unwrap_or(f64::NAN);
189 let mut vars = [0.0f64; 16];
192 vars[0] = a; vars[1] = b; vars[2] = self.pre_count as f64; vars[3] = self.post_count as f64; vars[4] = self.buffer.len() as f64; vars[5] = if self.triggered { 1.0 } else { 0.0 }; expression.evaluate_vars(&vars) != 0.0
199 }
200 };
201
202 if trigger {
203 self.trigger();
206 self.captured.push(array);
208 self.post_remaining -= 1;
209 if self.post_remaining == 0 {
210 self.triggered = false;
211 if self.preset_trigger_count > 0 && self.trigger_count >= self.preset_trigger_count
212 {
213 self.status = BufferStatus::AcquisitionCompleted;
214 } else {
215 self.status = BufferStatus::BufferFilling;
216 }
217 return true;
218 }
219 return false;
220 }
221
222 self.buffer.push_back(array);
224 if self.buffer.len() > self.pre_count {
225 self.buffer.pop_front();
226 }
227
228 false
229 }
230
231 pub fn trigger(&mut self) {
233 if self.status == BufferStatus::AcquisitionCompleted {
235 return;
236 }
237
238 self.triggered = true;
239 self.post_remaining = self.post_count;
240 self.trigger_count += 1;
241 self.status = BufferStatus::Flushing;
242 self.captured.clear();
244 self.captured.extend(self.buffer.drain(..));
245 }
246
247 pub fn take_captured(&mut self) -> Vec<Arc<NDArray>> {
249 std::mem::take(&mut self.captured)
250 }
251
252 pub fn is_triggered(&self) -> bool {
253 self.triggered
254 }
255
256 pub fn pre_buffer_len(&self) -> usize {
257 self.buffer.len()
258 }
259
260 pub fn reset(&mut self) {
261 self.buffer.clear();
262 self.captured.clear();
263 self.triggered = false;
264 self.post_remaining = 0;
265 self.trigger_count = 0;
266 self.status = BufferStatus::Idle;
267 }
268}
269
270#[derive(Default)]
274struct CBParamIndices {
275 control: Option<usize>,
276 status: Option<usize>,
277 trigger_a: Option<usize>,
278 trigger_b: Option<usize>,
279 trigger_a_val: Option<usize>,
280 trigger_b_val: Option<usize>,
281 trigger_calc: Option<usize>,
282 trigger_calc_val: Option<usize>,
283 pre_trigger: Option<usize>,
284 post_trigger: Option<usize>,
285 current_image: Option<usize>,
286 post_count: Option<usize>,
287 soft_trigger: Option<usize>,
288 triggered: Option<usize>,
289 preset_trigger_count: Option<usize>,
290 actual_trigger_count: Option<usize>,
291 flush_on_soft_trigger: Option<usize>,
292}
293
294pub struct CircularBuffProcessor {
295 buffer: CircularBuffer,
296 params: CBParamIndices,
297 trigger_a_name: String,
299 trigger_b_name: String,
300 trigger_calc_expr: String,
301}
302
303impl CircularBuffProcessor {
304 pub fn new(pre_count: usize, post_count: usize, condition: TriggerCondition) -> Self {
305 Self {
306 buffer: CircularBuffer::new(pre_count, post_count, condition),
307 params: CBParamIndices::default(),
308 trigger_a_name: String::new(),
309 trigger_b_name: String::new(),
310 trigger_calc_expr: String::new(),
311 }
312 }
313
314 pub fn trigger(&mut self) {
315 self.buffer.trigger();
316 }
317
318 pub fn buffer(&self) -> &CircularBuffer {
319 &self.buffer
320 }
321
322 fn rebuild_trigger_condition(&mut self) {
324 if !self.trigger_calc_expr.is_empty() {
325 if let Some(expr) = CalcExpression::parse(&self.trigger_calc_expr) {
326 self.buffer.trigger_condition = TriggerCondition::Calc {
327 attr_a: self.trigger_a_name.clone(),
328 attr_b: self.trigger_b_name.clone(),
329 expression: expr,
330 };
331 return;
332 }
333 }
334 if !self.trigger_a_name.is_empty() {
335 self.buffer.trigger_condition = TriggerCondition::AttributeThreshold {
336 name: self.trigger_a_name.clone(),
337 threshold: 0.5,
338 };
339 } else {
340 self.buffer.trigger_condition = TriggerCondition::External;
341 }
342 }
343}
344
345impl NDPluginProcess for CircularBuffProcessor {
346 fn process_array(&mut self, array: &NDArray, _pool: &NDArrayPool) -> ProcessResult {
347 use ad_core_rs::plugin::runtime::ParamUpdate;
348
349 let done = self.buffer.push(Arc::new(array.clone()));
350
351 let mut updates = Vec::new();
352 if let Some(idx) = self.params.status {
353 let status_val = match self.buffer.status() {
354 BufferStatus::Idle => 0,
355 BufferStatus::BufferFilling => 1,
356 BufferStatus::Flushing => 2,
357 BufferStatus::AcquisitionCompleted => 3,
358 };
359 updates.push(ParamUpdate::int32(idx, status_val));
360 }
361 if let Some(idx) = self.params.current_image {
362 updates.push(ParamUpdate::int32(idx, self.buffer.pre_buffer_len() as i32));
363 }
364 if let Some(idx) = self.params.triggered {
365 updates.push(ParamUpdate::int32(
366 idx,
367 if self.buffer.is_triggered() { 1 } else { 0 },
368 ));
369 }
370 if let Some(idx) = self.params.actual_trigger_count {
371 updates.push(ParamUpdate::int32(idx, self.buffer.trigger_count() as i32));
372 }
373
374 if done {
375 let mut result = ProcessResult::arrays(self.buffer.take_captured());
376 result.param_updates = updates;
377 result
378 } else {
379 ProcessResult::sink(updates)
380 }
381 }
382
383 fn plugin_type(&self) -> &str {
384 "NDPluginCircularBuff"
385 }
386
387 fn register_params(
388 &mut self,
389 base: &mut asyn_rs::port::PortDriverBase,
390 ) -> asyn_rs::error::AsynResult<()> {
391 use asyn_rs::param::ParamType;
392 base.create_param("CIRC_BUFF_CONTROL", ParamType::Int32)?;
393 base.create_param("CIRC_BUFF_STATUS", ParamType::Int32)?;
394 base.create_param("CIRC_BUFF_TRIGGER_A", ParamType::Octet)?;
395 base.create_param("CIRC_BUFF_TRIGGER_B", ParamType::Octet)?;
396 base.create_param("CIRC_BUFF_TRIGGER_A_VAL", ParamType::Float64)?;
397 base.create_param("CIRC_BUFF_TRIGGER_B_VAL", ParamType::Float64)?;
398 base.create_param("CIRC_BUFF_TRIGGER_CALC", ParamType::Octet)?;
399 base.create_param("CIRC_BUFF_TRIGGER_CALC_VAL", ParamType::Float64)?;
400 base.create_param("CIRC_BUFF_PRE_TRIGGER", ParamType::Int32)?;
401 base.create_param("CIRC_BUFF_POST_TRIGGER", ParamType::Int32)?;
402 base.create_param("CIRC_BUFF_CURRENT_IMAGE", ParamType::Int32)?;
403 base.create_param("CIRC_BUFF_POST_COUNT", ParamType::Int32)?;
404 base.create_param("CIRC_BUFF_SOFT_TRIGGER", ParamType::Int32)?;
405 base.create_param("CIRC_BUFF_TRIGGERED", ParamType::Int32)?;
406 base.create_param("CIRC_BUFF_PRESET_TRIGGER_COUNT", ParamType::Int32)?;
407 base.create_param("CIRC_BUFF_ACTUAL_TRIGGER_COUNT", ParamType::Int32)?;
408 base.create_param("CIRC_BUFF_FLUSH_ON_SOFTTRIGGER", ParamType::Int32)?;
409
410 self.params.control = base.find_param("CIRC_BUFF_CONTROL");
411 self.params.status = base.find_param("CIRC_BUFF_STATUS");
412 self.params.trigger_a = base.find_param("CIRC_BUFF_TRIGGER_A");
413 self.params.trigger_b = base.find_param("CIRC_BUFF_TRIGGER_B");
414 self.params.trigger_a_val = base.find_param("CIRC_BUFF_TRIGGER_A_VAL");
415 self.params.trigger_b_val = base.find_param("CIRC_BUFF_TRIGGER_B_VAL");
416 self.params.trigger_calc = base.find_param("CIRC_BUFF_TRIGGER_CALC");
417 self.params.trigger_calc_val = base.find_param("CIRC_BUFF_TRIGGER_CALC_VAL");
418 self.params.pre_trigger = base.find_param("CIRC_BUFF_PRE_TRIGGER");
419 self.params.post_trigger = base.find_param("CIRC_BUFF_POST_TRIGGER");
420 self.params.current_image = base.find_param("CIRC_BUFF_CURRENT_IMAGE");
421 self.params.post_count = base.find_param("CIRC_BUFF_POST_COUNT");
422 self.params.soft_trigger = base.find_param("CIRC_BUFF_SOFT_TRIGGER");
423 self.params.triggered = base.find_param("CIRC_BUFF_TRIGGERED");
424 self.params.preset_trigger_count = base.find_param("CIRC_BUFF_PRESET_TRIGGER_COUNT");
425 self.params.actual_trigger_count = base.find_param("CIRC_BUFF_ACTUAL_TRIGGER_COUNT");
426 self.params.flush_on_soft_trigger = base.find_param("CIRC_BUFF_FLUSH_ON_SOFTTRIGGER");
427 Ok(())
428 }
429
430 fn on_param_change(
431 &mut self,
432 reason: usize,
433 params: &ad_core_rs::plugin::runtime::PluginParamSnapshot,
434 ) -> ad_core_rs::plugin::runtime::ParamChangeResult {
435 use ad_core_rs::plugin::runtime::{ParamChangeResult, ParamChangeValue};
436
437 if Some(reason) == self.params.control {
438 let v = params.value.as_i32();
439 if v == 1 {
440 self.buffer.reset();
442 self.buffer.status = BufferStatus::BufferFilling;
443 } else {
444 self.buffer.status = BufferStatus::Idle;
446 }
447 } else if Some(reason) == self.params.pre_trigger {
448 self.buffer.pre_count = params.value.as_i32().max(0) as usize;
449 } else if Some(reason) == self.params.post_trigger {
450 self.buffer.post_count = params.value.as_i32().max(0) as usize;
451 } else if Some(reason) == self.params.preset_trigger_count {
452 self.buffer
453 .set_preset_trigger_count(params.value.as_i32().max(0) as usize);
454 } else if Some(reason) == self.params.flush_on_soft_trigger {
455 self.buffer
456 .set_flush_on_soft_trigger(params.value.as_i32() != 0);
457 } else if Some(reason) == self.params.soft_trigger {
458 if params.value.as_i32() != 0 {
459 self.buffer.trigger();
460 }
461 } else if Some(reason) == self.params.trigger_a {
462 if let ParamChangeValue::Octet(s) = ¶ms.value {
463 self.trigger_a_name = s.clone();
464 self.rebuild_trigger_condition();
465 }
466 } else if Some(reason) == self.params.trigger_b {
467 if let ParamChangeValue::Octet(s) = ¶ms.value {
468 self.trigger_b_name = s.clone();
469 self.rebuild_trigger_condition();
470 }
471 } else if Some(reason) == self.params.trigger_calc {
472 if let ParamChangeValue::Octet(s) = ¶ms.value {
473 self.trigger_calc_expr = s.clone();
474 self.rebuild_trigger_condition();
475 }
476 }
477
478 ParamChangeResult::updates(vec![])
479 }
480}
481
482#[cfg(test)]
483mod tests {
484 use super::*;
485 use ad_core_rs::attributes::{NDAttrSource, NDAttrValue, NDAttribute};
486 use ad_core_rs::ndarray::{NDDataType, NDDimension};
487
488 fn make_array(id: i32) -> Arc<NDArray> {
489 let mut arr = NDArray::new(vec![NDDimension::new(4)], NDDataType::UInt8);
490 arr.unique_id = id;
491 Arc::new(arr)
492 }
493
494 fn make_array_with_attr(id: i32, attr_val: f64) -> Arc<NDArray> {
495 let mut arr = NDArray::new(vec![NDDimension::new(4)], NDDataType::UInt8);
496 arr.unique_id = id;
497 arr.attributes.add(NDAttribute {
498 name: "trigger".into(),
499 description: "".into(),
500 source: NDAttrSource::Driver,
501 value: NDAttrValue::Float64(attr_val),
502 });
503 Arc::new(arr)
504 }
505
506 fn make_array_with_attrs(id: i32, a_val: f64, b_val: f64) -> Arc<NDArray> {
507 let mut arr = NDArray::new(vec![NDDimension::new(4)], NDDataType::UInt8);
508 arr.unique_id = id;
509 arr.attributes.add(NDAttribute {
510 name: "attr_a".into(),
511 description: "".into(),
512 source: NDAttrSource::Driver,
513 value: NDAttrValue::Float64(a_val),
514 });
515 arr.attributes.add(NDAttribute {
516 name: "attr_b".into(),
517 description: "".into(),
518 source: NDAttrSource::Driver,
519 value: NDAttrValue::Float64(b_val),
520 });
521 Arc::new(arr)
522 }
523
524 #[test]
525 fn test_pre_trigger_buffering() {
526 let mut cb = CircularBuffer::new(3, 2, TriggerCondition::External);
527
528 for i in 0..5 {
529 cb.push(make_array(i));
530 }
531 assert_eq!(cb.pre_buffer_len(), 3);
533 }
534
535 #[test]
536 fn test_external_trigger() {
537 let mut cb = CircularBuffer::new(2, 2, TriggerCondition::External);
538
539 cb.push(make_array(1));
540 cb.push(make_array(2));
541 cb.push(make_array(3));
542 cb.trigger();
545 assert!(cb.is_triggered());
546
547 cb.push(make_array(4));
548 let done = cb.push(make_array(5));
549 assert!(done);
550
551 let captured = cb.take_captured();
552 assert_eq!(captured.len(), 4); assert_eq!(captured[0].unique_id, 2);
554 assert_eq!(captured[1].unique_id, 3);
555 assert_eq!(captured[2].unique_id, 4);
556 assert_eq!(captured[3].unique_id, 5);
557 }
558
559 #[test]
560 fn test_attribute_trigger() {
561 let mut cb = CircularBuffer::new(
562 1,
563 2,
564 TriggerCondition::AttributeThreshold {
565 name: "trigger".into(),
566 threshold: 5.0,
567 },
568 );
569
570 cb.push(make_array_with_attr(1, 1.0));
571 cb.push(make_array_with_attr(2, 2.0));
572 assert!(!cb.is_triggered());
573
574 cb.push(make_array_with_attr(3, 5.0));
576 assert!(cb.is_triggered());
577
578 let done = cb.push(make_array(4));
579 assert!(done);
580
581 let captured = cb.take_captured();
582 assert_eq!(captured.len(), 3);
584 assert_eq!(captured[0].unique_id, 2);
585 assert_eq!(captured[1].unique_id, 3);
586 assert_eq!(captured[2].unique_id, 4);
587 }
588
589 #[test]
592 fn test_calc_trigger() {
593 let expr = CalcExpression::parse("A>5").unwrap();
595 let mut cb = CircularBuffer::new(
596 1,
597 2,
598 TriggerCondition::Calc {
599 attr_a: "attr_a".into(),
600 attr_b: "attr_b".into(),
601 expression: expr,
602 },
603 );
604
605 cb.push(make_array_with_attrs(1, 3.0, 0.0));
607 assert!(!cb.is_triggered());
608
609 cb.push(make_array_with_attrs(2, 6.0, 0.0));
611 assert!(cb.is_triggered());
612
613 let done = cb.push(make_array(3));
614 assert!(done);
615
616 let captured = cb.take_captured();
617 assert_eq!(captured.len(), 3);
619 assert_eq!(captured[0].unique_id, 1);
620 assert_eq!(captured[1].unique_id, 2);
621 assert_eq!(captured[2].unique_id, 3);
622 }
623
624 #[test]
625 fn test_calc_expression_parse() {
626 let expr = CalcExpression::parse("A>5").unwrap();
628 assert_eq!(expr.evaluate(6.0, 0.0), 1.0);
629 assert_eq!(expr.evaluate(4.0, 0.0), 0.0);
630 assert_eq!(expr.evaluate(5.0, 0.0), 0.0); let expr = CalcExpression::parse("A>=5").unwrap();
634 assert_eq!(expr.evaluate(5.0, 0.0), 1.0);
635 assert_eq!(expr.evaluate(4.9, 0.0), 0.0);
636
637 let expr = CalcExpression::parse("A>3&&B<10").unwrap();
639 assert_eq!(expr.evaluate(4.0, 5.0), 1.0);
640 assert_eq!(expr.evaluate(2.0, 5.0), 0.0);
641 assert_eq!(expr.evaluate(4.0, 15.0), 0.0);
642
643 let expr = CalcExpression::parse("(A>10)||(B>10)").unwrap();
645 assert_eq!(expr.evaluate(11.0, 0.0), 1.0);
646 assert_eq!(expr.evaluate(0.0, 11.0), 1.0);
647 assert_eq!(expr.evaluate(0.0, 0.0), 0.0);
648
649 let expr = CalcExpression::parse("A!=0").unwrap();
651 assert_eq!(expr.evaluate(1.0, 0.0), 1.0);
652 assert_eq!(expr.evaluate(0.0, 0.0), 0.0);
653
654 let expr = CalcExpression::parse("A==B").unwrap();
656 assert_eq!(expr.evaluate(5.0, 5.0), 1.0);
657 assert_eq!(expr.evaluate(5.0, 6.0), 0.0);
658
659 let expr = CalcExpression::parse("!A").unwrap();
661 assert_eq!(expr.evaluate(0.0, 0.0), 1.0);
662 assert_eq!(expr.evaluate(1.0, 0.0), 0.0);
663
664 let expr = CalcExpression::parse("A=5").unwrap();
667 assert_eq!(expr.evaluate(5.0, 0.0), 1.0);
668 assert_eq!(expr.evaluate(4.0, 0.0), 0.0);
669
670 let expr = CalcExpression::parse("A&B").unwrap();
671 assert_eq!(expr.evaluate(3.0, 1.0), 1.0);
673
674 let expr = CalcExpression::parse("ABS(A)").unwrap();
676 assert_eq!(expr.evaluate(-5.0, 0.0), 5.0);
677
678 let expr = CalcExpression::parse("SQRT(A)").unwrap();
679 assert!((expr.evaluate(9.0, 0.0) - 3.0).abs() < 1e-10);
680
681 let expr = CalcExpression::parse("A+B").unwrap();
682 assert_eq!(expr.evaluate(3.0, 4.0), 7.0);
683
684 let expr = CalcExpression::parse("A-B").unwrap();
685 assert_eq!(expr.evaluate(10.0, 3.0), 7.0);
686
687 let expr = CalcExpression::parse("A*B").unwrap();
688 assert_eq!(expr.evaluate(3.0, 4.0), 12.0);
689
690 let expr = CalcExpression::parse("A/B").unwrap();
691 assert_eq!(expr.evaluate(12.0, 4.0), 3.0);
692
693 let expr = CalcExpression::parse("A>5&&C>0").unwrap();
695 let mut vars = [0.0f64; 16];
696 vars[0] = 6.0; vars[2] = 1.0; assert_eq!(expr.evaluate_vars(&vars), 1.0);
699 vars[2] = 0.0; assert_eq!(expr.evaluate_vars(&vars), 0.0);
701
702 assert!(CalcExpression::parse("@@@").is_none());
704 }
705
706 #[test]
707 fn test_preset_trigger_count() {
708 let mut cb = CircularBuffer::new(1, 1, TriggerCondition::External);
709 cb.set_preset_trigger_count(2);
710
711 assert_eq!(cb.status(), BufferStatus::Idle);
712
713 cb.push(make_array(1));
715 assert_eq!(cb.status(), BufferStatus::BufferFilling);
716
717 cb.trigger();
719 assert_eq!(cb.trigger_count(), 1);
720 assert_eq!(cb.status(), BufferStatus::Flushing);
721
722 let done = cb.push(make_array(2));
723 assert!(done);
724 assert_eq!(cb.status(), BufferStatus::BufferFilling); cb.take_captured();
727
728 cb.push(make_array(3));
730
731 cb.trigger();
733 assert_eq!(cb.trigger_count(), 2);
734 assert_eq!(cb.status(), BufferStatus::Flushing);
735
736 let done = cb.push(make_array(4));
737 assert!(done);
738 assert_eq!(cb.status(), BufferStatus::AcquisitionCompleted);
739
740 cb.take_captured();
741
742 let done = cb.push(make_array(5));
744 assert!(!done);
745 assert_eq!(cb.status(), BufferStatus::AcquisitionCompleted);
746
747 cb.trigger();
749 assert_eq!(cb.trigger_count(), 2); }
751
752 #[test]
753 fn test_buffer_status_transitions() {
754 let mut cb = CircularBuffer::new(2, 1, TriggerCondition::External);
755
756 assert_eq!(cb.status(), BufferStatus::Idle);
758
759 cb.push(make_array(1));
761 assert_eq!(cb.status(), BufferStatus::BufferFilling);
762
763 cb.push(make_array(2));
764 assert_eq!(cb.status(), BufferStatus::BufferFilling);
765
766 cb.trigger();
768 assert_eq!(cb.status(), BufferStatus::Flushing);
769
770 let done = cb.push(make_array(3));
772 assert!(done);
773 assert_eq!(cb.status(), BufferStatus::BufferFilling);
774
775 cb.reset();
777 assert_eq!(cb.status(), BufferStatus::Idle);
778 assert_eq!(cb.trigger_count(), 0);
779 }
780}