1use super::super::pins::pins_to_backend_lookup_fields;
2use super::timeset_container::{
3 EventContainer, WaveContainer, WaveGroupContainer, WavetableContainer,
4};
5use origen::Error;
6use origen::DUT;
7use pyo3::prelude::*;
8use pyo3::types::{PyAny, PyDict, PyTuple};
9
10#[macro_export]
11macro_rules! pytimeset {
12 ($py:expr, $model:expr, $model_id:expr, $name:expr) => {
13 if $model.contains_timeset($name) {
14 Ok(Py::new(
15 $py,
16 crate::timesets::timeset::Timeset {
17 name: String::from($name),
18 model_id: $model_id,
19 },
20 )
21 .unwrap()
22 .to_object($py))
23 } else {
24 Err(PyErr::from(error!(
27 "No timeset {} has been added on block {}",
28 $name, $model.name
29 )))
30 }
31 };
32}
33
34#[macro_export]
37macro_rules! pytimeset_or_pynone {
38 ($py:expr, $model:expr, $model_id:expr, $name:expr) => {
39 if $model.contains_timeset($name) {
40 Py::new(
41 $py,
42 crate::timesets::timeset::Timeset {
43 name: String::from($name),
44 model_id: $model_id,
45 },
46 )
47 .unwrap()
48 .to_object($py)
49 } else {
50 $py.None()
51 }
52 };
53}
54
55#[macro_export]
56macro_rules! pywavetable {
57 ($py:expr, $timeset:expr, $t_id:expr, $name:expr) => {
58 if $timeset.contains_wavetable($name) {
59 Ok(Py::new(
60 $py,
61 crate::timesets::timeset::Wavetable {
62 name: String::from($name),
63 model_id: $timeset.model_id,
64 timeset_id: $timeset.id,
65 },
66 )
67 .unwrap()
68 .to_object($py))
69 } else {
70 Err(PyErr::from(error!(
73 "No wavetable {} has been added on block {}",
74 $name, $timeset.name
75 )))
76 }
77 };
78}
79
80#[macro_export]
81macro_rules! pywave_group {
82 ($py:expr, $wavetable:expr, $name:expr) => {
83 if $wavetable.contains_wave_group($name) {
84 Ok(Py::new(
85 $py,
86 crate::timesets::timeset::WaveGroup {
87 name: String::from($name),
88 model_id: $wavetable.model_id,
89 timeset_id: $wavetable.timeset_id,
90 wavetable_id: $wavetable.id,
91 },
92 )
93 .unwrap()
94 .to_object($py))
95 } else {
96 Err(PyErr::from(error!(
99 "No wave group {} has been added on block {}",
100 $name, $wavetable.name
101 )))
102 }
103 };
104}
105
106#[macro_export]
107macro_rules! pywave {
108 ($py:expr, $wave_group:expr, $name:expr) => {
109 if $wave_group.contains_wave($name) {
110 Ok(Py::new(
111 $py,
112 crate::timesets::timeset::Wave {
113 name: String::from($name),
114 model_id: $wave_group.model_id,
115 timeset_id: $wave_group.timeset_id,
116 wavetable_id: $wave_group.wavetable_id,
117 wave_group_id: $wave_group.id,
118 },
119 )
120 .unwrap()
121 .to_object($py))
122 } else {
123 Err(PyErr::from(error!(
126 "No wave {} has been added on block {}",
127 $name, $wave_group.name
128 )))
129 }
130 };
131}
132
133#[macro_export]
134macro_rules! pyevent {
135 ($py:expr, $wave:expr, $event_index:expr) => {
136 if $wave.events.len() > $event_index {
137 Ok(Py::new(
138 $py,
139 crate::timesets::timeset::Event {
140 model_id: $wave.model_id,
141 timeset_id: $wave.timeset_id,
142 wavetable_id: $wave.wavetable_id,
143 wave_group_id: $wave.wave_group_id,
144 wave_id: $wave.wave_id,
145 wave_indicator: $wave.indicator.clone(),
146 index: $event_index,
147 },
148 )
149 .unwrap()
150 .to_object($py))
151 } else {
152 Err(PyErr::from(error!(
155 "No event at {} has been added on wave {}",
156 $event_index, $wave.indicator
157 )))
158 }
159 };
160}
161
162#[pyclass]
163pub struct Timeset {
164 pub name: String,
165 pub model_id: usize,
166}
167
168#[pymethods]
169impl Timeset {
170 #[getter]
171 fn get_name(&self) -> PyResult<String> {
172 let dut = DUT.lock().unwrap();
173 let timeset = dut.get_timeset(self.model_id, &self.name);
174 Ok(timeset.unwrap().name.clone())
175 }
176
177 #[allow(non_snake_case)]
178 #[getter]
179 fn get___origen__model_id__(&self) -> PyResult<usize> {
180 Ok(self.model_id)
181 }
182
183 #[getter]
184 fn get_period(&self) -> PyResult<f64> {
185 let dut = DUT.lock().unwrap();
186 let timeset = dut._get_timeset(self.model_id, &self.name)?;
187 Ok(timeset.eval(Option::None)?)
188 }
189
190 #[getter]
191 fn get_default_period(&self, py: Python) -> PyResult<PyObject> {
192 let dut = DUT.lock().unwrap();
193 let timeset = dut._get_timeset(self.model_id, &self.name)?;
194
195 Ok(match timeset.default_period {
196 Some(p) => p.to_object(py),
197 None => py.None(),
198 })
199 }
200
201 #[allow(non_snake_case)]
202 #[getter]
203 fn get___eval_str__(&self) -> PyResult<String> {
204 let dut = DUT.lock().unwrap();
205 let timeset = dut._get_timeset(self.model_id, &self.name)?;
206 Ok(timeset.eval_str().clone())
207 }
208
209 #[allow(non_snake_case)]
210 #[getter]
211 fn get___period__(&self, py: Python) -> PyResult<PyObject> {
212 let dut = DUT.lock().unwrap();
213 let timeset = dut._get_timeset(self.model_id, &self.name)?;
214 Ok(match ×et.period_as_string {
215 Some(p) => p.clone().to_object(py),
216 None => py.None(),
217 })
218 }
219
220 #[getter]
221 fn wavetables(&self, py: Python) -> PyResult<Py<WavetableContainer>> {
222 let t_id;
223 {
224 t_id = self.get_origen_id()?;
225 }
226 Ok(pywavetable_container!(py, self.model_id, t_id, &self.name))
227 }
228
229 #[pyo3(signature=(name, **_kwargs))]
230 fn add_wavetable(
231 &self,
232 py: Python,
233 name: &str,
234 _kwargs: Option<&PyDict>,
235 ) -> PyResult<PyObject> {
236 let mut dut = DUT.lock().unwrap();
237 let t_id;
238 {
239 t_id = dut._get_timeset(self.model_id, &self.name).unwrap().id;
240 }
241 dut.create_wavetable(t_id, name)?;
242
243 let tset = dut._get_timeset(self.model_id, &self.name).unwrap();
244 Ok(pywavetable!(py, tset, t_id, name)?)
245 }
246
247 #[getter]
248 fn symbol_map(&self, py: Python) -> PyResult<PyObject> {
249 let dut = DUT.lock().unwrap();
250 let t_id;
251 {
252 t_id = dut._get_timeset(self.model_id, &self.name).unwrap().id;
253 }
254 let tester = origen::tester();
255
256 Ok(Py::new(
257 py,
258 crate::timesets::timeset::SymbolMap {
259 timeset_id: t_id,
260 target_name: {
261 match tester.focused_tester_name() {
262 Some(n) => n,
263 None => return Ok(py.None()),
264 }
265 },
266 },
267 )
268 .unwrap()
269 .to_object(py))
270 }
271
272 #[getter]
273 fn symbol_maps(&self, py: Python) -> PyResult<Vec<PyObject>> {
274 let dut = DUT.lock().unwrap();
275 let t = dut._get_timeset(self.model_id, &self.name).unwrap();
276 let t_id;
277 {
278 t_id = t.id;
279 }
280
281 let retn = t
282 .pin_action_resolvers
283 .keys()
284 .map({
285 |target| {
286 Py::new(
287 py,
288 crate::timesets::timeset::SymbolMap {
289 timeset_id: t_id,
290 target_name: target.to_string(),
291 },
292 )
293 .unwrap()
294 .to_object(py)
295 }
296 })
297 .collect::<Vec<PyObject>>();
298 Ok(retn)
299 }
300}
301
302impl Timeset {
303 pub fn new(name: &str, model_id: usize) -> Self {
304 Self {
305 name: String::from(name),
306 model_id: model_id,
307 }
308 }
309
310 pub fn get_origen_id(&self) -> Result<usize, Error> {
311 let dut = DUT.lock().unwrap();
312 let timeset = dut._get_timeset(self.model_id, &self.name)?;
313 Ok(timeset.id)
314 }
315}
316
317#[pyclass]
318pub struct Wavetable {
319 pub timeset_id: usize,
320 pub name: String,
321 pub model_id: usize,
322}
323
324#[pymethods]
325impl Wavetable {
326 #[pyo3(signature=(name, **_kwargs))]
327 fn add_waves(&self, py: Python, name: &str, _kwargs: Option<&PyDict>) -> PyResult<PyObject> {
328 let mut dut = DUT.lock().unwrap();
329 let w_id;
330 {
331 w_id = dut.get_wavetable(self.timeset_id, &self.name).unwrap().id;
332 }
333 dut.create_wave_group(w_id, name, Option::None)?;
334
335 let wt = dut.get_wavetable(self.timeset_id, &self.name).unwrap();
336 Ok(pywave_group!(py, wt, name)?)
337 }
338
339 #[pyo3(signature=(name, **_kwargs))]
340 fn add_wave(&self, py: Python, name: &str, _kwargs: Option<&PyDict>) -> PyResult<PyObject> {
341 self.add_waves(py, name, _kwargs)
342 }
343
344 #[getter]
345 fn get_waves(&self, py: Python) -> PyResult<Py<WaveGroupContainer>> {
346 let w_id;
347 {
348 w_id = self.get_origen_id()?;
349 }
350 Ok(pywave_group_container!(
351 py,
352 self.model_id,
353 self.timeset_id,
354 w_id,
355 &self.name
356 ))
357 }
358
359 fn applied_waves(&self, py: Python) -> PyResult<PyObject> {
384 let empty: [PyObject; 0] = [];
385 let t = PyTuple::new(py, &empty);
386 self.applied_waves_for(py, t, None)
387 }
388
389 #[pyo3(signature=(*pins, indicators))]
391 fn applied_waves_for(
392 &self,
393 py: Python,
394 pins: &PyTuple,
395 indicators: Option<Vec<String>>,
396 ) -> PyResult<PyObject> {
397 let dut = DUT.lock().unwrap();
398 let wt = dut._get_wavetable(self.timeset_id, &self.name)?;
399 let waves = wt.applied_waves(
400 &dut,
401 &pins_to_backend_lookup_fields(py, &pins)?,
402 &indicators.unwrap_or(vec![]),
403 )?;
404 Ok(waves.to_object(py))
405 }
406
407 #[getter]
408 fn get_symbol_map(&self, py: Python) -> PyResult<PyObject> {
409 let tester = origen::tester();
410 match tester.focused_tester_name() {
411 Some(name) => Ok(Py::new(py, SymbolMap::new(self.timeset_id, name))
412 .unwrap()
413 .to_object(py)),
414 None => Ok(py.None()),
415 }
416 }
417
418 #[getter]
419 fn get_name(&self) -> PyResult<String> {
420 let dut = DUT.lock().unwrap();
421 let wt = dut.get_wavetable(self.timeset_id, &self.name);
422 Ok(wt.unwrap().name.clone())
423 }
424
425 #[getter]
428 pub fn get_period(&self, py: Python) -> PyResult<PyObject> {
429 let dut = DUT.lock().unwrap();
430 let wt = dut.get_wavetable(self.timeset_id, &self.name);
431 let p = wt.unwrap().eval(Option::None)?;
432
433 match p {
434 Some(_p) => Ok(_p.to_object(py)),
435 None => Ok(py.None()),
436 }
437 }
438
439 #[setter]
442 pub fn set_period(&self, period: &PyAny) -> PyResult<()> {
443 let mut dut = DUT.lock().unwrap();
444 let wt = dut.get_mut_wavetable(self.timeset_id, &self.name).unwrap();
445 if let Ok(p) = period.extract::<String>() {
446 wt.set_period(Some(Box::new(p)))?;
447 } else if let Ok(p) = period.extract::<f64>() {
448 wt.set_period(Some(Box::new(p)))?;
449 } else if period.get_type().qualname()? == "NoneType" {
450 wt.set_period(Option::None)?;
451 } else {
452 return super::super::type_error!(format!("Could not interpret 'period' argument as Numeric, String, or NoneType! (class '{}')", period.get_type().qualname()?));
453 };
454 Ok(())
455 }
456
457 #[allow(non_snake_case)]
459 #[getter]
460 pub fn get___period__(&self, py: Python) -> PyResult<PyObject> {
461 let dut = DUT.lock().unwrap();
462 let wt = dut.get_wavetable(self.timeset_id, &self.name);
463 let p = &wt.unwrap().period;
464
465 match p {
466 Some(_p) => Ok(_p.to_object(py)),
467 None => Ok(py.None()),
468 }
469 }
470}
471
472impl Wavetable {
473 pub fn new(model_id: usize, timeset_id: usize, name: &str) -> Self {
474 Self {
475 timeset_id: timeset_id,
476 name: String::from(name),
477 model_id: model_id,
478 }
479 }
480
481 pub fn get_origen_id(&self) -> Result<usize, Error> {
482 let dut = DUT.lock().unwrap();
483 let timeset = &dut.timesets[self.timeset_id];
484 let w_id = timeset.get_wavetable_id(&self.name).unwrap();
485 Ok(w_id)
486 }
487}
488
489#[pyclass]
490pub struct WaveGroup {
491 pub model_id: usize,
492 pub timeset_id: usize,
493 pub wavetable_id: usize,
494 pub name: String,
495}
496
497#[pymethods]
498impl WaveGroup {
499 #[pyo3(signature=(name, **_kwargs))]
500 fn add_wave(&self, py: Python, name: &str, _kwargs: Option<&PyDict>) -> PyResult<PyObject> {
501 let mut dut = DUT.lock().unwrap();
502 let wgrp_id;
503 {
504 wgrp_id = dut
505 .get_wave_group(self.wavetable_id, &self.name)
506 .unwrap()
507 .id;
508 }
509 let mut derived_from = Option::None;
510 if let Some(args) = _kwargs {
511 if let Some(_derived_from) = args.get_item("derived_from")? {
512 if let Ok(_waves) = _derived_from.extract::<String>() {
513 derived_from = Some(vec![_waves]);
514 } else if let Ok(_waves) = _derived_from.extract::<Vec<String>>() {
515 derived_from = Some(_waves);
516 } else {
517 return type_error!("Could not interpret 'derived_From' argument as a string or as a list of strings!");
518 }
519 }
520 }
521 dut.create_wave(wgrp_id, name, derived_from)?;
522
523 let wgrp = dut.get_wave_group(self.wavetable_id, &self.name).unwrap();
524 Ok(pywave!(py, wgrp, name)?)
525 }
526
527 #[getter]
528 fn get_waves(&self, py: Python) -> PyResult<Py<WaveContainer>> {
529 let wgrp_id;
530 {
531 wgrp_id = self.get_origen_id()?;
532 }
533 Ok(pywave_container!(
534 py,
535 self.model_id,
536 self.timeset_id,
537 self.wavetable_id,
538 wgrp_id,
539 &self.name
540 ))
541 }
542
543 #[getter]
544 fn get_name(&self) -> PyResult<String> {
545 let dut = DUT.lock().unwrap();
546 let wt = dut.get_wavetable(self.timeset_id, &self.name);
547 Ok(wt.unwrap().name.clone())
548 }
549}
550
551impl WaveGroup {
552 pub fn new(model_id: usize, timeset_id: usize, wavetable_id: usize, name: &str) -> Self {
553 Self {
554 model_id: model_id,
555 timeset_id: timeset_id,
556 wavetable_id: wavetable_id,
557 name: String::from(name),
558 }
559 }
560
561 pub fn get_origen_id(&self) -> Result<usize, Error> {
562 let dut = DUT.lock().unwrap();
563 let wavetable = &dut.wavetables[self.wavetable_id];
564 let wgrp_id = wavetable.get_wave_group_id(&self.name).unwrap();
565 Ok(wgrp_id)
566 }
567}
568
569#[pyclass]
570pub struct Wave {
571 pub model_id: usize,
572 pub timeset_id: usize,
573 pub wavetable_id: usize,
574 pub wave_group_id: usize,
575 pub name: String,
576}
577
578#[pymethods]
579impl Wave {
580 #[getter]
581 fn get_events(&self, py: Python) -> PyResult<Py<EventContainer>> {
582 let wave_id;
583 {
584 wave_id = self.get_origen_id()?;
585 }
586 Ok(pyevent_container!(
587 py,
588 self.model_id,
589 self.timeset_id,
590 self.wavetable_id,
591 self.wave_group_id,
592 wave_id,
593 &self.name
594 ))
595 }
596
597 #[pyo3(signature=(**event))]
598 fn push_event(&self, py: Python, event: Option<&PyDict>) -> PyResult<PyObject> {
599 let mut dut = DUT.lock().unwrap();
600 let (w_id, e_index);
601 {
602 w_id = dut
603 .get_wave(self.wave_group_id, &self.name)
604 .unwrap()
605 .wave_id;
606 }
607
608 if event.is_none() {
609 return type_error!("Keywords 'at' and 'action' are required to push a new event!");
610 }
611
612 let (at, unit, action) = (
613 event.unwrap().get_item("at")?,
614 event.unwrap().get_item("unit")?,
615 event.unwrap().get_item("action")?,
616 );
617 {
618 let temp: String;
621 match action {
622 Some(_action) => {
623 if let Ok(val) = _action.extract::<String>() {
624 temp = val;
625 } else if _action.is_none() {
626 return type_error!("'action' keyword is required (found None)!");
627 } else {
628 return type_error!("Could not interpret 'action' argument as String!");
629 }
630 }
631 None => return type_error!("'action' keyword is required!"),
632 }
633 let e = dut.create_event(
634 w_id,
635 match at {
637 Some(_at) => {
638 if let Ok(val) = _at.extract::<String>() {
639 Box::new(val)
640 } else if let Ok(val) = _at.extract::<f64>() {
641 Box::new(val)
642 } else if _at.is_none() {
643 return type_error!("'at' keyword is required (found None)!");
644 } else {
645 return type_error!(
646 "Could not interpret 'at' argument as String or Numeric!"
647 );
648 }
649 }
650 None => return type_error!("'at' keyword is required!"),
651 },
652 match unit {
654 Some(_unit) => {
655 if let Ok(val) = _unit.extract::<String>() {
656 Some(val)
657 } else if _unit.is_none() {
658 Option::None
659 } else {
660 return type_error!(
661 "Could not interpret 'unit' argument as String or NoneType!"
662 );
663 }
664 }
665 None => Option::None,
666 },
667 &temp,
668 )?;
669 e_index = e.event_index;
670 }
671
672 let w = dut.get_wave(self.wave_group_id, &self.name).unwrap();
674 Ok(pyevent!(py, w, e_index)?)
675 }
676
677 #[getter]
678 fn get_indicator(&self) -> PyResult<String> {
679 let dut = DUT.lock().unwrap();
680 let w = dut.get_wave(self.wave_group_id, &self.name).unwrap();
681 Ok(w.indicator.clone())
682 }
683
684 #[setter]
685 fn set_indicator(&self, indicator: &str) -> PyResult<()> {
686 let mut dut = DUT.lock().unwrap();
687 let w = dut.get_mut_wave(self.wave_group_id, &self.name).unwrap();
688 w.set_indicator(&indicator)?;
689 Ok(())
690 }
691
692 #[getter]
693 fn get_applied_to(&self, py: Python) -> PyResult<Vec<PyObject>> {
694 let dut = DUT.lock().unwrap();
695 let w = dut.get_wave(self.wave_group_id, &self.name).unwrap();
696
697 let mut pins: Vec<PyObject> = vec![];
698 for p in w.applied_pin_ids.iter() {
699 let ppin = &dut.pins[*p];
700 pins.push(
701 super::super::pins::pin::Pin {
702 name: ppin.name.clone(),
703 model_id: ppin.model_id,
704 }
705 .into_py(py),
706 );
707 }
708 Ok(pins)
709 }
710
711 #[pyo3(signature=(*pins))]
712 fn apply_to(&self, py: Python, pins: Vec<String>) -> PyResult<PyObject> {
713 let mut dut = DUT.lock().unwrap();
714 let wid;
715 {
716 wid = dut
717 .get_wave(self.wave_group_id, &self.name)
718 .unwrap()
719 .wave_id;
720 }
721 let pins_with_model_id: Vec<(usize, String)> =
722 pins.iter().map(|pin| (0, pin.clone())).collect();
723 dut.apply_wave_id_to_pins(wid, &pins_with_model_id)?;
724
725 Ok(Py::new(
726 py,
727 crate::timesets::timeset::Wave {
728 name: self.name.clone(),
729 model_id: self.model_id,
730 timeset_id: self.timeset_id,
731 wavetable_id: self.wavetable_id,
732 wave_group_id: self.wave_group_id,
733 },
734 )
735 .unwrap()
736 .to_object(py))
737 }
738
739 #[allow(non_snake_case)]
740 #[getter]
741 pub fn get_name(&self) -> PyResult<String> {
742 Ok(self.name.clone())
743 }
744
745 #[allow(non_snake_case)]
746 #[getter]
747 pub fn get_DriveHigh(&self) -> PyResult<String> {
748 Ok(String::from("DriveHigh"))
749 }
750
751 #[allow(non_snake_case)]
752 #[getter]
753 pub fn get_DriveLow(&self) -> PyResult<String> {
754 Ok(String::from("DriveLow"))
755 }
756
757 #[allow(non_snake_case)]
758 #[getter]
759 pub fn get_HighZ(&self) -> PyResult<String> {
760 Ok(String::from("HighZ"))
761 }
762
763 #[allow(non_snake_case)]
764 #[getter]
765 pub fn get_VerifyHigh(&self) -> PyResult<String> {
766 Ok(String::from("VerifyHigh"))
767 }
768
769 #[allow(non_snake_case)]
770 #[getter]
771 pub fn get_VerifyLow(&self) -> PyResult<String> {
772 Ok(String::from("VerifyLow"))
773 }
774
775 #[allow(non_snake_case)]
776 #[getter]
777 pub fn get_VerifyZ(&self) -> PyResult<String> {
778 Ok(String::from("VerifyZ"))
779 }
780
781 #[allow(non_snake_case)]
782 #[getter]
783 pub fn get_Capture(&self) -> PyResult<String> {
784 Ok(String::from("Capture"))
785 }
786}
787
788impl Wave {
789 pub fn new(
790 model_id: usize,
791 timeset_id: usize,
792 wavetable_id: usize,
793 wave_group_id: usize,
794 name: &str,
795 ) -> Self {
796 Self {
797 model_id: model_id,
798 timeset_id: timeset_id,
799 wavetable_id: wavetable_id,
800 wave_group_id: wave_group_id,
801 name: String::from(name),
802 }
803 }
804
805 pub fn get_origen_id(&self) -> Result<usize, Error> {
806 let dut = DUT.lock().unwrap();
807 let wgrp = &dut.wave_groups[self.wave_group_id];
808 let w_id = wgrp.get_wave_id(&self.name).unwrap();
809 Ok(w_id)
810 }
811}
812
813#[pyclass]
814pub struct Event {
815 pub model_id: usize,
816 pub timeset_id: usize,
817 pub wavetable_id: usize,
818 pub wave_group_id: usize,
819 pub wave_id: usize,
820 pub wave_indicator: String,
821 pub index: usize,
822}
823
824#[pymethods]
825impl Event {
826 #[getter]
827 pub fn get_action(&self) -> PyResult<String> {
828 let dut = DUT.lock().unwrap();
829 let e = dut.get_event(self.wave_id, self.index).unwrap();
830 Ok(e.action.clone())
831 }
832
833 #[setter]
834 pub fn action(&self, action: &str) -> PyResult<()> {
835 let mut dut = DUT.lock().unwrap();
836 let e = dut.get_mut_event(self.wave_id, self.index).unwrap();
837 e.set_action(action)?;
838 Ok(())
839 }
840
841 #[getter]
842 pub fn unit(&self, py: Python) -> PyResult<PyObject> {
843 let dut = DUT.lock().unwrap();
844 let e = dut.get_event(self.wave_id, self.index).unwrap();
845
846 match &e.unit {
847 Some(unit) => Ok(unit.clone().to_object(py)),
848 None => Ok(py.None()),
849 }
850 }
851
852 #[getter]
853 pub fn at(&self, py: Python) -> PyResult<PyObject> {
854 let dut = DUT.lock().unwrap();
855 let e = dut.get_event(self.wave_id, self.index).unwrap();
856 Ok(e.eval(&dut, Option::None)?.to_object(py))
857 }
858
859 #[getter]
860 pub fn __at__(&self) -> PyResult<String> {
861 let dut = DUT.lock().unwrap();
862 let e = dut.get_event(self.wave_id, self.index).unwrap();
863 Ok(e.at.clone())
864 }
865}
866
867impl Event {
868 pub fn new(
869 model_id: usize,
870 timeset_id: usize,
871 wavetable_id: usize,
872 wave_group_id: usize,
873 wave_id: usize,
874 wave_indicator: &str,
875 id: usize,
876 ) -> Self {
877 Self {
878 model_id: model_id,
879 timeset_id: timeset_id,
880 wavetable_id: wavetable_id,
881 wave_group_id: wave_group_id,
882 wave_id: wave_id,
883 wave_indicator: String::from(wave_indicator),
884 index: id,
885 }
886 }
887}
888
889fn action_from_pyany(action: &PyAny) -> PyResult<origen::core::model::pins::pin::PinAction> {
890 Ok(
891 origen::core::model::pins::pin::PinAction::from_delimiter_optional(
892 {
893 let t;
894 if let Ok(a) = action.extract::<String>() {
895 t = a.clone();
896 } else if action.get_type().qualname()? == "PinActions" {
897 let pin_actions = action
898 .extract::<PyRef<super::super::pins::pin_actions::PinActions>>()
899 .unwrap();
900 if pin_actions.actions.len() == 1 {
901 t = pin_actions.actions.first().unwrap().to_string();
902 } else {
903 return Err(pyo3::exceptions::PyValueError::new_err(
904 "SymbolMap lookups can only retrieve single symbols at a time",
905 ));
906 }
907 } else {
908 return super::super::type_error!(&format!(
909 "Cannot cast type {} to a valid PinAction",
910 action.get_type().qualname()?
911 ));
912 }
913 t
914 }
915 .as_str(),
916 )?,
917 )
918}
919
920#[pyclass]
921pub struct SymbolMap {
922 timeset_id: usize,
923 target_name: String,
924}
925
926impl SymbolMap {
927 pub fn new(timeset_id: usize, target_name: String) -> Self {
928 Self {
929 timeset_id: timeset_id,
930 target_name: target_name,
931 }
932 }
933}
934
935#[pymethods]
936impl SymbolMap {
937 fn keys(&self) -> PyResult<Vec<String>> {
938 let dut = DUT.lock().unwrap();
939 let resolver = &dut.timesets[self.timeset_id].pin_action_resolvers[&self.target_name];
940 Ok(resolver
941 .mapping()
942 .iter()
943 .map(|(k, _)| k.to_string())
944 .collect())
945 }
946
947 fn values(&self) -> PyResult<Vec<String>> {
948 let dut = DUT.lock().unwrap();
949 let resolver = &dut.timesets[self.timeset_id].pin_action_resolvers[&self.target_name];
950 Ok(resolver
951 .mapping()
952 .iter()
953 .map(|(_, v)| v.to_string())
954 .collect::<Vec<String>>())
955 }
956
957 fn items(&self) -> PyResult<Vec<(String, String)>> {
958 let dut = DUT.lock().unwrap();
959 let resolver = &dut.timesets[self.timeset_id].pin_action_resolvers[&self.target_name];
960
961 Ok(resolver
962 .mapping()
963 .iter()
964 .map(|(k, v)| (k.to_string(), v.to_string()))
965 .collect::<Vec<(String, String)>>())
966 }
967
968 fn get(&self, py: Python, action: &PyAny) -> PyResult<PyObject> {
969 match self.__getitem__(action) {
970 Ok(a) => Ok(a.into_py(py)),
971 Err(_) => Ok(py.None()),
972 }
973 }
974
975 fn set_symbol(
976 &mut self,
977 action: &PyAny,
978 new_resolution: String,
979 target: Option<String>,
980 ) -> PyResult<()> {
981 if let Some(t) = target {
982 let mut dut = DUT.lock().unwrap();
983 let tset = &mut dut.timesets[self.timeset_id];
984 if let Some(resolver) = tset.pin_action_resolvers.get_mut(&t) {
985 resolver.update_mapping(action_from_pyany(action)?, new_resolution.clone());
986 Ok(())
987 } else {
988 Err(pyo3::exceptions::PyKeyError::new_err(format!(
989 "Timeset '{}' does not have a symbol map targeting '{}' (The target must be set prior to timeset creation)",
990 tset.name,
991 t
992 )))
993 }
994 } else {
995 self.__setitem__(action, new_resolution)
996 }
997 }
998
999 fn for_target(&self, py: Python, target: String) -> PyResult<PyObject> {
1000 let dut = DUT.lock().unwrap();
1001 {
1002 let t = &dut.timesets[self.timeset_id];
1003 if !t.pin_action_resolvers.contains_key(&target) {
1004 return Err(pyo3::exceptions::PyKeyError::new_err(format!(
1005 "Timeset '{}' does not have a symbol map targeting '{}' (The target must be set prior to timeset creation)",
1006 t.name,
1007 target
1008 )));
1009 }
1010 }
1011
1012 Ok(Py::new(
1013 py,
1014 crate::timesets::timeset::SymbolMap {
1015 timeset_id: self.timeset_id,
1016 target_name: target,
1017 },
1018 )
1019 .unwrap()
1020 .to_object(py))
1021 }
1022
1023 fn __getitem__(&self, action: &PyAny) -> PyResult<String> {
1024 let dut = DUT.lock().unwrap();
1025 let resolver = &dut.timesets[self.timeset_id].pin_action_resolvers[&self.target_name];
1026
1027 if let Some(r) = resolver.resolve(&action_from_pyany(action)?) {
1028 Ok(r)
1029 } else {
1030 Err(pyo3::exceptions::PyKeyError::new_err(format!(
1031 "No symbol found for {}",
1032 action
1033 )))
1034 }
1035 }
1036
1037 fn __setitem__(&mut self, action: &PyAny, new_resolution: String) -> PyResult<()> {
1038 let mut dut = DUT.lock().unwrap();
1039 let tester = origen::tester();
1040 for target in tester.targets_as_strs().iter() {
1041 let resolver = &mut dut.timesets[self.timeset_id].pin_action_resolvers[target];
1043 resolver.update_mapping(action_from_pyany(action)?, new_resolution.clone())
1044 }
1045 Ok(())
1046 }
1047
1048 fn __len__(&self) -> PyResult<usize> {
1049 let dut = DUT.lock().unwrap();
1050 let resolver = &dut.timesets[self.timeset_id].pin_action_resolvers[&self.target_name];
1051 Ok(resolver.mapping().len())
1052 }
1053
1054 fn __contains__(&self, item: &PyAny) -> PyResult<bool> {
1055 match self.__getitem__(&item) {
1056 Ok(_) => Ok(true),
1057 Err(_) => Ok(false),
1058 }
1059 }
1060
1061 fn __iter__(slf: PyRefMut<Self>) -> PyResult<SymbolMapIter> {
1062 Ok(SymbolMapIter {
1063 keys: slf.keys().unwrap(),
1064 i: 0,
1065 })
1066 }
1067}
1068
1069#[pyclass]
1070pub struct SymbolMapIter {
1071 pub keys: Vec<String>,
1072 pub i: usize,
1073}
1074
1075#[pymethods]
1076impl SymbolMapIter {
1077 fn __iter__(slf: PyRefMut<Self>) -> PyResult<Py<Self>> {
1078 Ok(slf.into())
1079 }
1080
1081 fn __next__(mut slf: PyRefMut<Self>) -> PyResult<Option<String>> {
1082 if slf.i >= slf.keys.len() {
1083 return Ok(None);
1084 }
1085 let name = slf.keys[slf.i].clone();
1086 slf.i += 1;
1087 Ok(Some(name))
1088 }
1089}