DynExp
Highly flexible laboratory automation for dynamically changing experiments.
Loading...
Searching...
No Matches
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 "ui_Trajectory1D.h"
6#include "Trajectory1D.h"
7
8namespace DynExpModule
9{
11 : QModuleWidget(Owner, parent),
12 ui(std::make_unique<Ui::Trajectory1D>())
13 {
14 ui->setupUi(this);
15 }
16
21
23 {
26 PosMultiplier = 1.0;
27 RepeatCount = 1;
28 DwellTime = std::chrono::milliseconds(100);
29
31 Samples.clear();
32
35 Ready = false;
37 }
38
40 {
42 { "Trigger disabled (start immediately)", Trajectory1DData::TriggerModeType::Continuous },
43 { "Trigger only manually and stop after playback", Trajectory1DData::TriggerModeType::ManualOnce },
44 { "Trigger only manually each time a trigger event occurs", Trajectory1DData::TriggerModeType::Manual },
45 { "Trigger when the trajectory data stream changes", Trajectory1DData::TriggerModeType::OnStreamChanged }
46 };
47
48 return List;
49 }
50
52 {
54 { "Data stream samples are treated as absolute positions", Trajectory1DData::PositioningModeType::Absolute },
55 { "Data stream samples are treated as positions relative to the current positioner position", Trajectory1DData::PositioningModeType::Relative }
56 };
57
58 return List;
59 }
60
62 {
63 try
64 {
65 auto ModuleData = DynExp::dynamic_ModuleData_cast<Trajectory1D>(Instance.ModuleDataGetter());
66
69
71 } // ModuleData and instruments' data unlocked here.
72 catch (const Util::TimeoutException& e)
73 {
74 if (NumFailedUpdateAttempts++ >= 3)
75 Instance.GetOwner().SetWarning(e);
76 }
77
79 }
80
85
86 std::unique_ptr<DynExp::QModuleWidget> Trajectory1D::MakeUIWidget()
87 {
88 auto Widget = std::make_unique<Trajectory1DWidget>(*this);
89
90 Connect(Widget->GetUI()->BStart, &QPushButton::clicked, this, &Trajectory1D::OnStartClicked);
91 Connect(Widget->GetUI()->BStop, &QPushButton::clicked, this, &Trajectory1D::OnStopClicked);
92 Connect(Widget->GetUI()->BForce, &QPushButton::clicked, this, &Trajectory1D::OnTriggerClicked);
93
94 return Widget;
95 }
96
97 void Trajectory1D::UpdateUIChild(const ModuleBase::ModuleDataGetterType& ModuleDataGetter)
98 {
99 auto Widget = GetWidget<Trajectory1DWidget>();
100 auto ModuleData = DynExp::dynamic_ModuleData_cast<Trajectory1D>(ModuleDataGetter());
101
102 Widget->GetUI()->LESampleCount->setText(QString::number(ModuleData->GetSamples().size()));
103
104 Widget->GetUI()->LProgress->setVisible(ModuleData->IsReady() && ModuleData->GetSamples().size());
105 Widget->GetUI()->PBProgress->setVisible(ModuleData->IsReady() && ModuleData->GetSamples().size());
106 Widget->GetUI()->LRepetition->setVisible(ModuleData->IsReady() && ModuleData->GetSamples().size());
107 if (ModuleData->GetSamples().size())
108 Widget->GetUI()->PBProgress->setValue(static_cast<int>((static_cast<double>(ModuleData->GetCurrentRepeatCount()) / ModuleData->GetRepeatCount() +
109 std::max(0.0, static_cast<double>(ModuleData->GetCurrentPlaybackPos()) - 1.0)
110 / ModuleData->GetRepeatCount() / ModuleData->GetSamples().size()) * 100.0));
111 Widget->GetUI()->LRepetition->setText(QString("Repetition ") + QString::number(ModuleData->GetCurrentRepeatCount() + 1)
112 + " / " + QString::number(ModuleData->GetRepeatCount()));
113
114 Widget->GetUI()->BStart->setEnabled(!ModuleData->IsReady());
115 Widget->GetUI()->BStop->setEnabled(ModuleData->IsReady());
116 Widget->GetUI()->BForce->setEnabled(ModuleData->IsReady());
117 }
118
120 {
121 auto TrajectoryDataInstrData = DynExp::dynamic_InstrumentData_cast<DynExpInstr::DataStreamInstrument>(ModuleData->GetTrajectoryDataInstr()->GetInstrumentData());
122 auto SampleStream = TrajectoryDataInstrData->GetSampleStream();
123
124 if (SampleStream->GetNumSamplesWritten() != ModuleData->GetLastWrittenSampleID())
125 {
126 if (SampleStream->GetNumSamplesWritten() < ModuleData->GetLastWrittenSampleID())
127 ModuleData->SetLastWrittenSampleID(0); // e.g. if SampleStream has been cleared.
128
129 SampleStream->SeekBeg(std::ios_base::in);
130 ModuleData->SetSamples(SampleStream->ReadBasicSamples(SampleStream->GetStreamSizeRead()));
131 ModuleData->SetLastWrittenSampleID(SampleStream->GetNumSamplesWritten());
132
133 if (ModuleData->GetSamples().empty())
134 return;
135
136 if (!SampleStream->IsBasicSampleTimeUsed())
137 for (size_t i = 0; i < ModuleData->GetSamples().size(); ++i)
138 ModuleData->GetSamples()[i].Time = static_cast<DynExpInstr::BasicSample::DataType>(ModuleData->GetDwellTime().count())
139 * i / decltype(ModuleData->GetDwellTime())::period::den;
140
141 switch (ModuleData->GetTriggerMode())
142 {
146 break;
148 ModuleData->SetCurrentPlaybackPos(0);
149 ModuleData->SetCurrentRepeatCount(0);
150 break;
151 default:
153 }
154 }
155 }
156
158 {
159 if (!ModuleData->IsReady() || !ModuleData->GetCurrentPlaybackPos())
160 return;
161
162 std::chrono::system_clock::duration TimeEllapsed;
163 if (ModuleData->GetCurrentPlaybackPos() == 1)
164 {
165 ModuleData->SetTrajectoryStartedTime(std::chrono::system_clock::now());
166 TimeEllapsed = std::chrono::milliseconds(0);
167 }
168 else
169 TimeEllapsed = std::chrono::system_clock::now() - ModuleData->GetTrajectoryStartedTime();
170
171 const auto& Samples = ModuleData->GetSamples();
172 for (size_t i = ModuleData->GetCurrentPlaybackPos() - 1; i < Samples.size(); ++i)
173 {
174 auto ThisSampleStart = std::chrono::milliseconds(Util::NumToT<std::chrono::milliseconds::rep>(Samples[i].Time * std::chrono::milliseconds::period::den));
175 auto NextSampleStart = i + 1 >= Samples.size() ? std::chrono::milliseconds(0)
176 : std::chrono::milliseconds(Util::NumToT<std::chrono::milliseconds::rep>(Samples[i + 1].Time * std::chrono::milliseconds::period::den));
177
178 // 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.
179 if ((ThisSampleStart <= TimeEllapsed && NextSampleStart > TimeEllapsed) ||
180 (ThisSampleStart <= TimeEllapsed && i + 1 == Samples.size()))
181 {
182 const auto Dest = Util::NumToT<DynExpInstr::PositionerStageData::PositionType>(Samples[i].Value * ModuleData->GetPosMultiplier());
184 ModuleData->GetPositionerStage()->MoveAbsolute(Dest);
185 else
186 ModuleData->GetPositionerStage()->MoveRelative(Dest);
187
188 ModuleData->SetCurrentPlaybackPos(i + 2);
189
190 break;
191 }
192 }
193
194 // End reached? If applicable, retrigger.
195 if (ModuleData->GetCurrentPlaybackPos() > ModuleData->GetSamples().size())
196 {
197 ModuleData->SetCurrentRepeatCount(ModuleData->GetCurrentRepeatCount() + 1);
198 if (ModuleData->GetCurrentRepeatCount() < ModuleData->GetRepeatCount())
199 ModuleData->SetCurrentPlaybackPos(1);
200 else
201 {
202 switch (ModuleData->GetTriggerMode())
203 {
206 break;
207 case Trajectory1DData::TriggerModeType::Manual: [[fallthrough]];
209 ModuleData->SetCurrentPlaybackPos(0);
210 ModuleData->SetCurrentRepeatCount(0);
211 break;
212 default:
213 ModuleData->SetReady(false); // Do not call Stop() to let the positioner complete its motion.
214 }
215 }
216 }
217 }
218
220 {
221 if (ModuleData->GetSamples().size())
222 {
223 ModuleData->SetReady(true);
224 ModuleData->SetCurrentPlaybackPos(0);
225 ModuleData->SetCurrentRepeatCount(0);
226
229 }
230 }
231
233 {
234 ModuleData->GetPositionerStage()->StopMotion();
235 ModuleData->SetReady(false);
236 }
237
239 {
240 if (ModuleData->IsReady() && ModuleData->GetSamples().size() &&
242 (!ModuleData->GetCurrentPlaybackPos() && !ModuleData->GetCurrentRepeatCount())))
243 {
244 ModuleData->SetCurrentPlaybackPos(1);
245 ModuleData->SetCurrentRepeatCount(0);
246 }
247 }
248
250 {
254
255 auto ModuleParams = DynExp::dynamic_Params_cast<Trajectory1D>(Instance->ParamsGetter());
256 auto ModuleData = DynExp::dynamic_ModuleData_cast<Trajectory1D>(Instance->ModuleDataGetter());
257
258 Instance->LockObject(ModuleParams->TrajectoryDataInstr, ModuleData->GetTrajectoryDataInstr());
259 Instance->LockObject(ModuleParams->PositionerStage, ModuleData->GetPositionerStage());
260 if (ModuleParams->Communicator.ContainsID())
261 Instance->LockObject(ModuleParams->Communicator, ModuleData->GetCommunicator());
262
263 ModuleData->SetTriggerMode(ModuleParams->TriggerMode);
264 ModuleData->SetPositioningMode(ModuleParams->PositioningMode);
265 ModuleData->SetPosMultiplier(ModuleParams->PosMultiplier);
266 ModuleData->SetRepeatCount(std::max(static_cast<size_t>(1), Util::NumToT<size_t>(ModuleParams->RepeatCount)));
267 ModuleData->SetDwellTime(std::chrono::milliseconds(Util::NumToT<std::chrono::milliseconds::rep>(std::max(1.0, ModuleParams->DwellTime.Get()))));
268
270 }
271
273 {
274 auto ModuleData = DynExp::dynamic_ModuleData_cast<Trajectory1D>(Instance->ModuleDataGetter());
275
277
278 Instance->UnlockObject(ModuleData->GetTrajectoryDataInstr());
279 Instance->UnlockObject(ModuleData->GetPositionerStage());
280 Instance->UnlockObject(ModuleData->GetCommunicator());
281
285 }
286
288 {
289 auto ModuleData = DynExp::dynamic_ModuleData_cast<Trajectory1D>(Instance->ModuleDataGetter());
290
292 }
293
295 {
296 auto ModuleData = DynExp::dynamic_ModuleData_cast<Trajectory1D>(Instance->ModuleDataGetter());
297
299 }
300
302 {
303 auto ModuleData = DynExp::dynamic_ModuleData_cast<Trajectory1D>(Instance->ModuleDataGetter());
304
306 }
307}
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.
DynExpInstr::DataStreamBase::BasicSampleListType Samples
std::chrono::time_point< std::chrono::system_clock > TrajectoryStartedTime
PositioningModeType PositioningMode
void ResetImpl(dispatch_tag< QModuleDataBase >) override final
bool Ready
Running (not necessarily triggered yet) if true.
std::chrono::milliseconds DwellTime
static Util::TextValueListType< Trajectory1DData::PositioningModeType > PositioningModeTypeStrList()
static Util::TextValueListType< Trajectory1DData::TriggerModeType > TriggerModeTypeStrList()
std::unique_ptr< Ui::Trajectory1D > ui
Trajectory1DWidget(Trajectory1D &Owner, QModuleWidget *parent=nullptr)
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
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
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
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, ItemIDType CommunicatorID=ItemIDNotSet)
Registers/Subscribes module Listener to the event with the event function EventFunc....
Definition Module.h:1262
static void Deregister(const ModuleBase &Listener)
Deregisters/unsubscribes module Listener from the event, regardless of the inter-module communicator ...
Definition Module.h:1271
const std::unique_ptr< ModuleDataType > ModuleData
Module data belonging to this ModuleBase instance.
Definition Module.h:788
Refer to ParamsBase::dispatch_tag.
Definition Module.h:191
Defines data for a thread belonging to a ModuleBase instance. Refer to RunnableInstance.
Definition Module.h:840
const ModuleBase::ModuleDataGetterType ModuleDataGetter
Getter for module's data. Refer to ModuleBase::ModuleDataGetterType.
Definition Module.h:872
Refer to ParamsBase::dispatch_tag.
Definition Object.h:2018
QModuleWidget * Widget
User interface widget belonging to the module.
Definition Module.h:1807
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:1816
const Object::ParamsGetterType ParamsGetter
Invoke to obtain the parameters (derived from ParamsBase) of Owner.
Definition Object.h:3710
void UnlockObject(LinkedObjectWrapperContainer< ObjectT > &ObjectWrapperContainer)
Unlocks an Object instance stored in the LinkedObjectWrapperContainer ObjectWrapperContainer....
Definition Object.h:3609
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:3593
const auto & GetOwner() const noexcept
Returns Owner.
Definition Object.h:3556
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:262
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.