summaryrefslogtreecommitdiffstats
path: root/servers/gpib_server_lin/src/gpib_conn.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'servers/gpib_server_lin/src/gpib_conn.cpp')
-rw-r--r--servers/gpib_server_lin/src/gpib_conn.cpp489
1 files changed, 489 insertions, 0 deletions
diff --git a/servers/gpib_server_lin/src/gpib_conn.cpp b/servers/gpib_server_lin/src/gpib_conn.cpp
new file mode 100644
index 0000000..5b52430
--- /dev/null
+++ b/servers/gpib_server_lin/src/gpib_conn.cpp
@@ -0,0 +1,489 @@
+/*
+ * Remote Laboratory GPIB 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 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 <errno.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <unistd.h>
+#include <sys/signal.h>
+#include <sys/types.h>
+
+#include <tqtimer.h>
+#include <tqfile.h>
+
+#include <klocale.h>
+
+#include <gpib/ib.h>
+
+#include "gpib_functions.h"
+#include "scope_functions.h"
+#include "signal_functions.h"
+#include "commanalyzer_functions.h"
+
+#include "gpib_conn.h"
+
+#define ABORT_SOCKET(s) s->close(); \
+ s->disconnect(); \
+ delete s; \
+ s = NULL;
+
+#define NETWORK_COMM_TIMEOUT_MS 5000
+
+/* exception handling */
+struct exit_exception {
+ int c;
+ exit_exception(int c):c(c) { }
+};
+
+/*
+ The GPIBSocket 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.
+*/
+GPIBSocket::GPIBSocket(int sock, TQObject *parent, const char *name) :
+ TDEKerberosServerSocket(parent, name), m_criticalSection(0), m_loopTimer(NULL), m_config(static_cast<GPIBServer*>(parent)->m_config),
+ m_serverParent(static_cast<GPIBServer*>(parent)), m_commandLoopState(0)
+{
+
+ // Initialize timers
+ m_kerberosInitTimer = new TQTimer();
+ connect(m_kerberosInitTimer, SIGNAL(timeout()), this, SLOT(finishKerberosHandshake()));
+ m_servClientTimeout = new TQTimer();
+
+ setServiceName("remotefpga");
+
+ line = 0;
+ connect(this, SIGNAL(connectionClosed()), SLOT(connectionClosedHandler()));
+ connect(this, SIGNAL(connectionClosed()), parent, SLOT(remoteConnectionClosed()));
+ setSocket(sock);
+}
+
+GPIBSocket::~GPIBSocket() {
+ if (m_servClientTimeout) {
+ m_servClientTimeout->stop();
+ delete m_servClientTimeout;
+ m_servClientTimeout = NULL;
+ }
+ 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 GPIBSocket::close() {
+ if (state() == TQSocket::Connected) {
+ TDEKerberosServerSocket::close();
+ connectionClosedHandler();
+ TQTimer::singleShot(0, parent(), SLOT(remoteConnectionClosed()));
+ }
+}
+
+void GPIBSocket::connectionClosedHandler() {
+ printf("[DEBUG] Connection from %s closed\n\r", m_remoteHost.ascii());
+
+ if (m_criticalSection > 0) {
+ throw exit_exception(-1);
+ }
+}
+
+void GPIBSocket::initiateKerberosHandshake() {
+ setUsingKerberos(true);
+ m_kerberosInitTimer->start(100, TRUE);
+}
+
+void GPIBSocket::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)) {
+ printf("[DEBUG] Connection from %s closed due to authentication failure (attempted connection as user %s@%s)\n\r", m_remoteHost.ascii(), masterUser.ascii(), masterRealm.ascii());
+ close();
+ return;
+ }
+
+ setDataTimeout(NETWORK_COMM_TIMEOUT_MS);
+
+ TQDataStream ds(this);
+ ds.setPrintableData(true);
+ ds << TQString("OK");
+ writeEndOfFrame();
+
+ enterCommandLoop();
+ return;
+ }
+ else {
+ printf("[DEBUG] Connection from %s closed due to Kerberos failure\n\r", m_remoteHost.ascii()); fflush(stdout);
+ close();
+ return;
+ }
+}
+
+void GPIBSocket::commandLoop() {
+ bool transferred_data;
+
+ m_criticalSection++;
+ try {
+ transferred_data = false;
+ if (state() == TQSocket::Connected) {
+ if (m_commandLoopState == 0) {
+ if (canReadLine()) {
+ processPendingData();
+ }
+ if (canReadFrame()) {
+ TQDataStream ds(this);
+ ds.setPrintableData(true);
+ TQString instrumentRequest;
+ ds >> instrumentRequest;
+ clearFrameTail();
+
+ m_activeDeviceType = 0;
+ if (instrumentRequest == "LIST") {
+ TQStringList deviceList;
+ if (m_serverParent->m_serialDevice != "") {
+ deviceList.append("SERIAL PORT");
+ }
+ if (m_serverParent->m_scopeType != "") {
+ deviceList.append("OSCILLOSCOPE");
+ }
+ if (m_serverParent->m_funcgenType != "") {
+ deviceList.append("FUNCTION GENERATOR");
+ }
+ if (m_serverParent->m_commanalyzerType != "") {
+ deviceList.append("COMMUNICATIONS ANALYZER");
+ }
+ ds << deviceList;
+ writeEndOfFrame();
+ }
+ else if (instrumentRequest == "SERIAL PORT") {
+ m_activeDeviceType = 1;
+ }
+ else if (instrumentRequest == "OSCILLOSCOPE") {
+ m_activeDeviceType = 2;
+ }
+ else if (instrumentRequest == "FUNCTION GENERATOR") {
+ m_activeDeviceType = 3;
+ }
+ else if (instrumentRequest == "COMMUNICATIONS ANALYZER") {
+ m_activeDeviceType = 4;
+ }
+
+ if (m_activeDeviceType != 0) {
+ m_servClientTimeout->start(NETWORK_COMM_TIMEOUT_MS, TRUE);
+ transferred_data = true;
+ m_commandLoopState = 1;
+ }
+ }
+ }
+ else if (m_commandLoopState == 1) {
+ if (canReadLine()) {
+ processPendingData();
+ }
+ if (m_activeDeviceType == 1) {
+ // Serial port
+ if (canReadFrame()) {
+ TQDataStream ds(this);
+ ds.setPrintableData(true);
+ TQByteArray recData;
+ ds >> recData;
+ if (recData.size() > 0) {
+ if (write(m_serverParent->m_serialDeviceSocket, recData.data(), recData.size()) < 0) {
+ // ERROR
+ }
+ transferred_data = true;
+ printf("[DEBUG] Got %d bytes from the network interface\n\r", recData.size()); fflush(stdout);
+ }
+ }
+ TQByteArray txData;
+ txData.resize(10000);
+ int cc = read(m_serverParent->m_serialDeviceSocket, txData.data(), txData.size());
+ if (cc > 0) {
+ TQDataStream ds(this);
+ ds.setPrintableData(true);
+ ds << txData;
+ writeEndOfFrame();
+ transferred_data = true;
+ printf("[DEBUG] Got %d bytes from the serial port\n\r", cc); fflush(stdout);
+ }
+ }
+ else {
+ if (canReadFrame()) {
+ TQDataStream ds(this);
+ ds.setPrintableData(true);
+ ds >> m_instrumentCommand;
+ clearFrameTail();
+
+ if (m_instrumentCommand != "") {
+ m_servClientTimeout->start(NETWORK_COMM_TIMEOUT_MS, TRUE);
+ transferred_data = true;
+ m_commandLoopState = 2;
+ }
+ }
+ }
+ }
+ else if (m_commandLoopState == 2) {
+ if (canReadLine()) {
+ processPendingData();
+ }
+ if (canReadFrame()) {
+ if (m_activeDeviceType == 2) {
+ // Oscilloscope
+ }
+ else if (m_activeDeviceType == 3) {
+ // Function generator
+ }
+ else if (m_activeDeviceType == 4) {
+ // Communications analyzer
+ }
+ else {
+ // Unknown
+ transferred_data = true;
+ m_commandLoopState = 0;
+ }
+ }
+ }
+ }
+ m_criticalSection--;
+ if (transferred_data) {
+ if (m_loopTimer) m_loopTimer->start(0, TRUE);
+ }
+ else {
+ if (m_loopTimer) m_loopTimer->start(100, TRUE);
+ }
+ return;
+ }
+ catch (...) {
+ m_criticalSection--;
+ return;
+ }
+}
+
+int GPIBSocket::enterCommandLoop() {
+ m_commandLoopState = 0;
+ 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 GPIBServer class handles new connections to the server. For every
+ client that connects, it creates a new GPIBSocket -- that instance is now
+ responsible for the communication with that client.
+*/
+GPIBServer::GPIBServer(TQObject* parent, int port, KSimpleConfig* config) :
+ TQServerSocket( port, 1, parent ), m_config(config), m_numberOfConnections(0),
+ m_scopeDeviceSocket(-1), m_funcgenDeviceSocket(-1), m_commanalyzerDeviceSocket(-1) {
+
+ if ( !ok() ) {
+ printf("[ERROR] Failed to bind to port %d\n\r", port);
+ exit(1);
+ }
+
+ if (readConfig() != 0) {
+ exit(-1);
+ }
+
+ printf("[INFO] Server started on port %d\n\r", port); fflush(stdout);
+}
+
+GPIBServer::~GPIBServer() {
+ //
+}
+
+void GPIBServer::newConnection(int socket) {
+ GPIBSocket *s = new GPIBSocket(socket, this);
+ s->m_remoteHost = s->peerAddress().toString();
+ printf("[DEBUG] New connection from %s\n\r", s->m_remoteHost.ascii());
+ connect(s, SIGNAL(connectionClosed()), s, SLOT(deleteLater()));
+ s->initiateKerberosHandshake();
+ emit newConnect(s);
+}
+
+void GPIBServer::remoteConnectionClosed() {
+ m_numberOfConnections--;
+}
+
+int GPIBServer::readConfig() {
+ // Serial port
+ m_config->setGroup("Serial Port");
+ m_serialDevice = m_config->readEntry("device", "");
+ TQString desiredBaudRate = m_config->readEntry("baudrate", "9600");
+ if (desiredBaudRate == "1200") {
+ m_serialBaud = B1200;
+ }
+ else if (desiredBaudRate == "9600") {
+ m_serialBaud = B9600;
+ }
+ else if (desiredBaudRate == "19200") {
+ m_serialBaud = B19200;
+ }
+ else if (desiredBaudRate == "115200") {
+ m_serialBaud = B115200;
+ }
+ else {
+ printf("[WARNING] Invalid baudrate %s specified, selecting 9600 instead\n\r", desiredBaudRate.ascii()); fflush(stdout);
+ desiredBaudRate = "9600";
+ m_serialBaud = B9600;
+ }
+
+ // Oscilloscope
+ m_config->setGroup("Oscilloscope");
+ m_scopeType = m_config->readEntry("type", "");
+ m_scopeConnection = m_config->readEntry("connection", "gpib");
+ m_scopeBoard = m_config->readNumEntry("board", 0);
+ m_scopeDevice = m_config->readNumEntry("device", 0);
+
+ // Function generator
+ m_config->setGroup("Function Generator");
+ m_funcgenType = m_config->readEntry("type", "");
+ m_funcgenConnection = m_config->readEntry("connection", "gpib");
+ m_funcgenBoard = m_config->readNumEntry("board", 0);
+ m_funcgenDevice = m_config->readNumEntry("device", 0);
+
+ // Communications analyzer
+ m_config->setGroup("Communications Analyzer");
+ m_commanalyzerType = m_config->readEntry("type", "");
+ m_commanalyzerConnection = m_config->readEntry("connection", "gpib");
+ m_commanalyzerBoard = m_config->readNumEntry("board", 0);
+ m_commanalyzerDevice = m_config->readNumEntry("device", 0);
+
+ if (m_serialDevice != "") {
+ struct termios oldtio, newtio;
+
+ m_serialDeviceSocket = ::open(m_serialDevice.ascii(), O_RDWR | O_NOCTTY | O_NONBLOCK | O_APPEND);
+ if (m_serialDeviceSocket < 0) {
+ printf("[FAIL] Unable to open serial device %s\n\r", m_serialDevice.ascii()); fflush(stdout);
+ return 1;
+ }
+
+ tcgetattr(m_serialDeviceSocket, &oldtio); // Save current port settings
+
+ bzero(&newtio, sizeof(newtio));
+ newtio.c_cflag = m_serialBaud | CS8 | CLOCAL | CREAD;
+ newtio.c_iflag = IGNPAR;
+ newtio.c_oflag = 0;
+
+ // Set input mode (non-canonical, no echo,...)
+ newtio.c_lflag = 0;
+
+ newtio.c_cc[VTIME] = 0; // Inter-character timer unused
+ newtio.c_cc[VMIN] = 0; // Blocking read unused
+
+ tcflush(m_serialDeviceSocket, TCIFLUSH);
+ tcsetattr(m_serialDeviceSocket, TCSANOW, &newtio);
+
+ printf("[INFO] Serial port on node %s activated at %s baud\n\r", m_serialDevice.ascii(), desiredBaudRate.ascii());
+ }
+
+ if (m_scopeType != "") {
+ printf("[INFO] Oscilloscope conjectured to be on GPIB address %d:%d\n\r", m_scopeBoard, m_scopeDevice);
+ m_scopeDeviceSocket = open_gpib_device(m_scopeBoard, m_scopeDevice);
+ if (m_scopeDeviceSocket < 0) {
+ // return -1;
+ }
+ else {
+ time_t rawtime;
+ struct tm * timeinfo;
+ char datebuffer [80];
+ char timebuffer [80];
+ time ( &rawtime );
+ timeinfo = localtime ( &rawtime );
+ strftime(timebuffer,80,"TIME \"%H:%M:%S\"",timeinfo);
+ strftime(datebuffer,80,"DATE \"%Y-%m-%d\"",timeinfo);
+ printf("[INFO] Configuring %s oscilloscope\n\r", scopeLongDescription(m_scopeType.ascii()));
+ printf("[INFO] %s\n\r", datebuffer);
+ printf("[INFO] %s\n\r", timebuffer);
+ if (gpib_write(m_scopeDeviceSocket, timebuffer) == 0) {
+ gpib_write(m_scopeDeviceSocket, datebuffer);
+ printf("[INFO] Communication verified\n\r");
+ }
+ else {
+ printf("[WARN] Communication failed!\n\r");
+ }
+ }
+ }
+
+ if (m_funcgenType != "") {
+ printf("[INFO] Function generator conjectured to be on GPIB address %d:%d\n\r", m_funcgenBoard, m_funcgenDevice);
+ m_funcgenDeviceSocket = open_gpib_device(m_funcgenBoard, m_funcgenDevice);
+ if (m_funcgenDeviceSocket < 0) {
+ //return 1;
+ }
+ else {
+ printf("[INFO] Configuring %s function generator\n\r", funcgenLongDescription(m_funcgenType.ascii()));
+ if (gpib_write(m_funcgenDeviceSocket, "RESET") == 0) {
+ printf("[INFO] Communication verified\n\r");
+ }
+ else {
+ printf("[WARN] Communication failed!\n\r");
+ }
+ }
+ }
+
+ if (m_commanalyzerType != "") {
+ printf("[INFO] Communications analyzer conjectured to be on GPIB address %d:%d\n\r", m_commanalyzerBoard, m_commanalyzerDevice);
+ m_commanalyzerDeviceSocket = open_gpib_device(m_commanalyzerBoard, m_commanalyzerDevice);
+ if (m_commanalyzerDeviceSocket < 0) {
+ //return 1;
+ }
+ else {
+ time_t rawtime;
+ struct tm * timeinfo;
+ time ( &rawtime );
+ timeinfo = localtime ( &rawtime );
+ printf("[INFO] Configuring %s communications analyzer\n\r", commanalyzerLongDescription(m_commanalyzerType.ascii()));
+ if (commanalyzer_set_time(timeinfo, m_commanalyzerType.ascii(), m_commanalyzerDeviceSocket) == 0) {
+ commanalyzer_set_date(timeinfo, m_commanalyzerType.ascii(), m_commanalyzerDeviceSocket);
+ printf("[INFO] Communication verified\n\r");
+ }
+ else {
+ printf("[WARN] Communication failed!\n\r");
+ }
+ }
+ }
+
+ return 0;
+} \ No newline at end of file