summaryrefslogtreecommitdiffstats
path: root/clients
diff options
context:
space:
mode:
authorTimothy Pearson <kb9vqf@pearsoncomputing.net>2015-09-12 19:55:59 -0500
committerTimothy Pearson <kb9vqf@pearsoncomputing.net>2015-09-12 19:55:59 -0500
commita4eb3d14df4d5c3bb2067bdfdb2c93cce7828a71 (patch)
tree0f797acfa0d661175169ba094c298227099470d7 /clients
parent305821c2b3a71f6baa33c29d60147204aefcad76 (diff)
parent71f607c43a88e54efaf4a1eae82141e933bbdd11 (diff)
downloadulab-a4eb3d14df4d5c3bb2067bdfdb2c93cce7828a71.tar.gz
ulab-a4eb3d14df4d5c3bb2067bdfdb2c93cce7828a71.zip
Merge branch 'master' of https://scm.trinitydesktop.org/scm/git/remotelaboratory
Diffstat (limited to 'clients')
-rw-r--r--clients/tde/src/part/fpgaview/Makefile.am2
-rw-r--r--clients/tde/src/part/fpgaview/layout.ui9
-rw-r--r--clients/tde/src/part/fpgaview/part.cpp427
-rw-r--r--clients/tde/src/part/fpgaview/part.h43
-rw-r--r--clients/tde/src/part/prototerminal/part.cpp327
-rw-r--r--clients/tde/src/part/prototerminal/part.h64
-rw-r--r--clients/tde/src/widgets/Makefile.am5
-rw-r--r--clients/tde/src/widgets/floatspinbox.cpp4
-rw-r--r--clients/tde/src/widgets/sevensegment.cpp621
-rw-r--r--clients/tde/src/widgets/sevensegment.h99
-rw-r--r--clients/tde/src/widgets/tracewidget.cpp2
-rw-r--r--clients/tde/src/widgets/tracewidget.h9
12 files changed, 1024 insertions, 588 deletions
diff --git a/clients/tde/src/part/fpgaview/Makefile.am b/clients/tde/src/part/fpgaview/Makefile.am
index a3f4d3c..f1efd6a 100644
--- a/clients/tde/src/part/fpgaview/Makefile.am
+++ b/clients/tde/src/part/fpgaview/Makefile.am
@@ -6,6 +6,6 @@ KDE_ICON = libremotelab_fpgaviewer
# Part
kde_module_LTLIBRARIES = libremotelab_fpgaviewer.la
-libremotelab_fpgaviewer_la_LIBADD = ../../widgets/libtracewidget.la ../../widgets/libfloatspinbox.la $(LIB_KFILE) $(LIB_TDEPARTS) $(LIB_TDEUI) $(LIB_QT) -ltdekrbsocket -ltqtrla
+libremotelab_fpgaviewer_la_LIBADD = ../../widgets/libtracewidget.la ../../widgets/libfloatspinbox.la ../../widgets/libsevensegment.la $(LIB_KFILE) $(LIB_TDEPARTS) $(LIB_TDEUI) $(LIB_QT) -ltdekrbsocket -ltqtrla
libremotelab_fpgaviewer_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) $(LIB_TDECORE) $(LIB_TDEUI) -ltdeio -ltdefx -ltdemdi
libremotelab_fpgaviewer_la_SOURCES = part.cpp layout.ui
diff --git a/clients/tde/src/part/fpgaview/layout.ui b/clients/tde/src/part/fpgaview/layout.ui
index 95328ab..c31612a 100644
--- a/clients/tde/src/part/fpgaview/layout.ui
+++ b/clients/tde/src/part/fpgaview/layout.ui
@@ -452,7 +452,7 @@
<property name="margin">
<number>2</number>
</property>
- <widget class="FPGA7Segment" row="0" column="0">
+ <widget class="Display7Segment" row="0" column="0">
<property name="name">
<cstring>LEDOutputDisplayDigit0</cstring>
</property>
@@ -463,7 +463,7 @@
</size>
</property>
</widget>
- <widget class="FPGA7Segment" row="0" column="1">
+ <widget class="Display7Segment" row="0" column="1">
<property name="name">
<cstring>LEDOutputDisplayDigit1</cstring>
</property>
@@ -474,7 +474,7 @@
</size>
</property>
</widget>
- <widget class="FPGA7Segment" row="0" column="2">
+ <widget class="Display7Segment" row="0" column="2">
<property name="name">
<cstring>LEDOutputDisplayDigit2</cstring>
</property>
@@ -485,7 +485,7 @@
</size>
</property>
</widget>
- <widget class="FPGA7Segment" row="0" column="3">
+ <widget class="Display7Segment" row="0" column="3">
<property name="name">
<cstring>LEDOutputDisplayDigit3</cstring>
</property>
@@ -838,6 +838,7 @@
<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>
<include location="local" impldecl="in implementation">part.h</include>
</includes>
<layoutdefaults spacing="3" margin="6"/>
diff --git a/clients/tde/src/part/fpgaview/part.cpp b/clients/tde/src/part/fpgaview/part.cpp
index 2e2a615..fd7aec9 100644
--- a/clients/tde/src/part/fpgaview/part.cpp
+++ b/clients/tde/src/part/fpgaview/part.cpp
@@ -128,433 +128,6 @@ void FPGAPushButton::leaveEvent(TQEvent *e) {
}
}
-FPGA7Segment::FPGA7Segment( TQWidget *parent, const char *name )
- : TQFrame( parent, name )
-{
- init();
-}
-
-FPGA7Segment::~FPGA7Segment() {
- free(m_prevSegments);
- free(m_currentSegments);
-}
-
-void FPGA7Segment::init() {
- setFrameStyle(TQFrame::Box | TQFrame::Raised);
- prevSegments = 0;
- val = 0;
- smallPoint = TRUE;
- setSegmentStyle(Flat);
- m_prevSegments = (char*)malloc(sizeof(char)*9);
- m_currentSegments = (char*)malloc(sizeof(char)*9);
- m_prevSegments[0] = 99;
- m_currentSegments[0] = 99;
- setSizePolicy(TQSizePolicy(TQSizePolicy::Minimum, TQSizePolicy::Minimum));
-}
-
-void FPGA7Segment::setLitSegments(unsigned char segs) {
- // This produces an array of up to 10 chars, with each char being the number of a lit segment, and the list being terminated with the number 99
- // The bit input in segs is active high
- // The bit sequence, MSB to LSB, is dp a b c d e f g
- // Segment letters are taken from ug130.pdf
-
- if (prevSegments != segs) {
- int i = 0;
- if (segs & 0x80) { m_currentSegments[i] = 7; i++; }
- if (segs & 0x40) { m_currentSegments[i] = 0; i++; }
- if (segs & 0x20) { m_currentSegments[i] = 2; i++; }
- if (segs & 0x10) { m_currentSegments[i] = 5; i++; }
- if (segs & 0x08) { m_currentSegments[i] = 6; i++; }
- if (segs & 0x04) { m_currentSegments[i] = 4; i++; }
- if (segs & 0x02) { m_currentSegments[i] = 1; i++; }
- if (segs & 0x01) { m_currentSegments[i] = 3; i++; }
-
- m_currentSegments[i] = 99;
-
- update();
- }
-
- prevSegments = segs;
-}
-
-void FPGA7Segment::drawContents( TQPainter *p )
-{
- // Draw all segments
- TQPoint pos;
- int digitSpace = smallPoint ? 2 : 1;
- int xSegLen = width()*5/(1*(5 + digitSpace) + digitSpace);
- int ySegLen = height()*5/12;
- int segLen = ySegLen > xSegLen ? xSegLen : ySegLen;
- int xAdvance = segLen*( 5 + 1 )/5;
- int xOffset = ( width() - xAdvance + segLen/5 )/2;
- int yOffset = ( height() - segLen*2 )/2;
-
- pos = TQPoint(xOffset, yOffset);
- drawDigit(pos, *p, segLen, m_currentSegments);
-}
-
-TQSize FPGA7Segment::sizeHint() const {
- return TQSize(10 + 9 * (1 + (smallPoint ? 0 : 1)), 23);
-}
-
-void FPGA7Segment::setSegmentStyle( SegmentStyle s ) {
- fill = (s == Flat || s == Filled);
- shadow = (s == Outline || s == Filled);
- update();
-}
-
-FPGA7Segment::SegmentStyle FPGA7Segment::segmentStyle() const {
- Q_ASSERT(fill || shadow);
- if (!fill && shadow) {
- return Outline;
- }
- if (fill && shadow) {
- return Filled;
- }
- return Flat;
-}
-
-static void addPoint( TQPointArray &a, const TQPoint &p ) {
- uint n = a.size();
- a.resize(n + 1);
- a.setPoint(n, p);
-}
-
-void FPGA7Segment::drawDigit(const TQPoint &pos, TQPainter &p, int segLen, const char *newSegs) {
- char updates[20][2]; // Can hold 2 times number of segments, only
- // first 10 used if segment table is correct
- int nErases;
- int nUpdates;
- const char *segs;
- int i,j;
-
- const char erase = 0;
- const char draw = 1;
-// const char leaveAlone = 2;
-
- segs = m_prevSegments;
- for ( nErases=0; segs[nErases] != 99; nErases++ ) {
- updates[nErases][0] = erase; // Get segments to erase to
- updates[nErases][1] = segs[nErases]; // remove old char
- }
- nUpdates = nErases;
- segs = newSegs;
- for(i = 0 ; segs[i] != 99 ; i++) {
- for ( j=0; j<nErases; j++ ) {
- if ( segs[i] == updates[j][1] ) { // Same segment ?
-// FIXME
-// Always redraw segments for now, as dragging windows in front of the LED display currently erases the occluded portion(s) of the display!
-#if 0
- updates[j][0] = leaveAlone; // yes, already on screen
- break;
-#endif
- }
- }
- if ( j == nErases ) { // If not already on screen
- updates[nUpdates][0] = draw;
- updates[nUpdates][1] = segs[i];
- nUpdates++;
- }
- }
- for ( i=0; i<nUpdates; i++ ) {
- if ( updates[i][0] == draw ) {
- drawSegment( pos, updates[i][1], p, segLen );
- }
- if (updates[i][0] == erase) {
- drawSegment( pos, updates[i][1], p, segLen, TRUE );
- }
- }
-
- memcpy(m_prevSegments, newSegs, sizeof(char)*9);
-}
-
-void FPGA7Segment::drawSegment(const TQPoint &pos, char segmentNo, TQPainter &p, int segLen, bool erase) {
- TQPoint pt = pos;
- int width = segLen/5;
-
- const TQColorGroup & g = colorGroup();
- TQColor lightColor,darkColor,fgColor;
- if (erase) {
- lightColor = backgroundColor();
- darkColor = lightColor;
- fgColor = lightColor;
- }
- else {
- lightColor = g.light();
- darkColor = g.dark();
- fgColor = g.foreground();
- }
-
-#define LINETO(X,Y) addPoint( a, TQPoint(pt.x() + (X),pt.y() + (Y)))
-#define LIGHT
-#define DARK
-
- if ( fill ) {
- TQPointArray a(0);
-
- //The following is an exact copy of the switch below.
- //don't make any changes here
- switch ( segmentNo ) {
- case 0 :
- p.moveTo(pt);
- LIGHT;
- LINETO(segLen - 1,0);
- DARK;
- LINETO(segLen - width - 1,width);
- LINETO(width,width);
- LINETO(0,0);
- break;
- case 1 :
- pt += TQPoint(0 , 1);
- p.moveTo(pt);
- LIGHT;
- LINETO(width,width);
- DARK;
- LINETO(width,segLen - width/2 - 2);
- LINETO(0,segLen - 2);
- LIGHT;
- LINETO(0,0);
- break;
- case 2 :
- pt += TQPoint(segLen - 1 , 1);
- p.moveTo(pt);
- DARK;
- LINETO(0,segLen - 2);
- LINETO(-width,segLen - width/2 - 2);
- LIGHT;
- LINETO(-width,width);
- LINETO(0,0);
- break;
- case 3 :
- pt += TQPoint(0 , segLen);
- p.moveTo(pt);
- LIGHT;
- LINETO(width,-width/2);
- LINETO(segLen - width - 1,-width/2);
- LINETO(segLen - 1,0);
- DARK;
- if (width & 1) { // adjust for integer division error
- LINETO(segLen - width - 3,width/2 + 1);
- LINETO(width + 2,width/2 + 1);
- } else {
- LINETO(segLen - width - 1,width/2);
- LINETO(width,width/2);
- }
- LINETO(0,0);
- break;
- case 4 :
- pt += TQPoint(0 , segLen + 1);
- p.moveTo(pt);
- LIGHT;
- LINETO(width,width/2);
- DARK;
- LINETO(width,segLen - width - 2);
- LINETO(0,segLen - 2);
- LIGHT;
- LINETO(0,0);
- break;
- case 5 :
- pt += TQPoint(segLen - 1 , segLen + 1);
- p.moveTo(pt);
- DARK;
- LINETO(0,segLen - 2);
- LINETO(-width,segLen - width - 2);
- LIGHT;
- LINETO(-width,width/2);
- LINETO(0,0);
- break;
- case 6 :
- pt += TQPoint(0 , segLen*2);
- p.moveTo(pt);
- LIGHT;
- LINETO(width,-width);
- LINETO(segLen - width - 1,-width);
- LINETO(segLen - 1,0);
- DARK;
- LINETO(0,0);
- break;
- case 7 :
- if ( smallPoint ) // if smallpoint place'.' between other digits
- pt += TQPoint(segLen + width/2 , segLen*2);
- else
- pt += TQPoint(segLen/2 , segLen*2);
- p.moveTo(pt);
- DARK;
- LINETO(width,0);
- LINETO(width,-width);
- LIGHT;
- LINETO(0,-width);
- LINETO(0,0);
- break;
- case 8 :
- pt += TQPoint(segLen/2 - width/2 + 1 , segLen/2 + width);
- p.moveTo(pt);
- DARK;
- LINETO(width,0);
- LINETO(width,-width);
- LIGHT;
- LINETO(0,-width);
- LINETO(0,0);
- break;
- case 9 :
- pt += TQPoint(segLen/2 - width/2 + 1 , 3*segLen/2 + width);
- p.moveTo(pt);
- DARK;
- LINETO(width,0);
- LINETO(width,-width);
- LIGHT;
- LINETO(0,-width);
- LINETO(0,0);
- break;
-#if defined(QT_CHECK_RANGE)
- default :
- tqWarning( "FPGA7Segment::drawSegment: (%s) Internal error."
- " Illegal segment id: %d\n",
- name( "unnamed" ), segmentNo );
-#endif
- }
- // End exact copy
- p.setPen( fgColor );
- p.setBrush( fgColor );
- p.drawPolygon( a );
- p.setBrush( NoBrush );
-
- pt = pos;
- }
-#undef LINETO
-#undef LIGHT
-#undef DARK
-
-#define LINETO(X,Y) p.lineTo(TQPoint(pt.x() + (X),pt.y() + (Y)))
-#define LIGHT p.setPen(lightColor)
-#define DARK p.setPen(darkColor)
- if ( shadow ) {
- switch ( segmentNo ) {
- case 0 :
- p.moveTo(pt);
- LIGHT;
- LINETO(segLen - 1,0);
- DARK;
- LINETO(segLen - width - 1,width);
- LINETO(width,width);
- LINETO(0,0);
- break;
- case 1 :
- pt += TQPoint(0,1);
- p.moveTo(pt);
- LIGHT;
- LINETO(width,width);
- DARK;
- LINETO(width,segLen - width/2 - 2);
- LINETO(0,segLen - 2);
- LIGHT;
- LINETO(0,0);
- break;
- case 2 :
- pt += TQPoint(segLen - 1 , 1);
- p.moveTo(pt);
- DARK;
- LINETO(0,segLen - 2);
- LINETO(-width,segLen - width/2 - 2);
- LIGHT;
- LINETO(-width,width);
- LINETO(0,0);
- break;
- case 3 :
- pt += TQPoint(0 , segLen);
- p.moveTo(pt);
- LIGHT;
- LINETO(width,-width/2);
- LINETO(segLen - width - 1,-width/2);
- LINETO(segLen - 1,0);
- DARK;
- if (width & 1) { // adjust for integer division error
- LINETO(segLen - width - 3,width/2 + 1);
- LINETO(width + 2,width/2 + 1);
- } else {
- LINETO(segLen - width - 1,width/2);
- LINETO(width,width/2);
- }
- LINETO(0,0);
- break;
- case 4 :
- pt += TQPoint(0 , segLen + 1);
- p.moveTo(pt);
- LIGHT;
- LINETO(width,width/2);
- DARK;
- LINETO(width,segLen - width - 2);
- LINETO(0,segLen - 2);
- LIGHT;
- LINETO(0,0);
- break;
- case 5 :
- pt += TQPoint(segLen - 1 , segLen + 1);
- p.moveTo(pt);
- DARK;
- LINETO(0,segLen - 2);
- LINETO(-width,segLen - width - 2);
- LIGHT;
- LINETO(-width,width/2);
- LINETO(0,0);
- break;
- case 6 :
- pt += TQPoint(0 , segLen*2);
- p.moveTo(pt);
- LIGHT;
- LINETO(width,-width);
- LINETO(segLen - width - 1,-width);
- LINETO(segLen - 1,0);
- DARK;
- LINETO(0,0);
- break;
- case 7 :
- if ( smallPoint ) // if smallpoint place'.' between other digits
- pt += TQPoint(segLen + width/2 , segLen*2);
- else
- pt += TQPoint(segLen/2 , segLen*2);
- p.moveTo(pt);
- DARK;
- LINETO(width,0);
- LINETO(width,-width);
- LIGHT;
- LINETO(0,-width);
- LINETO(0,0);
- break;
- case 8 :
- pt += TQPoint(segLen/2 - width/2 + 1 , segLen/2 + width);
- p.moveTo(pt);
- DARK;
- LINETO(width,0);
- LINETO(width,-width);
- LIGHT;
- LINETO(0,-width);
- LINETO(0,0);
- break;
- case 9 :
- pt += TQPoint(segLen/2 - width/2 + 1 , 3*segLen/2 + width);
- p.moveTo(pt);
- DARK;
- LINETO(width,0);
- LINETO(width,-width);
- LIGHT;
- LINETO(0,-width);
- LINETO(0,0);
- break;
-#if defined(QT_CHECK_RANGE)
- default :
- tqWarning( "FPGA7Segment::drawSegment: (%s) Internal error."
- " Illegal segment id: %d\n",
- name( "unnamed" ), segmentNo );
-#endif
- }
- }
-
-#undef LINETO
-#undef LIGHT
-#undef DARK
-}
-
ImageViewerWindow::ImageViewerWindow(TQString caption, TQWidget *parent, const char *name)
: KMdiChildView(caption, parent, name)
{
diff --git a/clients/tde/src/part/fpgaview/part.h b/clients/tde/src/part/fpgaview/part.h
index 023c051..57e1971 100644
--- a/clients/tde/src/part/fpgaview/part.h
+++ b/clients/tde/src/part/fpgaview/part.h
@@ -26,7 +26,6 @@
#include <tdekrbclientsocket.h>
#include <tqcstring.h>
-#include <tqframe.h>
#include <tqimage.h>
#include <ksimpleconfig.h>
@@ -41,6 +40,8 @@
#include <tqtrla.h>
+#include <sevensegment.h>
+
class TDEAboutData;
using KParts::StatusBarExtension;
class TraceWidget;
@@ -90,46 +91,6 @@ class FPGAPushButton : public KLed
bool mouseDown;
};
-class FPGA7SegmentPrivate;
-
-class TQ_EXPORT FPGA7Segment : public TQFrame
-{
- Q_OBJECT
- TQ_ENUMS(SegmentStyle)
- TQ_PROPERTY(SegmentStyle segmentStyle READ segmentStyle WRITE setSegmentStyle)
-
- public:
- FPGA7Segment(TQWidget* parent=0, const char* name=0);
- ~FPGA7Segment();
-
- enum SegmentStyle { Outline, Filled, Flat };
-
- SegmentStyle segmentStyle() const;
- virtual void setSegmentStyle(SegmentStyle);
-
- void setLitSegments(unsigned char);
-
- TQSize sizeHint() const;
-
- protected:
- void drawContents(TQPainter *);
-
- private:
- void init();
- void drawSegment(const TQPoint &, char, TQPainter &, int, bool = FALSE);
- void drawDigit(const TQPoint &, TQPainter &, int, const char *);
-
- char* m_prevSegments;
- char* m_currentSegments;
-
- unsigned int prevSegments;
- double val;
- uint smallPoint : 1;
- uint fill : 1;
- uint shadow : 1;
- FPGA7SegmentPrivate *d;
-};
-
class ImageViewerWindow : public KMdiChildView
{
Q_OBJECT
diff --git a/clients/tde/src/part/prototerminal/part.cpp b/clients/tde/src/part/prototerminal/part.cpp
index 7818988..b5e5a1d 100644
--- a/clients/tde/src/part/prototerminal/part.cpp
+++ b/clients/tde/src/part/prototerminal/part.cpp
@@ -15,11 +15,20 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * (c) 2014 Timothy Pearson
+ * (c) 2014 - 2015 Timothy Pearson
* Raptor Engineering
* http://www.raptorengineeringinc.com
*/
+/* This part illustrates the correct method of transmitting and receiving
+ * data in a dedicated thread, using two separate message queues to enable
+ * fully non-blocking, event-driven execution.
+ *
+ * NOTE
+ * inboundQueue is filled by the GUI thread with data inbound to the worker thread
+ * outboundQueue is filled by the worker thread with data outbound to the GUI thread
+ */
+
#include "define.h"
#include "part.h"
@@ -60,6 +69,146 @@ typedef KParts::GenericFactory<RemoteLab::ProtoTerminalPart> Factory;
#define CLIENT_LIBRARY "libremotelab_prototerminal"
K_EXPORT_COMPONENT_FACTORY( libremotelab_prototerminal, RemoteLab::Factory )
+ProtoTerminalWorker::ProtoTerminalWorker() : TQObject() {
+ m_networkDataMutex = new TQMutex(false);
+ m_outboundQueueMutex = new TQMutex(false);
+ m_inboundQueueMutex = new TQMutex(false);
+ m_newData = false;
+}
+
+ProtoTerminalWorker::~ProtoTerminalWorker() {
+ delete m_networkDataMutex;
+ m_networkDataMutex = NULL;
+ delete m_inboundQueueMutex;
+ m_inboundQueueMutex = NULL;
+ delete m_outboundQueueMutex;
+ m_outboundQueueMutex = NULL;
+}
+
+void ProtoTerminalWorker::run() {
+ TQEventLoop* eventLoop = TQApplication::eventLoop();
+ if (!eventLoop) {
+ return;
+ }
+
+ while (1) {
+ m_instrumentMutex->lock();
+
+ // Handle inbound queue
+ m_inboundQueueMutex->lock();
+ if (m_inboundQueue.count() > 0) {
+ TQDataStream ds(m_socket);
+ ds.setPrintableData(true);
+
+ ProtoTerminalEventQueue::iterator it;
+ for (it = m_inboundQueue.begin(); it != m_inboundQueue.end(); ++it) {
+ if ((*it).first == TxRxSyncPoint) {
+ break;
+ }
+ if ((*it).first == ConsoleTextSend) {
+ ds << (*it).second.toString();
+ m_socket->writeEndOfFrame();
+ }
+ it = m_inboundQueue.erase(it);
+ }
+ 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);
+
+ // Get command status
+ TQString input;
+ while (!ds.atEnd()) {
+ ds >> input;
+ m_outboundQueueMutex->lock();
+ m_outboundQueue.push_back(ProtoTerminalEvent(ConsoleTextReceive, TQVariant(input)));
+ m_outboundQueueMutex->unlock();
+ queue_modified = true;
+ }
+ m_socket->clearFrameTail();
+ }
+ m_networkDataMutex->unlock();
+
+ if (queue_modified) {
+ m_inboundQueueMutex->lock();
+ ProtoTerminalEventQueue::iterator it = m_inboundQueue.begin();
+ if ((it) && (it != m_inboundQueue.end())) {
+ // Remove sync point
+ if ((*it).first == TxRxSyncPoint) {
+ it = m_inboundQueue.erase(it);
+ }
+ }
+ m_inboundQueueMutex->unlock();
+ 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 ProtoTerminalWorker::appendItemToInboundQueue(ProtoTerminalEvent item, bool syncPoint) {
+ m_inboundQueueMutex->lock();
+ m_inboundQueue.push_back(item);
+ if (syncPoint) {
+ m_inboundQueue.push_back(ProtoTerminalEvent(TxRxSyncPoint, TQVariant()));
+ }
+ m_inboundQueueMutex->unlock();
+}
+
+bool ProtoTerminalWorker::syncPointActive() {
+ bool active = false;
+
+ m_inboundQueueMutex->lock();
+ ProtoTerminalEventQueue::iterator it = m_inboundQueue.begin();
+ if ((it) && (it != m_inboundQueue.end())) {
+ if ((*it).first == TxRxSyncPoint) {
+ active = true;
+ }
+ }
+ m_inboundQueueMutex->unlock();
+
+ return active;
+}
+
+void ProtoTerminalWorker::wake() {
+ // Do nothing -- the main event loop will wake when this is called
+}
+
+void ProtoTerminalWorker::dataReceived() {
+ m_networkDataMutex->lock();
+ m_newData = true;
+ m_networkDataMutex->unlock();
+}
+
+void ProtoTerminalWorker::lockOutboundQueue() {
+ m_outboundQueueMutex->lock();
+}
+
+void ProtoTerminalWorker::unlockOutboundQueue() {
+ m_outboundQueueMutex->unlock();
+}
+
+ProtoTerminalEventQueue* ProtoTerminalWorker::outboundQueue() {
+ return &m_outboundQueue;
+}
ProtoTerminalPart::ProtoTerminalPart( 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_base(0)
@@ -74,11 +223,16 @@ ProtoTerminalPart::ProtoTerminalPart( TQWidget *parentWidget, const char *widget
setInstance(Factory::instance());
setWidget(new TQVBox(parentWidget, widgetName));
+ // Set up worker
+ m_worker = new ProtoTerminalWorker();
+ 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_forcedUpdateTimer = new TQTimer(this);
- connect(m_forcedUpdateTimer, SIGNAL(timeout()), this, SLOT(mainEventLoop()));
m_updateTimeoutTimer = new TQTimer(this);
- connect(m_updateTimeoutTimer, SIGNAL(timeout()), this, SLOT(mainEventLoop()));
+ connect(m_updateTimeoutTimer, SIGNAL(timeout()), this, SLOT(networkTimeout()));
// Create widgets
m_base = new ProtoTerminalBase(widget());
@@ -99,6 +253,15 @@ ProtoTerminalPart::~ProtoTerminalPart() {
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 ProtoTerminalPart::postInit() {
@@ -129,22 +292,31 @@ void ProtoTerminalPart::processLockouts() {
}
void ProtoTerminalPart::disconnectFromServerCallback() {
- m_forcedUpdateTimer->stop();
m_updateTimeoutTimer->stop();
m_connectionActiveAndValid = false;
}
void ProtoTerminalPart::connectionFinishedCallback() {
+ // Finish worker setup
+ m_worker->m_socket = m_socket;
+ m_worker->m_instrumentMutex = m_instrumentMutex;
+ m_socket->moveToThread(m_workerThread);
+
connect(m_socket, SIGNAL(readyRead()), m_socket, SLOT(processPendingData()));
m_socket->processPendingData();
- connect(m_socket, SIGNAL(newDataReceived()), this, SLOT(mainEventLoop()));
+ 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();
- mainEventLoop();
+ networkTick();
return;
}
@@ -176,119 +348,60 @@ void ProtoTerminalPart::setTickerMessage(TQString message) {
}
}
-#define UPDATEDISPLAY_TIMEOUT m_connectionActiveAndValid = false; \
- m_tickerState = 0; \
- m_commHandlerState = 2; \
- m_commHandlerMode = 0; \
- m_socket->clearIncomingData(); \
- setStatusMessage(i18n("Server ping timeout. Please verify the status of your network connection.")); \
- m_updateTimeoutTimer->start(NETWORK_COMM_TIMEOUT_MS, TRUE); \
- m_instrumentMutex->unlock(); \
- return;
-
-#define COMMUNICATIONS_FAILED m_connectionActiveAndValid = false; \
- m_tickerState = 0; \
- m_commHandlerState = 2; \
- m_commHandlerMode = 0; \
- m_socket->clearIncomingData(); \
- setStatusMessage(i18n("Instrument communication failure. Please verify the status of your network connection.")); \
- m_updateTimeoutTimer->start(NETWORK_COMM_TIMEOUT_MS, TRUE); \
- m_instrumentMutex->unlock(); \
- return;
-
-#define SET_WATCHDOG_TIMER if (!m_updateTimeoutTimer->isActive()) m_updateTimeoutTimer->start(NETWORK_COMM_TIMEOUT_MS, TRUE);
-#define PAT_WATCHDOG_TIMER m_updateTimeoutTimer->stop(); m_updateTimeoutTimer->start(NETWORK_COMM_TIMEOUT_MS, TRUE); \
- setTickerMessage(i18n("Connected"));
-
-#define SET_NEXT_STATE(x) if (m_commHandlerMode == 0) { \
- m_commHandlerState = x; \
- } \
- else { \
- m_commHandlerState = 255; \
- }
-
-#define EXEC_NEXT_STATE_IMMEDIATELY m_forcedUpdateTimer->start(0, TRUE);
-
-void ProtoTerminalPart::mainEventLoop() {
- TQDataStream ds(m_socket);
- ds.setPrintableData(true);
-
- if (!m_instrumentMutex->tryLock()) {
- EXEC_NEXT_STATE_IMMEDIATELY
- return;
- }
-
- if (m_socket) {
- if ((m_commHandlerMode == 0) || (m_commHandlerMode == 1)) {
- if (m_commHandlerState == 0) {
- // Setup functions go here
- setTickerMessage("Connection established");
-
- m_commHandlerState = 1;
- EXEC_NEXT_STATE_IMMEDIATELY
- }
- else if (m_commHandlerState == 1) {
- // Receive data
- if (m_socket->canReadFrame()) {
- PAT_WATCHDOG_TIMER
-
- // Get command status
- TQString input;
- while (!ds.atEnd()) {
- ds >> input;
-
- if (input != "") {
- input.replace("\r", "\n");
- m_base->textOutput->append(">>>" + input);
- }
- }
- m_socket->clearFrameTail();
- EXEC_NEXT_STATE_IMMEDIATELY
- }
- else {
- if (!m_updateTimeoutTimer->isActive()) {
- UPDATEDISPLAY_TIMEOUT
- }
- }
-
- // Send data
- if (m_TextToSend != "") {
- ds << m_TextToSend;
- m_socket->writeEndOfFrame();
+void ProtoTerminalPart::processOutboundQueue() {
+ bool had_events = false;
- m_base->textOutput->append("<<<" + m_TextToSend);
- m_TextToSend = "";
+ m_worker->lockOutboundQueue();
- EXEC_NEXT_STATE_IMMEDIATELY
- }
-
- // Never time out
- PAT_WATCHDOG_TIMER
- }
- else if (m_commHandlerState == 2) {
- // Ignore timeouts
- m_commHandlerState = 1;
- EXEC_NEXT_STATE_IMMEDIATELY
+ ProtoTerminalEventQueue* eventQueue = m_worker->outboundQueue();
+ ProtoTerminalEventQueue::iterator it;
+ for (it = eventQueue->begin(); it != eventQueue->end(); ++it) {
+ if ((*it).first == ConsoleTextReceive) {
+ TQString input = (*it).second.toString();
+ if (input != "") {
+ input.replace("\r", "\n");
+ m_base->textOutput->append(">>>" + input);
}
- SET_WATCHDOG_TIMER
}
+ had_events = true;
}
- else {
- m_commHandlerState = 0;
- m_commHandlerCommandState = 0;
+ if (had_events) {
+ networkTick();
+ eventQueue->clear();
}
+ m_worker->unlockOutboundQueue();
+
processLockouts();
+}
- m_instrumentMutex->unlock();
+void ProtoTerminalPart::networkTick() {
+ m_updateTimeoutTimer->stop();
+ setTickerMessage(i18n("Connected"));
+ m_connectionActiveAndValid = true;
+ processLockouts();
+}
+
+void ProtoTerminalPart::networkTimeout() {
+ m_updateTimeoutTimer->stop();
+ m_socket->clearIncomingData();
+ setStatusMessage(i18n("Server ping timeout. Please verify the status of your network connection."));
+ m_connectionActiveAndValid = false;
+ processLockouts();
}
void ProtoTerminalPart::sendTextClicked() {
- m_TextToSend = m_TextToSend + m_base->textInput->text();
- m_base->textInput->setText("");
+ if (!m_worker->syncPointActive()) {
+ m_TextToSend = m_TextToSend + m_base->textInput->text();
+ m_base->textInput->setText("");
- // Transmit!
- EXEC_NEXT_STATE_IMMEDIATELY
+ m_worker->appendItemToInboundQueue(ProtoTerminalEvent(ConsoleTextSend, TQVariant(m_TextToSend)), true);
+ m_base->textOutput->append("<<<" + m_TextToSend);
+ m_TextToSend = "";
+
+ emit wakeWorkerThread();
+ m_updateTimeoutTimer->start(NETWORK_COMM_TIMEOUT_MS, TRUE);
+ }
}
TDEAboutData* ProtoTerminalPart::createAboutData() {
diff --git a/clients/tde/src/part/prototerminal/part.h b/clients/tde/src/part/prototerminal/part.h
index 5bc0a02..a7ad658 100644
--- a/clients/tde/src/part/prototerminal/part.h
+++ b/clients/tde/src/part/prototerminal/part.h
@@ -15,7 +15,7 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * (c) 2014 Timothy Pearson
+ * (c) 2014 - 2015 Timothy Pearson
* Raptor Engineering
* http://www.raptorengineeringinc.com
*/
@@ -23,6 +23,12 @@
#ifndef REMOTELAB_PROTOTERMINALPART_H
#define REMOTELAB_PROTOTERMINALPART_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>
@@ -41,6 +47,51 @@ class ProtoTerminalBase;
namespace RemoteLab
{
+ typedef enum ProtoTerminalEventType {
+ ConsoleTextReceive = 0,
+ ConsoleTextSend = 1,
+ TxRxSyncPoint = 2
+ } ProtoTerminalEventType;
+
+ typedef TQPair<ProtoTerminalEventType, TQVariant> ProtoTerminalEvent;
+ typedef TQValueVector<ProtoTerminalEvent> ProtoTerminalEventQueue;
+
+ class ProtoTerminalWorker : public TQObject
+ {
+ TQ_OBJECT
+
+ public:
+ ProtoTerminalWorker();
+ ~ProtoTerminalWorker();
+
+ signals:
+ void outboundQueueUpdated();
+
+ public slots:
+ void run();
+ void wake();
+ void dataReceived();
+
+ public:
+ void appendItemToInboundQueue(ProtoTerminalEvent item, bool syncPoint=false);
+ bool syncPointActive();
+ void lockOutboundQueue();
+ void unlockOutboundQueue();
+ ProtoTerminalEventQueue* outboundQueue();
+
+ public:
+ TDEKerberosClientSocket* m_socket;
+ TQMutex* m_instrumentMutex;
+
+ private:
+ ProtoTerminalEventQueue m_outboundQueue;
+ ProtoTerminalEventQueue m_inboundQueue;
+ TQMutex* m_outboundQueueMutex;
+ TQMutex* m_inboundQueueMutex;
+ TQMutex* m_networkDataMutex;
+ bool m_newData;
+ };
+
class ProtoTerminalPart : public KParts::RemoteInstrumentPart
{
Q_OBJECT
@@ -53,8 +104,12 @@ namespace RemoteLab
virtual bool closeURL();
static TDEAboutData *createAboutData();
+ signals:
+ void wakeWorkerThread();
+
public slots:
virtual bool openURL(const KURL &url);
+ void processOutboundQueue();
private slots:
void postInit();
@@ -63,20 +118,23 @@ namespace RemoteLab
void disconnectFromServerCallback();
void connectionStatusChangedCallback();
void setTickerMessage(TQString message);
- void mainEventLoop();
+ void networkTick();
+ void networkTimeout();
void sendTextClicked();
private:
int m_commHandlerState;
int m_commHandlerMode;
int m_commHandlerCommandState;
- TQTimer* m_forcedUpdateTimer;
TQTimer* m_updateTimeoutTimer;
bool m_connectionActiveAndValid;
unsigned char m_tickerState;
ProtoTerminalBase* m_base;
TQMutex* m_instrumentMutex;
TQString m_TextToSend;
+
+ ProtoTerminalWorker* m_worker;
+ TQEventLoopThread* m_workerThread;
};
}
diff --git a/clients/tde/src/widgets/Makefile.am b/clients/tde/src/widgets/Makefile.am
index fac5e76..47f84e0 100644
--- a/clients/tde/src/widgets/Makefile.am
+++ b/clients/tde/src/widgets/Makefile.am
@@ -1,6 +1,7 @@
INCLUDES = $(all_includes) $(KDE_INCLUDES)/tde
METASOURCES = AUTO
-noinst_LTLIBRARIES = libtracewidget.la libfloatspinbox.la
+noinst_LTLIBRARIES = libtracewidget.la libfloatspinbox.la libsevensegment.la
libtracewidget_la_SOURCES = tracewidget.cpp
libtracewidget_la_LDFLAGS = $(all_libraries) -ltqtrla
-libfloatspinbox_la_SOURCES = floatspinbox.cpp \ No newline at end of file
+libfloatspinbox_la_SOURCES = floatspinbox.cpp
+libsevensegment_la_SOURCES = sevensegment.cpp \ No newline at end of file
diff --git a/clients/tde/src/widgets/floatspinbox.cpp b/clients/tde/src/widgets/floatspinbox.cpp
index caf0d31..9592968 100644
--- a/clients/tde/src/widgets/floatspinbox.cpp
+++ b/clients/tde/src/widgets/floatspinbox.cpp
@@ -108,4 +108,6 @@ void FloatSpinBox::acceptValueChanged(int ival) {
FloatSpinBox::~FloatSpinBox()
{
//
-} \ No newline at end of file
+}
+
+#include "floatspinbox.moc" \ No newline at end of file
diff --git a/clients/tde/src/widgets/sevensegment.cpp b/clients/tde/src/widgets/sevensegment.cpp
new file mode 100644
index 0000000..d7e7a07
--- /dev/null
+++ b/clients/tde/src/widgets/sevensegment.cpp
@@ -0,0 +1,621 @@
+/*
+ * Remote Laboratory Seven Segment Display Widget
+ *
+ * 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) 2012 - 2015 Timothy Pearson
+ * Raptor Engineering
+ * http://www.raptorengineeringinc.com
+ */
+
+#include <stdlib.h>
+
+#include <tqpainter.h>
+
+#include "sevensegment.h"
+
+Display7Segment::Display7Segment( TQWidget *parent, const char *name )
+ : TQFrame( parent, name )
+{
+ init();
+}
+
+Display7Segment::~Display7Segment() {
+ free(m_prevSegments);
+ free(m_currentSegments);
+}
+
+void Display7Segment::init() {
+ setFrameStyle(TQFrame::Box | TQFrame::Raised);
+ prevSegments = 0;
+ val = 0;
+ smallPoint = TRUE;
+ setSegmentStyle(Flat);
+ m_prevSegments = (char*)malloc(sizeof(char)*9);
+ m_currentSegments = (char*)malloc(sizeof(char)*9);
+ m_prevSegments[0] = 99;
+ m_currentSegments[0] = 99;
+ setSizePolicy(TQSizePolicy(TQSizePolicy::Minimum, TQSizePolicy::Minimum));
+}
+
+void Display7Segment::setLitSegments(unsigned char segs) {
+ // This produces an array of up to 10 chars, with each char being the number of a lit segment, and the list being terminated with the number 99
+ // The bit input in segs is active high
+ // The bit sequence, MSB to LSB, is dp a b c d e f g
+ // Segment letters are taken from ug130.pdf
+
+ if (prevSegments != segs) {
+ int i = 0;
+ if (segs & 0x80) { m_currentSegments[i] = 7; i++; }
+ if (segs & 0x40) { m_currentSegments[i] = 0; i++; }
+ if (segs & 0x20) { m_currentSegments[i] = 2; i++; }
+ if (segs & 0x10) { m_currentSegments[i] = 5; i++; }
+ if (segs & 0x08) { m_currentSegments[i] = 6; i++; }
+ if (segs & 0x04) { m_currentSegments[i] = 4; i++; }
+ if (segs & 0x02) { m_currentSegments[i] = 1; i++; }
+ if (segs & 0x01) { m_currentSegments[i] = 3; i++; }
+
+ m_currentSegments[i] = 99;
+
+ update();
+ }
+
+ prevSegments = 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 (dp) {
+ ret |= 0x80;
+ }
+
+ return ret;
+}
+
+void Display7Segment::drawContents( TQPainter *p )
+{
+ // Draw all segments
+ TQPoint pos;
+ int digitSpace = smallPoint ? 2 : 1;
+ int xSegLen = width()*5/(1*(5 + digitSpace) + digitSpace);
+ int ySegLen = height()*5/12;
+ int segLen = ySegLen > xSegLen ? xSegLen : ySegLen;
+ int xAdvance = segLen*( 5 + 1 )/5;
+ int xOffset = ( width() - xAdvance + segLen/5 )/2;
+ int yOffset = ( height() - segLen*2 )/2;
+
+ pos = TQPoint(xOffset, yOffset);
+ drawDigit(pos, *p, segLen, m_currentSegments);
+}
+
+TQSize Display7Segment::sizeHint() const {
+ return TQSize(10 + 9 * (1 + (smallPoint ? 0 : 1)), 23);
+}
+
+void Display7Segment::setSegmentStyle( SegmentStyle s ) {
+ fill = (s == Flat || s == Filled);
+ shadow = (s == Outline || s == Filled);
+ update();
+}
+
+Display7Segment::SegmentStyle Display7Segment::segmentStyle() const {
+ Q_ASSERT(fill || shadow);
+ if (!fill && shadow) {
+ return Outline;
+ }
+ if (fill && shadow) {
+ return Filled;
+ }
+ return Flat;
+}
+
+static void addPoint( TQPointArray &a, const TQPoint &p ) {
+ uint n = a.size();
+ a.resize(n + 1);
+ a.setPoint(n, p);
+}
+
+void Display7Segment::drawDigit(const TQPoint &pos, TQPainter &p, int segLen, const char *newSegs) {
+ char updates[20][2]; // Can hold 2 times number of segments, only
+ // first 10 used if segment table is correct
+ int nErases;
+ int nUpdates;
+ const char *segs;
+ int i,j;
+
+ const char erase = 0;
+ const char draw = 1;
+// const char leaveAlone = 2;
+
+ segs = m_prevSegments;
+ for ( nErases=0; segs[nErases] != 99; nErases++ ) {
+ updates[nErases][0] = erase; // Get segments to erase to
+ updates[nErases][1] = segs[nErases]; // remove old char
+ }
+ nUpdates = nErases;
+ segs = newSegs;
+ for(i = 0 ; segs[i] != 99 ; i++) {
+ for ( j=0; j<nErases; j++ ) {
+ if ( segs[i] == updates[j][1] ) { // Same segment ?
+// FIXME
+// Always redraw segments for now, as dragging windows in front of the LED display currently erases the occluded portion(s) of the display!
+#if 0
+ updates[j][0] = leaveAlone; // yes, already on screen
+ break;
+#endif
+ }
+ }
+ if ( j == nErases ) { // If not already on screen
+ updates[nUpdates][0] = draw;
+ updates[nUpdates][1] = segs[i];
+ nUpdates++;
+ }
+ }
+ for ( i=0; i<nUpdates; i++ ) {
+ if ( updates[i][0] == draw ) {
+ drawSegment( pos, updates[i][1], p, segLen );
+ }
+ if (updates[i][0] == erase) {
+ drawSegment( pos, updates[i][1], p, segLen, TRUE );
+ }
+ }
+
+ memcpy(m_prevSegments, newSegs, sizeof(char)*9);
+}
+
+void Display7Segment::drawSegment(const TQPoint &pos, char segmentNo, TQPainter &p, int segLen, bool erase) {
+ TQPoint pt = pos;
+ int width = segLen/5;
+
+ const TQColorGroup & g = colorGroup();
+ TQColor lightColor,darkColor,fgColor;
+ if (erase) {
+ lightColor = backgroundColor();
+ darkColor = lightColor;
+ fgColor = lightColor;
+ }
+ else {
+ lightColor = g.light();
+ darkColor = g.dark();
+ fgColor = g.foreground();
+ }
+
+#define LINETO(X,Y) addPoint( a, TQPoint(pt.x() + (X),pt.y() + (Y)))
+#define LIGHT
+#define DARK
+
+ if ( fill ) {
+ TQPointArray a(0);
+
+ //The following is an exact copy of the switch below.
+ //don't make any changes here
+ switch ( segmentNo ) {
+ case 0 :
+ p.moveTo(pt);
+ LIGHT;
+ LINETO(segLen - 1,0);
+ DARK;
+ LINETO(segLen - width - 1,width);
+ LINETO(width,width);
+ LINETO(0,0);
+ break;
+ case 1 :
+ pt += TQPoint(0 , 1);
+ p.moveTo(pt);
+ LIGHT;
+ LINETO(width,width);
+ DARK;
+ LINETO(width,segLen - width/2 - 2);
+ LINETO(0,segLen - 2);
+ LIGHT;
+ LINETO(0,0);
+ break;
+ case 2 :
+ pt += TQPoint(segLen - 1 , 1);
+ p.moveTo(pt);
+ DARK;
+ LINETO(0,segLen - 2);
+ LINETO(-width,segLen - width/2 - 2);
+ LIGHT;
+ LINETO(-width,width);
+ LINETO(0,0);
+ break;
+ case 3 :
+ pt += TQPoint(0 , segLen);
+ p.moveTo(pt);
+ LIGHT;
+ LINETO(width,-width/2);
+ LINETO(segLen - width - 1,-width/2);
+ LINETO(segLen - 1,0);
+ DARK;
+ if (width & 1) { // adjust for integer division error
+ LINETO(segLen - width - 3,width/2 + 1);
+ LINETO(width + 2,width/2 + 1);
+ } else {
+ LINETO(segLen - width - 1,width/2);
+ LINETO(width,width/2);
+ }
+ LINETO(0,0);
+ break;
+ case 4 :
+ pt += TQPoint(0 , segLen + 1);
+ p.moveTo(pt);
+ LIGHT;
+ LINETO(width,width/2);
+ DARK;
+ LINETO(width,segLen - width - 2);
+ LINETO(0,segLen - 2);
+ LIGHT;
+ LINETO(0,0);
+ break;
+ case 5 :
+ pt += TQPoint(segLen - 1 , segLen + 1);
+ p.moveTo(pt);
+ DARK;
+ LINETO(0,segLen - 2);
+ LINETO(-width,segLen - width - 2);
+ LIGHT;
+ LINETO(-width,width/2);
+ LINETO(0,0);
+ break;
+ case 6 :
+ pt += TQPoint(0 , segLen*2);
+ p.moveTo(pt);
+ LIGHT;
+ LINETO(width,-width);
+ LINETO(segLen - width - 1,-width);
+ LINETO(segLen - 1,0);
+ DARK;
+ LINETO(0,0);
+ break;
+ case 7 :
+ if ( smallPoint ) // if smallpoint place'.' between other digits
+ pt += TQPoint(segLen + width/2 , segLen*2);
+ else
+ pt += TQPoint(segLen/2 , segLen*2);
+ p.moveTo(pt);
+ DARK;
+ LINETO(width,0);
+ LINETO(width,-width);
+ LIGHT;
+ LINETO(0,-width);
+ LINETO(0,0);
+ break;
+ case 8 :
+ pt += TQPoint(segLen/2 - width/2 + 1 , segLen/2 + width);
+ p.moveTo(pt);
+ DARK;
+ LINETO(width,0);
+ LINETO(width,-width);
+ LIGHT;
+ LINETO(0,-width);
+ LINETO(0,0);
+ break;
+ case 9 :
+ pt += TQPoint(segLen/2 - width/2 + 1 , 3*segLen/2 + width);
+ p.moveTo(pt);
+ DARK;
+ LINETO(width,0);
+ LINETO(width,-width);
+ LIGHT;
+ LINETO(0,-width);
+ LINETO(0,0);
+ break;
+#if defined(QT_CHECK_RANGE)
+ default :
+ tqWarning( "Display7Segment::drawSegment: (%s) Internal error."
+ " Illegal segment id: %d\n",
+ name( "unnamed" ), segmentNo );
+#endif
+ }
+ // End exact copy
+ p.setPen( fgColor );
+ p.setBrush( fgColor );
+ p.drawPolygon( a );
+ p.setBrush( NoBrush );
+
+ pt = pos;
+ }
+#undef LINETO
+#undef LIGHT
+#undef DARK
+
+#define LINETO(X,Y) p.lineTo(TQPoint(pt.x() + (X),pt.y() + (Y)))
+#define LIGHT p.setPen(lightColor)
+#define DARK p.setPen(darkColor)
+ if ( shadow ) {
+ switch ( segmentNo ) {
+ case 0 :
+ p.moveTo(pt);
+ LIGHT;
+ LINETO(segLen - 1,0);
+ DARK;
+ LINETO(segLen - width - 1,width);
+ LINETO(width,width);
+ LINETO(0,0);
+ break;
+ case 1 :
+ pt += TQPoint(0,1);
+ p.moveTo(pt);
+ LIGHT;
+ LINETO(width,width);
+ DARK;
+ LINETO(width,segLen - width/2 - 2);
+ LINETO(0,segLen - 2);
+ LIGHT;
+ LINETO(0,0);
+ break;
+ case 2 :
+ pt += TQPoint(segLen - 1 , 1);
+ p.moveTo(pt);
+ DARK;
+ LINETO(0,segLen - 2);
+ LINETO(-width,segLen - width/2 - 2);
+ LIGHT;
+ LINETO(-width,width);
+ LINETO(0,0);
+ break;
+ case 3 :
+ pt += TQPoint(0 , segLen);
+ p.moveTo(pt);
+ LIGHT;
+ LINETO(width,-width/2);
+ LINETO(segLen - width - 1,-width/2);
+ LINETO(segLen - 1,0);
+ DARK;
+ if (width & 1) { // adjust for integer division error
+ LINETO(segLen - width - 3,width/2 + 1);
+ LINETO(width + 2,width/2 + 1);
+ } else {
+ LINETO(segLen - width - 1,width/2);
+ LINETO(width,width/2);
+ }
+ LINETO(0,0);
+ break;
+ case 4 :
+ pt += TQPoint(0 , segLen + 1);
+ p.moveTo(pt);
+ LIGHT;
+ LINETO(width,width/2);
+ DARK;
+ LINETO(width,segLen - width - 2);
+ LINETO(0,segLen - 2);
+ LIGHT;
+ LINETO(0,0);
+ break;
+ case 5 :
+ pt += TQPoint(segLen - 1 , segLen + 1);
+ p.moveTo(pt);
+ DARK;
+ LINETO(0,segLen - 2);
+ LINETO(-width,segLen - width - 2);
+ LIGHT;
+ LINETO(-width,width/2);
+ LINETO(0,0);
+ break;
+ case 6 :
+ pt += TQPoint(0 , segLen*2);
+ p.moveTo(pt);
+ LIGHT;
+ LINETO(width,-width);
+ LINETO(segLen - width - 1,-width);
+ LINETO(segLen - 1,0);
+ DARK;
+ LINETO(0,0);
+ break;
+ case 7 :
+ if ( smallPoint ) // if smallpoint place'.' between other digits
+ pt += TQPoint(segLen + width/2 , segLen*2);
+ else
+ pt += TQPoint(segLen/2 , segLen*2);
+ p.moveTo(pt);
+ DARK;
+ LINETO(width,0);
+ LINETO(width,-width);
+ LIGHT;
+ LINETO(0,-width);
+ LINETO(0,0);
+ break;
+ case 8 :
+ pt += TQPoint(segLen/2 - width/2 + 1 , segLen/2 + width);
+ p.moveTo(pt);
+ DARK;
+ LINETO(width,0);
+ LINETO(width,-width);
+ LIGHT;
+ LINETO(0,-width);
+ LINETO(0,0);
+ break;
+ case 9 :
+ pt += TQPoint(segLen/2 - width/2 + 1 , 3*segLen/2 + width);
+ p.moveTo(pt);
+ DARK;
+ LINETO(width,0);
+ LINETO(width,-width);
+ LIGHT;
+ LINETO(0,-width);
+ LINETO(0,0);
+ break;
+#if defined(QT_CHECK_RANGE)
+ default :
+ tqWarning( "Display7Segment::drawSegment: (%s) Internal error."
+ " Illegal segment id: %d\n",
+ name( "unnamed" ), segmentNo );
+#endif
+ }
+ }
+
+#undef LINETO
+#undef LIGHT
+#undef DARK
+}
+
+Display7SegmentArray::Display7SegmentArray( TQWidget *parent, const char *name )
+ : TQFrame( parent, name ),
+ m_numberOfDigits(0),
+ m_segmentStyle(Flat)
+{
+ init();
+}
+
+Display7SegmentArray::~Display7SegmentArray() {
+ unsigned int i;
+
+ // Delete displays
+ for (i=0; i < m_numberOfDigits; i++) {
+ delete m_displayArray[i];
+ }
+ delete m_displayArray;
+ m_displayArray = NULL;
+}
+
+void Display7SegmentArray::init() {
+ unsigned int i;
+
+ // Set up grid layout
+ m_layout = new TQGridLayout(this, 1, m_numberOfDigits);
+ m_layout->setAutoAdd(true);
+
+ // Allocate display array
+ m_displayArray = (Display7Segment**)malloc(sizeof(Display7Segment*) * m_numberOfDigits);
+
+ // Create displays
+ for (i=0; i < m_numberOfDigits; i++) {
+ m_displayArray[i] = new Display7Segment(this);
+ }
+
+ setSizePolicy(TQSizePolicy(TQSizePolicy::Minimum, TQSizePolicy::Minimum));
+
+ // Set up displays
+ for (i=0; i < m_numberOfDigits; i++) {
+ m_displayArray[i]->setBackgroundColor(TQt::black);
+ m_displayArray[i]->setPaletteForegroundColor(TQColor(0, 255, 64));
+ }
+
+ // The LED display can work one of two ways
+#if 0
+ // Separated segments
+ for (i=0; i < m_numberOfDigits; i++) {
+ m_displayArray[i]->setFrameStyle(TQFrame::Box | TQFrame::Raised);
+ }
+ setFrameStyle(TQFrame::NoFrame);
+#else
+ // Combined segments
+ for (i=0; i < m_numberOfDigits; i++) {
+ m_displayArray[i]->setFrameStyle(TQFrame::NoFrame);
+ }
+ setBackgroundColor(TQt::black);
+ setFrameStyle(TQFrame::Box | TQFrame::Raised);
+#endif
+}
+
+void Display7SegmentArray::setNumberOfDigits(unsigned int count) {
+ unsigned int i;
+
+ if (m_numberOfDigits != count) {
+ // Delete displays
+ if (m_displayArray) {
+ for (i=0; i < m_numberOfDigits; i++) {
+ delete m_displayArray[i];
+ }
+ delete m_displayArray;
+ m_displayArray = NULL;
+ }
+
+ // Destroy layout
+ if (m_layout) {
+ delete m_layout;
+ }
+
+ // Set display count
+ m_numberOfDigits = count;
+
+ // Reinitialize
+ init();
+ }
+}
+
+void Display7SegmentArray::setSegmentStyle(SegmentStyle s) {
+ unsigned int i;
+
+ m_segmentStyle = s;
+ for (i=0; i < m_numberOfDigits; i++) {
+ m_displayArray[i]->setSegmentStyle((Display7Segment::SegmentStyle)m_segmentStyle);
+ }
+}
+
+Display7SegmentArray::SegmentStyle Display7SegmentArray::segmentStyle() const {
+ return m_segmentStyle;
+}
+
+void Display7SegmentArray::setValue(double value, int maxDecimalLength, bool forceMinDecimalLength) {
+ bool dp;
+ unsigned int i;
+ TQString displayString = TQString("%1").arg(value);
+ if (maxDecimalLength >= 0) {
+ int decPos = displayString.find(".");
+ if (decPos >= 0) {
+ int decLen = (displayString.length() - 1) - decPos;
+ if (decLen > maxDecimalLength) {
+ displayString.truncate(displayString.length() - (decLen - maxDecimalLength));
+ }
+ }
+ if (forceMinDecimalLength) {
+ if (decPos < 0) {
+ displayString.append(".");
+ decPos = displayString.length() - 1;
+ }
+ for (int i = displayString.length(); i < decPos + maxDecimalLength + 1; i++) {
+ displayString.append("0");
+ }
+ }
+ }
+ int last_char = displayString.length();
+ int current_char = (last_char - (int)m_numberOfDigits);
+ if (displayString.contains(".")) {
+ current_char--;
+ }
+ for (i=0; i < m_numberOfDigits; i++) {
+ if (current_char < 0) {
+ m_displayArray[i]->setLitSegments(0x0);
+ }
+ else {
+ dp = false;
+ if (current_char < (displayString.length() - 1)) {
+ if (displayString[current_char + 1] == '.') {
+ dp = true;
+ }
+ }
+ if (displayString[current_char] == '.') {
+ current_char++;
+ }
+ m_displayArray[i]->setLitSegments(Display7Segment::segmentsForNumericDigit(TQString(displayString[current_char]).toInt(NULL, 10), dp));
+ }
+ current_char++;
+ }
+}
+
+#include "sevensegment.moc" \ No newline at end of file
diff --git a/clients/tde/src/widgets/sevensegment.h b/clients/tde/src/widgets/sevensegment.h
new file mode 100644
index 0000000..a14e3c5
--- /dev/null
+++ b/clients/tde/src/widgets/sevensegment.h
@@ -0,0 +1,99 @@
+/*
+ * Remote Laboratory Seven Segment Display Widget
+ *
+ * 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) 2012 - 2015 Timothy Pearson
+ * Raptor Engineering
+ * http://www.raptorengineeringinc.com
+ */
+
+#ifndef REMOTELAB_DISPLAY7SEGEMENT_H
+#define REMOTELAB_DISPLAY7SEGEMENT_H
+
+#include <tqframe.h>
+#include <tqlayout.h>
+
+class Display7SegmentPrivate;
+
+class TQ_EXPORT Display7Segment : public TQFrame
+{
+ Q_OBJECT
+ TQ_ENUMS(SegmentStyle)
+ TQ_PROPERTY(SegmentStyle segmentStyle READ segmentStyle WRITE setSegmentStyle)
+
+ public:
+ Display7Segment(TQWidget* parent=0, const char* name=0);
+ ~Display7Segment();
+
+ enum SegmentStyle { Outline, Filled, Flat };
+
+ SegmentStyle segmentStyle() const;
+ virtual void setSegmentStyle(SegmentStyle);
+
+ void setLitSegments(unsigned char);
+ static unsigned char segmentsForNumericDigit(unsigned char val, bool dp);
+
+ TQSize sizeHint() const;
+
+ protected:
+ void drawContents(TQPainter *);
+
+ private:
+ void init();
+ void drawSegment(const TQPoint &, char, TQPainter &, int, bool = FALSE);
+ void drawDigit(const TQPoint &, TQPainter &, int, const char *);
+
+ char* m_prevSegments;
+ char* m_currentSegments;
+
+ unsigned int prevSegments;
+ double val;
+ uint smallPoint : 1;
+ uint fill : 1;
+ uint shadow : 1;
+ Display7SegmentPrivate *d;
+};
+
+class TQ_EXPORT Display7SegmentArray : public TQFrame
+{
+ Q_OBJECT
+ TQ_ENUMS(SegmentStyle)
+ TQ_PROPERTY(SegmentStyle segmentStyle READ segmentStyle WRITE setSegmentStyle)
+
+ public:
+ Display7SegmentArray(TQWidget* parent=0, const char* name=0);
+ ~Display7SegmentArray();
+
+ enum SegmentStyle { Outline, Filled, Flat };
+
+ SegmentStyle segmentStyle() const;
+ virtual void setSegmentStyle(SegmentStyle);
+
+ void setNumberOfDigits(unsigned int count);
+
+ void setValue(double value, int maxDecimalLength=-1, bool forceMinDecimalLength=false);
+
+ protected:
+ unsigned int m_numberOfDigits;
+ Display7Segment** m_displayArray;
+ TQGridLayout* m_layout;
+ SegmentStyle m_segmentStyle;
+
+ private:
+ void init();
+};
+
+#endif \ No newline at end of file
diff --git a/clients/tde/src/widgets/tracewidget.cpp b/clients/tde/src/widgets/tracewidget.cpp
index 5aec418..08cfe42 100644
--- a/clients/tde/src/widgets/tracewidget.cpp
+++ b/clients/tde/src/widgets/tracewidget.cpp
@@ -2652,3 +2652,5 @@ void TraceScrollWidget::setVScrollBarMode(TQScrollView::ScrollBarMode sm) {
TraceWidget* TraceScrollWidget::traceWidget() {
return m_traceScrollView->m_traceWidget;
}
+
+#include "tracewidget.moc" \ No newline at end of file
diff --git a/clients/tde/src/widgets/tracewidget.h b/clients/tde/src/widgets/tracewidget.h
index 389c7c0..e4cf255 100644
--- a/clients/tde/src/widgets/tracewidget.h
+++ b/clients/tde/src/widgets/tracewidget.h
@@ -15,11 +15,14 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * (c) 2012-2014 Timothy Pearson
+ * (c) 2012-2015 Timothy Pearson
* Raptor Engineering
* http://www.raptorengineeringinc.com
*/
+#ifndef REMOTELAB_TRACEWIDGET_H
+#define REMOTELAB_TRACEWIDGET_H
+
#include <tqvbox.h>
#include <tqwidget.h>
#include <tqpushbutton.h>
@@ -426,4 +429,6 @@ class TraceScrollWidget : public TQVBox
TraceScrollView* m_traceScrollView;
TQScrollBar* m_horizScrollBar;
TQScrollView::ScrollBarMode m_horizScrollBarMode;
-}; \ No newline at end of file
+};
+
+#endif \ No newline at end of file