|
34 | 34 | import time |
35 | 35 | from functools import reduce |
36 | 36 | from threading import Lock |
37 | | -import copy |
38 | 37 |
|
39 | | -# Third party imports |
40 | 38 |
|
41 | 39 | # Local application imports |
42 | 40 | from .image_writer import ImageWriter |
@@ -199,6 +197,62 @@ def data_func(self, frame_ids): |
199 | 197 | return True |
200 | 198 |
|
201 | 199 |
|
| 200 | +class WaitForExternalTrigger: |
| 201 | + """WaitForExternalTrigger class to time parts of the feature list using external input. |
| 202 | +
|
| 203 | + This class waits for either an external trigger (or the timeout) before continuing |
| 204 | + on to the next feature block in the list. Useful when combined with LoopByCounts |
| 205 | + when each iteration may depend on some external event happening. |
| 206 | +
|
| 207 | + Notes: |
| 208 | + ------ |
| 209 | + - This class pauses the data thread while waiting for the trigger to avoid |
| 210 | + camera timeout issues. |
| 211 | + |
| 212 | + - Only digital triggers are handeled at this time: use the PFI inputs on the DAQ. |
| 213 | + """ |
| 214 | + |
| 215 | + def __init__(self, model, trigger_channel="/PCIe-6738/PFI4", timeout=-1): |
| 216 | + """Initialize the WaitForExternalTrigger class. |
| 217 | +
|
| 218 | + Parameters: |
| 219 | + ---------- |
| 220 | + model : MicroscopeModel |
| 221 | + The microscope model object used for synchronization. |
| 222 | + trigger_channel : str |
| 223 | + The name of the DAQ PFI digital input. |
| 224 | + timeout : float |
| 225 | + Continue on anyway if timeout is reached. timeout < 0 will |
| 226 | + run forever. |
| 227 | + """ |
| 228 | + self.model = model |
| 229 | + |
| 230 | + self.wait_interval = 0.001 # sec |
| 231 | + |
| 232 | + self.task = None |
| 233 | + self.trigger_channel = trigger_channel |
| 234 | + self.timeout = timeout |
| 235 | + |
| 236 | + self.config_table = { |
| 237 | + "signal": { |
| 238 | + "main": self.signal_func, |
| 239 | + } |
| 240 | + } |
| 241 | + |
| 242 | + def signal_func(self): |
| 243 | + |
| 244 | + # Pause the data thread to prevent camera timeout |
| 245 | + self.model.pause_data_thread() |
| 246 | + |
| 247 | + result = self.model.active_microscope.daq.wait_for_external_trigger( |
| 248 | + self.trigger_channel, self.wait_interval, self.timeout |
| 249 | + ) |
| 250 | + |
| 251 | + # Resume the data thread |
| 252 | + self.model.resume_data_thread() |
| 253 | + |
| 254 | + return result |
| 255 | + |
202 | 256 | class WaitToContinue: |
203 | 257 | """WaitToContinue class for synchronizing signal and data acquisition. |
204 | 258 |
|
@@ -619,11 +673,16 @@ def signal_func(self): |
619 | 673 | self.model.pause_data_thread() |
620 | 674 |
|
621 | 675 | self.current_idx += 1 |
| 676 | + # Make sure to go back to the beginning if using LoopByCount |
| 677 | + if self.current_idx == self.position_count: |
| 678 | + self.current_idx = 0 |
| 679 | + |
622 | 680 | abs_pos_dict = dict(map(lambda k: (f"{k}_abs", pos_dict[k]), pos_dict.keys())) |
623 | 681 | self.model.logger.debug(f"MoveToNextPositionInMultiPosition: " f"{pos_dict}") |
624 | 682 | self.model.move_stage(abs_pos_dict, wait_until_done=True) |
625 | 683 |
|
626 | 684 | self.model.logger.debug("MoveToNextPositionInMultiPosition: move done") |
| 685 | + |
627 | 686 | # resume data thread |
628 | 687 | if should_pause_data_thread: |
629 | 688 | self.model.resume_data_thread() |
|
0 commit comments