Scope
DaqController_p.h
1 #pragma once
2 
3 #include "DaqController.h"
4 #include "BaseController_p.h"
5 #include "helpers/SyncQueues.h"
6 #include "devices/Shutter.h"
7 #include "devices/SwitchResonance.h"
8 #include "parameters/IO.h"
9 #include "helpers/ScopeException.h"
10 #include "devices/StimulationVector.h"
11 #include "scanmodes/ScannerVectorFrameBasic.h"
12 #include "ScopeDatatypes.h"
13 #include "helpers/DaqChunk.h"
14 #include "helpers/DaqChunkResonance.h"
15 #include "ScopeLogger.h"
16 #include "devices/OutputsDAQmx.h"
17 #include "devices/OutputsDAQmxLineClock.h"
18 #include "devices/OutputsDAQmxResonance.h"
19 #include "devices/OutputsDAQmxSlave.h"
20 #include "devices/InputsDAQmx.h"
21 #include "devices/InputsFPGA.h"
22 #include "devices/StimulationsDAQmx.h"
23 #include "devices/GaterDAQmx.h"
24 
25 namespace scope {
26 
29  : public BaseController<SCOPE_NAREAS>::Impl {
30 
31 protected:
33  std::array<SynchronizedQueue<ScopeMessage<SCOPE_DAQCHUNKPTR_T>>, SCOPE_NAREAS>* const output_queues;
34 
36  std::array<std::unique_ptr<Outputs>, SCOPE_NAREAS> outputs;
37 
39  std::array<std::unique_ptr<Inputs>, SCOPE_NAREAS> inputs;
40 
42  std::unique_ptr<SCOPE_STIMULATIONS_T> stimulation;
43 
45  std::array<Shutter, SCOPE_NAREAS> shutters;
46 
48  std::array<SwitchResonance, SCOPE_NAREAS> switches;
49 
51  std::array<ScannerVectorFrameBasicPtr, SCOPE_NAREAS> scannervecs;
52 
55 
57  std::array<uint32_t, SCOPE_NAREAS> chunksizes;
58 
60  std::array<std::condition_variable, SCOPE_NAREAS> online_update_done;
61 
63  std::array<std::atomic<bool>, SCOPE_NAREAS> online_update_done_flag;
64 
66  std::array<std::mutex, SCOPE_NAREAS> online_update_done_mutexe;
67 
70 
71 protected:
73  Impl(const Impl& i);
74 
76  Impl operator=(const Impl& i);
77 
80  ControllerReturnStatus Run(StopCondition* const sc, const uint32_t& _area) override {
81  DBOUT(L"DaqController::Impl::Run area " << _area << L" beginning");
82  ControllerReturnStatus returnstatus(ControllerReturnStatus::none);
83 
84  const DaqMode requested_mode = parameters.requested_mode();
85  uint32_t chunksize = inputs[_area]->StandardChunkSize();
86  const uint32_t requested_samples = inputs[_area]->RequestedSamples();
87  uint32_t readsamples = 0;
88  int32_t currentlyread = 0;
89  bool timedout = false;
90 
91  // Main acquisition loop
92  while ( !sc->IsSet() ) {
93  // adjust size of last chunk to read if in nframes mode
94  if ( requested_mode == DaqModeHelper::nframes ) {
95  if ( (readsamples + chunksize) > requested_samples )
96  chunksize = requested_samples - readsamples;
97  }
98 
99  // Create a new chunk...
100  auto chunk = std::make_shared<SCOPE_DAQCHUNK_T>(chunksize, parameters.areas[_area]->daq.inputs->channels(), _area);
101 
102  // With this loop we can interrupt a thread that is waiting here for a trigger (see FiberMRI program)
103  // or which waits for samples (which never come because of an error)
104  currentlyread = 0;
105  do {
106  // Read data from inputs into the chunk. Timeout 1 second.
107  currentlyread = inputs[_area]->Read(*chunk, timedout, 1);
108  DBOUT(L"DaqController::Impl::Run read");
109  // In case of timeout attempt to read as long as stop condition is not set
110  } while ( timedout && !sc->IsSet() );
111  timedout = false;
112 
114  msg.tag = ScopeMessageTag::nothing;
115  msg.cargo = chunk;
116 
117  // ...and put it in the queue
118  output_queues->at(_area).Enqueue(msg);
119 
120  // advance number of read pixels
121  readsamples += currentlyread;
122  DBOUT(L"DaqController::Impl::Run area " << _area << L" read " << readsamples << L" of requested " << requested_samples);
123 
124  // Check if we read enough samples (if not live scanning)
125  if ( (requested_mode == DaqModeHelper::nframes) && (readsamples == requested_samples) ) {
126  // if yes we want to stop
127  sc->Set(true);
128  returnstatus = ControllerReturnStatus::finished;
129  DBOUT(L"DaqController::Impl::Run area " << _area << L" - all requested pixels read\n");
130  }
131  }
132 
133  // Force abort of online update
134  outputs[_area]->AbortWrite();
135 
136  outputs[_area]->Stop();
137  inputs[_area]->Stop();
138 
139  // Close the shutters
140  for ( auto& s : shutters )
141  s.Close();
142 
143  // Turn the resonance scanner relay off
144  for ( auto& s : switches )
145  s.TurnOff();
146 
147  ATLTRACE(L"DaqController::DaqControllerImpl::Run end\n");
148  return returnstatus;
149  }
150 
151 public:
155  explicit Impl(std::array<SynchronizedQueue<ScopeMessage<SCOPE_DAQCHUNKPTR_T>>, SCOPE_NAREAS>* const _oqueues, const parameters::Scope& _parameters)
156  : BaseController<SCOPE_NAREAS>::Impl(_parameters)
157  , output_queues(_oqueues)
158  , stimulation(nullptr) {
159  std::fill(std::begin(chunksizes), std::end(chunksizes), 16000);
160  std::fill(std::begin(online_update_done_flag), std::end(online_update_done_flag), false);
161  uint32_t a = 0;
162  for ( auto& sh : shutters )
163  sh.Initialize(parameters.areas[a++]->daq.shutterline());
164  a = 0;
165  for ( auto& sw : switches )
166  sw.Initialize(parameters.areas[a++]->daq.switchresonanceline());
167 
169  }
170 
172  virtual ~Impl() {
173  StopAll();
174  WaitForAll(-1);
176  DBOUT(L"DaqController::Impl::~DaqControllerImpl");
177  }
178 
183  void Start(const parameters::Scope& _params) override {
184  DBOUT(L"DaqController::Impl::Start");
185 
186  parameters = _params;
187  // Reset outputs and inputs (configures tasks etc. inside them)
188  for ( uint32_t a = 0; a < SCOPE_NAREAS ; a++ ) {
189  // Choose output type depending on that area being a slave area
190  if ( parameters.areas[a]->isslave() )
191  outputs[a].reset(new SCOPE_SLAVEOUTPUTS_T(a, *dynamic_cast<parameters::SCOPE_SLAVEOUTPUTS_T*>(parameters.areas[a]->daq.outputs.get()), parameters));
192  else
193  outputs[a].reset(new SCOPE_OUTPUTS_T(a, *dynamic_cast<parameters::SCOPE_OUTPUTS_T*>(parameters.areas[a]->daq.outputs.get()), parameters));
194  ScopeController scope_controller;
195  inputs[a].reset(new SCOPE_INPUTS_T(a, dynamic_cast<parameters::SCOPE_INPUTS_T*>(scope_controller.GuiParameters.areas[a]->daq.inputs.get()), parameters));
196  }
197 
198  // Calculate and write stimulationvector to device
199  if ( parameters.stimulation.enable() ) {
200  stimulation.reset(new SCOPE_STIMULATIONS_T(parameters));
202  stimulation->Write(stimvec.GetVector());
203  stimulation->Start();
204  }
205  else
206  stimulation.reset(nullptr);
207 
208  // Write scannervectors to devices
209  for ( uint32_t a = 0 ; a < SCOPE_NAREAS ; a++ )
210  outputs[a]->Write(scannervecs[a]->GetInterleavedVector(), 1);
211 
212  // Open shutters
213  for ( auto& s : shutters )
214  s.Open();
215 
216  // Turn the resonance scanner relay on
217  for ( auto& s : switches )
218  s.TurnOn();
219  // Wait until the synchronization signal is in the steady state
220 // std::this_thread::sleep_for(std::chrono::milliseconds(600));
221 // std::this_thread::sleep_for(std::chrono::milliseconds(1500));
222 
223  // Define lambdas for starting all inputs and all outputs
224  // always area 0 last, so it (e.g. its /ao/StartTrigger) can serve as common master trigger for everything else
225  std::function<void(void)> start_inputs = [&](){
226  for ( uint32_t a = 1 ; a < SCOPE_NAREAS ; a++ )
227  inputs[a]->Start();
228  inputs[0]->Start();
229  };
230  std::function<void(void)> start_outputs = [&](){
231  for ( uint32_t a = 1 ; a < SCOPE_NAREAS ; a++ )
232  outputs[a]->Start();
233  outputs[0]->Start();
234  };
235 
236  // start inputs or outputs first
237  if ( parameters.startinputsfirst() ) {
238  start_inputs();
239  start_outputs();
240  } else {
241  start_outputs();
242  start_inputs();
243  }
244 
245  // Let "Run" run asynchronously
246  for( uint32_t a = 0; a < SCOPE_NAREAS ; a++ ) {
247  // Reset the stop condition
248  stops[a].Set(false);
249  // Get the async's future
250  futures[a] = std::async(std::bind(&Impl::Run, this, &stops[a], a));
251  }
252  }
253 
256  void OnlineParameterUpdate(const parameters::Area& _areaparameters) {
257  uint32_t area = _areaparameters.area();
258 
259  // update parameters
260  *parameters.areas[area] = _areaparameters;
261  // Note: scannervector was updated already from ScopeControllerImpl
262 
263  // Lock now so starting an async Worker is only possible if a putative previous wait on that lock finished
264  std::unique_lock<std::mutex> lock(online_update_done_mutexe[area]);
265 
266  // If we are scanning live do async online update. Always catch the async future since the futures destructor waits (see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3451.pdf)
267  if ( parameters.requested_mode() == DaqModeHelper::continuous )
268  auto f = std::async(std::bind(&Impl::WorkerOnlineParameterUpdate, this, area));
269 
270  // wait until online update is done or aborted in async WorkerOnlineParameterUpdate
271  while ( !online_update_done_flag[area] )
272  online_update_done[area].wait(lock);
273  }
274 
276  void WorkerOnlineParameterUpdate(const uint32_t _area) {
277  DBOUT(L"WorkerOnlineParameterUpdate starting");
278  auto scannervec = scannervecs[_area]->GetInterleavedVector();
279 
280  // Number of blocks => around 4 blocks per second frame time
281  uint32_t blocks = round2ui32(4.0 * parameters.areas[_area]->FrameTime());
282 
283  DBOUT(L"WorkerOnlineParameterUpdate blocks" << blocks);
284  online_update_done_flag[_area] = false;
285 
286  // If we call outputs[_area]->AbortWrite this Write exits prematurely
287  outputs[_area]->Write(scannervec, blocks);
288 
289  // when update is done, signal the waiting condition_variable in OnlineParameterUpdate
290  online_update_done_flag[_area] = true;
291  online_update_done[_area].notify_all();
292  DBOUT(L"WorkerOnlineParameterUpdate ended");
293  }
294 
297  void AbortOnlineParameterUpdate(const uint32_t& _area) {
298  // Abort the output on its next block write. Note, the Write is inside lock
299  outputs[_area]->AbortWrite();
300  }
301 
304  // Cancel all currently configured tasks
305  for ( auto& o : outputs ) {
306  if ( o.get() != nullptr )
307  o.reset(nullptr);
308  }
309  for ( auto& i : inputs ) {
310  if ( i.get() != nullptr )
311  i.reset(nullptr);
312  }
313  stimulation.reset(nullptr);
314 
315  // Do the zero outputs tasks
316  for ( const auto& ap : parameters.areas ) {
317  if ( ap->isslave() )
318  SCOPE_ZEROOUTPUTSSLAVE_T zero(*dynamic_cast<parameters::SCOPE_SLAVEOUTPUTS_T*>(ap->daq.outputs.get()));
319  else
320  SCOPE_ZEROOUTPUTS_T zero(*dynamic_cast<parameters::SCOPE_OUTPUTS_T*>(ap->daq.outputs.get()));
321  }
322  }
323 
325  void SetScannerVector(const uint32_t& _area, ScannerVectorFrameBasicPtr _sv) {
326  scannervecs[_area] = _sv;
327  }
328 
330  void OpenCloseShutter(const uint32_t& _area, const bool& _open) {
331  for ( auto& s : shutters )
332  s.Set(_open);
333  }
334 
336  bool GetShutterState(const uint32_t _area) const {
337  return shutters[_area].GetState();
338  }
339 
341  void TurnOnOffSwitchResonance(const uint32_t& _area, const bool& _on) {
342  for ( auto& s : switches )
343  s.Set(_on);
344  }
345 
347  bool GetSwitchResonanceState(const uint32_t _area) const {
348  return switches[_area].GetState();
349  }
350 };
351 
352 
353 
354 }
Main controller of microscope hardware and acquisition, also interface to the GUI.
Parameters for a whole area (includes a daq and a fpu)
Definition: Scope.h:64
parameters::Scope parameters
the Controller's own set of ScopeParameters
Impl(std::array< SynchronizedQueue< ScopeMessage< SCOPE_DAQCHUNKPTR_T >>, SCOPE_NAREAS > *const _oqueues, const parameters::Scope &_parameters)
Sets the output queues, generates initial ScannerVectors and initializes the shutters and the resonan...
The implementation class of the DaqController.
Thread-safe lock-free bool to signal a requested stop to the worker function currently executed in th...
Definition: helpers.h:87
std::unique_ptr< SCOPE_STIMULATIONS_T > stimulation
The stimulation output.
The master parameters class.
Definition: Scope.h:204
Impl(const Impl &i)
disable copy
std::array< std::unique_ptr< Area >, SCOPE_NAREAS > areas
holds AreaParameters for all areas.
Definition: Scope.h:231
std::shared_ptr< const std::vector< uint8_t > > GetVector() const
std::array< std::unique_ptr< Inputs >, SCOPE_NAREAS > inputs
The inputs (pointers to base class)
Calculates a basic digital stimulation pattern.
void ZeroGalvoOutputs()
Zeros galvo outputs.
std::array< StopCondition, N_ACTIVES > stops
handed to the asynchronous Run worker functions
ControllerReturnStatus Run(StopCondition *const sc, const uint32_t &_area) override
Main function for running data acquisition.
ScopeLogger scope_logger
a ScopeLogger kept handy here
ScopeMessageTag tag
the tag of the message, at the moment only nothing or abort
Definition: helpers.h:69
ScopeNumber< bool > enable
stimulation enabled/disabled
Definition: Scope.h:42
void AbortOnlineParameterUpdate(const uint32_t &_area)
Aborts a running online parameters update (aborts the block-wise Outputs::Write operation) ...
Base class for all Scope datatypes here, provides a uniform interface (and saves typing...).
std::array< std::shared_future< ControllerReturnStatus >, N_ACTIVES > futures
futures from the asynchronous Run worker functions
StimulationVector stimvec
stimulation
virtual ~Impl()
Stops and interrupts everything and zeros galvo outputs.
void Start(const parameters::Scope &_params) override
Starts the DaqController.
A logger class to log various messages and user comments.
Definition: ScopeLogger.h:24
std::array< std::unique_ptr< Outputs >, SCOPE_NAREAS > outputs
The outputs (pointers to base class)
std::array< uint32_t, SCOPE_NAREAS > chunksizes
size of a read chunk in samples per channel
std::array< std::condition_variable, SCOPE_NAREAS > online_update_done
condition variables to wait for until online updates is done (new frame is completely written to buff...
ScopeValue< DaqMode > requested_mode
requested acquisition mode (see DaqModeHelper)
Definition: Scope.h:279
std::array< Shutter, SCOPE_NAREAS > shutters
array holding shutter class for every area
void OnlineParameterUpdate(const parameters::Area &_areaparameters)
Handles update of parameters during scanning.
T cargo
the cargo
Definition: helpers.h:72
In here all declarations for all kinds of datatypes Scope needs.
void SetScannerVector(const uint32_t &_area, ScannerVectorFrameBasicPtr _sv)
Sets a scanner vector.
virtual ControllerReturnStatus WaitForAll(const int32_t &_wait_time)
Wait for the futures of all async worker functions.
virtual void StopAll()
Request all async worker function to stop.
void OpenCloseShutter(const uint32_t &_area, const bool &_open)
Opens/closes the shutter.
#define DBOUT(s)
A debug output to the debug console.
Definition: helpers.h:153
Impl operator=(const Impl &i)
disable assignment
std::array< std::mutex, SCOPE_NAREAS > online_update_done_mutexe
mutexe for the condition variables
A synchronized, thread-safe queue was modeled after ringbuffer example from boost?! and/or a Herb Sutter column?!
Definition: DaqController.h:7
void TurnOnOffSwitchResonance(const uint32_t &_area, const bool &_on)
Turns the resonance scanner relay on and off.
std::array< ScannerVectorFrameBasicPtr, SCOPE_NAREAS > scannervecs
The scanner vector for frame scanning.
void Set(const bool &_a=true)
Definition: helpers.h:108
ScopeNumber< uint32_t > area
the number of this area
Definition: Scope.h:69
bool GetShutterState(const uint32_t _area) const
std::array< std::atomic< bool >, SCOPE_NAREAS > online_update_done_flag
bool flag to set after online update is done
std::array< SynchronizedQueue< ScopeMessage< SCOPE_DAQCHUNKPTR_T > >, SCOPE_NAREAS > *const output_queues
array holding the output queues to the PipelineControllers
void SetParameters(const parameters::Stimulation &_parameters)
Sets parameters.
ScopeNumber< bool > startinputsfirst
true: start inputs first, then outputs with output of area 0 as last, so it (e.g. ...
Definition: Scope.h:256
std::array< SwitchResonance, SCOPE_NAREAS > switches
array holding SwitchResonance class for every area
static parameters::Scope GuiParameters
The complete pseudo-global parameter set of the microscope.
Base class for all controllers.
void WorkerOnlineParameterUpdate(const uint32_t _area)
Does the actual writing to device for an online update.
Stimulation stimulation
the StimulationParameters
Definition: Scope.h:249
bool GetSwitchResonanceState(const uint32_t _area) const
bool IsSet() const
Definition: helpers.h:105