From adaabec5759a7c57a432fc6cb439a493203c1634 Mon Sep 17 00:00:00 2001 From: Phil Taylor Date: Thu, 4 Mar 2021 20:19:05 +0000 Subject: [PATCH] Move pseudoterm into dedicated class --- commhandler.cpp | 122 ------------------ commhandler.h | 6 - pttyhandler.cpp | 277 +++++++++++++++++++++++++++++++++++++++++ pttyhandler.h | 69 ++++++++++ rigcommander.cpp | 33 +++++ rigcommander.h | 4 +- wfmain.cpp | 4 +- wfview.pro | 6 +- wfview.vcxproj | 2 + wfview.vcxproj.filters | 7 ++ 10 files changed, 397 insertions(+), 133 deletions(-) create mode 100644 pttyhandler.cpp create mode 100644 pttyhandler.h diff --git a/commhandler.cpp b/commhandler.cpp index 8a528c2..5038840 100644 --- a/commhandler.cpp +++ b/commhandler.cpp @@ -27,10 +27,7 @@ commHandler::commHandler() //port->setReadBufferSize(1024); // manually. 256 never saw any return from the radio. why... //qDebug(logSerial()) << "Serial buffer size: " << port->readBufferSize(); - initializePt(); - connect(port, SIGNAL(readyRead()), this, SLOT(receiveDataIn())); - connect(pseudoterm, SIGNAL(readyRead()), this, SLOT(receiveDataInPt())); } commHandler::commHandler(QString portName, quint32 baudRate) @@ -55,86 +52,15 @@ commHandler::commHandler(QString portName, quint32 baudRate) //port->setReadBufferSize(1024); // manually. 256 never saw any return from the radio. why... //qDebug(logSerial()) << "Serial buffer size: " << port->readBufferSize(); - - initializePt(); - connect(port, SIGNAL(readyRead()), this, SLOT(receiveDataIn())); - connect(pseudoterm, SIGNAL(readyRead()), this, SLOT(receiveDataInPt())); // sometimes it seems the connection fails. - } -void commHandler::initializePt() -{ - // qDebug(logSerial()) << "init pt"; - pseudoterm = new QSerialPort(); - setupPtComm(); - openPtPort(); -} - -void commHandler::setupPtComm() -{ - qDebug(logSerial()) << "Setting up Pseudo Term"; - pseudoterm->setPortName("/dev/ptmx"); - // pseudoterm->setBaudRate(baudrate); - // pseudoterm->setStopBits(QSerialPort::OneStop); -} - -void commHandler::openPtPort() -{ - // qDebug(logSerial()) << "opening pt port"; - bool success; -#ifndef Q_OS_WIN - char ptname[128]; - int sysResult=0; -#endif - QString ptLinkCmd = "ln -s "; - success = pseudoterm->open(QIODevice::ReadWrite); - if(success) - { - -#ifndef Q_OS_WIN - - qDebug(logSerial()) << "Opened pt device, attempting to grant pt status"; - ptfd = pseudoterm->handle(); - qDebug(logSerial()) << "ptfd: " << ptfd; - if(grantpt(ptfd)) - { - qDebug(logSerial()) << "Failed to grantpt"; - return; - } - if(unlockpt(ptfd)) - { - qDebug(logSerial()) << "Failed to unlock pt"; - return; - } - // we're good! - qDebug(logSerial()) << "Opened pseudoterminal."; - qDebug(logSerial()) << "Slave name: " << ptsname(ptfd); - - ptsname_r(ptfd, ptname, 128); - ptDevSlave = QString::fromLocal8Bit(ptname); - ptLinkCmd.append(ptDevSlave); - ptLinkCmd.append(" /tmp/rig"); - sysResult = system("rm /tmp/rig"); - sysResult = system(ptLinkCmd.toStdString().c_str()); - if(sysResult) - { - qDebug(logSerial()) << "Received error from pseudo-terminal symlink command: code: [" << sysResult << "]" << " command: [" << ptLinkCmd << "]"; - } -#endif - - } else { - ptfd = 0; - qDebug(logSerial()) << "Could not open pseudo-terminal."; - } -} commHandler::~commHandler() { this->closePort(); } - void commHandler::setupComm() { serialError = false; @@ -169,37 +95,6 @@ void commHandler::sendDataOut(const QByteArray &writeData) mutex.unlock(); } -void commHandler::sendDataOutPt(const QByteArray &writeData) -{ - ptMutex.lock(); - //printHex(writeData, false, true); - -#ifdef QT_DEBUG - qint64 bytesWritten; - bytesWritten = port->write(writeData); - qDebug(logSerial()) << "pseudo-term bytesWritten: " << bytesWritten << " length of byte array: " << \ - writeData.length() << " size of byte array: " << writeData.size()\ - << ", wrote all: " << (bool)(bytesWritten == (qint64)writeData.size()); -#else - pseudoterm->write(writeData); -#endif - ptMutex.unlock(); -} - - -void commHandler::receiveDataInPt() -{ - // We received data from the pseudo-term. - //qDebug(logSerial()) << "Sending data from pseudo-terminal to radio"; - // Send this data to the radio: - //QByteArray ptdata = pseudoterm->readAll(); - // should check the data and rollback - // for now though... - //sendDataOut(ptdata); - sendDataOut(pseudoterm->readAll()); - //qDebug(logSerial()) << "Returned from sendDataOut with pseudo-terminal send data."; -} - void commHandler::receiveDataIn() { // connected to comm port data signal @@ -217,17 +112,6 @@ void commHandler::receiveDataIn() // good! port->commitTransaction(); emit haveDataFromPort(inPortData); - if( (inPortData[2] == (char)0x00) || (inPortData[2] == (char)0xE0) || (inPortData[3] == (char)0xE0) ) - { - // send to the pseudo port as well - // index 2 is dest, 0xE1 is wfview, 0xE0 is assumed to be the other device. - // Maybe change to "Not 0xE1" - // 0xE1 = wfview - // 0xE0 = pseudo-term host - // 0x00 = broadcast to all - //qDebug(logSerial()) << "Sending data from radio to pseudo-terminal"; - sendDataOutPt(inPortData); - } if(rolledBack) { @@ -286,11 +170,6 @@ void commHandler::closePort() port->close(); delete port; } - if(pseudoterm) - { - pseudoterm->close(); - delete pseudoterm; - } isConnected = false; } @@ -304,7 +183,6 @@ void commHandler::debugThis() } - void commHandler::printHex(const QByteArray &pdata, bool printVert, bool printHoriz) { qDebug(logSerial()) << "---- Begin hex dump -----:"; diff --git a/commhandler.h b/commhandler.h index 8bf92ce..e7e5580 100644 --- a/commhandler.h +++ b/commhandler.h @@ -23,7 +23,6 @@ public: private slots: void receiveDataIn(); // from physical port - void receiveDataInPt(); // from pseudo-term void receiveDataFromUserToRig(const QByteArray &data); void debugThis(); @@ -39,12 +38,7 @@ private: void openPort(); void closePort(); - void initializePt(); // like ch constructor - void setupPtComm(); - void openPtPort(); - void sendDataOut(const QByteArray &writeData); // out to radio - void sendDataOutPt(const QByteArray &writeData); // out to pseudo-terminal void debugMe(); void hexPrint(); diff --git a/pttyhandler.cpp b/pttyhandler.cpp new file mode 100644 index 0000000..ab2bfe3 --- /dev/null +++ b/pttyhandler.cpp @@ -0,0 +1,277 @@ +#include "pttyhandler.h" +#include "logcategories.h" + +#include + +// Copyright 2017-2021 Elliott H. Liggett & Phil Taylor + +pttyHandler::pttyHandler() +{ + //constructor + // grab baud rate and other comm port details + // if they need to be changed later, please + // destroy this and create a new one. + port = new QSerialPort(); + + // TODO: The following should become arguments and/or functions + // Add signal/slot everywhere for comm port setup. + // Consider how to "re-setup" and how to save the state for next time. + baudRate = 115200; + stopBits = 1; + +#ifdef Q_OS_WIN + portName = "COM20"; +#else + portName = "/dev/ttyUSB0"; +#endif + setupPtty(); // basic parameters + openPort(); + //qDebug(logSerial()) << "Serial buffer size: " << port->readBufferSize(); + //port->setReadBufferSize(1024); // manually. 256 never saw any return from the radio. why... + //qDebug(logSerial()) << "Serial buffer size: " << port->readBufferSize(); + + connect(port, SIGNAL(readyRead()), this, SLOT(receiveDataIn())); +} + +pttyHandler::pttyHandler(QString portName, quint32 baudRate) +{ + //constructor + // grab baud rate and other comm port details + // if they need to be changed later, please + // destroy this and create a new one. + + port = new QSerialPort(); + + this->portName = portName; + this->baudRate = baudRate; + + setupPtty(); // basic parameters + openPort(); + + // TODO: The following should become arguments and/or functions + // Add signal/slot everywhere for comm port setup. + // Consider how to "re-setup" and how to save the state for next time. + // qDebug(logSerial()) << "Serial buffer size: " << port->readBufferSize(); + //port->setReadBufferSize(1024); // manually. 256 never saw any return from the radio. why... + //qDebug(logSerial()) << "Serial buffer size: " << port->readBufferSize(); + + connect(port, SIGNAL(readyRead()), this, SLOT(receiveDataIn())); +} + +void pttyHandler::setupPtty() +{ + qDebug(logSerial()) << "Setting up Pseudo Term"; + serialError = false; + port->setPortName(portName); + port->setBaudRate(baudRate); + port->setStopBits(QSerialPort::OneStop);// OneStop is other option +} + + +void pttyHandler::openPort() +{ + // qDebug(logSerial()) << "opening pt port"; + bool success; +#ifndef Q_OS_WIN + char ptname[128]; + int sysResult = 0; + QString ptLinkCmd = "ln -s "; +#endif + success = port->open(QIODevice::ReadWrite); + if (success) + { +#ifndef Q_OS_WIN + + qDebug(logSerial()) << "Opened pt device, attempting to grant pt status"; + ptfd = port->handle(); + qDebug(logSerial()) << "ptfd: " << ptfd; + if (grantpt(ptfd)) + { + qDebug(logSerial()) << "Failed to grantpt"; + return; + } + if (unlockpt(ptfd)) + { + qDebug(logSerial()) << "Failed to unlock pt"; + return; + } + // we're good! + qDebug(logSerial()) << "Opened pseudoterminal."; + qDebug(logSerial()) << "Slave name: " << ptsname(ptfd); + + ptsname_r(ptfd, ptname, 128); + ptDevSlave = QString::fromLocal8Bit(ptname); + ptLinkCmd.append(ptDevSlave); + ptLinkCmd.append(" /tmp/rig"); + sysResult = system("rm /tmp/rig"); + sysResult = system(ptLinkCmd.toStdString().c_str()); + if (sysResult) + { + qDebug(logSerial()) << "Received error from pseudo-terminal symlink command: code: [" << sysResult << "]" << " command: [" << ptLinkCmd << "]"; + } + + isConected = true; +#endif + + } + else { + ptfd = 0; + qDebug(logSerial()) << "Could not open pseudo terminal port " << portName << " , please restart."; + isConnected = false; + serialError = true; + emit haveSerialPortError(portName, "Could not open pseudo terminal port. Please restart."); + return; + } +} + +pttyHandler::~pttyHandler() +{ + this->closePort(); +} + +void pttyHandler::receiveDataFromRigToPtty(const QByteArray& data) +{ + if (data[2] != (char)0xE1) + { + // send to the pseudo port as well + // index 2 is dest, 0xE1 is wfview, 0xE0 is assumed to be the other device. + // Maybe change to "Not 0xE1" + // 0xE1 = wfview + // 0xE0 = pseudo-term host + // 0x00 = broadcast to all + //qDebug(logSerial()) << "Sending data from radio to pseudo-terminal"; + sendDataOut(data); + } +} + +void pttyHandler::sendDataOut(const QByteArray& writeData) +{ + + mutex.lock(); + +#ifdef QT_DEBUG + + qint64 bytesWritten; + + bytesWritten = port->write(writeData); + + if (bytesWritten != writeData.length()) { + qDebug(logSerial()) << "bytesWritten: " << bytesWritten << " length of byte array: " << writeData.length()\ + << " size of byte array: " << writeData.size()\ + << " Wrote all bytes? " << (bool)(bytesWritten == (qint64)writeData.size()); + } +#else + port->write(writeData); + +#endif + mutex.unlock(); +} + + +void pttyHandler::receiveDataIn() +{ + // connected to comm port data signal + + // Here we get a little specific to CIV radios + // because we know what constitutes a valid "frame" of data. + + // new code: + port->startTransaction(); + inPortData = port->readAll(); + if (inPortData.startsWith("\xFE\xFE")) + { + if (inPortData.endsWith("\xFD")) + { + // good! + port->commitTransaction(); + + // filter 1A 05 01 12 = C-IV transceive command before forwarding on. + if (inPortData.length()>6 && inPortData[4] != (char)0x1A && inPortData[5] != (char)0x05 && inPortData[6] != (char)0x01 && inPortData[7] != (char)0x12) + { + emit haveDataFromPort(inPortData); + } + + if (rolledBack) + { + // qDebug(logSerial()) << "Rolled back and was successfull. Length: " << inPortData.length(); + //printHex(inPortData, false, true); + rolledBack = false; + } + } + else { + // did not receive the entire thing so roll back: + // qDebug(logSerial()) << "Rolling back transaction. End not detected. Lenth: " << inPortData.length(); + //printHex(inPortData, false, true); + port->rollbackTransaction(); + rolledBack = true; + } + } + else { + port->commitTransaction(); // do not emit data, do not keep data. + //qDebug(logSerial()) << "Warning: received data with invalid start. Dropping data."; + //qDebug(logSerial()) << "THIS SHOULD ONLY HAPPEN ONCE!!"; + // THIS SHOULD ONLY HAPPEN ONCE! + + // unrecoverable. We did not receive the start and must + // have missed it earlier because we did not roll back to + // preserve the beginning. + + //printHex(inPortData, false, true); + + } +} + +void pttyHandler::closePort() +{ + if (port) + { + port->close(); + delete port; + } + isConnected = false; +} + + +void pttyHandler::debugThis() +{ + // Do not use, function is for debug only and subject to change. + qDebug(logSerial()) << "comm debug called."; + + inPortData = port->readAll(); + emit haveDataFromPort(inPortData); +} + + + +void pttyHandler::printHex(const QByteArray& pdata, bool printVert, bool printHoriz) +{ + qDebug(logSerial()) << "---- Begin hex dump -----:"; + QString sdata("DATA: "); + QString index("INDEX: "); + QStringList strings; + + for (int i = 0; i < pdata.length(); i++) + { + strings << QString("[%1]: %2").arg(i, 8, 10, QChar('0')).arg((unsigned char)pdata[i], 2, 16, QChar('0')); + sdata.append(QString("%1 ").arg((unsigned char)pdata[i], 2, 16, QChar('0'))); + index.append(QString("%1 ").arg(i, 2, 10, QChar('0'))); + } + + if (printVert) + { + for (int i = 0; i < strings.length(); i++) + { + //sdata = QString(strings.at(i)); + qDebug(logSerial()) << strings.at(i); + } + } + + if (printHoriz) + { + qDebug(logSerial()) << index; + qDebug(logSerial()) << sdata; + } + qDebug(logSerial()) << "----- End hex dump -----"; +} + + diff --git a/pttyhandler.h b/pttyhandler.h new file mode 100644 index 0000000..417f34b --- /dev/null +++ b/pttyhandler.h @@ -0,0 +1,69 @@ +#ifndef PTTYHANDLER_H +#define PTTYHANDLER_H + +#include + +#include +#include +#include + +// This class abstracts the comm port in a useful way and connects to +// the command creator and command parser. + +class pttyHandler : public QObject +{ + Q_OBJECT + +public: + pttyHandler(); + pttyHandler(QString portName, quint32 baudRate); + bool serialError; + + ~pttyHandler(); + +private slots: + void receiveDataIn(); // from physical port + void receiveDataFromRigToPtty(const QByteArray& data); + void debugThis(); + +signals: + void haveTextMessage(QString message); // status, debug only + void haveDataFromPort(QByteArray data); // emit this when we have data, connect to rigcommander + void haveSerialPortError(const QString port, const QString error); + void haveStatusUpdate(const QString text); + +private: + void setupPtty(); + void openPort(); + void closePort(); + + void sendDataOut(const QByteArray& writeData); // out to radio + void debugMe(); + void hexPrint(); + + //QDataStream stream; + QByteArray outPortData; + QByteArray inPortData; + + //QDataStream outStream; + //QDataStream inStream; + + unsigned char buffer[256]; + + QString portName; + QSerialPort* port; + qint32 baudRate; + unsigned char stopBits; + bool rolledBack; + + int ptfd; // pseudo-terminal file desc. + bool havePt; + QString ptDevSlave; + + bool isConnected; // port opened + mutable QMutex mutex; + void printHex(const QByteArray& pdata, bool printVert, bool printHoriz); + +}; + +#endif // PTTYHANDLER_H diff --git a/rigcommander.cpp b/rigcommander.cpp index f148163..e394a69 100644 --- a/rigcommander.cpp +++ b/rigcommander.cpp @@ -49,16 +49,25 @@ void rigCommander::commSetup(unsigned char rigCivAddr, QString rigSerialPort, qu this->rigBaudRate = rigBaudRate; comm = new commHandler(rigSerialPort, rigBaudRate); + ptty = new pttyHandler(); // data from the comm port to the program: connect(comm, SIGNAL(haveDataFromPort(QByteArray)), this, SLOT(handleNewData(QByteArray))); + // data from the ptty to the rig: + connect(ptty, SIGNAL(haveDataFromPort(QByteArray)), comm, SLOT(receiveDataFromUserToRig(QByteArray))); + // data from the program to the comm port: connect(this, SIGNAL(dataForComm(QByteArray)), comm, SLOT(receiveDataFromUserToRig(QByteArray))); + // data from the rig to the ptty: + connect(this, SIGNAL(dataForComm(QByteArray)), ptty, SLOT(receiveDataFromRigToPtty(QByteArray))); + connect(comm, SIGNAL(haveSerialPortError(QString, QString)), this, SLOT(handleSerialPortError(QString, QString))); + connect(ptty, SIGNAL(haveSerialPortError(QString, QString)), this, SLOT(handleSerialPortError(QString, QString))); connect(this, SIGNAL(getMoreDebug()), comm, SLOT(debugThis())); + connect(this, SIGNAL(getMoreDebug()), ptty, SLOT(debugThis())); emit commReady(); } @@ -102,16 +111,36 @@ void rigCommander::commSetup(unsigned char rigCivAddr, udpPreferences prefs) emit initUdpHandler(); + this->rigSerialPort = rigSerialPort; + this->rigBaudRate = rigBaudRate; + + ptty = new pttyHandler(); + + + + + connect(udp, SIGNAL(haveDataFromPort(QByteArray)), this, SLOT(handleNewData(QByteArray))); + // data from the rig to the ptty: + connect(udp, SIGNAL(haveDataFromPort(QByteArray)), ptty, SLOT(receiveDataFromRigToPtty(QByteArray))); + connect(udp, SIGNAL(haveAudioData(audioPacket)), this, SLOT(receiveAudioData(audioPacket))); + // data from the program to the comm port: connect(this, SIGNAL(dataForComm(QByteArray)), udp, SLOT(receiveDataFromUserToRig(QByteArray))); + // data from the ptty to the rig: + connect(ptty, SIGNAL(haveDataFromPort(QByteArray)), udp, SLOT(receiveDataFromUserToRig(QByteArray))); + connect(this, SIGNAL(haveChangeLatency(quint16)), udp, SLOT(changeLatency(quint16))); // Connect for errors/alerts connect(udp, SIGNAL(haveNetworkError(QString, QString)), this, SLOT(handleSerialPortError(QString, QString))); connect(udp, SIGNAL(haveNetworkStatus(QString)), this, SLOT(handleStatusUpdate(QString))); + + connect(ptty, SIGNAL(haveSerialPortError(QString, QString)), this, SLOT(handleSerialPortError(QString, QString))); + connect(this, SIGNAL(getMoreDebug()), ptty, SLOT(debugThis())); + } // data from the comm port to the program: @@ -134,6 +163,10 @@ void rigCommander::closeComm() udpHandlerThread->wait(); } udp = Q_NULLPTR; + + if (ptty != Q_NULLPTR) { + delete ptty; + } } void rigCommander::setup() diff --git a/rigcommander.h b/rigcommander.h index ba1aebe..f5bd3ce 100644 --- a/rigcommander.h +++ b/rigcommander.h @@ -5,6 +5,7 @@ #include #include "commhandler.h" +#include "pttyhandler.h" #include "udphandler.h" #include "rigidentities.h" @@ -245,7 +246,8 @@ private: void printHex(const QByteArray &pdata); void printHex(const QByteArray &pdata, bool printVert, bool printHoriz); - commHandler * comm=Q_NULLPTR; + commHandler* comm = Q_NULLPTR; + pttyHandler* ptty = Q_NULLPTR; udpHandler* udp=Q_NULLPTR; QThread* udpHandlerThread = Q_NULLPTR; diff --git a/wfmain.cpp b/wfmain.cpp index 15f021f..624460f 100644 --- a/wfmain.cpp +++ b/wfmain.cpp @@ -695,9 +695,9 @@ void wfmain::receiveFoundRigID(rigCapabilities rigCaps) receiveRigID(rigCaps); getInitialRigState(); - QString message = QString("Found model: ").append(rigCaps.modelName); + //QString message = QString("Found model: ").append(rigCaps.modelName); - ui->statusBar->showMessage(message, 0); + //ui->statusBar->showMessage(message, 0); return; } diff --git a/wfview.pro b/wfview.pro index b0c1ce6..96e2251 100644 --- a/wfview.pro +++ b/wfview.pro @@ -87,7 +87,8 @@ SOURCES += main.cpp\ udpserversetup.cpp \ udpserver.cpp \ meter.cpp \ - qledlabel.cpp + qledlabel.cpp \ + pttyhandler.cpp HEADERS += wfmain.h \ commhandler.h \ @@ -103,7 +104,8 @@ HEADERS += wfmain.h \ udpserver.h \ packettypes.h \ meter.h \ - qledlabel.h + qledlabel.h \ + pttyhandler.h FORMS += wfmain.ui \ diff --git a/wfview.vcxproj b/wfview.vcxproj index d133e44..cf67190 100644 --- a/wfview.vcxproj +++ b/wfview.vcxproj @@ -204,6 +204,7 @@ + @@ -235,6 +236,7 @@ + diff --git a/wfview.vcxproj.filters b/wfview.vcxproj.filters index 03cba3d..158fab7 100644 --- a/wfview.vcxproj.filters +++ b/wfview.vcxproj.filters @@ -105,6 +105,9 @@ Source Files + + Source Files + @@ -152,6 +155,9 @@ Header Files + + Header Files + @@ -316,6 +322,7 @@ +