Scope
ScopeController_p.h
1 #pragma once
2 
3 #include "ScopeController.h"
4 #include "ScopeControllerModes.h"
5 #include "ScopeDefines.h"
6 #include "version.h"
7 #include "scanmodes/ScannerVectorFrameBasic.h"
8 #include "scanmodes/ScannerVectorFrameSaw.h"
9 #include "scanmodes/ScannerVectorFrameBiDi.h"
10 #include "scanmodes/ScannerVectorFramePlaneHopper.h"
11 #include "scanmodes/ScannerVectorFrameResonanceBiDi.h"
12 #include "scanmodes/ScannerVectorFrameResonanceHopper.h"
13 #include "helpers/ScopeMultiImage.h"
14 #include "helpers/ScopeMultiImageResonanceSW.h"
15 #include "DaqController.h"
16 #include "PipelineController.h"
17 #include "DisplayController.h"
18 #include "StorageController.h"
19 #include "helpers/ScopeException.h"
20 #include "FPUController.h"
21 #include "ScopeLogger.h"
22 #include "gui/ChannelFrame.h"
23 #include "gui/HistogramFrame.h"
24 #include "devices/xyz/XYZControl.h"
25 #include "devices/xyz/XYZControlGalil.h"
26 #include "devices/xyz/XYZControlSutter.h"
27 #include "devices/GaterDAQmx.h"
28 
29 namespace scope {
30 
33  : public BaseController<1, true>::Impl {
34 
35 protected:
37  std::array<SynchronizedQueue<ScopeMessage<SCOPE_DAQCHUNKPTR_T>>, SCOPE_NAREAS> daq_to_pipeline;
38 
41 
44 
48  std::array<ScannerVectorFrameBasicPtr, SCOPE_NAREAS> framescannervecs;
53  DaqController theDaq;
54  PipelineController thePipeline;
55  StorageController theStorage;
56  DisplayController theDisplay;
61 
63  std::condition_variable waitbetweenrepeats_cond;
64 
67 
69  std::future<void> onlineupdate_future;
70 
72  std::atomic<bool> onlineupdate_running;
73 
75  DWORD time;
76 
79 
81  std::wstring currentconfigfile;
82 
84  std::vector<std::function<void(const uint32_t&, const ScannerVectorType&)>> scanmodecallbacks;
85 
88 
89 protected:
91  Impl(const Impl& i);
92 
94  Impl operator=(const Impl& i);
95 
97  void LogRun() {
98  if ( parameters.storage.autosave() ) {
99  std::wstring msg(L"");
100  switch ( parameters.run_state().t ) {
101  case RunStateHelper::RunningContinuous:
102  if ( parameters.storage.savelive() )
103  msg += L"Live scan (saving)";
104  break;
105  case RunStateHelper::RunningSingle:
106  msg += L"Single scan";
107  break;
108  case RunStateHelper::RunningStack:
109  msg += L"Stack scan";
110  break;
111  case RunStateHelper::RunningTimeseries:
112  msg = L"Timeseries scan";
113  break;
114  case RunStateHelper::RunningBehavior:
115  msg = L"Behavior scan";
116  break;
117  }
118  scope_logger.Log(msg, log_info);
119  }
120  }
121 
124  time = ::timeGetTime();
125  theDisplay.Start(parameters);
126  theStorage.Start(parameters);
127  thePipeline.Start(parameters);
128  theDaq.Start(parameters);
129  }
130 
133  theDisplay.StopAll();
134  theStorage.StopAll();
135  thePipeline.StopAll();
136  theDaq.StopAll();
137 
138  try {
139  ControllerReturnStatus sdisp = theDisplay.WaitForAll(500);
140  } catch (...) { ScopeExceptionHandler(__FUNCTION__); }
141  try {
142  ControllerReturnStatus sstor = theStorage.WaitForAll(500);
143  } catch (...) { ScopeExceptionHandler(__FUNCTION__); }
144  try {
145  ControllerReturnStatus spipe = thePipeline.WaitForAll(2000);
146  } catch (...) { ScopeExceptionHandler(__FUNCTION__); }
147  try {
148  ControllerReturnStatus sdaq = theDaq.WaitForAll(2000);
149  } catch (...) { ScopeExceptionHandler(__FUNCTION__); }
150  time = ::timeGetTime() - time;
151  }
152 
155  theDisplay.WaitForAll();
156  theStorage.WaitForAll();
157  thePipeline.WaitForAll();
158  theDaq.WaitForAll();
159  }
160 
162  void ClearAllQueues() {
163  for ( auto& d : daq_to_pipeline )
164  d.Clear();
165  pipeline_to_display.Clear();
166  pipeline_to_storage.Clear();
167  }
168 
171  DBOUT(L"ScopeControllerImpl::SetScannerVectorParameters");
172  for ( uint32_t a = 0 ; a < SCOPE_NAREAS ; a++ )
173  framescannervecs[a]->SetParameters(&parameters.areas[a]->daq, &parameters.areas[a]->Currentframe(), &parameters.areas[a]->fpuzstage);
174  }
175 
177  ControllerReturnStatus RunLive(StopCondition* const sc) {
178  ClearAllQueues();
180  DBOUT(L"ScopeController::RunLive()");
182  return ControllerReturnStatus::finished;
183  }
184 
186  ControllerReturnStatus RunSingle(StopCondition* const sc) {
187  ClearAllQueues();
188  LogRun();
192  ClearAfterStop();
193  return ControllerReturnStatus::finished;
194  }
195 
197  ControllerReturnStatus RunStack(StopCondition* const sc) {
198  ClearAllQueues();
199  LogRun();
201 
202  // We do the same number of planes in each area (if fast z and not that many planes in range in one area, Pockels was set to zero in parameters::stack::UpdatePlanes)
203  for ( auto& a : parameters.areas )
204  a->daq.requested_frames = parameters.stack.planes___.size();
205 
206  // StorageController and DisplayController saves/displays the number of slices in each area
207  theStorage.Start(parameters);
208  theDisplay.Start(parameters);
209 
210  // At every slice Daq and PipelineController expect 1 frame (they calculate averages themselves)
211  // do not manipulate GuiParameters here, otherwise we have a problem on restarting the stack
212  for ( auto& ap : parameters.areas )
213  ap->daq.requested_frames = 1;
214 
215  // Set scale for the progress indicator
217 
218  // Go through all the precalculated planes
219  for ( uint32_t p = 0 ; p < parameters.stack.planes___.size() ; p++ ) {
220 
221  // Move to precalculated position (stage position is the same for all areas, no of slices thus also the same)
222  if ( parameters.stack.zdevicetype().t == ZDeviceHelper::ZStage ) {
223  theStage.MoveAbsolute(theStage.CurrentXPosition(), theStage.CurrentYPosition(), parameters.stack.planes___[p][0].position());
224  // Wait one second for movement to complete
225  std::this_thread::sleep_for(std::chrono::milliseconds(1000));
226  }
227  else if ( parameters.stack.zdevicetype().t == ZDeviceHelper::FastZ ) {
228  for ( uint32_t a = 0 ; a < SCOPE_NAREAS ; a++ ) {
229  parameters.areas[a]->Currentframe().fastz = parameters.stack.planes___[p][a].position();
230  // Also change GuiParameters so the users sees what is happening during stacking
231  GuiParameters.areas[a]->Currentframe().fastz = parameters.stack.planes___[p][a].position();
232  }
233  }
234 
235  // Set pockels to precalculated value
236  for ( uint32_t a = 0 ; a < SCOPE_NAREAS ; a++ ) {
237  parameters.areas[a]->Currentframe().pockels = parameters.stack.planes___[p][a].pockels();
238  // Also change GuiParameters so the users sees what is happening during stacking
239  GuiParameters.areas[a]->Currentframe().pockels = parameters.stack.planes___[p][a].pockels();
240  }
241 
242  // Calculate scanner vectors
244 
245  // Start
246  theDaq.Start(parameters);
247  thePipeline.Start(parameters);
248 
249  // and wait for them to end
250  theDaq.WaitForAll();
251  thePipeline.WaitForAll();
252 
253  // Stop the stack if abort requested
254  if ( repeat_abort.IsSet() )
255  break;
256 
257  // Advance progress indicator
258  PlaneCounter = p+1;
259  }
260 
261  theDisplay.WaitForAll();
262  theStorage.WaitForAll();
263  ClearAfterStop();
264 
265  PlaneCounter = 0;
266 
267  return ControllerReturnStatus::finished;
268  }
269 
271  ControllerReturnStatus RunTimeseries(StopCondition* const sc) {
272  LogRun();
273  ClearAllQueues();
275 
276  // Set repeat counter limits (for progress bar display)
278 
279  // Go through all repeats
280  for ( uint32_t t = 0 ; t < parameters.timeseries.repeats() ; t++ ) {
281  RepeatCounter = t+1;
282 
283  ClearAllQueues();
284 
285  // Start a timeseries
287 
288  // Start waiting, wait from beginning of timeseries until beginning of next one
289  std::unique_lock<std::mutex> lock(waitbetweenrepeats_mutex);
290  std::chrono::milliseconds waittime(static_cast<long>(1000*parameters.timeseries.betweenrepeats()));
291  // Waits or is notified before by a call to Stop
292  waitbetweenrepeats_cond.wait_for(lock, waittime);
293 
294  // This should return immediately, because waittime is always longer than duration of one timeseries
295  // or because StopAllControllers was called from Stop
297 
298  // Alternate planes if planes defined
299  if ( parameters.timeseries.planes.size() != 0 ) {
300  for ( uint32_t a = 0 ; a < SCOPE_NAREAS ; a++ )
301  parameters.areas[a]->Currentframe().fastz = parameters.timeseries.planes[t % parameters.timeseries.planes.size()][a].position();
303  }
304 
305  // Break if abort condition set (from Stop)
306  if ( repeat_abort.IsSet() ) {
307  RepeatCounter = 1;
308  break;
309  }
310  }
311 
312  ClearAfterStop();
313  return ControllerReturnStatus::finished;
314  }
315 
317  ControllerReturnStatus RunBehavior(StopCondition* const sc) {
318  LogRun();
319  ClearAllQueues();
321  uint32_t trials = 0;
322  DWORD starttime = ::timeGetTime();
323  GaterDAQmx gater(parameters.behavior.gateline(), sc);
324 
325  // Set trial counter limits
327 
328  // Record trials until StopCondition set or requested number of trials is reached
329  while ( !sc->IsSet() || parameters.behavior.unlimited_repeats() || trials < parameters.behavior.repeats() ) {
330  // Wait for high signal then start acquisition, on StopCondition break from loop
331  if ( !gater.WaitFor(true) )
332  break;
333 
334  //Band-Aid Jerry - Forced Behavior Acquisition to run in Live Scan Mode with Live saving enabled
336  parameters.run_state = RunStateHelper::RunningContinuous;
337  parameters.storage.savelive = true;
338 
340  // Update time
341  TotalTime = static_cast<double>(::timeGetTime() - starttime) / 1000;
342 
343  // Wait for low signal and then stop acquisition, on StopCondition break from loop
344  if ( !gater.WaitFor(false) )
345  break;
347  ClearAllQueues();
348  // Update counters and time
349  trials++;
350  TrialCounter = trials;
351  TotalTime = static_cast<double>(::timeGetTime() - starttime) / 1000;
352  }
353 
354  ClearAfterStop();
355  return ControllerReturnStatus::finished;
356  }
357 
359  void ClearAfterStop() {
360  DBOUT(L"ScopeControllerImpl::CleanAfterStop");
361  ClearAllQueues();
362  repeat_abort.Set(false);
363  parameters.run_state = RunStateHelper::Stopped;
364  GuiParameters.run_state = RunStateHelper::Stopped;
365  SetGuiCtrlState();
366  }
367 
368 public:
371  FPUController theFPUs;
372  SCOPE_XYZCONTROL_T theStage;
375 public:
377  explicit Impl()
378  : BaseController::Impl(parameters::Scope())
379  , daq_to_pipeline()
380  , pipeline_to_display()
381  , pipeline_to_storage()
382  , theDaq(&daq_to_pipeline, parameters)
383  , thePipeline(&daq_to_pipeline, &pipeline_to_storage, &pipeline_to_display, parameters)
384  , theStorage(&pipeline_to_storage, parameters)
385  , theDisplay(&pipeline_to_display, parameters)
386  , repeat_abort(false)
387  , onlineupdate_running(false)
388  , time(0)
389  , initialparametersloaded(false, false, true)
390  , currentconfigfile(L"NONE")
391  , scope_logger() {
392  // Connect static buttons in ScopeController to ScopeController::Impl functions
393  // QuitButton is connected in CMainDlgFrame
394  StartSingleButton.Connect(std::bind(&Impl::StartSingle, this));
395  StartLiveButton.Connect(std::bind(&Impl::StartLive, this));
396  StartStackButton.Connect(std::bind(&Impl::StartStack, this));
397  StartTimeseriesButton.Connect(std::bind(&Impl::StartTimeseries, this));
398  StartBehaviorButton.Connect(std::bind(&Impl::StartBehavior, this));
399  StopButton.Connect(std::bind(&Impl::Stop, this));
400 
401  // We cannot connect directly to XYZStage::SetZero because std::bind needs the class to be copyable (which it may not)
402  StageZeroButton.Connect(std::bind(&Impl::SetStageZero, this));
403 
404  StackStartHereButton.Connect(std::bind(&Impl::StackStartHere, this));
405  StackStopHereButton.Connect(std::bind(&Impl::StackStopHere, this));
406 
407  for ( uint32_t a = 0 ; a < SCOPE_NAREAS ; a++ ) {
408  // Initially choose the first supported scannervector in the list
410 
411  // Set counters to zero
412  FrameCounter[a] = 0;
413  SingleFrameProgress[a] = 0;
414 
415  // Connect the buttons for scan mode switching (if a master area)
416  if ( !ThisIsSlaveArea(a) ) {
417  for ( auto& b : ScanMode[a].map )
418  b.second.Connect(std::bind(&Impl::SetScanMode, this, a, b.first));
419  }
420 
421  // Connect all imaging parameters
422  for ( auto& sv : GuiParameters.areas[a]->scannervectorframesmap ) {
423  sv.second->ConnectOnlineUpdate(std::bind(&Impl::UpdateAreaParametersFromGui, this, a));
424  sv.second->ConnectResolutionChange(std::bind(&Impl::ResolutionChange, this, a));
425  }
426 
427  GuiParameters.areas[a]->daq.pixeltime.ConnectOther(std::bind(&Impl::UpdateAreaParametersFromGui, this, a));
428  GuiParameters.areas[a]->daq.scannerdelay.ConnectOther(std::bind(&Impl::UpdateAreaParametersFromGui, this, a));
429  GuiParameters.areas[a]->histrange.ConnectOther(std::bind(&Impl::UpdateAreaParametersFromGui, this, a));
430 
431  // Connect FPU XY movements inside the FPUController!!
432  }
433 
434  SetGuiCtrlState();
435  }
436 
438  ~Impl() {
439  Stop();
440  }
441 
444  void PrepareQuit() {
445  SetFPUButtonsState(false);
446  StopButton.Enable(false);
447  theStage.StopPolling();
448  for ( const auto& s : theFPUs.theXYStages )
449  s->StopPolling();
450  Stop();
451  SetGuiCtrlState();
452  }
453 
455  void Version() const {
456  // Extract last commit date
457  std::wstring revstr = CA2W(STR(LASTGITCOMMIT));
458  revstr = L"Scope (Last Git commit " + revstr + L")";
459  DBOUT(revstr.c_str());
460  }
461 
463  std::wstring CurrentConfigFile() const {
464  return currentconfigfile;
465  }
466 
469  // Give GuiParameters by reference, so hardware has parameters and can connect to ScopeNumbers
470  theStage.Initialize(GuiParameters.stage);
471  theFPUs.Initialize(GuiParameters);
472  }
473 
475  void StartLive() {
476  if ( parameters.run_state() == RunStateHelper::Mode::Stopped ) {
477  GuiParameters.requested_mode.Set(DaqModeHelper::Mode::continuous);
478  GuiParameters.run_state.Set(RunStateHelper::Mode::RunningContinuous);
482  SetGuiCtrlState();
483  stops[0].Set(false);
484  futures[0] = std::async(std::bind(&Impl::RunLive, this, &stops[0]));
485  futures[0].wait(); // Wait here, because RunLive should quickly return
486  }
487  }
488 
490  void StartStack() {
491  if ( parameters.run_state() == RunStateHelper::Mode::Stopped ) {
492  GuiParameters.requested_mode.Set(DaqModeHelper::Mode::nframes);
495  GuiParameters.run_state.Set(RunStateHelper::Mode::RunningStack);
497  SetGuiCtrlState();
498  stops[0].Set(false);
499  futures[0] = std::async(std::bind(&Impl::RunStack, this, &stops[0]));
500  }
501  }
502 
504  void StartSingle() {
505  if ( parameters.run_state() == RunStateHelper::Mode::Stopped ) {
506  GuiParameters.requested_mode.Set(DaqModeHelper::Mode::nframes);
507  GuiParameters.run_state.Set(RunStateHelper::Mode::RunningSingle);
511  SetGuiCtrlState();
512  stops[0].Set(false);
513  futures[0] = std::async(std::bind(&Impl::RunSingle, this, &stops[0]));
514  }
515  }
516 
519  if ( parameters.run_state() == RunStateHelper::Mode::Stopped ) {
520  // Same number of frames for all areas. However, this is non-ideal...
521  for ( uint32_t a = 1 ; a < SCOPE_NAREAS ; ++a )
523  GuiParameters.run_state.Set(RunStateHelper::Mode::RunningTimeseries);
524  GuiParameters.requested_mode.Set(DaqModeHelper::Mode::nframes);
527  for ( uint32_t a = 0 ; a < SCOPE_NAREAS ; a++ )
528  GuiParameters.areas[a]->daq.requested_frames = GuiParameters.timeseries.frames[a]();
530  SetGuiCtrlState();
531  stops[0].Set(false);
532  futures[0] = std::async(std::bind(&Impl::RunTimeseries, this, &stops[0]));
533  }
534  }
535 
537  void StartBehavior() {
538  if ( parameters.run_state() == RunStateHelper::Mode::Stopped ) {
539  GuiParameters.run_state.Set(RunStateHelper::Mode::RunningBehavior);
540  GuiParameters.requested_mode.Set(DaqModeHelper::Mode::continuous);
544  SetGuiCtrlState();
545  stops[0].Set(false);
546  futures[0] = std::async(std::bind(&Impl::RunBehavior, this, &stops[0]));
547  }
548  }
549 
551  void Stop() {
552  DBOUT(L"ScopeController::stop()\n");
553  stops[0].Set();
554 
555  if ( (parameters.run_state() == RunStateHelper::RunningStack) || (parameters.run_state() == RunStateHelper::Mode::RunningTimeseries) )
556  repeat_abort.Set(true);
557 
558  // Notify the condition variable waiting betweenrepeats in RunTimeseries
559  if ( parameters.run_state() == RunStateHelper::Mode::RunningTimeseries )
560  waitbetweenrepeats_cond.notify_one();
561 
562  if ( parameters.run_state() != RunStateHelper::Mode::Stopped ) {
563  // If we currently running an online update, wait until it is ready before stopping controllers!
564  if ( onlineupdate_future.valid() )
565  onlineupdate_future.get();
566 
568  // If we ran live we have to call the ClearAfterStop here (since RunLive does not wait for scanning to finish. How could it...)
569  if ( static_cast<RunState>(parameters.run_state()) == RunStateHelper::Mode::RunningContinuous ) {
570  ClearAfterStop();
571  }
572  //futures[0].wait();
573  }
574  DBOUT(L"ScopeController::stop end()\n");
575  }
576 
578  void UpdateAreaParametersFromGui(const uint32_t& _area) {
579  DBOUT(L"ScopeController::update_parameters_from_gui()\n");
580  if ( parameters.run_state() == RunStateHelper::Mode::Stopped )
581  return;
582 
583  // Check if online update is commencing right now, abort it (i.e. abort Outputs::Write in DaqController, since this is
584  // the bottleneck! Then wait for the future.
585  if ( onlineupdate_running ) {
586  DBOUT(L"ScopeController::UpdateAreaParametersFromGui aborting previous online update");
587  // Signal the DaqControllerImpl to abort current update of scannervec in device buffer
588  theDaq.AbortOnlineParameterUpdate(_area);
589  // Now wait for the future of the online update (see async lambda below) to make sure the "old" online update
590  // is done/aborted
591  if ( onlineupdate_future.valid() )
592  onlineupdate_future.get();
593  // Now the old async online_update is successfully aborted and we can start the current/new one
594  }
595 
596  // If no online update is running right now, start a new one asynchronically
597  if ( !onlineupdate_running ) {
598  onlineupdate_future = std::async([&]() {
599  DBOUT(L"ScopeController::UpdateAreaParametersFromGui starting new online update");
600  onlineupdate_running = true;
601  try {
602  *parameters.areas[_area] = *GuiParameters.areas[_area];
603  DBOUT(L"ScopeController::UpdateAreaParametersFromGui guioffset " << GuiParameters.areas[_area]->Currentframe().xoffset() << L" " << GuiParameters.areas[_area]->Currentframe().yoffset());
604  // This is the expensive step, the recalculation of the scannervector
605  framescannervecs[_area]->SetParameters(&parameters.areas[_area]->daq, &parameters.areas[_area]->Currentframe(), &parameters.areas[_area]->fpuzstage);
606 
607  // This returns only after the updated scannervec is written to the device buffer or the whole update write is aborted
608  theDaq.OnlineParameterUpdate(*parameters.areas[_area]);
609 
610  theDisplay.ResolutionChange(*parameters.areas[_area]);
611  }
612  catch (...) {
613  ScopeExceptionHandler(__FUNCTION__);
614  }
615  // Whatever exceptions happen, we have to set this to false!
616  onlineupdate_running = false;
617  });
618  }
619  }
620 
623  bool LoadParameters(const std::wstring& _filepath) {
624  currentconfigfile = _filepath.substr(_filepath.find_last_of(L'\\')+1, std::wstring::npos);
625  GuiParameters.Load(_filepath);
627  if ( initialparametersloaded() == false ) {
629  initialparametersloaded = true;
630  }
631  return true;
632  }
633 
636  bool SaveParameters(const std::wstring& _filepath) {
638  parameters.Save(_filepath);
639  return true;
640  }
641 
644  // This gets parameters::Windows of CChannelFrames and CHistogramFrames that are attached to the display controller
646 
647  GuiParameters.frames.AddWindow(L"CLogFrame", 0, scope_logger.GetLogFrameWindow());
648  }
649 
651  void SetStageZero() {
652  theStage.SetZero();
653  }
654 
656  void StackStartHere() {
657  for ( uint32_t a = 0 ; a < SCOPE_NAREAS ; a++ ) {
658  // If z stage every area has the same start position
659  if ( GuiParameters.stack.zdevicetype() == ZDeviceHelper::ZStage )
660  GuiParameters.stack.startat[a].position = theStage.CurrentZPosition();
661  // If fast z then each area can have different positions
662  else
663  GuiParameters.stack.startat[a].position = GuiParameters.areas[a]->Currentframe().fastz();
664 
665  GuiParameters.stack.startat[a].pockels = GuiParameters.areas[a]->Currentframe().pockels();
666  }
667  }
668 
670  void StackStopHere() {
671  for ( uint32_t a = 0 ; a < SCOPE_NAREAS ; a++ ) {
672  // If z stage every area has the same start position
673  if ( GuiParameters.stack.zdevicetype() == ZDeviceHelper::ZStage )
674  GuiParameters.stack.stopat[a].position = theStage.CurrentZPosition();
675  // If fast z then each area can have different positions
676  else
677  GuiParameters.stack.stopat[a].position = GuiParameters.areas[a]->Currentframe().fastz();
678 
679  GuiParameters.stack.stopat[a].pockels = GuiParameters.areas[a]->Currentframe().pockels();
680  }
681  }
682 
685  if ( parameters.run_state() == RunStateHelper::Mode::Stopped ) {
686  DBOUT(L"Zeroing galvo outputs\n");
687  theDaq.ZeroGalvoOutputs();
688  }
689  }
690 
692  void OpenCloseShutter(const uint32_t& _area, const bool& _open) {
693  theDaq.OpenCloseShutter(_area, _open);
694  }
695 
697  bool GetShutterState(const uint32_t& _area) const {
698  return theDaq.GetShutterState(_area);
699  }
700 
702  void TurnOnOffSwitchResonance(const uint32_t& _area, const bool& _on) {
703  theDaq.TurnOnOffSwitchResonance(_area, _on);
704  }
705 
707  bool GetSwitchResonanceState(const uint32_t& _area) const {
708  return theDaq.GetSwitchResonanceState(_area);
709  }
710 
712  void SetFPUButtonsState(const bool& state) {
713  for ( auto& b : FPU ) {
714  b.LeftButton.Enable(state);
715  b.RightButton.Enable(state);
716  b.UpButton.Enable(state);
717  b.DownButton.Enable(state);
718  }
719  }
720 
724  // Signal other GUI elements (e.g. preset combo box in CFrameScanPage, see CFrameScanPage::SetReadOnlyWhileScanning)
725  ReadOnlyWhileScanning.Set((parameters.run_state()==RunStateHelper::Mode::Stopped)?false:true);
726 
727  // This takes care of all the parameters
729 
730  // Now we set the state of all buttons
731  const bool buttonenabler = (parameters.run_state()==RunStateHelper::Mode::Stopped)?true:false;
732 
733  StartSingleButton.Enable(buttonenabler);
734  StartLiveButton.Enable(buttonenabler);
735  StartStackButton.Enable(buttonenabler);
736  StartTimeseriesButton.Enable(buttonenabler);
737  StartBehaviorButton.Enable(buttonenabler);
738 
739  for ( uint32_t a = 0 ; a < SCOPE_NAREAS ; a++ ) {
740  // Only enable scan mode buttons for master area and only if the mode is supported by builtin scanners
741  if ( !ThisIsSlaveArea(a) ) {
742  for ( auto& b : ScanMode[a].map )
743  b.second.Enable(buttonenabler && ScannerSupportedVectors::IsBuiltinSupported(b.first));
744  }
745  // Disable slave area's scan mode buttons
746  else {
747  for ( auto& b : ScanMode[a].map )
748  b.second.Enable(false);
749  }
750  }
751  // Leave these enabled during live scanning
752  StackStartHereButton.Enable(buttonenabler || (parameters.run_state() == RunStateHelper::Mode::RunningContinuous));
753  StackStopHereButton.Enable(buttonenabler || (parameters.run_state() == RunStateHelper::Mode::RunningContinuous));
754  }
755 
757  void AttachFrame(gui::CChannelFrame* const cframe) {
758  theDisplay.AttachFrame(cframe);
759  }
760 
762  void DetachFrame(gui::CChannelFrame* const cframe) {
763  theDisplay.DetachFrame(cframe);
764  }
765 
767  void AttachFrame(gui::CHistogramFrame* const hframe) {
768  theDisplay.AttachFrame(hframe);
769  }
770 
772  bool HistogramAlreadyAttached(const uint32_t& _area) {
773  return theDisplay.HistogramAlreadyAttached(_area);
774  }
775 
777  void DetachFrame(gui::CHistogramFrame* const hframe) {
778  theDisplay.DetachFrame(hframe);
779  }
780 
782  void ResolutionChange(const uint32_t& _area) {
783  theDisplay.ResolutionChange(*GuiParameters.areas[_area]);
784  }
785 
787  void SetHistogramLimits(const uint32_t& _area, const uint32_t& _channel, const uint16_t& _lower, const uint16_t& _upper) {
788  theDisplay.SetHistogramLimits(_area, _channel, _lower, _upper);
789  }
790 
794  void SetScanMode(const uint32_t& _area, const ScannerVectorType& _mode) {
795  // Make sure the choosen mode/scannervector is supported by the built-in scannertype
797  // Triggers update of areas.currentframe (connected to areas.ChangeScanMode)
798  GuiParameters.areas[_area]->scanmode = _mode;
800  ScannerVectorFillType filltype = (parameters.areas[_area]->isslave())?SCOPE_SLAVEFRAMEVECTORFILL:SCOPE_MASTERFRAMEVECTORFILL;
801  framescannervecs[_area] = ScannerVectorFrameBasic::Factory(parameters.areas[_area]->scanmode(), filltype);
802  theDaq.SetScannerVector(_area, framescannervecs[_area]);
803  thePipeline.SetScannerVector(_area, framescannervecs[_area]);
804  for ( auto& c : scanmodecallbacks )
805  c(_area, parameters.areas[_area]->scanmode());
806  } else {
807  throw ScopeException("Choosen ScanMode is not supported by built-in scanner type");
808  }
809  }
810 
813  void RegisterScanmodeCallback(std::function<void(const uint32_t&, const ScannerVectorType&)> _callback) {
814  scanmodecallbacks.push_back(_callback);
815  }
816 };
817 
818 }
ScopeLogger scope_logger
a logger kept handy
std::condition_variable waitbetweenrepeats_cond
for abortable waiting between timeseries repeats
void StopAllControllers()
Stops all controllers in the correct order and waits for them to finish.
void StartBehavior()
Starts a behavior triggered acquisition by running RunBehavior asynchronously.
void OpenCloseShutter(const uint32_t &_area, const bool &_open)
Opens/closes the shutter.
parameters::Scope parameters
the Controller's own set of ScopeParameters
void AttachFrame(gui::CChannelFrame *const cframe)
Attach a CChannelFrame as observer.
void StopAll()
Stop the controller, calls BaseController::Impl::StopAll.
void ResolutionChange(const uint32_t &_area)
Called via change of GuiParameters.areas[x].framesaw.scanvec.xres etc.
std::future< void > onlineupdate_future
future for the online update thread
void SetScannerVector(const uint32_t &_area, ScannerVectorFrameBasicPtr _sv)
Sets a scanner vector.
ScopeNumber< bool > unlimited_repeats
Should acquisition go on until Stop pressed (true) or until repeats done (false)? ...
Definition: Runstates.h:118
void DetachFrame(gui::CChannelFrame *const cframe)
Detach an observing CChannelFrame.
static ScopeButton StageZeroButton
Button to zero main stage coordinates.
void SetGuiCtrlState()
Sets the state of GUI controls (via the corresponding ScopeNumbers).
static ScopeNumber< double > TrialCounter
Updated from ScopeControllerImpl::RunBehavior, connected to edit control in CBehaviorSettingsPage.
ControllerReturnStatus RunSingle(StopCondition *const sc)
Worker function to control a single scan.
Thread-safe lock-free bool to signal a requested stop to the worker function currently executed in th...
Definition: helpers.h:87
virtual T Set(const T &_v, const bool &_callguisignal=true, const bool &_callothersignal=true, const bool &_callatnochange=false)
Sets the value and calls both change signals if the value actually changed.
Definition: ScopeValue.h:67
ScopeValue< ZDevice > zdevicetype
type of z device to use
Definition: Runstates.h:38
ScopeNumber< bool > autosave
autosave all acquisitions (except live scan)
Definition: Storage.h:31
static std::array< ScopeNumber< double >, SCOPE_NAREAS > FrameCounter
Updated from PipelineControllerImpl::Run, connected to progress indicator in CTimeSeriesSettingsPage ...
Impl operator=(const Impl &i)
disable assignment
Simple exception class for Scope.
Definition: ScopeException.h:9
~Impl()
Stop whatever is running.
ScopeString date
current date
Definition: Scope.h:216
void SetFPUButtonsState(const bool &state)
Sets the state of the GUI buttons for FPU control (via the corresponding ScopeButtons).
void SetScannerVector(const uint32_t &_area, ScannerVectorFrameBasicPtr _sv)
Sets a scanner vector.
void Initialize(const parameters::Scope &_params)
Initialize the FPU's hardware.
std::array< PlaneProperties, SCOPE_NAREAS > startat
Start plane, measured with the zdevicetype.
Definition: Runstates.h:26
void StartTimeseries()
Starts a timeseries by running RunTimeseries asynchronously.
bool GetShutterState(const uint32_t &_area) const
Stack stack
the StackParameters
Definition: Scope.h:237
The PipelineController controls everything from pixels to complete images, i.e.
WindowCollection frames
The parameters for windows on the screen.
Definition: Scope.h:252
std::array< std::unique_ptr< Area >, SCOPE_NAREAS > areas
holds AreaParameters for all areas.
Definition: Scope.h:231
ScopeNumber< uint32_t > repeats
How often should the timeseries be repeated.
Definition: Runstates.h:87
void LogRun()
Logs the current scan (not live scans)
void Clear()
Clears the queue.
Definition: SyncQueues.h:37
ScopeNumber< bool > savelive
autosave live scan acquisitions
Definition: Storage.h:34
bool LoadParameters(const std::wstring &_filepath)
Loads current parameter set from disk.
void RegisterScanmodeCallback(std::function< void(const uint32_t &, const ScannerVectorType &)> _callback)
Registers a function to call when scanmode is changed.
void AbortOnlineParameterUpdate(const uint32_t &_area)
Aborts a potentially currently running online update.
ControllerReturnStatus RunTimeseries(StopCondition *const sc)
Worker function to control a timeseries scan.
std::mutex waitbetweenrepeats_mutex
for abortable waiting between timeseries repeats
ControllerReturnStatus WaitForAll(const int32_t &_wait_time=-1)
Wait until the controller threads finished, calls BaseController::Impl::WaitForAll.
void UpdateAreaParametersFromGui(const uint32_t &_area)
Updates area parameters and scanner vectors in the controllers from the GuiParameters set without sto...
std::array< StopCondition, N_ACTIVES > stops
handed to the asynchronous Run worker functions
void SetStageZero()
Sets the current xyz stage position as zero.
The DaqController controls the data acquisition hardware, both outputs for scanners as well as input ...
Definition: DaqController.h:32
void ResolutionChange(const parameters::Area &_parameters)
Request resize of CChannelFrame observers to cope with new image size.
void OpenCloseShutter(const uint32_t &_area, const bool &_open)
Opens/closes the shutter.
void Version() const
Prints out the last Git commit date of the currently running version (see description at ScopeControl...
SCOPE_XYZCONTROL_T stage
the parameters for the xyz stage (set type in ScopeDefines.h)
Definition: Scope.h:246
static bool IsBuiltinSupported(const ScannerVectorTypeHelper::Mode &_scanmode)
Returns true if a given scannervector/scanmode is supported by the builtin/hardcoded (see ScopeDefine...
void ZeroGalvoOutputs()
Sets all galvos to zero position, needed for microscope alignment.
Starts a DAQmx task that waits until the digital line is either high or low (depending on _waitforhig...
Definition: GaterDAQmx.h:10
void Load(const std::wstring &filename)
Load all from file.
Definition: Scope.cpp:475
std::array< ScopeNumber< uint32_t >, SCOPE_NAREAS > frames
number of frames in timeseries for each area
Definition: Runstates.h:72
Impl()
Initializes and connects stuff.
Base class for all Scope datatypes here, provides a uniform interface (and saves typing...).
Manages the display of images.
Definition: ChannelFrame.h:26
void AddWindow(const std::wstring &_type, const uint32_t &_area, HWND _hwnd)
Add a window to the collection.
Definition: Windows.cpp:38
StopCondition repeat_abort
thread-safe bool to signal a requested abort of a stack scan
T SetWithLimits(const T &v, const T &ll, const T &ul)
Sets new value and new limits at the same time.
Definition: ScopeNumber.h:161
std::array< std::shared_future< ControllerReturnStatus >, N_ACTIVES > futures
futures from the asynchronous Run worker functions
void SetHistogramLimits(const uint32_t &_area, const uint32_t &_channel, const uint16_t &_lower, const uint16_t &_upper)
Sets the color limits for displaying imgages, calls DisplayController::SetHistogramLimits.
Timeseries timeseries
the TimeseriesParameters
Definition: Scope.h:240
std::vector< std::array< PlaneProperties, SCOPE_NAREAS > > planes___
Vector with properties for every plane.
Definition: Runstates.h:35
Behavior behavior
the BehaviorParameters
Definition: Scope.h:243
Storage storage
the StorageParameters
Definition: Scope.h:234
bool GetShutterState(const uint32_t &_area) const
A logger class to log various messages and user comments.
Definition: ScopeLogger.h:24
void StackStopHere()
Sets the stop stack position to the current z position.
The display controller handles displaying images and histograms.
std::array< ScannerVectorFrameBasicPtr, SCOPE_NAREAS > framescannervecs
Scanner vectors.
void DetachFrame(gui::CChannelFrame *const cframe)
Detaches a CChannelFrame as an observer.
void DetachFrame(gui::CHistogramFrame *const hframe)
Detach an observing CHistogramFrame.
void StartStack()
Start a stack scan by running RunStack asynchronously.
bool SaveParameters(const std::wstring &_filepath)
Saves the current parameter set to disk.
ScopeValue< DaqMode > requested_mode
requested acquisition mode (see DaqModeHelper)
Definition: Scope.h:279
void Log(const std::wstring &message, const log_message_type &msgtype)
Logs a message.
Definition: ScopeLogger.cpp:26
std::wstring currentconfigfile
currently loaded config
ScopeNumber< uint32_t > repeats
How many repeats should be acquired if not unlimited_repeats?
Definition: Runstates.h:121
void StartAllControllers()
Starts all controllers with the current parameters.
SynchronizedQueue< ScopeMessage< SCOPE_MULTIIMAGEPTR_T > > pipeline_to_display
queue from the pipelines to the display
std::atomic< bool > onlineupdate_running
set if an online update is currently running, to prevent to simultaneous online update threads ...
void Stop()
Stops whatever scanning is going on and clears the queues.
void OnlineParameterUpdate(const parameters::Area &_areaparameters)
Changes daq parameters during live scan.
std::wstring GetCurrentDateString()
Definition: helpers.cpp:4
void SetScannerVectorParameters()
Set parameters for scanner vectors, since these are shared_ptr in DaqControllerDAQmx and PipelineCont...
DWORD time
stores the time to run a scan
void InitializeHardware()
(Re-)Initializes ScopeControllers own hardware components (XYControl/Stage, ZControl, and FPU stuff)
static ScopeNumber< double > PlaneCounter
Updated from ScopeControllerImpl::RunStack, connected to progress indicator in CStackSettingsPage.
bool GetSwitchResonanceState(const uint32_t &_area) const
ScopeNumber< bool > initialparametersloaded
true after parameter set on program start is loaded
void SetReadOnlyWhileScanning(const RunState &_runstate) override
set values that must not be changed to read-only during scanning.
Definition: Scope.cpp:566
std::wstring CurrentConfigFile() const
static std::unique_ptr< ScannerVectorFrameBasic > Factory(const ScannerVectorType &_type, const ScannerVectorFillType &_filltype)
A static factory method for scan vectors.
#define DBOUT(s)
A debug output to the debug console.
Definition: helpers.h:153
void Save(const std::wstring &filename) const
Save all to file.
Definition: Scope.cpp:513
void SetHistogramLimits(const uint32_t &_area, const uint32_t &_channel, const uint16_t &_lower, const uint16_t &_upper)
calls DisplayController::Impl::SetHistogramLimits
The StorageController controls the conversion of multi images to TIFF and the storage of those...
void ScopeExceptionHandler(const std::string &_origin, const bool &_log, const bool &_showmessagebox, const bool &_trace, const bool &_rethrow)
Handles all exceptions and does nice logging.
void Start(const parameters::Scope &_parameters)
Start the controller, calls BaseController::Impl::Start.
Manages the display of histograms.
void ClearAfterStop()
Clears queues, resets run state, and reenables controls.
ControllerReturnStatus RunStack(StopCondition *const sc)
Worker function to control a stack scan.
static ScopeNumber< double > TotalTime
Updated from e.g.
void WaitForAllControllers()
Waits for all controllers to intrinsically finish.
static std::array< ScanModeButtons, SCOPE_NAREAS > ScanMode
Buttons for switching the scan mode.
void StackStartHere()
Sets the start stack position to the current z position.
void AttachFrame(gui::CHistogramFrame *const hframe)
Attach a CHistogramFrame as observer.
void StartLive()
Starts live scanning by running RunLive asynchronously.
void AttachFrame(gui::CChannelFrame *const cframe)
Attaches a CChannelFrame as an observer.
A synchronized, thread-safe queue was modeled after ringbuffer example from boost?! and/or a Herb Sutter column?!
Definition: DaqController.h:7
void StartSingle()
Starts a single frame scan by running RunSingle asynchronously.
ScopeString time
current time
Definition: Scope.h:219
ScopeValue< RunState > run_state
current RunState
Definition: Scope.h:276
ControllerReturnStatus RunLive(StopCondition *const sc)
Worker function to control live scanning (basically only starting everything up)
void TurnOnOffSwitchResonance(const uint32_t &_area, const bool &_on)
Turns the resonance scanner relay on and off.
void SetScanMode(const uint32_t &_area, const ScannerVectorType &_mode)
Sets the type of scanning.
void Set(const bool &_a=true)
Definition: helpers.h:108
void PrepareQuit()
Called via CMainDialogFrame::QuitApplication.
parameters::WindowCollection GetWindowCollection() const
Adds frames to WindowCollection of ScopeController::GuiParameters.
std::array< PlaneProperties, SCOPE_NAREAS > stopat
Stop plane, measured with the zdevicetype.
Definition: Runstates.h:29
std::vector< std::array< PlaneProperties, SCOPE_NAREAS > > planes
vector with properties for all planes, for alternating planes on repeating timeseries, one for each area
Definition: Runstates.h:96
void SaveCurrentWindowPositions()
Saves current positions of windows by adding frames to WindowCollection of ScopeController::GuiParame...
static std::array< FPUButtons, SCOPE_NAREAS > FPU
Buttons for FPU nudge.
ScopeNumber< double > betweenrepeats
Time in seconds between the beginning of one and beginning of the next timeseries.
Definition: Runstates.h:90
boost::signals2::connection Connect(signalchange_t::slot_type slot)
Connect slot to signal.
Definition: ScopeButton.cpp:35
std::array< SynchronizedQueue< ScopeMessage< SCOPE_DAQCHUNKPTR_T > >, SCOPE_NAREAS > daq_to_pipeline
queues from the daqs to the pipelines
static std::array< ScopeNumber< double >, SCOPE_NAREAS > SingleFrameProgress
Updated from PipelineControllerImpl::Run.
std::vector< std::function< void(const uint32_t &, const ScannerVectorType &)> > scanmodecallbacks
list of callbacks for scan mode switching
static parameters::Scope GuiParameters
The complete pseudo-global parameter set of the microscope.
Base class for all controllers.
void TurnOnOffSwitchResonance(const uint32_t &_area, const bool &_on)
Turns the resonance scanner relay on and off.
void ZeroGalvoOutputs()
Calls the DaqController to set Galvo outputs to zero.
The FPUController.
Definition: FPUController.h:15
bool HistogramAlreadyAttached(const uint32_t &_area) const
std::array< std::unique_ptr< SCOPE_FPUXYCONTROL_T >, SCOPE_NAREAS > theXYStages
for xy movement of FPU stages
Definition: FPUController.h:26
ControllerReturnStatus RunBehavior(StopCondition *const sc)
Worker function to control a behavior triggered scan.
bool HistogramAlreadyAttached(const uint32_t &_area)
static ScopeNumber< bool > ReadOnlyWhileScanning
Set to true while scanning, GUI elements can connect to this to disable buttons and controls (that ar...
static ScopeNumber< double > RepeatCounter
Updated from ScopeControllerImpl::RunTimeseries, connected to progress indicator in CTimeSeriesSettin...
ScopeString gateline
The DAQmx digital line for gating.
Definition: Runstates.h:127
void ClearAllQueues()
Clear all queues between controllers.
SynchronizedQueue< ScopeMessage< SCOPE_MULTIIMAGEPTR_T > > pipeline_to_storage
queue from the pipelines to the storage
HWND GetLogFrameWindow()
Saves log frame parameters into Window (for recreating windows on startup).
Definition: ScopeLogger.cpp:34
std::wstring GetCurrentTimeString(const bool &_filenamecompatible)
Definition: helpers.cpp:12
static std::vector< ScannerVectorTypeHelper::Mode > List(const ScannerTypeHelper::Mode &_scannertype=SCOPE_SCANNERTYPE)
Returns a vector with all supported scannervectors for a given scannertype.
The implementation class of the ScopeController.
bool IsSet() const
Definition: helpers.h:105
bool GetSwitchResonanceState(const uint32_t &_area) const