Scope
PipelineController_p.h
1 #pragma once
2 
3 #include "PipelineController.h"
4 #include "BaseController_p.h"
5 #include "ScopeController_p.h"
6 #include "helpers/SyncQueues.h"
7 #include "parameters/Scope.h"
8 #include "helpers/DaqChunk.h"
9 #include "helpers/DaqChunkResonance.h"
10 #include "helpers/ScopeMultiImage.h"
11 #include "scanmodes/PixelmapperBasic.h"
12 #include "ScopeDatatypes.h"
13 
14 namespace scope {
15 
18  : public BaseController<SCOPE_NAREAS>::Impl {
19 
20 protected:
22  std::array<SynchronizedQueue<ScopeMessage<SCOPE_DAQCHUNKPTR_T>>, SCOPE_NAREAS>* const input_queues;
23 
26 
29 
31  std::array<ScannerVectorFrameBasicPtr, SCOPE_NAREAS> scannervecs;
32 
34  std::array<std::mutex, SCOPE_NAREAS> online_update_mutexe;
35 
37  std::array<bool, SCOPE_NAREAS> online_updates;
38 
39 protected:
41  Impl(const Impl& i);
42 
44  Impl operator=(const Impl& i);
45 
48  ControllerReturnStatus Run(StopCondition* const sc, const uint32_t& _area) {
49  ATLTRACE(L"PipelineController::Impl::Run beginning\n");
50  uint32_t framecount = 0;
51  uint32_t avgcount = 0;
52  ScopeController scope_controller;
53  std::unique_lock<std::mutex> online_update_lock(online_update_mutexe[_area], std::defer_lock);
54  online_updates[_area] = false;
55  ControllerReturnStatus returnstatus(ControllerReturnStatus::none);
56  PixelmapperResult pixelmapper_result(Error);
57 
58  const uint32_t downsampling = (parameters.areas[_area]->daq.inputs->oversampling())?round2ui32(parameters.areas[_area]->daq.pixeltime() / parameters.areas[_area]->daq.inputs->MinimumPixeltime()):1;
59  // Get some values as locals, avoid the mutexed access to parameters later on (really necessary??)
60  const DaqMode requested_mode = parameters.requested_mode();
61  const uint32_t requested_frames = parameters.areas[_area]->daq.requested_frames();
62  const uint32_t requested_averages = parameters.areas[ThisAreaOrMasterArea(_area)]->daq.averages();
63  const double totalframepixels = parameters.areas[_area]->Currentframe().XTotalPixels()*parameters.areas[_area]->Currentframe().YTotalLines();
64 
65  // Make the first multiimage
66  SCOPE_MULTIIMAGEPTR_T current_frame = std::make_shared<SCOPE_MULTIIMAGE_T>(_area
67  , parameters.areas[_area]->daq.inputs->channels()
68  , parameters.areas[_area]->Currentframe().yres()
69  , parameters.areas[_area]->Currentframe().xres());
70  SCOPE_MULTIIMAGEPTR_T next_frame = current_frame; //std::make_shared<ScopeMultiImage>(_area, channels, yres, xres);
71  current_frame->SetAvgMax(requested_averages);
72 
73  std::unique_ptr<PixelmapperBasic> pixel_mapper(PixelmapperBasic::Factory(SCOPE_SCANNERTYPE, parameters.areas[_area]->scanmode()));
74  pixel_mapper->SetLookupVector(scannervecs[_area]->GetLookupVector());
75  pixel_mapper->SetParameters(scannervecs[_area]->GetSVParameters());
76  pixel_mapper->SetCurrentFrame(current_frame);
77 
78  scope_controller.FrameCounter[_area].SetWithLimits(0, 0, requested_frames);
79  scope_controller.SingleFrameProgress[_area].SetWithLimits(0, 0, 100);
80 
81  // Dequeue and pixelmap loop
82  while ( !sc->IsSet() ) {
83  // Dequeue
84  ScopeMessage<SCOPE_DAQCHUNKPTR_T> msg(input_queues->at(_area).Dequeue());
85 
86  // If message has abort tag, break from while loop
87  if ( msg.tag == ScopeMessageTag::abort ) {
88  returnstatus = stopped;
89  break;
90  }
91  SCOPE_DAQCHUNKPTR_T chunk = msg.cargo;
92 
93  // If we oversampled during acquisition, now downsample to pixeltime
94  chunk->Downsample(downsampling);
95 
96  // Map until the whole data chunk is mapped (could be overlapping the end of a frame)
97  do {
98  // Map the chunk into the current_frame
99  // Attention: this blocks ScopeOverlay::Create in CChannelFrame since we need write access to the image here!
100  pixelmapper_result = pixel_mapper->LookupChunk(chunk, avgcount);
101 
102  // Set progress and frame properties
103  scope_controller.SingleFrameProgress[_area] += 100.0 * chunk->PerChannel() / totalframepixels;
104  current_frame->SetPercentComplete(scope_controller.SingleFrameProgress[_area].Value());
105  current_frame->SetAvgCount(avgcount+1);
106  current_frame->SetImageNumber(framecount+1);
107 
108  // Put current_frame in outgoing message
110  outmsg.cargo = current_frame;
111 
112  // If one frame is mapped completely...
113  if ( (pixelmapper_result & FrameComplete) != 0 ) {
114  current_frame->SetCompleteFrame(true);
115  scope_controller.SingleFrameProgress[_area] = 0.0;
116  // If all the averages for one frame have been done...
117  if ( ++avgcount == requested_averages ) {
118  avgcount = 0;
119  current_frame->SetCompleteAvg(true);
120 
121  // the next frame is a copy of the old (allows for continuous updating effect, no black pixels in new frame)
122  next_frame = std::make_shared<SCOPE_MULTIIMAGE_T>(*current_frame);
123 
124  // Enqueue current frame for storage
125  storage_queue->Enqueue(outmsg);
126 
127  // Increase frame counters
128  framecount++;
129  scope_controller.FrameCounter[_area] += 1;
130 
131  // Set frame properties
132  next_frame->SetCompleteAvg(false);
133  next_frame->SetAvgMax(requested_averages);
134  next_frame->SetCompleteFrame(false);
135  next_frame->SetPercentComplete(0.0);
136 
137  // Give pixelmapper the new frame
138  pixel_mapper->SetCurrentFrame(next_frame);
139  }
140  }
141 
142  // enqueue always for display, for running update
143  display_queue->Enqueue(outmsg);
144 
145  // Let current_frame pointer point to next one (the actual image persists since the shared_ptr in msg is still pointing to it)
146  current_frame = next_frame;
147 
148  // while loop ends with end of chunk of if stop condition is set (this allows abort during mapping of one chunk)
149  } while ( ((pixelmapper_result & EndOfChunk) != EndOfChunk) && !sc->IsSet() );
150 
151  // Check if an online parameter update was requested and we have to update the LookupVector etc
152  // Only really needed for scannerdelay change (since zoom etc. leave the lookup vector untouched)
153  online_update_lock.lock();
154  if ( online_updates[_area] && (requested_mode == DaqModeHelper::continuous) ) {
155  DBOUT(L"PipelineController::Impl::Run online update\n");
156  // Give pixelmapper the current lookup vector
157  pixel_mapper->SetLookupVector(scannervecs[_area]->GetLookupVector());
158  pixel_mapper->SetParameters(scannervecs[_area]->GetSVParameters());
159  online_updates[_area] = false;
160  }
161  online_update_lock.unlock();
162 
163  // Check if we read enough samples (if not live scanning)
164  if ( (requested_mode == DaqModeHelper::nframes) && (requested_frames == framecount) ) { // are we done?
165  returnstatus = finished;
166  sc->Set(true);
167  DBOUT(L"PipelineController all requested frames from area " << _area << L" processed\n");
168  }
169  }
170 
171  if ( sc->IsSet() )
172  returnstatus = ControllerReturnStatus(returnstatus || ControllerReturnStatus::stopped);
173 
174  DBOUT(L"PipelineController::Impl::Run end\n");
175  return returnstatus;
176  }
177 
178 public:
180  explicit Impl(std::array<SynchronizedQueue<ScopeMessage<SCOPE_DAQCHUNKPTR_T>>, SCOPE_NAREAS>* const _iqueues
183  , const parameters::Scope& _parameters)
184  : BaseController::Impl(_parameters)
185  , input_queues(_iqueues)
186  , storage_queue(_squeue)
187  , display_queue(_dqueue) {
188  }
189 
190  ~Impl() {
191  StopAll();
192  WaitForAll(-1);
193  }
194 
195  void StopOne(const uint32_t& _a) override {
196  // This sets stop condition
198  // This enqueues abort message (just to be sure)
199  ScopeMessage<SCOPE_DAQCHUNKPTR_T> stopmsg(ScopeMessageTag::abort, nullptr);
200  input_queues->at(_a).Enqueue(stopmsg);
201  }
202 
204  void OnlineParameterUpdate(const parameters::Area& _areaparameters) {
205  const uint32_t area = _areaparameters.area();
206  std::lock_guard<std::mutex> lock(online_update_mutexe[area]); // lock, thus worker thread waits and we can safely update parameters
207  // update parameters
208  *parameters.areas[area] = _areaparameters;
209  online_updates[area] = true;
210  }
211 
213  void SetScannerVector(const uint32_t& _area, ScannerVectorFrameBasicPtr _sv) {
214  scannervecs[_area] = _sv;
215  }
216 };
217 
218 }
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
Thread-safe lock-free bool to signal a requested stop to the worker function currently executed in th...
Definition: helpers.h:87
void StopOne(const uint32_t &_a) override
Request one async worker function to stop by settings its StopCondition to true.
static std::array< ScopeNumber< double >, SCOPE_NAREAS > FrameCounter
Updated from PipelineControllerImpl::Run, connected to progress indicator in CTimeSeriesSettingsPage ...
The master parameters class.
Definition: Scope.h:204
std::array< std::unique_ptr< Area >, SCOPE_NAREAS > areas
holds AreaParameters for all areas.
Definition: Scope.h:231
SynchronizedQueue< ScopeMessage< SCOPE_MULTIIMAGEPTR_T > > *const display_queue
output queue to the DisplayController
void SetScannerVector(const uint32_t &_area, ScannerVectorFrameBasicPtr _sv)
Sets the pointers to the scanner vector.
Base class for all Scope datatypes here, provides a uniform interface (and saves typing...).
void Enqueue(const T &elem)
Enqueues an element and notifies one waiting operation that queue is not empty.
Definition: SyncQueues.h:43
ControllerReturnStatus Run(StopCondition *const sc, const uint32_t &_area)
Main function for running pixel mapping.
SynchronizedQueue< ScopeMessage< SCOPE_MULTIIMAGEPTR_T > > *const storage_queue
output queue to the StorageController
std::array< std::mutex, SCOPE_NAREAS > online_update_mutexe
protection for online updates during live scanning
~Impl()
It is important that this is virtual, only by this the correct destructor for the pimpl is called in ...
Impl(const Impl &i)
disable copy
Impl operator=(const Impl &i)
disable assignment
ScopeValue< DaqMode > requested_mode
requested acquisition mode (see DaqModeHelper)
Definition: Scope.h:279
T cargo
the cargo
Definition: helpers.h:72
std::array< SynchronizedQueue< ScopeMessage< SCOPE_DAQCHUNKPTR_T > >, SCOPE_NAREAS > *const input_queues
input queue from the DaqController
Impl(std::array< SynchronizedQueue< ScopeMessage< SCOPE_DAQCHUNKPTR_T >>, SCOPE_NAREAS > *const _iqueues, SynchronizedQueue< ScopeMessage< SCOPE_MULTIIMAGEPTR_T >> *const _squeue, SynchronizedQueue< ScopeMessage< SCOPE_MULTIIMAGEPTR_T >> *const _dqueue, const parameters::Scope &_parameters)
Connect queues and get scanner vectors and parameters.
In here all declarations for all kinds of datatypes Scope needs.
virtual ControllerReturnStatus WaitForAll(const int32_t &_wait_time)
Wait for the futures of all async worker functions.
std::array< ScannerVectorFrameBasicPtr, SCOPE_NAREAS > scannervecs
array with the scanner vectors
virtual void StopAll()
Request all async worker function to stop.
virtual void StopOne(const uint32_t &_a)
Request one async worker function to stop by settings its StopCondition to true.
#define DBOUT(s)
A debug output to the debug console.
Definition: helpers.h:153
The implementation class of the PipelineController.
A synchronized, thread-safe queue was modeled after ringbuffer example from boost?! and/or a Herb Sutter column?!
Definition: DaqController.h:7
void Set(const bool &_a=true)
Definition: helpers.h:108
ScopeNumber< uint32_t > area
the number of this area
Definition: Scope.h:69
std::array< bool, SCOPE_NAREAS > online_updates
trigger for online updates during live scanning
static std::array< ScopeNumber< double >, SCOPE_NAREAS > SingleFrameProgress
Updated from PipelineControllerImpl::Run.
Base class for all controllers.
static std::unique_ptr< PixelmapperBasic > Factory(const ScannerType &_scanner, const ScannerVectorType &_type)
A static factor method for pixelmappers.
void OnlineParameterUpdate(const parameters::Area &_areaparameters)
Handles update of parameters during scanning.
bool IsSet() const
Definition: helpers.h:105