diff options
author | Timothy Pearson <kb9vqf@pearsoncomputing.net> | 2014-01-13 05:09:08 -0600 |
---|---|---|
committer | Timothy Pearson <kb9vqf@pearsoncomputing.net> | 2014-01-13 05:09:08 -0600 |
commit | 55f109d36572b1fcacfd6709f6c8f955d15fd7c4 (patch) | |
tree | 3d1782f9c74c3017a9a8ec58bce4d4c2274e8944 /clients/tde/src | |
parent | c912b0f1d3994cde07d472e2c53f0375518a74df (diff) | |
download | ulab-55f109d36572b1fcacfd6709f6c8f955d15fd7c4.tar.gz ulab-55f109d36572b1fcacfd6709f6c8f955d15fd7c4.zip |
Add serial console client
Diffstat (limited to 'clients/tde/src')
-rw-r--r-- | clients/tde/src/part/Makefile.am | 2 | ||||
-rw-r--r-- | clients/tde/src/part/prototerminal/part.cpp | 2 | ||||
-rw-r--r-- | clients/tde/src/part/prototerminal/part.h | 6 | ||||
-rw-r--r-- | clients/tde/src/part/serialconsole/Makefile.am | 12 | ||||
-rw-r--r-- | clients/tde/src/part/serialconsole/hi16-action-libremotelab_serialconsole.png | bin | 0 -> 666 bytes | |||
-rw-r--r-- | clients/tde/src/part/serialconsole/layout.ui | 58 | ||||
-rw-r--r-- | clients/tde/src/part/serialconsole/part.cpp | 284 | ||||
-rw-r--r-- | clients/tde/src/part/serialconsole/part.h | 64 |
8 files changed, 423 insertions, 5 deletions
diff --git a/clients/tde/src/part/Makefile.am b/clients/tde/src/part/Makefile.am index f9bfb88..17387e4 100644 --- a/clients/tde/src/part/Makefile.am +++ b/clients/tde/src/part/Makefile.am @@ -1 +1 @@ -SUBDIRS = scope commanalyzer fpgaview fpgaprogram sensormonitor adminconsole adminusermgmt prototerminal +SUBDIRS = scope commanalyzer fpgaview fpgaprogram sensormonitor adminconsole adminusermgmt serialconsole prototerminal diff --git a/clients/tde/src/part/prototerminal/part.cpp b/clients/tde/src/part/prototerminal/part.cpp index 2913a43..cf7e283 100644 --- a/clients/tde/src/part/prototerminal/part.cpp +++ b/clients/tde/src/part/prototerminal/part.cpp @@ -1,4 +1,4 @@ -//Author: Timothy Pearson <kb9vqf@pearsoncomputing.net>, (C) 2012 +//Author: Timothy Pearson <kb9vqf@pearsoncomputing.net>, (C) 2014 //Copyright: See COPYING file that comes with this distribution #include "define.h" diff --git a/clients/tde/src/part/prototerminal/part.h b/clients/tde/src/part/prototerminal/part.h index 0f90745..8e51829 100644 --- a/clients/tde/src/part/prototerminal/part.h +++ b/clients/tde/src/part/prototerminal/part.h @@ -1,8 +1,8 @@ -//Author: Timothy Pearson <kb9vqf@pearsoncomputing.net>, (C) 2012 +//Author: Timothy Pearson <kb9vqf@pearsoncomputing.net>, (C) 2014 //Copyright: See COPYING file that comes with this distribution -#ifndef REMOTELAB_COMMANALYZERPART_H -#define REMOTELAB_COMMANALYZERPART_H +#ifndef REMOTELAB_PROTOTERMINALPART_H +#define REMOTELAB_PROTOTERMINALPART_H #include <tdeparts/browserextension.h> #include <tdeparts/statusbarextension.h> diff --git a/clients/tde/src/part/serialconsole/Makefile.am b/clients/tde/src/part/serialconsole/Makefile.am new file mode 100644 index 0000000..0b941f5 --- /dev/null +++ b/clients/tde/src/part/serialconsole/Makefile.am @@ -0,0 +1,12 @@ +INCLUDES = $(all_includes) -I$(top_srcdir)/src -I$(top_srcdir)/src/widgets $(KDE_INCLUDES)/tde +KDE_CXXFLAGS = $(USE_EXCEPTIONS) +METASOURCES = AUTO + +KDE_ICON = libremotelab_serialconsole + +#Part +kde_module_LTLIBRARIES = libremotelab_serialconsole.la +libremotelab_serialconsole_la_LIBADD = $(LIB_KFILE) $(LIB_TDEPARTS) $(LIB_TDEUI) $(LIB_QT) +libremotelab_serialconsole_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) -ltdecore -ltdeui -ltdeio -ltdefx -ltdekrbsocket -ltqtrla +libremotelab_serialconsole_la_SOURCES = \ + part.cpp layout.ui diff --git a/clients/tde/src/part/serialconsole/hi16-action-libremotelab_serialconsole.png b/clients/tde/src/part/serialconsole/hi16-action-libremotelab_serialconsole.png Binary files differnew file mode 100644 index 0000000..75fa314 --- /dev/null +++ b/clients/tde/src/part/serialconsole/hi16-action-libremotelab_serialconsole.png diff --git a/clients/tde/src/part/serialconsole/layout.ui b/clients/tde/src/part/serialconsole/layout.ui new file mode 100644 index 0000000..48969a4 --- /dev/null +++ b/clients/tde/src/part/serialconsole/layout.ui @@ -0,0 +1,58 @@ +<!DOCTYPE UI><UI version="3.0" stdsetdef="1"> + <class>SerialConsoleBase</class> + <widget class="TQWidget"> + <property name="name"> + <cstring>SerialConsoleBase</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>519</width> + <height>356</height> + </rect> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KTextEdit" row="0" column="0" colspan="3"> + <property name="name"> + <cstring>textOutput</cstring> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + <widget class="TQLabel" row="1" column="0" colspan="1"> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="text"> + <string>Input:</string> + </property> + <property name="textFormat"> + <enum>PlainText</enum> + </property> + </widget> + <widget class="KLineEdit" row="1" column="1" colspan="1"> + <property name="name"> + <cstring>textInput</cstring> + </property> + </widget> + <widget class="TQPushButton" row="1" column="2" colspan="1"> + <property name="name"> + <cstring>sendText</cstring> + </property> + <property name="text"> + <cstring>Send</cstring> + </property> + </widget> + </grid> + </widget> + <includes> + <include location="local" impldecl="in implementation">SerialConsoleBase.ui.h</include> + </includes> + <layoutdefaults spacing="3" margin="6"/> + <layoutfunctions spacing="KDialog::spacingHint" margin="KDialog::marginHint"/> +</UI> diff --git a/clients/tde/src/part/serialconsole/part.cpp b/clients/tde/src/part/serialconsole/part.cpp new file mode 100644 index 0000000..9343f38 --- /dev/null +++ b/clients/tde/src/part/serialconsole/part.cpp @@ -0,0 +1,284 @@ +//Author: Timothy Pearson <kb9vqf@pearsoncomputing.net>, (C) 2014 +//Copyright: See COPYING file that comes with this distribution + +#include "define.h" +#include "part.h" + +#include <tdeaboutdata.h> //::createAboutData() +#include <tdeaction.h> +#include <tdelocale.h> +#include <tdemessagebox.h> //::start() +#include <tdeparts/genericfactory.h> +#include <kstatusbar.h> +#include <kstdaction.h> +#include <tqfile.h> //encodeName() +#include <tqtimer.h> +#include <tqvbox.h> +#include <tqsocket.h> +#include <tqmutex.h> +#include <tqeventloop.h> +#include <tqapplication.h> +#include <tqpushbutton.h> +#include <klineedit.h> +#include <ktextedit.h> +#include <unistd.h> //access() +#include <stdint.h> +#include <cmath> + +#include "layout.h" + +#define NETWORK_COMM_TIMEOUT_MS 15000 + +/* exception handling */ +struct exit_exception { + int c; + exit_exception(int c):c(c) { } +}; + +namespace RemoteLab { + +typedef KParts::GenericFactory<RemoteLab::SerialConsolePart> Factory; +#define CLIENT_LIBRARY "libremotelab_serialconsole" +K_EXPORT_COMPONENT_FACTORY( libremotelab_serialconsole, RemoteLab::Factory ) + + +SerialConsolePart::SerialConsolePart( 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) +{ + // Initialize important base class variables + m_clientLibraryName = CLIENT_LIBRARY; + + // Initialize mutex + m_instrumentMutex = new TQMutex(false); + + // Initialize kpart + setInstance(Factory::instance()); + setWidget(new TQVBox(parentWidget, widgetName)); + + // 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())); + + // Create widgets + m_base = new SerialConsoleBase(widget()); + + connect(m_base->sendText, SIGNAL(clicked()), this, SLOT(sendTextClicked())); + connect(m_base->textInput, SIGNAL(returnPressed()), m_base->sendText, SIGNAL(clicked())); + + TQTimer::singleShot(0, this, TQT_SLOT(postInit())); +} + +SerialConsolePart::~SerialConsolePart() { + if (m_instrumentMutex->locked()) { + printf("[WARNING] Exiting when data transfer still in progress!\n\r"); fflush(stdout); + } + + disconnectFromServer(); + delete m_instrumentMutex; +} + +void SerialConsolePart::postInit() { + setUsingFixedSize(false); +} + +bool SerialConsolePart::openURL(const KURL &url) { + int ret; + m_connectionActiveAndValid = false; + ret = connectToServer(url.url()); + processLockouts(); + return (ret != 0); +} + +bool SerialConsolePart::closeURL() { + disconnectFromServer(); + m_url = KURL(); + return true; +} + +void SerialConsolePart::processLockouts() { + if (m_connectionActiveAndValid) { + m_base->setEnabled(true); + } + else { + m_base->setEnabled(false); + } +} + +void SerialConsolePart::disconnectFromServerCallback() { + m_forcedUpdateTimer->stop(); + m_updateTimeoutTimer->stop(); + m_connectionActiveAndValid = false; +} + +void SerialConsolePart::connectionFinishedCallback() { + connect(m_socket, SIGNAL(readyRead()), m_socket, SLOT(processPendingData())); + m_socket->processPendingData(); + connect(m_socket, SIGNAL(newDataReceived()), this, SLOT(mainEventLoop())); + m_tickerState = 0; + m_commHandlerState = 0; + m_commHandlerMode = 0; + m_socket->setDataTimeout(NETWORK_COMM_TIMEOUT_MS); + m_updateTimeoutTimer->start(NETWORK_COMM_TIMEOUT_MS, TRUE); + processLockouts(); + mainEventLoop(); + return; +} + +void SerialConsolePart::connectionStatusChangedCallback() { + processLockouts(); +} + +void SerialConsolePart::setTickerMessage(TQString message) { + m_connectionActiveAndValid = true; + TQString tickerChar; + switch (m_tickerState) { + case 0: + tickerChar = "-"; + break; + case 1: + tickerChar = "\\"; + break; + case 2: + tickerChar = "|"; + break; + case 3: + tickerChar = "/"; + break; + } + setStatusMessage(message + TQString("... %1").arg(tickerChar)); + m_tickerState++; + if (m_tickerState > 3) { + m_tickerState = 0; + } +} + +#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 SerialConsolePart::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) { + ds << TQString("PING"); + m_socket->writeEndOfFrame(); + + 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 == "DATA") { + TQByteArray data; + ds >> data; + TQString textData(data); + textData.replace("\r", "\n>>>"); + m_base->textOutput->append(">>>" + textData); + } + } + m_socket->clearFrameTail(); + EXEC_NEXT_STATE_IMMEDIATELY + } + else { + if (!m_updateTimeoutTimer->isActive()) { + UPDATEDISPLAY_TIMEOUT + } + } + + // Send data + if (m_TextToSend != "") { + TQByteArray data; + data.duplicate(m_TextToSend.ascii(), strlen(m_TextToSend.ascii())); + ds << TQString("SEND"); + ds << data; + m_socket->writeEndOfFrame(); + + m_base->textOutput->append("<<<" + m_TextToSend); + m_TextToSend = ""; + + EXEC_NEXT_STATE_IMMEDIATELY + } + else { + ds << TQString("PING"); + m_socket->writeEndOfFrame(); + } + } + else if (m_commHandlerState == 2) { + // Ignore timeouts + m_commHandlerState = 1; + EXEC_NEXT_STATE_IMMEDIATELY + } + SET_WATCHDOG_TIMER + } + } + else { + m_commHandlerState = 0; + m_commHandlerCommandState = 0; + } + + processLockouts(); + + m_instrumentMutex->unlock(); +} + +void SerialConsolePart::sendTextClicked() { + m_TextToSend = m_TextToSend + m_base->textInput->text(); + m_base->textInput->setText(""); + + // Transmit! + EXEC_NEXT_STATE_IMMEDIATELY +} + +TDEAboutData* SerialConsolePart::createAboutData() { + return new TDEAboutData( APP_NAME, I18N_NOOP( APP_PRETTYNAME ), APP_VERSION ); +} + +} //namespace RemoteLab + +#include "part.moc" diff --git a/clients/tde/src/part/serialconsole/part.h b/clients/tde/src/part/serialconsole/part.h new file mode 100644 index 0000000..1c4f8a0 --- /dev/null +++ b/clients/tde/src/part/serialconsole/part.h @@ -0,0 +1,64 @@ +//Author: Timothy Pearson <kb9vqf@pearsoncomputing.net>, (C) 2014 +//Copyright: See COPYING file that comes with this distribution + +#ifndef REMOTELAB_SERIALCONSOLEPART_H +#define REMOTELAB_SERIALCONSOLEPART_H + +#include <tdeparts/browserextension.h> +#include <tdeparts/statusbarextension.h> +#include <tdeparts/part.h> +#include <kurl.h> + +#include <tqtrla.h> + +class TDEAboutData; +using KParts::StatusBarExtension; +class TraceWidget; +class TQSocket; +class TQTimer; +class TQMutex; +class TQRectF; +class SerialConsoleBase; + +namespace RemoteLab +{ + class SerialConsolePart : public KParts::RemoteInstrumentPart + { + Q_OBJECT + + public: + SerialConsolePart( QWidget *, const char *, TQObject *, const char *, const TQStringList&); + ~SerialConsolePart(); + + virtual bool openFile() { return false; } // pure virtual in the base class + virtual bool closeURL(); + static TDEAboutData *createAboutData(); + + public slots: + virtual bool openURL(const KURL &url); + + private slots: + void postInit(); + void processLockouts(); + void connectionFinishedCallback(); + void disconnectFromServerCallback(); + void connectionStatusChangedCallback(); + void setTickerMessage(TQString message); + void mainEventLoop(); + 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; + SerialConsoleBase* m_base; + TQMutex* m_instrumentMutex; + TQString m_TextToSend; + }; +} + +#endif |