Timothy Pearson 9 years ago
commit a4eb3d14df

@ -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

@ -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"/>

@ -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)
{

@ -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

@ -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() {

@ -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;
};
}

@ -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
libfloatspinbox_la_SOURCES = floatspinbox.cpp
libsevensegment_la_SOURCES = sevensegment.cpp

@ -108,4 +108,6 @@ void FloatSpinBox::acceptValueChanged(int ival) {
FloatSpinBox::~FloatSpinBox()
{
//
}
}
#include "floatspinbox.moc"

@ -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"

@ -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

@ -2652,3 +2652,5 @@ void TraceScrollWidget::setVScrollBarMode(TQScrollView::ScrollBarMode sm) {
TraceWidget* TraceScrollWidget::traceWidget() {
return m_traceScrollView->m_traceWidget;
}
#include "tracewidget.moc"

@ -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;
};
};
#endif
Loading…
Cancel
Save