summaryrefslogtreecommitdiffstats
path: root/servers/logic_analyzer_server_lin/src/logic_analyzer_server.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'servers/logic_analyzer_server_lin/src/logic_analyzer_server.cpp')
-rw-r--r--servers/logic_analyzer_server_lin/src/logic_analyzer_server.cpp331
1 files changed, 331 insertions, 0 deletions
diff --git a/servers/logic_analyzer_server_lin/src/logic_analyzer_server.cpp b/servers/logic_analyzer_server_lin/src/logic_analyzer_server.cpp
new file mode 100644
index 0000000..1e846d5
--- /dev/null
+++ b/servers/logic_analyzer_server_lin/src/logic_analyzer_server.cpp
@@ -0,0 +1,331 @@
+/*
+ * Remote Laboratory Logic Analyzer Server
+ *
+ * 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-2014 Timothy Pearson
+ * Raptor Engineering
+ * http://www.raptorengineeringinc.com
+ */
+
+#include <stdio.h> /* perror() */
+#include <stdlib.h> /* atoi() */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h> /* read() */
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <termios.h>
+#include <unistd.h>
+#include <sys/signal.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <math.h>
+
+#include <tqtimer.h>
+
+#include <tdelocale.h>
+
+#include "logic_analyzer_server.h"
+
+#include "bbb-gpmc-init.h"
+
+#define FLUSH_IN 0
+#define FLUSH_OUT 1
+#define FLUSH_BOTH 2
+
+#define ABORT_SOCKET(s) s->close(); \
+ s->disconnect(); \
+ delete s; \
+ s = NULL;
+
+/* exception handling */
+struct exit_exception {
+ int c;
+ exit_exception(int c):c(c) { }
+};
+
+/*
+ The LogicAnalyzerSocket class provides a socket that is connected with a client.
+ For every client that connects to the server, the server creates a new
+ instance of this class.
+*/
+LogicAnalyzerSocket::LogicAnalyzerSocket(int sock, TQObject *parent, const char *name) :
+ TDEKerberosServerSocket(parent, name), m_criticalSection(0), m_pollInterval(10), enableDebug(false), m_loopTimer(NULL), m_config(static_cast<LogicAnalyzerServer*>(parent)->m_config) {
+
+ // Read settings
+ m_config->setGroup("Tuning");
+ m_pollInterval = m_config->readNumEntry("pollInterval", m_pollInterval);
+ enableDebug = m_config->readBoolEntry("enableDebug", enableDebug);
+
+ // Initialize timers
+ m_kerberosInitTimer = new TQTimer();
+ connect(m_kerberosInitTimer, SIGNAL(timeout()), this, SLOT(finishKerberosHandshake()));
+
+ setServiceName("ulab");
+
+ line = 0;
+ connect(this, SIGNAL(connectionClosed()), SLOT(connectionClosedHandler()));
+ connect(this, SIGNAL(connectionClosed()), parent, SLOT(remoteConnectionClosed()));
+ setSocket(sock);
+}
+
+LogicAnalyzerSocket::~LogicAnalyzerSocket() {
+ if (m_kerberosInitTimer) {
+ m_kerberosInitTimer->stop();
+ delete m_kerberosInitTimer;
+ m_kerberosInitTimer = NULL;
+ }
+ if (m_loopTimer) {
+ m_loopTimer->stop();
+ delete m_loopTimer;
+ m_loopTimer = NULL;
+ }
+}
+
+void LogicAnalyzerSocket::close() {
+ if (state() == TQSocket::Connected) {
+ TDEKerberosServerSocket::close();
+ connectionClosedHandler();
+ TQTimer::singleShot(0, parent(), SLOT(remoteConnectionClosed()));
+ }
+}
+
+void LogicAnalyzerSocket::connectionClosedHandler() {
+ if (enableDebug) {
+ printf("[DEBUG] Connection from %s closed\n\r", m_remoteHost.ascii()); fflush(stdout);
+ }
+
+ if (m_criticalSection > 0) {
+ throw exit_exception(-1);
+ }
+}
+
+void LogicAnalyzerSocket::initiateKerberosHandshake() {
+ setUsingKerberos(true);
+ m_kerberosInitTimer->start(100, TRUE);
+}
+
+void LogicAnalyzerSocket::finishKerberosHandshake() {
+ if (kerberosStatus() == TDEKerberosServerSocket::KerberosInitializing) {
+ m_kerberosInitTimer->start(100, TRUE);
+ return;
+ }
+ if (kerberosStatus() == TDEKerberosServerSocket::KerberosInUse) {
+ m_config->setGroup("Security");
+ TQString masterUser = m_config->readEntry("masteruser");
+ TQString masterRealm = m_config->readEntry("masterrealm");
+ if (masterRealm == "") {
+ masterRealm = "(NULL)";
+ }
+ if ((m_authenticatedUserName != masterUser) || (m_authenticatedRealmName != masterRealm)) {
+ if (enableDebug) {
+ printf("[DEBUG] Connection from %s closed due to authentication failure (attempted connection as user %s@%s)\n\r", m_remoteHost.ascii(), m_authenticatedUserName.ascii(), m_authenticatedRealmName.ascii()); fflush(stdout);
+ }
+ close();
+ return;
+ }
+ if (setupGPMC() != 0) {
+ if (enableDebug) {
+ printf("[DEBUG] Connection from %s closed due to GPMC initialization failure\n\r", m_remoteHost.ascii()); fflush(stdout);
+ }
+ close();
+ return;
+ }
+
+ TQDataStream ds(this);
+ ds.setPrintableData(true);
+ ds << TQString("OK");
+ writeEndOfFrame();
+
+ enterCommandLoop();
+ return;
+ }
+ else {
+ if (enableDebug) {
+ printf("[DEBUG] Connection from %s closed due to Kerberos failure\n\r", m_remoteHost.ascii()); fflush(stdout);
+ }
+ close();
+ return;
+ }
+}
+
+int LogicAnalyzerSocket::setupGPMC() {
+ int i;
+ int ret;
+
+ ret = setup_gpmc_bbb();
+ if (ret == 0) {
+ // Verify attached uLab hardware model and version
+ unsigned char model = read_gpmc(0x00);
+ unsigned char version = read_gpmc(0x01);
+ if ((model != 0x42) || (version < 1)) {
+ printf("A compatible uLab hardware debug interface was not detected! Please verify your configuration.\n");
+ return -1;
+ }
+ printf("[DEBUG] Detected a compatible uLab hardware debug interface (model number 0x%02x, firmware version 0x%02x)\n", model, version);
+ }
+
+ return 0;
+}
+
+int gpmc_channel_count() {
+ return 64;
+}
+
+int gpmc_sample_count() {
+ return 2048;
+}
+
+int gpmc_get_channel_traces(TQDoubleArray& traceData, TQDoubleArray& positionData, unsigned int traceNumber) {
+ unsigned int i;
+ int traceLength;
+
+ traceLength = gpmc_sample_count();
+ traceData.resize(traceLength);
+ positionData.resize(traceLength);
+ for (i=0; i<traceLength; i++) {
+ traceData[i] = ((read_gpmc_llong(0x800 + i) & (1 << traceNumber)) >> traceNumber);
+ positionData[i] = i;
+ }
+
+ return traceLength;
+}
+
+void LogicAnalyzerSocket::commandLoop() {
+ bool transferred_data;
+ TQString instrumentCommand;
+
+ m_criticalSection++;
+ try {
+ transferred_data = false;
+ if (state() == TQSocket::Connected) {
+ if (canReadFrame()) {
+ TQDataStream ds(this);
+ ds.setPrintableData(true);
+ ds >> instrumentCommand;
+
+ if (instrumentCommand != "") {
+ if ((instrumentCommand == "GETLOGICTRACES")) { // Want all channel traces
+ ds << TQString("ACK");
+ int i;
+ int channels = gpmc_channel_count();
+ for (i=0; i<channels; i++) {
+ TQDoubleArray traceData;
+ TQDoubleArray positionData;
+ gpmc_get_channel_traces(traceData, positionData, i);
+ ds << traceData;
+ ds << positionData;
+ }
+ writeEndOfFrame();
+ }
+ }
+ else if (instrumentCommand == "GETTRACESAMPLECOUNT") { // Want to get number of samples in a trace
+ TQ_INT32 samples = gpmc_sample_count();
+ if (samples > 0) {
+ ds << TQString("ACK");
+ ds << samples;
+ writeEndOfFrame();
+ }
+ else {
+ ds << TQString("NCK");
+ writeEndOfFrame();
+ }
+ }
+ else if (instrumentCommand == "GETNUMBEROFCHANNELS") { // Want the number of channels available
+ TQ_INT32 channels = gpmc_channel_count();
+ if (channels > 0) {
+ ds << TQString("ACK");
+ ds << channels;
+ writeEndOfFrame();
+ }
+ else {
+ ds << TQString("NCK");
+ writeEndOfFrame();
+ }
+ }
+ else {
+ printf("[WARNING] Received unknown command %s from host %s\n\r", instrumentCommand.ascii(), m_remoteHost.ascii()); fflush(stdout);
+ ds << TQString("NCK");
+ writeEndOfFrame();
+ }
+
+ transferred_data = true;
+ }
+ }
+ m_criticalSection--;
+ if (transferred_data) {
+ if (m_loopTimer) m_loopTimer->start(0, TRUE);
+ }
+ else {
+ if (m_loopTimer) m_loopTimer->start(m_pollInterval, TRUE);
+ }
+ return;
+ }
+ catch (...) {
+ m_criticalSection--;
+ return;
+ }
+}
+
+int LogicAnalyzerSocket::enterCommandLoop() {
+ if (!m_loopTimer) {
+ m_loopTimer = new TQTimer();
+ connect(m_loopTimer, SIGNAL(timeout()), this, SLOT(commandLoop()));
+ }
+ if (m_loopTimer) m_loopTimer->start(0, TRUE);
+ return 0;
+}
+
+/*
+ The LogicAnalyzerServer class handles new connections to the server. For every
+ client that connects, it creates a new LogicAnalyzerSocket -- that instance is now
+ responsible for the communication with that client.
+*/
+LogicAnalyzerServer::LogicAnalyzerServer(TQObject* parent, int port, KSimpleConfig* config) :
+ TQServerSocket( port, 1, parent ), m_config(config), m_numberOfConnections(0) {
+
+ if ( !ok() ) {
+ printf("[ERROR] Failed to bind to port %d\n\r", port);
+ exit(1);
+ }
+
+ printf("[INFO] Server started on port %d\n\r", port); fflush(stdout);
+}
+
+LogicAnalyzerServer::~LogicAnalyzerServer() {
+ //
+}
+
+void LogicAnalyzerServer::newConnection(int socket) {
+ LogicAnalyzerSocket *s = new LogicAnalyzerSocket(socket, this);
+ s->m_remoteHost = s->peerAddress().toString();
+ printf("[DEBUG] New connection from %s\n\r", s->m_remoteHost.ascii()); fflush(stdout);
+ if (m_numberOfConnections > 0) {
+ printf("[DEBUG] Connection from %s closed due to multiple access attempt\n\r", s->m_remoteHost.ascii()); fflush(stdout);
+ ABORT_SOCKET(s)
+ return;
+ }
+ connect(s, SIGNAL(connectionClosed()), s, SLOT(deleteLater()));
+ s->initiateKerberosHandshake();
+ emit newConnect(s);
+}
+
+void LogicAnalyzerServer::remoteConnectionClosed() {
+ m_numberOfConnections--;
+}