DynExp
Highly flexible laboratory automation for dynamically changing experiments.
Trajectory1D.cpp
Go to the documentation of this file.
1 // This file is part of DynExp.
2 
3 #include "stdafx.h"
4 #include "moc_Trajectory1D.cpp"
5 #include "Trajectory1D.h"
6 
7 namespace DynExpModule
8 {
9  Trajectory1DWidget::Trajectory1DWidget(Trajectory1D& Owner, QModuleWidget* parent) : QModuleWidget(Owner, parent)
10  {
11  ui.setupUi(this);
12  }
13 
15  {
16  Init();
17  }
18 
20  {
21  TriggerMode = TriggerModeType::Manual;
22  RepeatCount = 1;
23  DwellTime = std::chrono::milliseconds(100);
24 
26  Samples.clear();
27 
30  Ready = false;
32  }
33 
35  {
37  { "Trigger disabled (start immediately)", Trajectory1DData::TriggerModeType::Continuous },
38  { "Trigger only manually and stop after playback", Trajectory1DData::TriggerModeType::ManualOnce },
39  { "Trigger only manually each time a trigger event occurs", Trajectory1DData::TriggerModeType::Manual },
40  { "Trigger when the trajectory data stream changes", Trajectory1DData::TriggerModeType::OnStreamChanged }
41  };
42 
43  return List;
44  }
45 
47  {
48  try
49  {
50  auto ModuleData = DynExp::dynamic_ModuleData_cast<Trajectory1D>(Instance.ModuleDataGetter());
51 
54 
56  } // ModuleData and instruments' data unlocked here.
57  catch (const Util::TimeoutException& e)
58  {
59  if (NumFailedUpdateAttempts++ >= 3)
60  Instance.GetOwner().SetWarning(e);
61  }
62 
64  }
65 
67  {
69  }
70 
71  std::unique_ptr<DynExp::QModuleWidget> Trajectory1D::MakeUIWidget()
72  {
73  auto Widget = std::make_unique<Trajectory1DWidget>(*this);
74 
75  Connect(Widget->GetUI().BStart, &QPushButton::clicked, this, &Trajectory1D::OnStartClicked);
76  Connect(Widget->GetUI().BStop, &QPushButton::clicked, this, &Trajectory1D::OnStopClicked);
77  Connect(Widget->GetUI().BForce, &QPushButton::clicked, this, &Trajectory1D::OnTriggerClicked);
78 
79  return Widget;
80  }
81 
82  void Trajectory1D::UpdateUIChild(const ModuleBase::ModuleDataGetterType& ModuleDataGetter)
83  {
84  auto Widget = GetWidget<Trajectory1DWidget>();
85  auto ModuleData = DynExp::dynamic_ModuleData_cast<Trajectory1D>(ModuleDataGetter());
86 
87  Widget->GetUI().LESampleCount->setText(QString::number(ModuleData->GetSamples().size()));
88 
89  Widget->GetUI().LProgress->setVisible(ModuleData->IsReady() && ModuleData->GetSamples().size());
90  Widget->GetUI().PBProgress->setVisible(ModuleData->IsReady() && ModuleData->GetSamples().size());
91  Widget->GetUI().LRepetition->setVisible(ModuleData->IsReady() && ModuleData->GetSamples().size());
92  if (ModuleData->GetSamples().size())
93  Widget->GetUI().PBProgress->setValue(static_cast<int>((static_cast<double>(ModuleData->GetCurrentRepeatCount()) / ModuleData->GetRepeatCount() +
94  std::max(0.0, static_cast<double>(ModuleData->GetCurrentPlaybackPos()) - 1.0)
95  / ModuleData->GetRepeatCount() / ModuleData->GetSamples().size()) * 100.0));
96  Widget->GetUI().LRepetition->setText(QString("Repetition ") + QString::number(ModuleData->GetCurrentRepeatCount() + 1)
97  + " / " + QString::number(ModuleData->GetRepeatCount()));
98 
99  Widget->GetUI().BStart->setEnabled(!ModuleData->IsReady());
100  Widget->GetUI().BStop->setEnabled(ModuleData->IsReady());
101  Widget->GetUI().BForce->setEnabled(ModuleData->IsReady());
102  }
103 
105  {
106  auto TrajectoryDataInstrData = DynExp::dynamic_InstrumentData_cast<DynExpInstr::DataStreamInstrument>(ModuleData->GetTrajectoryDataInstr()->GetInstrumentData());
107  auto SampleStream = TrajectoryDataInstrData->GetSampleStream();
108 
109  if (SampleStream->GetNumSamplesWritten() != ModuleData->GetLastWrittenSampleID())
110  {
111  if (SampleStream->GetNumSamplesWritten() < ModuleData->GetLastWrittenSampleID())
112  ModuleData->SetLastWrittenSampleID(0); // e.g. if SampleStream has been cleared.
113 
114  SampleStream->SeekBeg(std::ios_base::in);
115  ModuleData->SetSamples(SampleStream->ReadBasicSamples(SampleStream->GetStreamSizeRead()));
116  ModuleData->SetLastWrittenSampleID(SampleStream->GetNumSamplesWritten());
117 
118  if (ModuleData->GetSamples().empty())
119  return;
120 
121  if (!SampleStream->IsBasicSampleTimeUsed())
122  for (size_t i = 0; i < ModuleData->GetSamples().size(); ++i)
123  ModuleData->GetSamples()[i].Time = static_cast<DynExpInstr::BasicSample::DataType>(ModuleData->GetDwellTime().count())
124  * i / decltype(ModuleData->GetDwellTime())::period::den;
125 
126  switch (ModuleData->GetTriggerMode())
127  {
128  case Trajectory1DData::TriggerModeType::Continuous: [[fallthrough]];
129  case Trajectory1DData::TriggerModeType::OnStreamChanged:
131  break;
132  case Trajectory1DData::TriggerModeType::Manual:
133  ModuleData->SetCurrentPlaybackPos(0);
134  ModuleData->SetCurrentRepeatCount(0);
135  break;
136  default:
137  Stop(ModuleData);
138  }
139  }
140  }
141 
143  {
144  if (!ModuleData->IsReady() || !ModuleData->GetCurrentPlaybackPos())
145  return;
146 
147  std::chrono::system_clock::duration TimeEllapsed;
148  if (ModuleData->GetCurrentPlaybackPos() == 1)
149  {
150  ModuleData->SetTrajectoryStartedTime(std::chrono::system_clock::now());
151  TimeEllapsed = std::chrono::milliseconds(0);
152  }
153  else
154  TimeEllapsed = std::chrono::system_clock::now() - ModuleData->GetTrajectoryStartedTime();
155 
156  const auto& Samples = ModuleData->GetSamples();
157  for (size_t i = ModuleData->GetCurrentPlaybackPos() - 1; i < Samples.size(); ++i)
158  {
159  auto ThisSampleStart = std::chrono::milliseconds(Util::NumToT<std::chrono::milliseconds::rep>(Samples[i].Time * std::chrono::milliseconds::period::den));
160  auto NextSampleStart = i + 1 >= Samples.size() ? std::chrono::milliseconds(0)
161  : std::chrono::milliseconds(Util::NumToT<std::chrono::milliseconds::rep>(Samples[i + 1].Time * std::chrono::milliseconds::period::den));
162 
163  // Move to sample i if time for next, but not for second-next sample has ellapsed or if time for next sample has ellapsed and end of sample list.
164  if ((ThisSampleStart <= TimeEllapsed && NextSampleStart > TimeEllapsed) ||
165  (ThisSampleStart <= TimeEllapsed && i + 1 == Samples.size()))
166  {
167  ModuleData->GetPositionerStage()->MoveAbsolute(Samples[i].Value);
168  ModuleData->SetCurrentPlaybackPos(i + 2);
169 
170  break;
171  }
172  }
173 
174  // End reached? If applicable, retrigger.
175  if (ModuleData->GetCurrentPlaybackPos() > ModuleData->GetSamples().size())
176  {
177  ModuleData->SetCurrentRepeatCount(ModuleData->GetCurrentRepeatCount() + 1);
178  if (ModuleData->GetCurrentRepeatCount() < ModuleData->GetRepeatCount())
179  ModuleData->SetCurrentPlaybackPos(1);
180  else
181  {
182  switch (ModuleData->GetTriggerMode())
183  {
186  break;
187  case Trajectory1DData::TriggerModeType::Manual: [[fallthrough]];
188  case Trajectory1DData::TriggerModeType::OnStreamChanged:
189  ModuleData->SetCurrentPlaybackPos(0);
190  ModuleData->SetCurrentRepeatCount(0);
191  break;
192  default:
193  ModuleData->SetReady(false); // Do not call Stop() to let the positioner complete its motion.
194  }
195  }
196  }
197  }
198 
200  {
201  if (ModuleData->GetSamples().size())
202  {
203  ModuleData->SetReady(true);
204  ModuleData->SetCurrentPlaybackPos(0);
205  ModuleData->SetCurrentRepeatCount(0);
206 
209  }
210  }
211 
213  {
214  ModuleData->GetPositionerStage()->StopMotion();
215  ModuleData->SetReady(false);
216  }
217 
219  {
220  if (ModuleData->IsReady() && ModuleData->GetSamples().size() &&
221  (ModuleData->GetTriggerMode() != Trajectory1DData::TriggerModeType::ManualOnce ||
222  (!ModuleData->GetCurrentPlaybackPos() && !ModuleData->GetCurrentRepeatCount())))
223  {
224  ModuleData->SetCurrentPlaybackPos(1);
225  ModuleData->SetCurrentRepeatCount(0);
226  }
227  }
228 
230  {
234 
235  auto ModuleParams = DynExp::dynamic_Params_cast<Trajectory1D>(Instance->ParamsGetter());
236  auto ModuleData = DynExp::dynamic_ModuleData_cast<Trajectory1D>(Instance->ModuleDataGetter());
237 
238  Instance->LockObject(ModuleParams->TrajectoryDataInstr, ModuleData->GetTrajectoryDataInstr());
239  Instance->LockObject(ModuleParams->PositionerStage, ModuleData->GetPositionerStage());
240  if (ModuleParams->Communicator.ContainsID())
241  Instance->LockObject(ModuleParams->Communicator, ModuleData->GetCommunicator());
242 
243  ModuleData->SetTriggerMode(ModuleParams->TriggerMode);
244  ModuleData->SetRepeatCount(std::max(static_cast<size_t>(1), Util::NumToT<size_t>(ModuleParams->RepeatCount)));
245  ModuleData->SetDwellTime(std::chrono::milliseconds(Util::NumToT<std::chrono::milliseconds::rep>(std::max(1.0, ModuleParams->DwellTime.Get()))));
246 
247  ModuleData->SetReady(ModuleData->GetTriggerMode() != Trajectory1DData::TriggerModeType::ManualOnce);
248  }
249 
251  {
252  auto ModuleData = DynExp::dynamic_ModuleData_cast<Trajectory1D>(Instance->ModuleDataGetter());
253 
254  Stop(ModuleData);
255 
256  Instance->UnlockObject(ModuleData->GetTrajectoryDataInstr());
257  Instance->UnlockObject(ModuleData->GetPositionerStage());
258  Instance->UnlockObject(ModuleData->GetCommunicator());
259 
260  StartEvent::Deregister(*this);
261  StopEvent::Deregister(*this);
263  }
264 
266  {
267  auto ModuleData = DynExp::dynamic_ModuleData_cast<Trajectory1D>(Instance->ModuleDataGetter());
268 
269  Start(ModuleData);
270  }
271 
273  {
274  auto ModuleData = DynExp::dynamic_ModuleData_cast<Trajectory1D>(Instance->ModuleDataGetter());
275 
276  Stop(ModuleData);
277  }
278 
280  {
281  auto ModuleData = DynExp::dynamic_ModuleData_cast<Trajectory1D>(Instance->ModuleDataGetter());
282 
284  }
285 }
Implementation of a module to interpret samples stored in a data stream instrument as trajectories of...
size_t CurrentPlaybackPos
0 means waiting for trigger. Values > 0 mean running. They indicate the sample to be written next.
Definition: Trajectory1D.h:94
DynExpInstr::DataStreamBase::BasicSampleListType Samples
Definition: Trajectory1D.h:92
std::chrono::time_point< std::chrono::system_clock > TrajectoryStartedTime
Definition: Trajectory1D.h:97
void ResetImpl(dispatch_tag< QModuleDataBase >) override final
bool Ready
Running (not necessarily triggered yet) if true.
Definition: Trajectory1D.h:96
std::chrono::milliseconds DwellTime
Definition: Trajectory1D.h:89
static Util::TextValueListType< Trajectory1DData::TriggerModeType > TriggerModeTypeStrList()
Trajectory1DWidget(Trajectory1D &Owner, QModuleWidget *parent=nullptr)
Definition: Trajectory1D.cpp:9
void ResetImpl(dispatch_tag< QModuleBase >) override final
void UpdateStream(Util::SynchronizedPointer< ModuleDataType > &ModuleData)
std::unique_ptr< DynExp::QModuleWidget > MakeUIWidget() override final
Used by InitUI() as a factory function for the module's user interface widget. Create the widget here...
void Start(Util::SynchronizedPointer< ModuleDataType > &ModuleData) const
void OnTriggerClicked(DynExp::ModuleInstance *Instance, bool) const
Definition: Trajectory1D.h:181
void OnTrigger(DynExp::ModuleInstance *Instance) const
void Trigger(Util::SynchronizedPointer< ModuleDataType > &ModuleData) const
void OnInit(DynExp::ModuleInstance *Instance) const override final
This event is triggered right before the module thread starts. Override it to lock instruments this m...
void OnStartClicked(DynExp::ModuleInstance *Instance, bool) const
Definition: Trajectory1D.h:179
void Stop(Util::SynchronizedPointer< ModuleDataType > &ModuleData) const
void OnExit(DynExp::ModuleInstance *Instance) const override final
This event is triggered right before the module thread terminates (not due to an exception,...
void OnStopClicked(DynExp::ModuleInstance *Instance, bool) const
Definition: Trajectory1D.h:180
void OnStop(DynExp::ModuleInstance *Instance) const
Util::DynExpErrorCodes::DynExpErrorCodes ModuleMainLoop(DynExp::ModuleInstance &Instance) override final
Module main loop. The function is executed periodically by the module thread. Also refer to GetMainLo...
void OnStart(DynExp::ModuleInstance *Instance) const
void Move(Util::SynchronizedPointer< ModuleDataType > &ModuleData)
void UpdateUIChild(const ModuleBase::ModuleDataGetterType &ModuleDataGetter) override final
static void Register(const ModuleBase &Listener, CallableT EventFunc)
Registers/Subscribes module Listener to the event with the event function EventFunc....
Definition: Module.h:1028
static void Deregister(const ModuleBase &Listener)
Deregisters/unsubscribes module Listener from the event. Indirectly calls ModuleBase::RemoveRegistere...
Definition: Module.h:1034
const std::unique_ptr< ModuleDataType > ModuleData
Module data belonging to this ModuleBase instance.
Definition: Module.h:743
Refer to ParamsBase::dispatch_tag.
Definition: Module.h:189
Defines data for a thread belonging to a ModuleBase instance. Refer to RunnableInstance.
Definition: Module.h:793
const ModuleBase::ModuleDataGetterType ModuleDataGetter
Getter for module's data. Refer to ModuleBase::ModuleDataGetterType.
Definition: Module.h:825
Refer to ParamsBase::dispatch_tag.
Definition: Object.h:2018
QModuleWidget * Widget
User interface widget belonging to the module.
Definition: Module.h:1491
void Connect(SenderType *Sender, SignalType Signal, ReceiverType *Receiver, EventType Event)
Uses Qt's connect mechanism to connect a QObject's signal to a DynExp module's event....
Definition: Module.h:1500
const Object::ParamsGetterType ParamsGetter
Invoke to obtain the parameters (derived from ParamsBase) of Owner.
Definition: Object.h:3671
void UnlockObject(LinkedObjectWrapperContainer< ObjectT > &ObjectWrapperContainer)
Unlocks an Object instance stored in the LinkedObjectWrapperContainer ObjectWrapperContainer....
Definition: Object.h:3570
void LockObject(const ParamsBase::Param< ObjectLink< ObjectT >> &LinkParam, LinkedObjectWrapperContainer< ObjectT > &ObjectWrapperContainer, std::chrono::milliseconds Timeout=ObjectLinkBase::LockObjectTimeoutDefault)
Locks an Object instance referenced by a parameter LinkParam of type ParamsBase::Param< ObjectLink< O...
Definition: Object.h:3554
const auto & GetOwner() const noexcept
Returns Owner.
Definition: Object.h:3524
Pointer to lock a class derived from ISynchronizedPointerLockable for synchronizing between threads....
Definition: Util.h:170
Thrown when an operation timed out before it could be completed, especially used for locking shared d...
Definition: Exception.h:261
@ Continuous
Run continuously disabling the trigger.
DynExp's module namespace contains the implementation of DynExp modules which extend DynExp's core fu...
DynExpErrorCodes
DynExp's error codes
Definition: Exception.h:22
std::vector< std::pair< TextType, ValueType > > TextValueListType
Type of a list containing key-value pairs where key is a text of type Util::TextType.
Definition: QtUtil.h:37
Accumulates include statements to provide a precompiled header.
double DataType
Data type of time and value.