summaryrefslogtreecommitdiffstats
path: root/clients
diff options
context:
space:
mode:
authorTimothy Pearson <kb9vqf@pearsoncomputing.net>2015-09-12 19:56:53 -0500
committerTimothy Pearson <kb9vqf@pearsoncomputing.net>2015-09-12 19:56:53 -0500
commit5d4ae8c1ec03ba409ad3aa37310ca6aa162f454b (patch)
tree56e82088afadb5726cd6abbd704b14a608954e54 /clients
parenta4eb3d14df4d5c3bb2067bdfdb2c93cce7828a71 (diff)
downloadulab-5d4ae8c1ec03ba409ad3aa37310ca6aa162f454b.tar.gz
ulab-5d4ae8c1ec03ba409ad3aa37310ca6aa162f454b.zip
Add inital component analyzer part
Fix a couple of Kerberos socket class threading problems Stop drawing garbage in trace viewer when trace data partially intialized Add FloatSpinBox explicit data accessor
Diffstat (limited to 'clients')
-rw-r--r--clients/tde/src/part/Makefile.am2
-rw-r--r--clients/tde/src/part/companalyzer/Makefile.am12
-rw-r--r--clients/tde/src/part/companalyzer/hi16-action-libremotelab_companalyzer.pngbin0 -> 749 bytes
-rw-r--r--clients/tde/src/part/companalyzer/layout.ui488
-rwxr-xr-xclients/tde/src/part/companalyzer/part.cpp1406
-rw-r--r--clients/tde/src/part/companalyzer/part.h260
-rw-r--r--clients/tde/src/widgets/floatspinbox.cpp10
-rw-r--r--clients/tde/src/widgets/floatspinbox.h3
-rwxr-xr-x[-rw-r--r--]clients/tde/src/widgets/sevensegment.cpp78
-rw-r--r--clients/tde/src/widgets/tracewidget.cpp9
10 files changed, 2242 insertions, 26 deletions
diff --git a/clients/tde/src/part/Makefile.am b/clients/tde/src/part/Makefile.am
index 2e4b01a..7c3f426 100644
--- a/clients/tde/src/part/Makefile.am
+++ b/clients/tde/src/part/Makefile.am
@@ -1 +1 @@
-SUBDIRS = scope logicanalyzer commanalyzer fpgaview fpgaprogram sensormonitor adminconsole adminusermgmt serialconsole prototerminal
+SUBDIRS = scope logicanalyzer commanalyzer companalyzer fpgaview fpgaprogram sensormonitor adminconsole adminusermgmt serialconsole prototerminal
diff --git a/clients/tde/src/part/companalyzer/Makefile.am b/clients/tde/src/part/companalyzer/Makefile.am
new file mode 100644
index 0000000..67e4865
--- /dev/null
+++ b/clients/tde/src/part/companalyzer/Makefile.am
@@ -0,0 +1,12 @@
+INCLUDES = $(all_includes) -I$(top_srcdir)/src -I$(top_srcdir)/src/widgets $(KDE_INCLUDES)/tde
+KDE_CXXFLAGS = $(USE_EXCEPTIONS)
+METASOURCES = AUTO
+
+KDE_ICON = libremotelab_companalyzer
+
+#Part
+kde_module_LTLIBRARIES = libremotelab_companalyzer.la
+libremotelab_companalyzer_la_LIBADD = ../../widgets/libtracewidget.la ../../widgets/libfloatspinbox.la ../../widgets/libsevensegment.la $(LIB_KFILE) $(LIB_TDEPARTS) $(LIB_TDEUI) $(LIB_QT)
+libremotelab_companalyzer_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) -ltdecore -ltdeui -ltdeio -ltdefx -ltdekrbsocket -ltqtrla
+libremotelab_companalyzer_la_SOURCES = \
+ part.cpp layout.ui
diff --git a/clients/tde/src/part/companalyzer/hi16-action-libremotelab_companalyzer.png b/clients/tde/src/part/companalyzer/hi16-action-libremotelab_companalyzer.png
new file mode 100644
index 0000000..937a414
--- /dev/null
+++ b/clients/tde/src/part/companalyzer/hi16-action-libremotelab_companalyzer.png
Binary files differ
diff --git a/clients/tde/src/part/companalyzer/layout.ui b/clients/tde/src/part/companalyzer/layout.ui
new file mode 100644
index 0000000..4523b6b
--- /dev/null
+++ b/clients/tde/src/part/companalyzer/layout.ui
@@ -0,0 +1,488 @@
+<!DOCTYPE UI><UI version="3.0" stdsetdef="1">
+ <class>CompAnalyzerBase</class>
+ <widget class="TQWidget">
+ <property name="name">
+ <cstring>CompAnalyzerBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>519</width>
+ <height>356</height>
+ </rect>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQLayoutWidget" row="0" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>unnamed_layout</cstring>
+ </property>
+ <grid>
+ <widget class="TQGroupBox" row="0" column="0">
+ <property name="name">
+ <cstring>groupParameterADisplay</cstring>
+ </property>
+ <property name="title">
+ <string>Parameter A:</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed_grid</cstring>
+ </property>
+ <widget class="Display7SegmentArray" row="0" column="0">
+ <property name="name">
+ <cstring>parameterADisplay</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="TQGroupBox" row="0" column="1">
+ <property name="name">
+ <cstring>groupParameterBDisplay</cstring>
+ </property>
+ <property name="title">
+ <string>Parameter B:</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed_grid</cstring>
+ </property>
+ <widget class="Display7SegmentArray" row="0" column="0">
+ <property name="name">
+ <cstring>parameterBDisplay</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="TQGroupBox" row="0" column="2">
+ <property name="name">
+ <cstring>groupFrequencyDisplay</cstring>
+ </property>
+ <property name="title">
+ <string>Frequency:</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed_grid</cstring>
+ </property>
+ <widget class="Display7SegmentArray" row="0" column="0">
+ <property name="name">
+ <cstring>frequencyDisplay</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="TQLayoutWidget" row="1" column="0" rowspan="1" colspan="1">
+ <property name="name">
+ <cstring>unnamed_layout</cstring>
+ </property>
+ <grid>
+ <widget class="TQGroupBox" row="1" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>groupMonitorView</cstring>
+ </property>
+ <property name="title">
+ <string>Trace Viewer</string>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQSplitter" row="0" column="0" colspan="1">
+ <property name="name">
+ <cstring>splitter1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <widget class="TraceWidget" row="0" column="0" colspan="1">
+ <property name="name">
+ <cstring>traceWidget</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ </widget>
+ <widget class="TraceWidget" row="1" column="0" colspan="1">
+ <property name="name">
+ <cstring>traceZoomWidget</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ </widget>
+ </widget>
+ </grid>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="TQGroupBox" row="1" column="1">
+ <property name="name">
+ <cstring>groupControl</cstring>
+ </property>
+ <property name="title">
+ <string>Controls</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQGroupBox" row="0" column="1">
+ <property name="name">
+ <cstring>groupMonitorCaptureControls</cstring>
+ </property>
+ <property name="title">
+ <string>Capture Controls</string>
+ </property>
+ <grid>
+ <widget class="TQLabel" row="0" column="0" colspan="1">
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="text">
+ <string>Parameter A:</string>
+ </property>
+ </widget>
+ <widget class="TQComboBox" row="0" column="1" colspan="1">
+ <property name="name">
+ <cstring>parameterASourceCombo</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="TQLabel" row="1" column="0" colspan="1">
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="text">
+ <string>Parameter B:</string>
+ </property>
+ </widget>
+ <widget class="TQComboBox" row="1" column="1" colspan="1">
+ <property name="name">
+ <cstring>parameterBSourceCombo</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="TQLabel" row="2" column="0" colspan="1">
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="text">
+ <string>Frequency:</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ <widget class="FloatSpinBox" row="2" column="1" colspan="1">
+ <property name="name">
+ <cstring>measurementFrequencyBox</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>80</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maxValue">
+ <number>1</number>
+ </property>
+ <property name="minValue">
+ <number>1</number>
+ </property>
+ <property name="value">
+ <number>1</number>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="TQGroupBox" row="1" column="1">
+ <property name="name">
+ <cstring>groupSweepControls</cstring>
+ </property>
+ <property name="title">
+ <string>Sweep Configuration</string>
+ </property>
+ <grid>
+ <widget class="TQLabel" row="0" column="0" colspan="1">
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="text">
+ <string>Start Frequency:</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ <widget class="FloatSpinBox" row="0" column="1" colspan="1">
+ <property name="name">
+ <cstring>sweepStartFrequencyBox</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>80</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maxValue">
+ <number>1</number>
+ </property>
+ <property name="minValue">
+ <number>1</number>
+ </property>
+ <property name="value">
+ <number>1</number>
+ </property>
+ </widget>
+ <widget class="TQLabel" row="1" column="0" colspan="1">
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="text">
+ <string>End Frequency:</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ <widget class="FloatSpinBox" row="1" column="1" colspan="1">
+ <property name="name">
+ <cstring>sweepEndFrequencyBox</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>80</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maxValue">
+ <number>1</number>
+ </property>
+ <property name="minValue">
+ <number>1</number>
+ </property>
+ <property name="value">
+ <number>1</number>
+ </property>
+ </widget>
+ <widget class="TQLabel" row="2" column="0" colspan="1">
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="text">
+ <string>Step Frequency:</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ <widget class="FloatSpinBox" row="2" column="1" colspan="1">
+ <property name="name">
+ <cstring>sweepStepFrequencyBox</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>80</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maxValue">
+ <number>1</number>
+ </property>
+ <property name="minValue">
+ <number>1</number>
+ </property>
+ <property name="value">
+ <number>1</number>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="TQGroupBox" row="2" column="1">
+ <property name="name">
+ <cstring>groupAcquisitionControls</cstring>
+ </property>
+ <property name="title">
+ <string>Acquisition Controls</string>
+ </property>
+ <grid>
+ <widget class="TQPushButton" row="0" column="0" colspan="1">
+ <property name="name">
+ <cstring>sweepStartButton</cstring>
+ </property>
+ <property name="text">
+ <string>Start Sweep</string>
+ </property>
+ </widget>
+ <widget class="TQPushButton" row="0" column="1" colspan="1">
+ <property name="name">
+ <cstring>sweepStopButton</cstring>
+ </property>
+ <property name="text">
+ <string>Stop Sweep</string>
+ </property>
+ </widget>
+ <widget class="TQPushButton" row="1" column="0" colspan="1">
+ <property name="name">
+ <cstring>waveformSave</cstring>
+ </property>
+ <property name="text">
+ <string>Save Waveforms</string>
+ </property>
+ </widget>
+ <widget class="TQPushButton" row="1" column="1" colspan="1">
+ <property name="name">
+ <cstring>waveformRecall</cstring>
+ </property>
+ <property name="text">
+ <string>Recall Waveforms</string>
+ </property>
+ </widget>
+ <widget class="TQCheckBox" row="2" column="0" colspan="2">
+ <property name="name">
+ <cstring>autoSave</cstring>
+ </property>
+ <property name="text">
+ <string>Enable Automatic Saving</string>
+ </property>
+ </widget>
+ <widget class="KURLRequester" row="3" column="0" colspan="2">
+ <property name="name">
+ <cstring>autoSaveFile</cstring>
+ </property>
+ <property name="mode">
+ <number>25</number>
+ </property>
+ <property name="filter">
+ <cstring>*.wfm|Waveform Files (*.wfm)</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="TQGroupBox" row="3" column="1">
+ <property name="name">
+ <cstring>groupTestNotes</cstring>
+ </property>
+ <property name="title">
+ <string>Notes</string>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>3</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <grid>
+ <widget class="KTextEdit" row="0" column="0" colspan="1">
+ <property name="name">
+ <cstring>userNotes</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>3</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </grid>
+ </widget>
+ </grid>
+ </widget>
+ <includes>
+ <include location="local" impldecl="in implementation">CompAnalyzerBase.ui.h</include>
+ </includes>
+ <includes>
+ <include location="local" impldecl="in implementation">tracewidget.h</include>
+ <include location="local" impldecl="in implementation">floatspinbox.h</include>
+ <include location="local" impldecl="in implementation">sevensegment.h</include>
+ </includes>
+ <layoutdefaults spacing="3" margin="6"/>
+ <layoutfunctions spacing="KDialog::spacingHint" margin="KDialog::marginHint"/>
+</UI>
diff --git a/clients/tde/src/part/companalyzer/part.cpp b/clients/tde/src/part/companalyzer/part.cpp
new file mode 100755
index 0000000..66eb188
--- /dev/null
+++ b/clients/tde/src/part/companalyzer/part.cpp
@@ -0,0 +1,1406 @@
+/*
+ * Remote Laboratory Component Analyzer Part
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (c) 2014 - 2015 Timothy Pearson
+ * Raptor Engineering
+ * http://www.raptorengineeringinc.com
+ */
+
+#include "define.h"
+#include "part.h"
+
+#include <tdeaboutdata.h> //::createAboutData()
+#include <tdeaction.h>
+#include <tdelocale.h>
+#include <tdemessagebox.h> //::start()
+#include <tdeparts/genericfactory.h>
+#include <kurlrequester.h>
+#include <tdefiledialog.h>
+#include <kstatusbar.h>
+#include <kstdaction.h>
+#include <tqfile.h> //encodeName()
+#include <tqtimer.h>
+#include <tqvbox.h>
+#include <tqsocket.h>
+#include <tqmutex.h>
+#include <tqeventloop.h>
+#include <tqapplication.h>
+#include <tqpushbutton.h>
+#include <tqcombobox.h>
+#include <tqcheckbox.h>
+#include <klineedit.h>
+#include <ktextedit.h>
+#include <unistd.h> //access()
+#include <stdint.h>
+#include <cmath>
+
+#include "layout.h"
+
+#include "tracewidget.h"
+#include "floatspinbox.h"
+
+#define NETWORK_COMM_TIMEOUT_MS 15000
+
+/* exception handling */
+struct exit_exception {
+ int c;
+ exit_exception(int c):c(c) { }
+};
+
+namespace RemoteLab {
+
+typedef KParts::GenericFactory<RemoteLab::CompAnalyzerPart> Factory;
+#define CLIENT_LIBRARY "libremotelab_companalyzer"
+K_EXPORT_COMPONENT_FACTORY( libremotelab_companalyzer, RemoteLab::Factory )
+
+#ifndef QT_NO_DATASTREAM
+TQDataStream &operator<<( TQDataStream &s, const CompAnalyzerMeasurement &data ) {
+ s << data.status;
+ s << data.parameter;
+ s << data.type;
+ s << data.value;
+ s << data.frequency;
+ return s;
+}
+
+TQDataStream &operator>>( TQDataStream &s, CompAnalyzerMeasurement &data ) {
+ s >> data.status;
+ s >> data.parameter;
+ s >> data.type;
+ s >> data.value;
+ s >> data.frequency;
+ return s;
+}
+#endif
+
+CompAnalyzerWorker::CompAnalyzerWorker() : TQObject() {
+ m_sweepStepMutex = new TQMutex(false);
+ m_currentStateMutex = new TQMutex(false);
+ m_networkDataMutex = new TQMutex(false);
+ m_outboundQueueMutex = new TQMutex(false);
+ m_inboundQueueMutex = new TQMutex(false);
+ m_newData = false;
+ m_currentState = Initializing;
+ m_startupState = StartSelectInstrument;
+ m_lastNetworkTransmissionEvent = NoEvent;
+}
+
+CompAnalyzerWorker::~CompAnalyzerWorker() {
+ delete m_sweepStepMutex;
+ m_sweepStepMutex = NULL;
+ delete m_currentStateMutex;
+ m_currentStateMutex = NULL;
+ delete m_networkDataMutex;
+ m_networkDataMutex = NULL;
+ delete m_inboundQueueMutex;
+ m_inboundQueueMutex = NULL;
+ delete m_outboundQueueMutex;
+ m_outboundQueueMutex = NULL;
+}
+
+void CompAnalyzerWorker::run() {
+ TQEventLoop* eventLoop = TQApplication::eventLoop();
+ if (!eventLoop) {
+ return;
+ }
+
+ while (1) {
+ m_instrumentMutex->lock();
+
+ CompAnalyzerPartState state = currentState();
+ CompAnalyzerEventType lastTxEvent = m_lastNetworkTransmissionEvent;
+
+ // Handle inbound queue
+ m_inboundQueueMutex->lock();
+ if (m_inboundQueue.count() > 0) {
+ TQDataStream ds(m_socket);
+ ds.setPrintableData(true);
+
+ CompAnalyzerEventQueue::iterator it;
+ for (it = m_inboundQueue.begin(); it != m_inboundQueue.end(); ++it) {
+ if ((*it).first == TxRxSyncPoint) {
+ break;
+ }
+ else if ((*it).first == Initialize) {
+ setCurrentState(Initializing);
+ m_lastNetworkTransmissionEvent = OtherEvent;
+ ds << TQString("COMPONENT ANALYZER");
+ m_socket->writeEndOfFrame();
+ it = m_inboundQueue.erase(it);
+ }
+ else if ((*it).first == GetMeasurement) {
+ m_lastNetworkTransmissionEvent = GetMeasurement;
+ ds << TQString("GETMEASUREMENT");
+ m_socket->writeEndOfFrame();
+ it = m_inboundQueue.erase(it);
+ }
+ else if ((*it).first == GetMaximumFrequency) {
+ m_lastNetworkTransmissionEvent = GetMaximumFrequency;
+ ds << TQString("GETMAXMEASUREMENTFREQUENCY");
+ m_socket->writeEndOfFrame();
+ it = m_inboundQueue.erase(it);
+ }
+ else if ((*it).first == GetMinimumFrequency) {
+ m_lastNetworkTransmissionEvent = GetMinimumFrequency;
+ ds << TQString("GETMINMEASUREMENTFREQUENCY");
+ m_socket->writeEndOfFrame();
+ it = m_inboundQueue.erase(it);
+ }
+ else if ((*it).first == SetFrequency) {
+ m_lastNetworkTransmissionEvent = SetFrequency;
+ ds << TQString("SETMEASUREMENTFREQUENCY");
+ ds << (*it).second.toDouble();
+ m_socket->writeEndOfFrame();
+ it = m_inboundQueue.erase(it);
+ }
+ else if ((*it).first == ChangeMeasurementSource) {
+ m_lastNetworkTransmissionEvent = ChangeMeasurementSource;
+ TQ_UINT8 number_of_parameters = 2;
+ ds << TQString("SETMEASUREDPARAMETERS");
+ ds << number_of_parameters;
+ ds << m_sourceList[0];
+ ds << m_sourceList[1];
+ m_socket->writeEndOfFrame();
+ it = m_inboundQueue.erase(it);
+ }
+
+ // If the next command is a sync point stop command list execution
+ if ((*it).first == TxRxSyncPoint) {
+ break;
+ }
+ }
+ m_socket->flush();
+ }
+ m_inboundQueueMutex->unlock();
+
+ // Handle outbound queue
+ if (m_newData) {
+ bool queue_modified = false;
+ m_networkDataMutex->lock();
+ m_newData = false;
+
+ // Receive data
+ if (m_socket->canReadFrame()) {
+ TQDataStream ds(m_socket);
+ ds.setPrintableData(true);
+
+ while (!ds.atEnd() && m_socket->canReadFrame(false)) {
+ // Get command status
+ TQString input;
+ ds >> input;
+
+ if (input == "") {
+ continue;
+ }
+
+ // Response received
+ clearInboundQueueSyncPoint();
+
+ if (state == Initializing) {
+ if (input == "ACK") {
+ if (m_startupState == StartSelectInstrument) {
+ m_startupState = StartGetMaximumFrequency;
+ appendItemToInboundQueue(CompAnalyzerEvent(GetMaximumFrequency, TQVariant()), true);
+ }
+ else if (m_startupState == StartGetMaximumFrequency) {
+ ds >> m_instrumentLimits.maxFrequency;
+
+ m_startupState = StartGetMinimumFrequency;
+ appendItemToInboundQueue(CompAnalyzerEvent(GetMinimumFrequency, TQVariant()), true);
+ }
+ else if (m_startupState == StartGetMinimumFrequency) {
+ ds >> m_instrumentLimits.minFrequency;
+
+ // TODO
+ // This should be loaded from the instrument
+ // Add requisite functionality to the GPIB server and then
+ // update this routine to use it....
+ m_instrumentLimits.allowedMeasurements.clear();
+ AllowedMeasurementInfoList parameterASourceValues;
+ parameterASourceValues.append(AllowedMeasurementInfo(0, i18n("Resistance")));
+ parameterASourceValues.append(AllowedMeasurementInfo(2, i18n("Conductance")));
+ parameterASourceValues.append(AllowedMeasurementInfo(4, i18n("Inductance")));
+ parameterASourceValues.append(AllowedMeasurementInfo(5, i18n("Capacitance")));
+ parameterASourceValues.append(AllowedMeasurementInfo(8, i18n("Impedance")));
+ parameterASourceValues.append(AllowedMeasurementInfo(9, i18n("Admittance")));
+ parameterASourceValues.append(AllowedMeasurementInfo(10, i18n("Reflection Coefficient (Absolute)")));
+ parameterASourceValues.append(AllowedMeasurementInfo(11, i18n("Reflection Coefficient (X)")));
+ AllowedMeasurementInfoList parameterBSourceValues;
+ parameterBSourceValues.append(AllowedMeasurementInfo(0, i18n("Resistance")));
+ parameterBSourceValues.append(AllowedMeasurementInfo(2, i18n("Conductance")));
+ parameterBSourceValues.append(AllowedMeasurementInfo(6, i18n("Dissipation Factor")));
+ parameterBSourceValues.append(AllowedMeasurementInfo(7, i18n("Quality Factor")));
+ parameterBSourceValues.append(AllowedMeasurementInfo(13, i18n("Phase Angle (°)")));
+ parameterBSourceValues.append(AllowedMeasurementInfo(14, i18n("Phase Angle (radians)")));
+ m_instrumentLimits.allowedMeasurements.append(parameterASourceValues);
+ m_instrumentLimits.allowedMeasurements.append(parameterBSourceValues);
+
+ m_startupState = StartDone;
+ setCurrentState(FreeRunning);
+
+ // Request first measurement
+ appendItemToInboundQueue(CompAnalyzerEvent(GetMeasurement, TQVariant()), true);
+
+ // Notify GUI that new configuration data is available
+ m_outboundQueueMutex->lock();
+ m_outboundQueue.push_back(CompAnalyzerEvent(ConfigurationDataReceived, TQVariant()));
+ m_outboundQueueMutex->unlock();
+ }
+ }
+ else {
+ setCurrentState(CommunicationFailure);
+ }
+ queue_modified = true;
+ }
+ else if ((state == FreeRunning) || (state == FrequencySweepRead)) {
+ if (input == "ACK") {
+ if (lastTxEvent == GetMeasurement) {
+ int i;
+ CompAnalyzerMeasurement measurement;
+ CompAnalyzerMeasurementList measurements;
+ TQ_UINT8 number_of_parameters;
+ ds >> number_of_parameters;
+ for (i=0; i < number_of_parameters; i++) {
+ ds >> measurement.status;
+ ds >> measurement.parameter;
+ ds >> measurement.type;
+ ds >> measurement.value;
+ ds >> measurement.frequency;
+ measurements.append(measurement);
+ }
+
+ if (nextInboundQueueEvent() == StartSweep) {
+ eraseNextInboundQueueEvent(true);
+
+ // Set initial sweep frequency
+ m_sweepCurrentFrequency = m_sweepStart;
+ m_sweepStepMutex->lock();
+ m_sweepStepNumber = 0;
+ m_sweepStepMutex->unlock();
+ appendItemToInboundQueue(CompAnalyzerEvent(SetFrequency, TQVariant(m_sweepCurrentFrequency)), true);
+ setCurrentState(FrequencySweepWrite);
+ }
+ else if (nextInboundQueueEvent() == AbortSweep) {
+ eraseNextInboundQueueEvent(true);
+
+ // Exit sweep mode
+ setCurrentState(FreeRunning);
+
+ // Request measurement
+ appendItemToInboundQueue(CompAnalyzerEvent(GetMeasurement, TQVariant()), true);
+ }
+ else {
+ if (state == FrequencySweepRead) {
+ // Set up next measurement frequency
+ m_sweepCurrentFrequency += m_sweepStep;
+ m_sweepStepMutex->lock();
+ m_sweepStepNumber++;
+ m_sweepStepMutex->unlock();
+
+ if (m_sweepCurrentFrequency <= m_sweepEnd) {
+ // Set next sweep frequency step
+ appendItemToInboundQueue(CompAnalyzerEvent(SetFrequency, TQVariant(m_sweepCurrentFrequency)), true);
+ setCurrentState(FrequencySweepWrite);
+ }
+ else {
+ // Exit sweep mode
+ setCurrentState(FreeRunning);
+
+ // Request measurement
+ appendItemToInboundQueue(CompAnalyzerEvent(GetMeasurement, TQVariant()), true);
+ }
+ }
+ else {
+ // Request another measurement
+ appendItemToInboundQueue(CompAnalyzerEvent(GetMeasurement, TQVariant()), true);
+ }
+ }
+
+ // Send data to GUI
+ TQByteArray measurementStreamData;
+ {
+ TQDataStream measurementStream(measurementStreamData, IO_WriteOnly);
+ measurementStream << measurements;
+ measurementStream << m_sweepStepNumber - 1;
+ }
+ m_outboundQueueMutex->lock();
+ if (state == FrequencySweepRead) {
+ m_outboundQueue.push_back(CompAnalyzerEvent(SweepMeasurementsReceived, TQVariant(measurementStreamData)));
+ }
+ else {
+ m_outboundQueue.push_back(CompAnalyzerEvent(MeasurementsReceived, TQVariant(measurementStreamData)));
+ }
+ m_outboundQueueMutex->unlock();
+ }
+ }
+ else if (input.startsWith("EXT")) {
+ // Extended error
+ TQString extendedError = input.remove(0, 3);
+ m_outboundQueue.push_back(CompAnalyzerEvent(ExtendedErrorReceived, TQVariant(extendedError)));
+ setCurrentState(CommunicationFailure);
+ }
+ else {
+ setCurrentState(CommunicationFailure);
+ }
+ queue_modified = true;
+ }
+ else if ((state == FreeRunning) || (state == FrequencySweepWrite)) {
+ // Request another measurement
+ appendItemToInboundQueue(CompAnalyzerEvent(GetMeasurement, TQVariant()), true);
+ setCurrentState(FrequencySweepRead);
+ }
+ m_socket->clearFrameTail();
+ }
+ }
+ m_networkDataMutex->unlock();
+
+ if (queue_modified) {
+ emit(outboundQueueUpdated());
+ }
+ }
+
+ m_instrumentMutex->unlock();
+
+ // Wait for queue status change or new network activity
+ if (!eventLoop->processEvents(TQEventLoop::ExcludeUserInput)) {
+ eventLoop->processEvents(TQEventLoop::ExcludeUserInput | TQEventLoop::WaitForMore);
+ }
+ }
+
+ eventLoop->exit(0);
+}
+
+void CompAnalyzerWorker::resetInboundQueue() {
+ m_inboundQueueMutex->lock();
+ m_inboundQueue.clear();
+ m_inboundQueueMutex->unlock();
+}
+
+void CompAnalyzerWorker::appendItemToInboundQueue(CompAnalyzerEvent item, bool syncPoint) {
+ m_inboundQueueMutex->lock();
+ m_inboundQueue.push_back(item);
+ if (syncPoint) {
+ m_inboundQueue.push_back(CompAnalyzerEvent(TxRxSyncPoint, TQVariant()));
+ }
+ m_inboundQueueMutex->unlock();
+}
+
+bool CompAnalyzerWorker::itemTypeInInboundQueue(CompAnalyzerEventType type) {
+ bool ret = false;
+
+ m_inboundQueueMutex->lock();
+ CompAnalyzerEventQueue::iterator it;
+ for (it = m_inboundQueue.begin(); it != m_inboundQueue.end(); ++it) {
+ if ((*it).first == type) {
+ ret = true;
+ }
+ }
+ m_inboundQueueMutex->unlock();
+
+ return ret;
+}
+
+bool CompAnalyzerWorker::syncPointActive() {
+ bool active = false;
+
+ m_inboundQueueMutex->lock();
+ CompAnalyzerEventQueue::iterator it = m_inboundQueue.begin();
+ if ((it) && (it != m_inboundQueue.end())) {
+ if ((*it).first == TxRxSyncPoint) {
+ active = true;
+ }
+ }
+ m_inboundQueueMutex->unlock();
+
+ return active;
+}
+
+void CompAnalyzerWorker::wake() {
+ // Do nothing -- the main event loop will wake when this is called
+}
+
+void CompAnalyzerWorker::dataReceived() {
+ if (!m_networkDataMutex->tryLock()) {
+ TQTimer::singleShot(0, this, TQT_SLOT(dataReceived()));
+ }
+ else {
+ m_newData = true;
+ m_networkDataMutex->unlock();
+ }
+}
+
+void CompAnalyzerWorker::lockOutboundQueue() {
+ m_outboundQueueMutex->lock();
+}
+
+void CompAnalyzerWorker::unlockOutboundQueue() {
+ m_outboundQueueMutex->unlock();
+}
+
+CompAnalyzerEventQueue* CompAnalyzerWorker::outboundQueue() {
+ return &m_outboundQueue;
+}
+
+CompAnalyzerEventType CompAnalyzerWorker::nextInboundQueueEvent() {
+ CompAnalyzerEventType ret = NoEvent;
+
+ m_inboundQueueMutex->lock();
+ CompAnalyzerEventQueue::iterator it = m_inboundQueue.begin();
+ if ((it) && (it != m_inboundQueue.end())) {
+ ret = (*it).first;
+ }
+ m_inboundQueueMutex->unlock();
+
+ return ret;
+}
+
+void CompAnalyzerWorker::clearInboundQueueSyncPoint() {
+ m_inboundQueueMutex->lock();
+ CompAnalyzerEventQueue::iterator it = m_inboundQueue.begin();
+ if ((it) && (it != m_inboundQueue.end())) {
+ if ((*it).first == TxRxSyncPoint) {
+ m_inboundQueue.erase(it);
+ }
+ }
+ m_inboundQueueMutex->unlock();
+}
+
+void CompAnalyzerWorker::eraseNextInboundQueueEvent(bool clearSyncPoint) {
+ m_inboundQueueMutex->lock();
+ CompAnalyzerEventQueue::iterator it = m_inboundQueue.begin();
+ if ((it) && (it != m_inboundQueue.end())) {
+ m_inboundQueue.erase(it);
+ }
+ if (clearSyncPoint) {
+ it = m_inboundQueue.begin();
+ if ((it) && (it != m_inboundQueue.end())) {
+ if ((*it).first == TxRxSyncPoint) {
+ m_inboundQueue.erase(it);
+ }
+ }
+ }
+ m_inboundQueueMutex->unlock();
+}
+
+CompAnalyzerInstrumentLimits CompAnalyzerWorker::getInstrumentLimits() {
+ return m_instrumentLimits;
+}
+
+void CompAnalyzerWorker::setNewParameterSourceList(TQValueList<TQ_UINT32> list) {
+ m_sourceList = list;
+}
+
+CompAnalyzerPartState CompAnalyzerWorker::currentState() {
+ CompAnalyzerPartState ret;
+
+ m_currentStateMutex->lock();
+ ret = m_currentState;
+ m_currentStateMutex->unlock();
+
+ return ret;
+}
+
+void CompAnalyzerWorker::setCurrentState(CompAnalyzerPartState state) {
+ CompAnalyzerPartState prevState = m_currentState;
+
+ m_currentStateMutex->lock();
+ m_currentState = state;
+ m_currentStateMutex->unlock();
+
+ if (m_currentState != prevState) {
+ m_outboundQueueMutex->lock();
+ m_outboundQueue.push_back(CompAnalyzerEvent(StateChanged, TQVariant()));
+ m_outboundQueueMutex->unlock();
+ }
+}
+
+void CompAnalyzerWorker::setSweepStartFrequency(double hz) {
+ m_sweepStart = hz;
+}
+
+void CompAnalyzerWorker::setSweepEndFrequency(double hz) {
+ m_sweepEnd = hz;
+}
+
+double CompAnalyzerWorker::sweepStartFrequency() {
+ return m_sweepStart;
+}
+
+double CompAnalyzerWorker::sweepEndFrequency() {
+ return m_sweepEnd;
+}
+
+void CompAnalyzerWorker::setSweepStepFrequency(double hz) {
+ m_sweepStep = hz;
+}
+
+unsigned int CompAnalyzerWorker::sweepStepNumber() {
+ unsigned int ret;
+
+ m_sweepStepMutex->lock();
+ ret = m_sweepStepNumber;
+ m_sweepStepMutex->unlock();
+
+ return ret;
+}
+
+CompAnalyzerPart::CompAnalyzerPart( TQWidget *parentWidget, const char *widgetName, TQObject *parent, const char *name, const TQStringList& )
+ : RemoteInstrumentPart( parent, name ), m_commHandlerState(-1), m_commHandlerMode(0), m_commHandlerCommandState(0), m_connectionActiveAndValid(false), m_instrumentSettingsValid(false), m_base(0)
+{
+ // Initialize important base class variables
+ m_clientLibraryName = CLIENT_LIBRARY;
+
+ // Initialize mutex
+ m_instrumentMutex = new TQMutex(false);
+
+ // Initialize kpart
+ setInstance(Factory::instance());
+ setWidget(new TQVBox(parentWidget, widgetName));
+
+ // Set up worker
+ m_worker = new CompAnalyzerWorker();
+ m_workerThread = new TQEventLoopThread();
+ m_worker->moveToThread(m_workerThread);
+ TQObject::connect(this, TQT_SIGNAL(wakeWorkerThread()), m_worker, TQT_SLOT(wake()));
+ TQObject::connect(m_worker, TQT_SIGNAL(outboundQueueUpdated()), this, TQT_SLOT(processOutboundQueue()));
+
+ // Create timers
+ m_updateTimeoutTimer = new TQTimer(this);
+ connect(m_updateTimeoutTimer, SIGNAL(timeout()), this, SLOT(networkTimeout()));
+
+ // Create widgets
+ m_base = new CompAnalyzerBase(widget());
+
+ // Initialize widgets
+ m_base->setMinimumSize(500, 350);
+
+ m_base->parameterADisplay->setNumberOfDigits(12);
+ m_base->parameterBDisplay->setNumberOfDigits(12);
+ m_base->frequencyDisplay->setNumberOfDigits(12);
+
+ m_traceWidget = m_base->traceWidget;
+ m_traceWidget->setSizePolicy(TQSizePolicy(TQSizePolicy::MinimumExpanding, TQSizePolicy::MinimumExpanding));
+ m_traceWidget->setNumberOfCursors(4);
+ m_traceWidget->setZoomCursorStartIndex(0);
+ m_traceWidget->setCursorOrientation(0, TQt::Horizontal);
+ m_traceWidget->setCursorOrientation(1, TQt::Horizontal);
+ m_traceWidget->setCursorOrientation(2, TQt::Vertical);
+ m_traceWidget->setCursorOrientation(3, TQt::Vertical);
+ m_traceWidget->setCursorEnabled(0, true);
+ m_traceWidget->setCursorEnabled(1, true);
+ m_traceWidget->setCursorEnabled(2, true);
+ m_traceWidget->setCursorEnabled(3, true);
+ m_traceWidget->setCursorName(0, "Cursor H1");
+ m_traceWidget->setCursorName(1, "Cursor H2");
+ m_traceWidget->setCursorName(2, "Cursor V1");
+ m_traceWidget->setCursorName(3, "Cursor V2");
+ m_traceWidget->setCursorPosition(0, 25);
+ m_traceWidget->setCursorPosition(1, 75);
+ m_traceWidget->setCursorPosition(2, 25);
+ m_traceWidget->setCursorPosition(3, 75);
+ TraceNumberList activeTraces;
+ for (uint trace=0; trace<MAXTRACES; trace++) {
+ activeTraces.append(trace);
+ }
+ m_traceWidget->setCursorActiveTraceList(0, activeTraces);
+ m_traceWidget->setCursorActiveTraceList(1, activeTraces);
+ m_traceWidget->setCursorActiveTraceList(2, activeTraces);
+ m_traceWidget->setCursorActiveTraceList(3, activeTraces);
+ m_traceWidget->setZoomBoxEnabled(true);
+
+ connect(m_base->parameterASourceCombo, SIGNAL(activated(int)), this, SLOT(parameterASourceChanged(int)));
+ connect(m_base->parameterBSourceCombo, SIGNAL(activated(int)), this, SLOT(parameterBSourceChanged(int)));
+ connect(m_base->measurementFrequencyBox, SIGNAL(floatValueChanged(double)), this, SLOT(frequencyInputChanged(double)));
+
+ connect(m_base->sweepStartFrequencyBox, SIGNAL(floatValueChanged(double)), this, SLOT(processLockouts()));
+ connect(m_base->sweepEndFrequencyBox, SIGNAL(floatValueChanged(double)), this, SLOT(processLockouts()));
+ connect(m_base->sweepStepFrequencyBox, SIGNAL(floatValueChanged(double)), this, SLOT(processLockouts()));
+
+ m_base->traceZoomWidget->setSizePolicy(TQSizePolicy(TQSizePolicy::MinimumExpanding, TQSizePolicy::MinimumExpanding));
+ connect(m_traceWidget, SIGNAL(zoomBoxChanged(const TQRectF&)), this, SLOT(updateZoomWidgetLimits(const TQRectF&)));
+
+ connect(m_base->sweepStartButton, SIGNAL(clicked()), this, SLOT(startSweepClicked()));
+ connect(m_base->sweepStopButton, SIGNAL(clicked()), this, SLOT(stopSweepClicked()));
+ connect(m_base->waveformSave, SIGNAL(clicked()), this, SLOT(saveWaveforms()));
+ connect(m_base->waveformRecall, SIGNAL(clicked()), this, SLOT(recallWaveforms()));
+ connect(m_base->autoSave, SIGNAL(clicked()), this, SLOT(processLockouts()));
+
+ // Initialize data
+ m_hdivs = 10;
+ m_vdivs = 8;
+ m_maxNumberOfTraces = 2;
+ for (int traceno=0; traceno<=MAXTRACES; traceno++) {
+ m_samplesInTrace[traceno] = 0;
+ m_channelActive[traceno] = false;
+ m_traceUnits[traceno] = "";
+ }
+ updateGraticule();
+
+ TQTimer::singleShot(0, this, TQT_SLOT(postInit()));
+}
+
+CompAnalyzerPart::~CompAnalyzerPart() {
+ if (m_instrumentMutex->locked()) {
+ printf("[WARNING] Exiting when data transfer still in progress!\n\r"); fflush(stdout);
+ }
+
+ disconnectFromServer();
+ delete m_instrumentMutex;
+
+ if (m_workerThread) {
+ m_workerThread->terminate();
+ m_workerThread->wait();
+ delete m_workerThread;
+ m_workerThread = NULL;
+ delete m_worker;
+ m_worker = NULL;
+ }
+}
+
+void CompAnalyzerPart::postInit() {
+ setUsingFixedSize(false);
+}
+
+bool CompAnalyzerPart::openURL(const KURL &url) {
+ int ret;
+ m_connectionActiveAndValid = false;
+ ret = connectToServer(url.url());
+ processLockouts();
+ return (ret != 0);
+}
+
+bool CompAnalyzerPart::closeURL() {
+ disconnectFromServer();
+ m_url = KURL();
+ return true;
+}
+
+void CompAnalyzerPart::processLockouts() {
+ CompAnalyzerPartState state = m_worker->currentState();
+
+ if (m_connectionActiveAndValid) {
+ m_base->setEnabled(true);
+ }
+ else {
+ m_base->setEnabled(false);
+ }
+
+ if ((state == FrequencySweepWrite) || (state == FrequencySweepRead)) {
+ m_base->sweepStartButton->setEnabled(false);
+ if (!m_worker->itemTypeInInboundQueue(AbortSweep)) {
+ m_base->sweepStopButton->setEnabled(true);
+ }
+ else {
+ m_base->sweepStopButton->setEnabled(false);
+ }
+ m_base->parameterASourceCombo->setEnabled(false);
+ m_base->parameterBSourceCombo->setEnabled(false);
+ m_base->measurementFrequencyBox->setEnabled(false);
+ m_base->sweepStartFrequencyBox->setEnabled(false);
+ m_base->sweepEndFrequencyBox->setEnabled(false);
+ m_base->sweepStepFrequencyBox->setEnabled(false);
+ }
+ else {
+ if (m_base->sweepEndFrequencyBox->floatValue() > m_base->sweepStartFrequencyBox->floatValue()) {
+ if (!m_worker->itemTypeInInboundQueue(StartSweep)) {
+ m_base->sweepStartButton->setEnabled(true);
+ }
+ else {
+ m_base->sweepStartButton->setEnabled(true);
+ }
+ }
+ else {
+ m_base->sweepStartButton->setEnabled(false);
+ }
+ m_base->sweepStopButton->setEnabled(false);
+ if (m_instrumentSettingsValid) {
+ m_base->parameterASourceCombo->setEnabled(true);
+ m_base->parameterBSourceCombo->setEnabled(true);
+ m_base->measurementFrequencyBox->setEnabled(true);
+ }
+ else {
+ m_base->parameterASourceCombo->setEnabled(false);
+ m_base->parameterBSourceCombo->setEnabled(false);
+ m_base->measurementFrequencyBox->setEnabled(false);
+ }
+ m_base->sweepStartFrequencyBox->setEnabled(true);
+ m_base->sweepEndFrequencyBox->setEnabled(true);
+ m_base->sweepStepFrequencyBox->setEnabled(true);
+ }
+
+ if (m_base->autoSave->isOn()) {
+ m_base->autoSaveFile->setEnabled(true);
+ }
+ else {
+ m_base->autoSaveFile->setEnabled(false);
+ }
+}
+
+void CompAnalyzerPart::disconnectFromServerCallback() {
+ m_updateTimeoutTimer->stop();
+ m_connectionActiveAndValid = false;
+}
+
+void CompAnalyzerPart::connectionFinishedCallback() {
+ // Finish worker setup
+ m_worker->m_socket = m_socket;
+ m_worker->m_instrumentMutex = m_instrumentMutex;
+ m_socket->moveToThread(m_workerThread);
+ m_worker->appendItemToInboundQueue(CompAnalyzerEvent(Initialize, TQVariant()), true);
+
+ connect(m_socket, SIGNAL(readyRead()), m_socket, SLOT(processPendingData()));
+ m_socket->processPendingData();
+ connect(m_socket, SIGNAL(newDataReceived()), m_worker, SLOT(dataReceived()));
+ m_tickerState = 0;
+ m_commHandlerState = 0;
+ m_commHandlerMode = 0;
+ m_socket->setDataTimeout(NETWORK_COMM_TIMEOUT_MS);
+ m_updateTimeoutTimer->start(NETWORK_COMM_TIMEOUT_MS, TRUE);
+
+ // Start worker
+ m_workerThread->start();
+ TQTimer::singleShot(0, m_worker, SLOT(run()));
+
+ processLockouts();
+ networkTick();
+ return;
+}
+
+void CompAnalyzerPart::connectionStatusChangedCallback() {
+ processLockouts();
+}
+
+void CompAnalyzerPart::setTickerMessage(TQString message) {
+ m_connectionActiveAndValid = true;
+ TQString tickerChar;
+ switch (m_tickerState) {
+ case 0:
+ tickerChar = "-";
+ break;
+ case 1:
+ tickerChar = "\\";
+ break;
+ case 2:
+ tickerChar = "|";
+ break;
+ case 3:
+ tickerChar = "/";
+ break;
+ }
+ setStatusMessage(message + TQString("... %1").arg(tickerChar));
+ m_tickerState++;
+ if (m_tickerState > 3) {
+ m_tickerState = 0;
+ }
+}
+
+void CompAnalyzerPart::patWatchDog() {
+ m_updateTimeoutTimer->stop();
+}
+
+void CompAnalyzerPart::requestNetworkOperation(CompAnalyzerEvent item, bool syncPoint) {
+ m_updateTimeoutTimer->stop();
+ m_worker->appendItemToInboundQueue(item, syncPoint);
+ m_updateTimeoutTimer->start(NETWORK_COMM_TIMEOUT_MS, TRUE);
+ emit(wakeWorkerThread());
+}
+
+void CompAnalyzerPart::processOutboundQueue() {
+ bool had_events = false;
+
+ m_worker->lockOutboundQueue();
+
+ CompAnalyzerEventQueue* eventQueue = m_worker->outboundQueue();
+ CompAnalyzerEventQueue::iterator it;
+ for (it = eventQueue->begin(); it != eventQueue->end(); ++it) {
+ patWatchDog();
+
+ if ((*it).first == StateChanged) {
+ CompAnalyzerPartState state = m_worker->currentState();
+ if (m_connectionActiveAndValid) {
+ if (state == CommunicationFailure) {
+ networkTimeout();
+ }
+ }
+ }
+ else if ((*it).first == ExtendedErrorReceived) {
+ m_updateTimeoutTimer->stop();
+ m_socket->clearIncomingData();
+ setStatusMessage((*it).second.toString());
+ m_connectionActiveAndValid = false;
+ processLockouts();
+
+ // Try to recover
+ m_worker->resetInboundQueue();
+ requestNetworkOperation(CompAnalyzerEvent(Initialize, TQVariant()), true);
+ }
+ else if ((*it).first == ConfigurationDataReceived) {
+ // Get configuration data
+ CompAnalyzerInstrumentLimits instrumentLimits = m_worker->getInstrumentLimits();
+ m_parameterSourceValues = instrumentLimits.allowedMeasurements;
+
+ m_base->measurementFrequencyBox->setLineStep(1);
+ m_base->measurementFrequencyBox->setFloatMax(instrumentLimits.maxFrequency / 1000000.0);
+ m_base->measurementFrequencyBox->setFloatMin(instrumentLimits.minFrequency / 1000000.0);
+ m_base->measurementFrequencyBox->setFloatValue(instrumentLimits.minFrequency / 1000000.0);
+
+ m_base->sweepStartFrequencyBox->setLineStep(1);
+ m_base->sweepStartFrequencyBox->setFloatMax(instrumentLimits.maxFrequency / 1000000.0);
+ m_base->sweepStartFrequencyBox->setFloatMin(instrumentLimits.minFrequency / 1000000.0);
+ m_base->sweepStartFrequencyBox->setFloatValue(instrumentLimits.minFrequency / 1000000.0);
+
+ m_base->sweepEndFrequencyBox->setLineStep(1);
+ m_base->sweepEndFrequencyBox->setFloatMax(instrumentLimits.maxFrequency / 1000000.0);
+ m_base->sweepEndFrequencyBox->setFloatMin(instrumentLimits.minFrequency / 1000000.0);
+ m_base->sweepEndFrequencyBox->setFloatValue(instrumentLimits.minFrequency / 1000000.0);
+
+ m_base->sweepStepFrequencyBox->setLineStep(1);
+ m_base->sweepStepFrequencyBox->setFloatMax((instrumentLimits.maxFrequency - instrumentLimits.minFrequency) / 1000000.0);
+ m_base->sweepStepFrequencyBox->setFloatMin(0.000001); // 1Hz
+ if (instrumentLimits.maxFrequency >= 1.0) {
+ m_base->sweepStepFrequencyBox->setFloatValue(1.0); // 1MHz
+ }
+ else {
+ // Fallback...
+ m_base->sweepStepFrequencyBox->setFloatValue(instrumentLimits.minFrequency);
+ }
+
+ m_instrumentSettingsValid = false;
+
+ // Update GUI
+ unsigned int parameter_number = 0;
+ TQValueList<AllowedMeasurementInfoList>::iterator it;
+ AllowedMeasurementInfoList::iterator it2;
+ for (it = m_parameterSourceValues.begin(); it != m_parameterSourceValues.end(); ++it) {
+ AllowedMeasurementInfoList allowedValuePairs = *it;
+ if (parameter_number == 0) {
+ m_base->parameterASourceCombo->clear();
+ for (it2 = allowedValuePairs.begin(); it2 != allowedValuePairs.end(); ++it2) {
+ m_base->parameterASourceCombo->insertItem((*it2).second, -1);
+ }
+ }
+ else if (parameter_number == 1) {
+ m_base->parameterBSourceCombo->clear();
+ for (it2 = allowedValuePairs.begin(); it2 != allowedValuePairs.end(); ++it2) {
+ m_base->parameterBSourceCombo->insertItem((*it2).second, -1);
+ }
+ }
+ parameter_number++;
+ }
+ m_connectionActiveAndValid = true;
+ }
+ else if (((*it).first == MeasurementsReceived) || ((*it).first == SweepMeasurementsReceived)) {
+ TQ_UINT32 sample_number;
+ unsigned int parameter_number;
+ CompAnalyzerMeasurementList measurements;
+ TQByteArray measurementStreamData = (*it).second.toByteArray();
+ TQDataStream measurementStream(measurementStreamData, IO_ReadOnly);
+ measurementStream >> measurements;
+ measurementStream >> sample_number;
+ // If frequency sweep is in progress, then add sample points to graph
+ if ((*it).first == SweepMeasurementsReceived) {
+ unsigned int traceno = 0;
+ CompAnalyzerMeasurementList::iterator it;
+ for (it = measurements.begin(); it != measurements.end(); ++it) {
+ TQDoubleArray sampleArray = m_traceWidget->samples(traceno);
+ TQDoubleArray positionArray = m_traceWidget->positions(traceno);
+ if (sampleArray.count() < (sample_number + 1)) {
+ sampleArray.resize(sample_number + 1);
+ }
+ if (positionArray.count() < (sample_number + 1)) {
+ positionArray.resize(sample_number + 1);
+ }
+ sampleArray[sample_number] = (*it).value;
+ positionArray[sample_number] = (*it).frequency;
+ if (sample_number == 0) {
+ m_sensorList[traceno].max = (*it).value;
+ m_sensorList[traceno].min = (*it).value;
+ }
+ else {
+ if ((*it).value > m_sensorList[traceno].max) {
+ m_sensorList[traceno].max = (*it).value;
+ }
+ if ((*it).value < m_sensorList[traceno].min) {
+ m_sensorList[traceno].min = (*it).value;
+ }
+ }
+ m_traceWidget->setSamples(traceno, sampleArray);
+ m_traceWidget->setPositions(traceno, positionArray);
+ m_base->traceZoomWidget->setSamples(traceno, sampleArray);
+ m_base->traceZoomWidget->setPositions(traceno, positionArray);
+ traceno++;
+ }
+ updateGraticule();
+ m_traceWidget->repaint(false);
+ m_base->traceZoomWidget->repaint(false);
+ processAutosave();
+ }
+ // Update displays
+ parameter_number = 0;
+ CompAnalyzerMeasurementList::iterator it;
+ for (it = measurements.begin(); it != measurements.end(); ++it) {
+ if (parameter_number == 0) {
+ m_base->parameterADisplay->setValue((*it).value, 5, true);
+ }
+ else if (parameter_number == 1) {
+ m_base->parameterBDisplay->setValue((*it).value, 5, true);
+ }
+ m_base->frequencyDisplay->setValue((*it).frequency / 1000000.0, 2, true);
+
+ // Update instrument control selectors
+ if (m_parameterSourceValues.count() < (parameter_number + 1)) {
+ continue;
+ }
+ AllowedMeasurementInfoList::iterator it2;
+ for (it2 = m_parameterSourceValues[parameter_number].begin(); it2 != m_parameterSourceValues[parameter_number].end(); ++it2) {
+ if ((*it2).first == (*it).parameter) {
+ if (parameter_number == 0) {
+ m_base->parameterASourceCombo->setCurrentText((*it2).second);
+ }
+ if (parameter_number == 1) {
+ m_base->parameterBSourceCombo->setCurrentText((*it2).second);
+ }
+ }
+ }
+
+ parameter_number++;
+ }
+ m_instrumentSettingsValid = true;
+ m_connectionActiveAndValid = true;
+ }
+ had_events = true;
+ }
+ if (had_events) {
+ if (m_connectionActiveAndValid) {
+ networkTick();
+ }
+ eventQueue->clear();
+ }
+
+ m_worker->unlockOutboundQueue();
+
+ processLockouts();
+}
+
+void CompAnalyzerPart::networkTick() {
+ setTickerMessage(i18n("Connected"));
+ m_connectionActiveAndValid = true;
+ processLockouts();
+}
+
+void CompAnalyzerPart::networkTimeout() {
+ m_updateTimeoutTimer->stop();
+ m_socket->clearIncomingData();
+ setStatusMessage(i18n("Server ping timeout. Please verify the status of your network connection."));
+ m_connectionActiveAndValid = false;
+ processLockouts();
+
+ // Try to recover
+ m_worker->resetInboundQueue();
+ requestNetworkOperation(CompAnalyzerEvent(Initialize, TQVariant()), true);
+}
+
+void CompAnalyzerPart::updateZoomWidgetLimits(const TQRectF& zoomRect) {
+ for (int traceno=0; traceno<m_maxNumberOfTraces; traceno++) {
+ TQRectF fullZoomRect = m_traceWidget->displayLimits(traceno);
+ double widthSpan = fullZoomRect.width()-fullZoomRect.x();
+ double heightSpan = fullZoomRect.height()-fullZoomRect.y();
+
+ TQRectF zoomLimitsRect((fullZoomRect.x()+(widthSpan*(zoomRect.x()/100.0))), (fullZoomRect.y()+(heightSpan*(zoomRect.y()/100.0))), (fullZoomRect.x()+(widthSpan*((zoomRect.x()/100.0)+(zoomRect.width()/100.0)))), (fullZoomRect.y()+(heightSpan*((zoomRect.y()/100.0)+(zoomRect.height()/100.0)))));
+
+ m_base->traceZoomWidget->setDisplayLimits(traceno, zoomLimitsRect);
+ }
+}
+
+void CompAnalyzerPart::updateGraticule() {
+ m_traceWidget->setNumberOfHorizontalDivisions(m_hdivs);
+ m_traceWidget->setNumberOfVerticalDivisions(m_vdivs);
+ m_base->traceZoomWidget->setNumberOfHorizontalDivisions(m_hdivs);
+ m_base->traceZoomWidget->setNumberOfVerticalDivisions(m_vdivs);
+
+ if (m_maxNumberOfTraces > 0) m_traceWidget->setTraceColor(0, TQColor(255, 255, 255));
+ if (m_maxNumberOfTraces > 1) m_traceWidget->setTraceColor(1, TQColor(128, 255, 128));
+ if (m_maxNumberOfTraces > 2) m_traceWidget->setTraceColor(2, TQColor(255, 255, 128));
+ if (m_maxNumberOfTraces > 3) m_traceWidget->setTraceColor(3, TQColor(128, 128, 255));
+
+ if (m_maxNumberOfTraces > 0) m_base->traceZoomWidget->setTraceColor(0, TQColor(255, 255, 255));
+ if (m_maxNumberOfTraces > 1) m_base->traceZoomWidget->setTraceColor(1, TQColor(128, 255, 128));
+ if (m_maxNumberOfTraces > 2) m_base->traceZoomWidget->setTraceColor(2, TQColor(255, 255, 128));
+ if (m_maxNumberOfTraces > 3) m_base->traceZoomWidget->setTraceColor(3, TQColor(128, 128, 255));
+
+ for (int traceno=0; traceno<m_maxNumberOfTraces; traceno++) {
+ if (m_sensorList.count() < (traceno + 1)) {
+ continue;
+ }
+ if (traceno == 0) {
+ m_sensorList[traceno].name = m_base->parameterASourceCombo->currentText();
+ }
+ else if (traceno == 1) {
+ m_sensorList[traceno].name = m_base->parameterBSourceCombo->currentText();
+ }
+ m_sensorList[traceno].units = parameterNameToMeasurementUnits(m_sensorList[traceno].name, traceno);
+
+ m_traceWidget->setTraceEnabled(traceno, m_channelActive[traceno]);
+ m_traceWidget->setTraceName(traceno, m_sensorList[traceno].name);
+ m_traceWidget->setTraceHorizontalUnits(traceno, "Hz");
+ m_traceWidget->setTraceVerticalUnits(traceno, m_sensorList[traceno].units);
+
+ m_base->traceZoomWidget->setTraceEnabled(traceno, m_channelActive[traceno], TraceWidget::SummaryText);
+ m_base->traceZoomWidget->setTraceName(traceno, m_sensorList[traceno].name);
+ m_base->traceZoomWidget->setTraceHorizontalUnits(traceno, "Hz");
+ m_base->traceZoomWidget->setTraceVerticalUnits(traceno, m_sensorList[traceno].units);
+
+ double startfreq = 0.0;
+ double endfreq = 0.0;
+ if (m_samplesInTrace[traceno] > 0) {
+ startfreq = m_worker->sweepStartFrequency();
+ endfreq = m_worker->sweepEndFrequency();
+ }
+ m_traceWidget->setDisplayLimits(traceno, TQRectF(startfreq, m_sensorList[traceno].max, endfreq, m_sensorList[traceno].min));
+ }
+ updateZoomWidgetLimits(m_traceWidget->zoomBox());
+}
+
+void CompAnalyzerPart::frequencyInputChanged(double value) {
+ double frequency = value * 1000000.0;
+
+ requestNetworkOperation(CompAnalyzerEvent(SetFrequency, TQVariant(frequency)), true);
+
+ processLockouts();
+}
+
+void CompAnalyzerPart::parameterASourceChanged(int index) {
+ TQValueList<TQ_UINT32> sourceIndexList;
+ TQString newSource = m_base->parameterASourceCombo->text(index);
+ TQString source = m_base->parameterBSourceCombo->currentText();
+
+ AllowedMeasurementInfoList::iterator it2;
+ for (it2 = m_parameterSourceValues[0].begin(); it2 != m_parameterSourceValues[0].end(); ++it2) {
+ if ((*it2).second == newSource) {
+ sourceIndexList.append((*it2).first);
+ break;
+ }
+ }
+
+ for (it2 = m_parameterSourceValues[1].begin(); it2 != m_parameterSourceValues[1].end(); ++it2) {
+ if ((*it2).second == source) {
+ sourceIndexList.append((*it2).first);
+ break;
+ }
+ }
+
+ if (sourceIndexList.count() >= 2) {
+ m_worker->setNewParameterSourceList(sourceIndexList);
+ requestNetworkOperation(CompAnalyzerEvent(ChangeMeasurementSource, TQVariant()), true);
+ }
+
+ processLockouts();
+}
+
+void CompAnalyzerPart::parameterBSourceChanged(int index) {
+ TQValueList<TQ_UINT32> sourceIndexList;
+ TQString newSource = m_base->parameterBSourceCombo->text(index);
+ TQString source = m_base->parameterASourceCombo->currentText();
+
+ AllowedMeasurementInfoList::iterator it2;
+ for (it2 = m_parameterSourceValues[0].begin(); it2 != m_parameterSourceValues[0].end(); ++it2) {
+ if ((*it2).second == source) {
+ sourceIndexList.append((*it2).first);
+ break;
+ }
+ }
+
+ for (it2 = m_parameterSourceValues[1].begin(); it2 != m_parameterSourceValues[1].end(); ++it2) {
+ if ((*it2).second == newSource) {
+ sourceIndexList.append((*it2).first);
+ break;
+ }
+ }
+
+ if (sourceIndexList.count() >= 2) {
+ m_worker->setNewParameterSourceList(sourceIndexList);
+ requestNetworkOperation(CompAnalyzerEvent(ChangeMeasurementSource, TQVariant()), true);
+ }
+
+ processLockouts();
+}
+
+void CompAnalyzerPart::startSweepClicked() {
+ int traceno;
+
+ double start = m_base->sweepStartFrequencyBox->floatValue() * 1000000.0;
+ double end = m_base->sweepEndFrequencyBox->floatValue() * 1000000.0;
+ double step = m_base->sweepStepFrequencyBox->floatValue() * 1000000.0;
+
+ if (end <= start) {
+ return;
+ }
+
+ m_worker->setSweepStartFrequency(start);
+ m_worker->setSweepEndFrequency(end);
+ m_worker->setSweepStepFrequency(step);
+
+ m_sensorList.clear();
+ for ( traceno=0; traceno<m_maxNumberOfTraces; traceno++) {
+ m_sensorList.append(SensorType());
+ }
+ for (traceno=0; traceno<m_maxNumberOfTraces; traceno++) {
+ m_samplesInTrace[traceno] = ((end - start) / step) + 1;
+ m_channelActive[traceno] = true;
+ m_sensorList[traceno].name = "";
+ m_sensorList[traceno].units = "";
+ m_sensorList[traceno].max = 0;
+ m_sensorList[traceno].min = 0;
+ m_traceUnits[traceno] = m_sensorList[traceno].units;
+ }
+ m_traceWidget->setNumberOfSamples(traceno, m_samplesInTrace[traceno]);
+ m_base->traceZoomWidget->setNumberOfSamples(traceno, m_samplesInTrace[traceno]);
+
+ // Clear graph
+ for (int traceno=0; traceno<m_maxNumberOfTraces; traceno++) {
+ TQDoubleArray sampleArray = m_traceWidget->samples(traceno);
+ TQDoubleArray positionArray = m_traceWidget->positions(traceno);
+ if (sampleArray.count() != (unsigned int)m_samplesInTrace[traceno]) {
+ sampleArray.resize(m_samplesInTrace[traceno]);
+ }
+ if (positionArray.count() != (unsigned int)m_samplesInTrace[traceno]) {
+ positionArray.resize(m_samplesInTrace[traceno]);
+ }
+ sampleArray.fill(NAN);
+ positionArray.fill(NAN);
+ m_traceWidget->setSamples(traceno, sampleArray);
+ m_traceWidget->setPositions(traceno, positionArray);
+ m_base->traceZoomWidget->setSamples(traceno, sampleArray);
+ m_base->traceZoomWidget->setPositions(traceno, positionArray);
+ }
+
+ updateGraticule();
+
+ requestNetworkOperation(CompAnalyzerEvent(StartSweep, TQVariant()), true);
+
+ processLockouts();
+}
+
+void CompAnalyzerPart::stopSweepClicked() {
+ requestNetworkOperation(CompAnalyzerEvent(AbortSweep, TQVariant()), true);
+
+ processLockouts();
+}
+
+void CompAnalyzerPart::processAutosave() {
+ if (m_base->autoSave->isOn()) {
+ if (m_base->autoSaveFile->url() != "") {
+ saveWaveforms(m_base->autoSaveFile->url());
+ }
+ }
+}
+
+#define WAVEFORM_MAGIC_NUMBER 3
+#define WAVEFORM_FILE_VERSION 1
+
+void CompAnalyzerPart::saveWaveforms() {
+ saveWaveforms(TQString::null);
+}
+
+void CompAnalyzerPart::saveWaveforms(TQString fileName) {
+ TQString saveFileName;
+ if (fileName != "") {
+ saveFileName = fileName;
+ }
+ else {
+ saveFileName = KFileDialog::getSaveFileName(TQString::null, "*.wfm|Waveform Files (*.wfm)", 0, i18n("Save waveforms..."));
+ }
+ if (saveFileName != "") {
+ TQFile file(saveFileName);
+ file.open(IO_WriteOnly);
+ TQDataStream ds(&file);
+ TQ_INT32 magicNumber = WAVEFORM_MAGIC_NUMBER;
+ TQ_INT32 version = WAVEFORM_FILE_VERSION;
+ ds << magicNumber;
+ ds << version;
+ ds << m_sensorList;
+ ds << m_hdivs;
+ ds << m_vdivs;
+ ds << m_maxNumberOfTraces;
+ for (int traceno=0; traceno<m_maxNumberOfTraces; traceno++) {
+ TQ_UINT8 boolValue;
+ boolValue = m_channelActive[traceno];
+ ds << boolValue;
+ ds << m_samplesInTrace[traceno];
+ ds << m_traceUnits[traceno];
+ ds << m_traceWidget->samples(traceno);
+ ds << m_traceWidget->positions(traceno);
+ }
+ for (int cursorno=0; cursorno<4; cursorno++) {
+ ds << m_traceWidget->cursorPosition(cursorno);
+ }
+ ds << m_base->userNotes->text();
+ }
+
+ processLockouts();
+}
+
+void CompAnalyzerPart::recallWaveforms() {
+ TQString openFileName = KFileDialog::getOpenFileName(TQString::null, "*.wfm|Waveform Files (*.wfm)", 0, i18n("Open waveforms..."));
+ if (openFileName != "") {
+ TQFile file(openFileName);
+ file.open(IO_ReadOnly);
+ TQDataStream ds(&file);
+ TQ_INT32 magicNumber;
+ TQ_INT32 version;
+ ds >> magicNumber;
+ if (magicNumber == WAVEFORM_MAGIC_NUMBER) {
+ ds >> version;
+ if (version == WAVEFORM_FILE_VERSION) {
+ ds >> m_sensorList;
+ ds >> m_hdivs;
+ ds >> m_vdivs;
+ ds >> m_maxNumberOfTraces;
+ for (int traceno=0; traceno<m_maxNumberOfTraces; traceno++) {
+ TQ_UINT8 boolValue;
+ ds >> boolValue;
+ m_channelActive[traceno] = (boolValue!=0)?true:false;
+ ds >> m_samplesInTrace[traceno];
+ ds >> m_traceUnits[traceno];
+ TQDoubleArray values;
+ TQDoubleArray positions;
+ ds >> values;
+ ds >> positions;
+ m_traceWidget->setNumberOfSamples(traceno, m_samplesInTrace[traceno], true);
+ m_traceWidget->setSamples(traceno, values);
+ m_traceWidget->setPositions(traceno, positions);
+ m_base->traceZoomWidget->setSamples(traceno, values);
+ m_base->traceZoomWidget->setPositions(traceno, positions);
+ m_traceWidget->setDisplayLimits(traceno, TQRectF(positions[0], m_sensorList[traceno].max, positions[positions.count() - 1], m_sensorList[traceno].min));
+ if (traceno == 0) {
+ m_worker->setSweepStartFrequency(positions[0]);
+ m_worker->setSweepEndFrequency(positions[positions.count() - 1]);
+ }
+ }
+ for (int cursorno=0; cursorno<4; cursorno++) {
+ double cursorPos;
+ ds >> cursorPos;
+ m_traceWidget->setCursorPosition(cursorno, cursorPos);
+ }
+ updateGraticule();
+ m_traceWidget->repaint(false);
+ m_base->traceZoomWidget->repaint(false);
+ TQString notes;
+ ds >> notes;
+ m_base->userNotes->setText(notes);
+ }
+ else {
+ KMessageBox::error(0, i18n("<qt>The selected waveform file version does not match this client</qt>"), i18n("Invalid File"));
+ }
+ }
+ else {
+ KMessageBox::error(0, i18n("<qt>Invalid waveform file selected</qt>"), i18n("Invalid File"));
+ }
+ }
+
+ processLockouts();
+}
+
+TQString CompAnalyzerPart::parameterMeasurementUnits(TQ_UINT32 parameter) {
+ TQString ret;
+
+ switch (parameter) {
+ case 0:
+ // Resistance
+ ret = i18n("Ω");
+ break;
+ case 1:
+ // Reactance
+ ret = i18n("Ω");
+ break;
+ case 2:
+ // Conductance
+ ret = i18n("S");
+ break;
+ case 3:
+ // Susceptance
+ ret = i18n("S");
+ break;
+ case 4:
+ // Inductance
+ ret = i18n("H");
+ break;
+ case 5:
+ // Capacitance
+ ret = i18n("F");
+ break;
+ case 6:
+ // Dissipation Factor
+ ret = TQString::null;
+ break;
+ case 7:
+ // Quality Factor
+ ret = TQString::null;
+ break;
+ case 8:
+ // Impedance
+ ret = i18n("Ω");
+ break;
+ case 9:
+ // Admittance
+ ret = i18n("S");
+ break;
+ case 10:
+ // Reflection (absolute)
+ ret = TQString::null;
+ break;
+ case 11:
+ // Reflection (X)
+ ret = TQString::null;
+ break;
+ case 12:
+ // Reflection (Y)
+ ret = TQString::null;
+ break;
+ case 13:
+ // Phase angle (degrees)
+ ret = i18n("°");
+ break;
+ case 14:
+ // Phase angle (radians)
+ ret = i18n("rad");
+ break;
+ }
+
+ return ret;
+}
+
+TQString CompAnalyzerPart::parameterNameToMeasurementUnits(TQString name, unsigned int parameter_index) {
+ TQString ret;
+
+ AllowedMeasurementInfoList::iterator it2;
+ for (it2 = m_parameterSourceValues[parameter_index].begin(); it2 != m_parameterSourceValues[parameter_index].end(); ++it2) {
+ if ((*it2).second == name) {
+ ret = parameterMeasurementUnits((*it2).first);
+ }
+ }
+
+ return ret;
+}
+
+TDEAboutData* CompAnalyzerPart::createAboutData() {
+ return new TDEAboutData( APP_NAME, I18N_NOOP( APP_PRETTYNAME ), APP_VERSION );
+}
+
+} //namespace RemoteLab
+
+#include "part.moc"
diff --git a/clients/tde/src/part/companalyzer/part.h b/clients/tde/src/part/companalyzer/part.h
new file mode 100644
index 0000000..7dfdd32
--- /dev/null
+++ b/clients/tde/src/part/companalyzer/part.h
@@ -0,0 +1,260 @@
+/*
+ * Remote Laboratory Component Analyzer Part
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (c) 2014 - 2015 Timothy Pearson
+ * Raptor Engineering
+ * http://www.raptorengineeringinc.com
+ */
+
+#ifndef REMOTELAB_COMPANALYZERPART_H
+#define REMOTELAB_COMPANALYZERPART_H
+
+#include <ntqthread.h>
+#include <ntqeventloop.h>
+
+#include <tqvariant.h>
+#include <tqvaluevector.h>
+
+#include <tdeparts/browserextension.h>
+#include <tdeparts/statusbarextension.h>
+#include <tdeparts/part.h>
+#include <kurl.h>
+
+#include <tqtrla.h>
+
+#include <sevensegment.h>
+
+#define MAXTRACES 255
+
+class TDEAboutData;
+using KParts::StatusBarExtension;
+class TraceWidget;
+class TQSocket;
+class TQTimer;
+class TQMutex;
+class TQRectF;
+class CompAnalyzerBase;
+
+namespace RemoteLab
+{
+ typedef enum CompAnalyzerEventType {
+ NoEvent = 0,
+ Initialize = 1,
+ TxRxSyncPoint = 2,
+ StateChanged = 3,
+ ExtendedErrorReceived = 4,
+ ConfigurationDataReceived = 5,
+ ChangeMeasurementSource = 6,
+ GetMeasurement = 7,
+ GetMaximumFrequency = 8,
+ GetMinimumFrequency = 9,
+ SetFrequency = 10,
+ MeasurementsReceived = 11,
+ SweepMeasurementsReceived = 12,
+ StartSweep = 13,
+ AbortSweep = 14,
+ OtherEvent = 15
+ } CompAnalyzerEventType;
+
+ typedef enum CompAnalyzerStartupState {
+ StartSelectInstrument = 0,
+ StartGetMaximumFrequency = 1,
+ StartGetMinimumFrequency = 2,
+ StartDone = 3
+ } CompAnalyzerStartupState;
+
+ typedef enum CompAnalyzerPartState {
+ Idle = 0,
+ Initializing = 1,
+ FreeRunning = 2,
+ FrequencySweepWrite = 3,
+ FrequencySweepRead = 4,
+ CommunicationFailure = 5
+ } CompAnalyzerPartState;
+
+ typedef struct CompAnalyzerMeasurement {
+ TQ_UINT32 status;
+ TQ_UINT32 parameter;
+ TQ_UINT32 type;
+ double value;
+ double frequency;
+ } CompAnalyzerMeasurement;
+
+ typedef TQPair<CompAnalyzerEventType, TQVariant> CompAnalyzerEvent;
+ typedef TQValueVector<CompAnalyzerEvent> CompAnalyzerEventQueue;
+ typedef TQValueList<CompAnalyzerMeasurement> CompAnalyzerMeasurementList;
+
+ typedef TQPair<unsigned int,TQString> AllowedMeasurementInfo;
+ typedef TQValueList<AllowedMeasurementInfo> AllowedMeasurementInfoList;
+
+ typedef struct CompAnalyzerInstrumentLimits {
+ TQValueList<AllowedMeasurementInfoList> allowedMeasurements;
+ double maxFrequency;
+ double minFrequency;
+ } CompAnalyzerInstrumentLimits;
+
+#ifndef QT_NO_DATASTREAM
+ Q_EXPORT TQDataStream &operator<<(TQDataStream &, const CompAnalyzerMeasurement &);
+ Q_EXPORT TQDataStream &operator>>(TQDataStream &, CompAnalyzerMeasurement &);
+#endif
+
+ class CompAnalyzerWorker : public TQObject
+ {
+ TQ_OBJECT
+
+ public:
+ CompAnalyzerWorker();
+ ~CompAnalyzerWorker();
+
+ signals:
+ void outboundQueueUpdated();
+
+ public slots:
+ void run();
+ void wake();
+ void dataReceived();
+
+ public:
+ void resetInboundQueue();
+ void appendItemToInboundQueue(CompAnalyzerEvent item, bool syncPoint=false);
+ bool itemTypeInInboundQueue(CompAnalyzerEventType type);
+ bool syncPointActive();
+ void lockOutboundQueue();
+ void unlockOutboundQueue();
+ CompAnalyzerEventQueue* outboundQueue();
+ CompAnalyzerPartState currentState();
+
+ CompAnalyzerInstrumentLimits getInstrumentLimits();
+ void setNewParameterSourceList(TQValueList<TQ_UINT32>);
+
+ void setSweepStartFrequency(double hz);
+ void setSweepEndFrequency(double hz);
+ void setSweepStepFrequency(double hz);
+ double sweepStartFrequency();
+ double sweepEndFrequency();
+ unsigned int sweepStepNumber();
+
+ private:
+ CompAnalyzerEventType nextInboundQueueEvent();
+ void clearInboundQueueSyncPoint();
+ void eraseNextInboundQueueEvent(bool clearSyncPoint=false);
+ void setCurrentState(CompAnalyzerPartState state);
+
+ public:
+ TDEKerberosClientSocket* m_socket;
+ TQMutex* m_instrumentMutex;
+
+ private:
+ CompAnalyzerEventQueue m_outboundQueue;
+ CompAnalyzerEventQueue m_inboundQueue;
+ TQMutex* m_outboundQueueMutex;
+ TQMutex* m_inboundQueueMutex;
+ TQMutex* m_networkDataMutex;
+ TQMutex* m_currentStateMutex;
+ TQMutex* m_sweepStepMutex;
+ CompAnalyzerPartState m_currentState;
+ CompAnalyzerStartupState m_startupState;
+ CompAnalyzerEventType m_lastNetworkTransmissionEvent;
+ bool m_newData;
+ TQValueList<TQ_UINT32> m_sourceList;
+ CompAnalyzerInstrumentLimits m_instrumentLimits;
+
+ double m_sweepStart;
+ double m_sweepEnd;
+ double m_sweepStep;
+ double m_sweepCurrentFrequency;
+ TQ_UINT32 m_sweepStepNumber;
+ };
+
+ class CompAnalyzerPart : public KParts::RemoteInstrumentPart
+ {
+ Q_OBJECT
+
+ public:
+ CompAnalyzerPart( QWidget *, const char *, TQObject *, const char *, const TQStringList&);
+ ~CompAnalyzerPart();
+
+ virtual bool openFile() { return false; } // pure virtual in the base class
+ virtual bool closeURL();
+ static TDEAboutData *createAboutData();
+
+ signals:
+ void wakeWorkerThread();
+
+ public slots:
+ virtual bool openURL(const KURL &url);
+ void processOutboundQueue();
+ void updateZoomWidgetLimits(const TQRectF& zoomRect);
+
+ private slots:
+ void postInit();
+ void processLockouts();
+ void connectionFinishedCallback();
+ void disconnectFromServerCallback();
+ void connectionStatusChangedCallback();
+ void setTickerMessage(TQString message);
+ void networkTick();
+ void networkTimeout();
+ void parameterASourceChanged(int);
+ void parameterBSourceChanged(int);
+ void frequencyInputChanged(double);
+ void startSweepClicked();
+ void stopSweepClicked();
+
+ void processAutosave();
+ void saveWaveforms();
+ void saveWaveforms(TQString fileName);
+ void recallWaveforms();
+
+ void updateGraticule();
+
+ private:
+ TQString parameterMeasurementUnits(TQ_UINT32 parameter);
+ TQString parameterNameToMeasurementUnits(TQString name, unsigned int parameter_index);
+ void requestNetworkOperation(CompAnalyzerEvent item, bool syncPoint=false);
+ void patWatchDog();
+
+ private:
+ int m_commHandlerState;
+ int m_commHandlerMode;
+ int m_commHandlerCommandState;
+ TQTimer* m_updateTimeoutTimer;
+ bool m_connectionActiveAndValid;
+ bool m_instrumentSettingsValid;
+ unsigned char m_tickerState;
+ CompAnalyzerBase* m_base;
+ TQMutex* m_instrumentMutex;
+ TQString m_TextToSend;
+ TQValueList<AllowedMeasurementInfoList> m_parameterSourceValues;
+
+ TraceWidget* m_traceWidget;
+ TQGridLayout* m_traceControlWidgetGrid;
+
+ SensorList m_sensorList;
+ TQ_INT16 m_maxNumberOfTraces;
+ TQ_INT16 m_hdivs;
+ TQ_INT16 m_vdivs;
+ TQ_INT32 m_samplesInTrace[MAXTRACES+1];
+ bool m_channelActive[MAXTRACES+1];
+ TQString m_traceUnits[MAXTRACES+1];
+
+ CompAnalyzerWorker* m_worker;
+ TQEventLoopThread* m_workerThread;
+ };
+}
+
+#endif
diff --git a/clients/tde/src/widgets/floatspinbox.cpp b/clients/tde/src/widgets/floatspinbox.cpp
index 9592968..9bcff87 100644
--- a/clients/tde/src/widgets/floatspinbox.cpp
+++ b/clients/tde/src/widgets/floatspinbox.cpp
@@ -100,6 +100,16 @@ void FloatSpinBox::setFloatValue(double d) {
setValue( ROUND( (value - min) * pow( 10, dec )) );
}
+double FloatSpinBox::floatValue() {
+ return value;
+}
+
+void FloatSpinBox::setEnabled(bool enable) {
+ if (enable != isEnabled()) {
+ TQSpinBox::setEnabled(enable);
+ }
+}
+
void FloatSpinBox::acceptValueChanged(int ival) {
Q_UNUSED(ival);
emit floatValueChanged( value );
diff --git a/clients/tde/src/widgets/floatspinbox.h b/clients/tde/src/widgets/floatspinbox.h
index a577649..102584f 100644
--- a/clients/tde/src/widgets/floatspinbox.h
+++ b/clients/tde/src/widgets/floatspinbox.h
@@ -44,6 +44,8 @@ class FloatSpinBox : public TQSpinBox
void setFloatMax(double max);
void setPrecision(int precision);
+ double floatValue();
+
private:
int dec;
virtual TQString mapValueToText(int value);
@@ -51,6 +53,7 @@ class FloatSpinBox : public TQSpinBox
public slots:
void setFloatValue(double d);
+ virtual void setEnabled(bool);
private slots:
void acceptValueChanged(int value);
diff --git a/clients/tde/src/widgets/sevensegment.cpp b/clients/tde/src/widgets/sevensegment.cpp
index d7e7a07..f6d8469 100644..100755
--- a/clients/tde/src/widgets/sevensegment.cpp
+++ b/clients/tde/src/widgets/sevensegment.cpp
@@ -77,16 +77,23 @@ void Display7Segment::setLitSegments(unsigned char segs) {
unsigned char Display7Segment::segmentsForNumericDigit(unsigned char val, bool dp) {
unsigned char ret = 0;
- if (val == 0) { ret = 0x7e; }
- else if (val == 1) { ret = 0x30; }
- else if (val == 2) { ret = 0x6d; }
- else if (val == 3) { ret = 0x79; }
- else if (val == 4) { ret = 0x33; }
- else if (val == 5) { ret = 0x5b; }
- else if (val == 6) { ret = 0x5f; }
- else if (val == 7) { ret = 0x70; }
- else if (val == 8) { ret = 0x7f; }
- else if (val == 9) { ret = 0x73; }
+ if (val == 0x0) { ret = 0x7e; }
+ else if (val == 0x1) { ret = 0x30; }
+ else if (val == 0x2) { ret = 0x6d; }
+ else if (val == 0x3) { ret = 0x79; }
+ else if (val == 0x4) { ret = 0x33; }
+ else if (val == 0x5) { ret = 0x5b; }
+ else if (val == 0x6) { ret = 0x5f; }
+ else if (val == 0x7) { ret = 0x70; }
+ else if (val == 0x8) { ret = 0x7f; }
+ else if (val == 0x9) { ret = 0x73; }
+ else if (val == 0xa) { ret = 0x7d; }
+ else if (val == 0xb) { ret = 0x1f; }
+ else if (val == 0xc) { ret = 0x0d; }
+ else if (val == 0xd) { ret = 0x3d; }
+ else if (val == 0xe) { ret = 0x4f; }
+ else if (val == 0xf) { ret = 0x67; }
+ else if (val == 0x10) { ret = 0x01; } // "-"
if (dp) {
ret |= 0x80;
@@ -496,7 +503,9 @@ void Display7SegmentArray::init() {
unsigned int i;
// Set up grid layout
- m_layout = new TQGridLayout(this, 1, m_numberOfDigits);
+ m_layout = new TQGridLayout(this, 1, m_numberOfDigits + 1);
+ TQSpacerItem *spacerItem = new TQSpacerItem(0, 0, TQSizePolicy::Expanding, TQSizePolicy::Fixed);
+ m_layout->addItem(spacerItem);
m_layout->setAutoAdd(true);
// Allocate display array
@@ -528,7 +537,7 @@ void Display7SegmentArray::init() {
m_displayArray[i]->setFrameStyle(TQFrame::NoFrame);
}
setBackgroundColor(TQt::black);
- setFrameStyle(TQFrame::Box | TQFrame::Raised);
+ setFrameStyle(TQFrame::Box);
#endif
}
@@ -575,6 +584,9 @@ void Display7SegmentArray::setValue(double value, int maxDecimalLength, bool for
bool dp;
unsigned int i;
TQString displayString = TQString("%1").arg(value);
+ if (displayString.contains("e")) {
+ maxDecimalLength = -1;
+ }
if (maxDecimalLength >= 0) {
int decPos = displayString.find(".");
if (decPos >= 0) {
@@ -598,23 +610,39 @@ void Display7SegmentArray::setValue(double value, int maxDecimalLength, bool for
if (displayString.contains(".")) {
current_char--;
}
- for (i=0; i < m_numberOfDigits; i++) {
- if (current_char < 0) {
- m_displayArray[i]->setLitSegments(0x0);
+ if (displayString.length() > m_numberOfDigits) {
+ // String is too large to display on the specified number of 7-segment digits
+ for (i=0; i < m_numberOfDigits; i++) {
+ m_displayArray[i]->setLitSegments(Display7Segment::segmentsForNumericDigit(0x10, false));
}
- else {
- dp = false;
- if (current_char < (displayString.length() - 1)) {
- if (displayString[current_char + 1] == '.') {
- dp = true;
- }
+ }
+ else {
+ for (i=0; i < m_numberOfDigits; i++) {
+ if (current_char < 0) {
+ m_displayArray[i]->setLitSegments(0x0);
}
- if (displayString[current_char] == '.') {
- current_char++;
+ else {
+ dp = false;
+ if (current_char < (displayString.length() - 1)) {
+ if (displayString[current_char + 1] == '.') {
+ dp = true;
+ }
+ }
+ if (displayString[current_char] == '.') {
+ current_char++;
+ }
+ if (displayString[current_char] == '-') {
+ m_displayArray[i]->setLitSegments(Display7Segment::segmentsForNumericDigit(0x10, dp));
+ }
+ else if (displayString[current_char] == 'e') {
+ m_displayArray[i]->setLitSegments(Display7Segment::segmentsForNumericDigit(0xe, dp));
+ }
+ else {
+ m_displayArray[i]->setLitSegments(Display7Segment::segmentsForNumericDigit(TQString(displayString[current_char]).toInt(NULL, 10), dp));
+ }
}
- m_displayArray[i]->setLitSegments(Display7Segment::segmentsForNumericDigit(TQString(displayString[current_char]).toInt(NULL, 10), dp));
+ current_char++;
}
- current_char++;
}
}
diff --git a/clients/tde/src/widgets/tracewidget.cpp b/clients/tde/src/widgets/tracewidget.cpp
index 08cfe42..1d5440c 100644
--- a/clients/tde/src/widgets/tracewidget.cpp
+++ b/clients/tde/src/widgets/tracewidget.cpp
@@ -695,6 +695,15 @@ void TraceData::drawTrace(TQPainter* p, int graticule_width, int graticule_heigh
activeSamples = abs(rightEdgeIndex-leftEdgeIndex);
incr = (activeSamples/virtual_width)+1;
for (n=leftEdgeIndex; n<numberOfSamples-incr; n=n+incr) {
+ // Detect invalid samples and skip drawing of those samples
+ // This avoids ugly drawing artifacts when not all sample data is available
+ if ( isnan(positionArray[n]) || isinf(positionArray[n])
+ || isnan(positionArray[n+incr]) || isinf(positionArray[n+incr])
+ || isnan(sampleArray[n]) || isinf(sampleArray[n])
+ || isnan(sampleArray[n+incr]) || isinf(sampleArray[n+incr])) {
+ continue;
+ }
+
x = (((positionArray[n]-leftEdge)/(rightEdge-leftEdge))*(virtual_width))-horizoffset;
y = ((((sampleArray[n]+offset)-topEdge)/(bottomEdge-topEdge))*(virtual_height));
x2 = (((positionArray[n+incr]-leftEdge)/(rightEdge-leftEdge))*(virtual_width))-horizoffset;