diff options
author | Timothy Pearson <kb9vqf@pearsoncomputing.net> | 2015-09-12 19:55:59 -0500 |
---|---|---|
committer | Timothy Pearson <kb9vqf@pearsoncomputing.net> | 2015-09-12 19:55:59 -0500 |
commit | a4eb3d14df4d5c3bb2067bdfdb2c93cce7828a71 (patch) | |
tree | 0f797acfa0d661175169ba094c298227099470d7 | |
parent | 305821c2b3a71f6baa33c29d60147204aefcad76 (diff) | |
parent | 71f607c43a88e54efaf4a1eae82141e933bbdd11 (diff) | |
download | ulab-a4eb3d14df4d5c3bb2067bdfdb2c93cce7828a71.tar.gz ulab-a4eb3d14df4d5c3bb2067bdfdb2c93cce7828a71.zip |
Merge branch 'master' of https://scm.trinitydesktop.org/scm/git/remotelaboratory
-rw-r--r-- | clients/tde/src/part/fpgaview/Makefile.am | 2 | ||||
-rw-r--r-- | clients/tde/src/part/fpgaview/layout.ui | 9 | ||||
-rw-r--r-- | clients/tde/src/part/fpgaview/part.cpp | 427 | ||||
-rw-r--r-- | clients/tde/src/part/fpgaview/part.h | 43 | ||||
-rw-r--r-- | clients/tde/src/part/prototerminal/part.cpp | 327 | ||||
-rw-r--r-- | clients/tde/src/part/prototerminal/part.h | 64 | ||||
-rw-r--r-- | clients/tde/src/widgets/Makefile.am | 5 | ||||
-rw-r--r-- | clients/tde/src/widgets/floatspinbox.cpp | 4 | ||||
-rw-r--r-- | clients/tde/src/widgets/sevensegment.cpp | 621 | ||||
-rw-r--r-- | clients/tde/src/widgets/sevensegment.h | 99 | ||||
-rw-r--r-- | clients/tde/src/widgets/tracewidget.cpp | 2 | ||||
-rw-r--r-- | clients/tde/src/widgets/tracewidget.h | 9 |
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 |