4 #include "moc_SignalDesigner.cpp"
10 : QModuleWidget(Owner, parent), PulsesContextMenu(new QMenu(this)),
11 AddPulseAction(nullptr), RemovePulseAction(nullptr), ClearPulsesAction(nullptr)
40 if (ModuleData->IsUIInitialized())
44 ModuleData->MinFuncDesc = ModuleData->GetFuncGen()->GetMinCaps();
45 ModuleData->MaxFuncDesc = ModuleData->GetFuncGen()->GetMaxCaps();
46 ModuleData->DefaultFuncDesc = ModuleData->GetFuncGen()->GetParamDefaults();
47 ModuleData->WaveformCaps = ModuleData->GetFuncGen()->GetWaveformCaps();
48 ModuleData->TriggerCaps = ModuleData->GetFuncGen()->GetTriggerCaps();
51 auto InstrData = DynExp::dynamic_InstrumentData_cast<DynExpInstr::FunctionGenerator>(ModuleData->GetFuncGen()->GetInstrumentData());
55 ModuleData->CurrentWaveform = InstrData->GetCurrentWaveformType();
56 ModuleData->CurrentFrequencyInHz = InstrData->GetCurrentFrequencyInHz();
57 ModuleData->CurrentAmplitude = InstrData->GetCurrentAmplitude();
58 ModuleData->CurrentOffset = InstrData->GetCurrentOffset();
59 ModuleData->CurrentPhaseInRad = InstrData->GetCurrentPhaseInRad();
60 ModuleData->CurrentDutyCycle = InstrData->GetCurrentDutyCycle();
61 ModuleData->CurrentPulses = InstrData->GetCurrentPulses();
77 ModuleData->CurrentFrequencyInHz = ModuleData->DefaultFuncDesc.FrequencyInHz;
78 ModuleData->CurrentAmplitude = ModuleData->DefaultFuncDesc.Amplitude;
79 ModuleData->CurrentOffset = ModuleData->DefaultFuncDesc.Offset;
80 ModuleData->CurrentPhaseInRad = 0;
81 ModuleData->CurrentDutyCycle = .5;
82 ModuleData->CurrentPulses.Reset();
85 ModuleData->CurrentTriggerMode = InstrData->GetCurrentTriggerMode();
86 ModuleData->CurrentTriggerEdge = InstrData->GetCurrentTriggerEdge();
87 ModuleData->CurrentAutostart = InstrData->GetShouldAutostart();
90 const QSignalBlocker SBFrequencyInHzBlocker(
ui.SBFrequencyInHz);
91 const QSignalBlocker SBAmplitudeBlocker(
ui.SBAmplitude);
92 const QSignalBlocker SBYOffsetBlocker(
ui.SBYOffset);
93 const QSignalBlocker SBPhaseInDegreeBlocker(
ui.SBPhaseInDegree);
94 const QSignalBlocker SBDutyCycleBlocker(
ui.SBDutyCycle);
95 const QSignalBlocker CBAutostartBlocker(
ui.CBAutostart);
96 const QSignalBlocker TWPulsesBlocker(
ui.TWPulses);
97 const QSignalBlocker CBTriggerModeBlocker(
ui.CBTriggerMode);
98 const QSignalBlocker CBTriggerEdgeBlocker(
ui.CBTriggerEdge);
99 const QSignalBlocker BPersistBlocker(
ui.BPersist);
102 auto SigTypeListView = qobject_cast<QListView*>(
ui.CBSignalType->view());
104 const QSignalBlocker CBSignalTypeBlocker(
ui.CBSignalType);
107 SigTypeListView->setRowHidden(
ui.CBSignalType->findText(
"Sine", Qt::MatchFlag::MatchContains),
111 SigTypeListView->setRowHidden(
ui.CBSignalType->findText(
"Rect", Qt::MatchFlag::MatchContains),
114 SigTypeListView->setRowHidden(
ui.CBSignalType->findText(
"Ramp", Qt::MatchFlag::MatchContains),
118 SigTypeListView->setRowHidden(
ui.CBSignalType->findText(
"Pulse", Qt::MatchFlag::MatchContains),
123 int CBSignalTypeIndex = -1;
125 !SigTypeListView->isRowHidden(
ui.CBSignalType->findText(
"Sine", Qt::MatchFlag::MatchContains)))
126 CBSignalTypeIndex =
ui.CBSignalType->findText(
"Sine", Qt::MatchFlag::MatchContains);
128 !SigTypeListView->isRowHidden(
ui.CBSignalType->findText(
"Rect", Qt::MatchFlag::MatchContains)))
129 CBSignalTypeIndex =
ui.CBSignalType->findText(
"Rect", Qt::MatchFlag::MatchContains);
131 !SigTypeListView->isRowHidden(
ui.CBSignalType->findText(
"Ramp", Qt::MatchFlag::MatchContains)))
132 CBSignalTypeIndex =
ui.CBSignalType->findText(
"Ramp", Qt::MatchFlag::MatchContains);
134 !SigTypeListView->isRowHidden(
ui.CBSignalType->findText(
"Pulse", Qt::MatchFlag::MatchContains)))
135 CBSignalTypeIndex =
ui.CBSignalType->findText(
"Pulse", Qt::MatchFlag::MatchContains);
137 const auto RowHiddenFunc = [SigTypeListView](
int i) {
return SigTypeListView->isRowHidden(i); };
138 const auto SignalTypeIndexRange = std::views::iota(0,
ui.CBSignalType->count());
139 if (std::ranges::all_of(SignalTypeIndexRange, RowHiddenFunc))
140 for (
auto* Widget : this->findChildren<QWidget*>())
141 Widget->setEnabled(
false);
142 else if (CBSignalTypeIndex < 0)
144 auto FirstAvailable = std::ranges::find_if(SignalTypeIndexRange, RowHiddenFunc);
146 if (FirstAvailable != SignalTypeIndexRange.end())
149 ui.CBSignalType->setCurrentIndex(*FirstAvailable);
150 emit
ui.CBSignalType->currentTextChanged(
ui.CBSignalType->currentText());
155 const QSignalBlocker CBSignalTypeBlocker(
ui.CBSignalType);
156 ui.CBSignalType->setCurrentIndex(CBSignalTypeIndex);
160 ui.SBFrequencyInHz->setMinimum(ModuleData->MinFuncDesc.FrequencyInHz);
161 ui.SBFrequencyInHz->setMaximum(ModuleData->MaxFuncDesc.FrequencyInHz);
162 ui.SBFrequencyInHz->setValue(ModuleData->CurrentFrequencyInHz);
167 ui.SBAmplitude->setMinimum(ModuleData->MinFuncDesc.Amplitude);
168 ui.SBAmplitude->setMaximum(ModuleData->MaxFuncDesc.Amplitude);
169 ui.SBAmplitude->setValue(ModuleData->CurrentAmplitude);
170 ui.SBAmplitude->setSuffix(QString(
" ") + ModuleData->GetFuncGen()->GetValueUnitStr());
174 if ((ModuleData->MinFuncDesc.Offset == 0 && ModuleData->MaxFuncDesc.Offset == 0)
177 ui.LYOffset->setVisible(
false);
178 ui.SBYOffset->setVisible(
false);
182 ui.LYOffset->setVisible(
true);
183 ui.SBYOffset->setVisible(
true);
184 ui.SBYOffset->setMinimum(ModuleData->MinFuncDesc.Offset);
185 ui.SBYOffset->setMaximum(ModuleData->MaxFuncDesc.Offset);
186 ui.SBYOffset->setValue(ModuleData->CurrentOffset);
187 ui.SBYOffset->setSuffix(QString(
" ") + ModuleData->GetFuncGen()->GetValueUnitStr());
191 if (ModuleData->GetFuncGen()->IsPhaseAdjustable())
192 ui.SBPhaseInDegree->setValue(ModuleData->CurrentPhaseInRad / std::numbers::pi * 180.0);
195 ui.SBDutyCycle->setValue(ModuleData->CurrentDutyCycle * 100.0);
198 ui.TWPulses->clear();
199 ui.TWPulses->setRowCount(0);
200 ui.TWPulses->setHorizontalHeaderLabels({
"Time [us]",
"Value [" + QString(ModuleData->GetFuncGen()->GetValueUnitStr()) +
"]" });
201 auto OldDelegate =
ui.TWPulses->itemDelegateForColumn(1);
205 OldDelegate->deleteLater();
206 for (
const auto&
Pulse : ModuleData->CurrentPulses.Pulses)
208 ui.TWPulses->insertRow(
ui.TWPulses->rowCount());
215 int CBTriggerModeIndex = 0;
217 CBTriggerModeIndex =
ui.CBTriggerMode->findText(
"Continuous", Qt::MatchFlag::MatchContains);
219 CBTriggerModeIndex =
ui.CBTriggerMode->findText(
"Single", Qt::MatchFlag::MatchContains);
220 else if (ModuleData->CurrentTriggerMode == DynExpInstr::FunctionGeneratorDefs::TriggerDescType::TriggerModeType::ExternStep)
221 CBTriggerModeIndex =
ui.CBTriggerMode->findText(
"Step", Qt::MatchFlag::MatchContains);
222 else if (ModuleData->CurrentTriggerMode == DynExpInstr::FunctionGeneratorDefs::TriggerDescType::TriggerModeType::Manual)
223 CBTriggerModeIndex =
ui.CBTriggerMode->findText(
"Manual", Qt::MatchFlag::MatchContains);
224 ui.CBTriggerMode->setCurrentIndex(CBTriggerModeIndex);
227 ui.CBTriggerEdge->findText(
"Fall", Qt::MatchFlag::MatchContains) :
ui.CBTriggerEdge->findText(
"Rise", Qt::MatchFlag::MatchContains));
232 ui.CBAutostart->setChecked(ModuleData->CurrentAutostart);
233 ui.BPersist->setChecked(ModuleData->CurrentPersistParameters);
235 ModuleData->SetUIInitialized();
245 ui.TWPulses->insertRow(
ui.TWPulses->rowCount());
250 auto SelectedItems =
ui.TWPulses->selectedItems();
251 QSet<int> SelectedRows;
254 for (
const auto Item : SelectedItems)
255 SelectedRows.insert(Item->row());
258 for (
int i = 0; i <
ui.TWPulses->rowCount(); ++i)
259 if (!
ui.TWPulses->item(i, 0) && !
ui.TWPulses->item(i, 1))
260 SelectedRows.insert(i);
262 auto RowsToRemove = SelectedRows.values();
265 std::sort(RowsToRemove.begin(), RowsToRemove.end(), std::greater{});
266 for (
const auto Row : RowsToRemove)
267 ui.TWPulses->removeRow(Row);
272 ui.TWPulses->clearContents();
273 ui.TWPulses->setRowCount(0);
278 ui.TWPulses->sortItems(0, Qt::SortOrder::AscendingOrder);
280 std::vector<double> PulseStarts, PulseAmplitudes;
281 for (
int i = 0; i <
ui.TWPulses->rowCount(); ++i)
284 if (!
ui.TWPulses->item(i, 0))
290 if (!
ui.TWPulses->item(i, 1))
296 PulseStarts.push_back(Start / std::micro::den);
297 PulseAmplitudes.push_back(Amplitude);
300 Pulses = { PulseStarts, PulseAmplitudes };
346 auto InstrData = DynExp::dynamic_InstrumentData_cast<DynExpInstr::FunctionGenerator>(
ModuleData->GetFuncGen()->GetInstrumentData());
347 ModuleData->CurrentStreamSize = InstrData->GetSampleStream()->GetStreamSizeWrite();
358 auto Widget = std::make_unique<SignalDesignerWidget>(*
this);
382 auto Widget = GetWidget<SignalDesignerWidget>();
383 auto ModuleData = DynExp::dynamic_ModuleData_cast<SignalDesigner>(ModuleDataGetter());
385 if (!
Widget->GetUI().CBSource->count())
387 const QSignalBlocker CBSourceBlocker(
Widget->GetUI().CBSource);
389 for (
const auto& FuncGenLabel :
ModuleData->GetFuncGenLabels())
390 Widget->GetUI().CBSource->addItem(QIcon(
ModuleData->GetFuncGenIconPath().data()), QString::fromStdString(FuncGenLabel));
392 Widget->GetUI().CBSource->setCurrentIndex(0);
393 Widget->GetUI().CBSource->setEnabled(
Widget->GetUI().CBSource->count() > 1);
398 if (!
Widget->GetUI().SBStreamSize->hasFocus() &&
ModuleData->CurrentStreamSize <= std::numeric_limits<int>::max())
400 const QSignalBlocker SBStreamSizeBlocker(
Widget->GetUI().SBStreamSize);
401 Widget->GetUI().SBStreamSize->setValue(
static_cast<int>(
ModuleData->CurrentStreamSize));
407 Widget->GetUI().LPhaseInDegree->setVisible(
ModuleData->GetFuncGen()->IsPhaseAdjustable() &&
409 Widget->GetUI().SBPhaseInDegree->setVisible(
ModuleData->GetFuncGen()->IsPhaseAdjustable() &&
420 "Rise/fall ratio" :
"Duty cycle");
423 if (
Widget->HavePulsesChanged())
456 auto ModuleParams = DynExp::dynamic_Params_cast<SignalDesigner>(Instance->
ParamsGetter());
459 ModuleData->LockFunctionGenerators(Instance, ModuleParams->FunctionGenerator);
466 ModuleData->UnlockFunctionGenerators(Instance);
480 if (Text.contains(
"Sine", Qt::CaseSensitivity::CaseInsensitive))
482 else if (Text.contains(
"Ramp", Qt::CaseSensitivity::CaseInsensitive))
484 else if (Text.contains(
"Rect", Qt::CaseSensitivity::CaseInsensitive))
486 else if (Text.contains(
"Pulse", Qt::CaseSensitivity::CaseInsensitive))
500 ModuleData->GetFuncGen()->SetStreamSize(Value);
524 ModuleData->CurrentPhaseInRad = Value / 180.0 * std::numbers::pi;
564 if (Text.contains(
"Single", Qt::CaseSensitivity::CaseInsensitive))
566 else if (Text.contains(
"Step", Qt::CaseSensitivity::CaseInsensitive))
567 ModuleData->CurrentTriggerMode = DynExpInstr::FunctionGeneratorDefs::TriggerDescType::TriggerModeType::ExternStep;
568 else if (Text.contains(
"Manual", Qt::CaseSensitivity::CaseInsensitive))
569 ModuleData->CurrentTriggerMode = DynExpInstr::FunctionGeneratorDefs::TriggerDescType::TriggerModeType::Manual;
580 if (Text.contains(
"Fall", Qt::CaseSensitivity::CaseInsensitive))
591 ModuleData->CurrentAutostart = Value == Qt::CheckState::Checked;
Implementation of a module to design waveforms and to store them in data streams of function generato...
@ LogicLevel
Logic level (TTL) units (1 or 0)
@ Rect
Rectangular waveform.
@ UserDefined
Arbitrary waveform.
@ Pulse
Manually defined pulses.
@ CanForce
Triggering can be forced (executed by the software).
@ CanConfigure
Trigger settings can be adjusted by the software.
DynExpInstr::FunctionGeneratorDefs::PulsesDescType CurrentPulses
DynExpInstr::FunctionGeneratorDefs::FunctionDescType MaxFuncDesc
bool CurrentPersistParameters
DynExpInstr::FunctionGeneratorDefs::TriggerDescType::TriggerEdgeType CurrentTriggerEdge
DynExpInstr::FunctionGeneratorDefs::TriggerDescType::TriggerModeType CurrentTriggerMode
Util::FeatureTester< DynExpInstr::FunctionGenerator::TriggerCapsType > TriggerCaps
DynExpInstr::FunctionGeneratorDefs::WaveformTypes CurrentWaveform
void SetCurrentFuncGenIndex(int Index)
DynExpInstr::FunctionGeneratorDefs::FunctionDescType MinFuncDesc
DynExpInstr::FunctionGeneratorDefs::FunctionDescType DefaultFuncDesc
Util::FeatureTester< DynExpInstr::FunctionGenerator::WaveformCapsType > WaveformCaps
void ResetImpl(dispatch_tag< QModuleDataBase >) override final
double CurrentFrequencyInHz
void OnPhaseChanged(DynExp::ModuleInstance *Instance, double Value) const
void UpdateUIChild(const ModuleBase::ModuleDataGetterType &ModuleDataGetter) override final
void OnForceTrigger(DynExp::ModuleInstance *Instance, bool) const
void OnTriggerModeChanged(DynExp::ModuleInstance *Instance, QString Text) const
void OnSourceChanged(DynExp::ModuleInstance *Instance, int Index) const
void OnSignalTypeChanged(DynExp::ModuleInstance *Instance, QString Text) const
void OnOffsetChanged(DynExp::ModuleInstance *Instance, double Value) 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 OnTriggerEdgeChanged(DynExp::ModuleInstance *Instance, QString Text) 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 ResetImpl(dispatch_tag< QModuleBase >) override final
void OnResetStreamSize(DynExp::ModuleInstance *Instance, bool) const
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 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 OnAmplitudeChanged(DynExp::ModuleInstance *Instance, double Value) const
void OnPersistParametersClicked(DynExp::ModuleInstance *Instance, bool Value) const
void OnAutostartChanged(DynExp::ModuleInstance *Instance, int Value) const
void OnStreamSizeChanged(DynExp::ModuleInstance *Instance, int Value) const
void OnDutyCycleChanged(DynExp::ModuleInstance *Instance, double Value) const
void OnStop(DynExp::ModuleInstance *Instance, bool) const
void OnStart(DynExp::ModuleInstance *Instance, bool) const
void OnFrequencyChanged(DynExp::ModuleInstance *Instance, double Value) const
void OnPulsesChanged(DynExp::ModuleInstance *Instance) const
void UpdateWaveform(Util::SynchronizedPointer< SignalDesignerData > &ModuleData, bool Autostart=false) const
const std::unique_ptr< ModuleDataType > ModuleData
Module data belonging to this ModuleBase instance.
void MakeAndEnqueueEvent(ReceiverType *Receiver, EventType EventFuncPtr, ArgsTs &&...Args) const
Calls MakeEvent() to construct a new event and subsequently enqueues the event into the module's even...
Refer to ParamsBase::dispatch_tag.
Defines data for a thread belonging to a ModuleBase instance. Refer to RunnableInstance.
const ModuleBase::ModuleDataGetterType ModuleDataGetter
Getter for module's data. Refer to ModuleBase::ModuleDataGetterType.
Refer to ParamsBase::dispatch_tag.
QModuleWidget * Widget
User interface widget belonging to the module.
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....
const Object::ParamsGetterType ParamsGetter
Invoke to obtain the parameters (derived from ParamsBase) of Owner.
Implements a QItemDelegate which forces e.g. a QTableWidgetItem's content to be boolean (0 or 1).
Implements a QItemDelegate which forces e.g. a QTableWidgetItem's content to be numeric (double-preci...
Pointer to lock a class derived from ISynchronizedPointerLockable for synchronizing between threads....
@ Rect
Rectangular waveform.
@ Pulse
Manually defined pulses.
@ None
Unspecified/arbitrary waveform.
@ Rise
Trigger on rising edge.
@ Fall
Trigger on falling edge.
@ ExternSingle
Run once after an external trigger signal has been detected.
@ 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
std::string ToStr(const T &Value, int Precision=-1)
Converts a (numeric) value of type T to a std::string using operator<< of std::stringstream.
const QLocale & GetDefaultQtLocale()
Returns the default locale properties to be assigned to Qt widgets.
Accumulates include statements to provide a precompiled header.
void Reset()
Removes all pulse segments from Pulses.