Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/linux-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ jobs:
qt5-qmake \
libqt5svg5-dev \
libqt5opengl5-dev \
libqt5serialport5-dev \
libgl1-mesa-dev \
libfuse2 \
dpkg-dev \
Expand Down
75 changes: 74 additions & 1 deletion Source/Links/controllink.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#include "controllink.h"
#include "seriallink.h"
#include <QtGlobal>
#include <QHostAddress>
#include <QTimer>

#ifdef Q_OS_WIN
#include "Ws2tcpip.h"
Expand All @@ -18,7 +20,10 @@ ControlLink::ControlLink(QObject *parent)
{
tcpSocket = new QTcpSocket(this);
tcpSocket->setSocketOption(QAbstractSocket::KeepAliveOption, 1);
serialLink = nullptr;
transport = CONTROL_LINK_TRANSPORT_TCP;
ipAddress = "0.0.0.0";
serialPortName = "";
portNumber = 0;
linkStatus = CONTROL_LINK_STATUS_DISABLED;
reconnectTimer = new QTimer(this);
Expand All @@ -28,7 +33,11 @@ ControlLink::ControlLink(QObject *parent)

ControlLink::~ControlLink()
{
if(linkStatus == CONTROL_LINK_STATUS_ESTABLISHED)
if(transport == CONTROL_LINK_TRANSPORT_SERIAL)
{
if(serialLink != nullptr) { serialLink->close(); delete serialLink; serialLink = nullptr; }
}
else if(linkStatus == CONTROL_LINK_STATUS_ESTABLISHED)
{
tcpSocket->disconnect();
}
Expand All @@ -48,6 +57,53 @@ control_link_status_t ControlLink::establishLink(QString aIpAddress, QString a
return linkStatus;
}

control_link_status_t ControlLink::establishSerialLink(QString aPortName, qint32 aBaudRate)
{
transport = CONTROL_LINK_TRANSPORT_SERIAL;
linkStatus = CONTROL_LINK_STATUS_DISABLED;
serialPortName = aPortName;
ipAddress = aPortName; /* reuse for display (getDeviceIP_Addr) */

if(serialLink == nullptr)
{
serialLink = new SerialLink(this);
connect(serialLink, &SerialLink::sigAsyncMessage, this, &ControlLink::sigAsyncMessage);
connect(serialLink, &SerialLink::sigDisconnected, this, &ControlLink::onSerialDisconnected);
}

if(!serialLink->open(aPortName, aBaudRate))
{
linkStatus = CONTROL_LINK_STATUS_DISABLED;
return linkStatus;
}

linkStatus = CONTROL_LINK_STATUS_ESTABLISHED;

/* Mirror TCP timing: deliver sigConnected through the event loop, after the
* caller has assigned this link to the Device and connected the signal. */
QTimer::singleShot(0, this, [this](){ emit sigConnected(); });

return linkStatus;
}

void ControlLink::onSerialDisconnected()
{
linkStatus = CONTROL_LINK_STATUS_DISABLED;
emit sigDisconnected();
}

bool ControlLink::transferBdWrite(const QByteArray& data, int timeout)
{
if(transport != CONTROL_LINK_TRANSPORT_SERIAL || serialLink == nullptr) return false;
return serialLink->transferBdWrite(data, timeout);
}

bool ControlLink::transferBdRead(QByteArray* out, int timeout)
{
if(transport != CONTROL_LINK_TRANSPORT_SERIAL || serialLink == nullptr) return false;
return serialLink->transferBdRead(out, timeout);
}

bool ControlLink::prvReadResponse(QString* response, int timeout)
{
QByteArray receivedData;
Expand Down Expand Up @@ -117,6 +173,7 @@ bool ControlLink::prvReadResponse(QString* response, int timeout)

void ControlLink::reconnect()
{
if(transport == CONTROL_LINK_TRANSPORT_SERIAL) return; /* serial auto-reconnect is Phase 2 */
tcpSocket->connectToHost(ipAddress, portNumber);
tcpSocket->waitForConnected(10);
}
Expand All @@ -141,6 +198,14 @@ bool ControlLink::executeCommand(QString command, QString* response, int timeout
return false;
}

/* ===== SERIAL (Charger): delegated to the threaded SerialLink ===== */
if(transport == CONTROL_LINK_TRANSPORT_SERIAL)
{
if(serialLink == nullptr) { *response = "Control link not established"; return false; }
return serialLink->executeCommand(command, response, timeout);
}

/* ===== TCP (EPP): binary 0xA5 framing ===== */
QByteArray packet;

/* HEADER */
Expand Down Expand Up @@ -171,6 +236,14 @@ bool ControlLink::executeCommand(QByteArray request, QString* response, int time
return false;
}

/* Binary (0xA5 'B') framing is EPP/TCP-only. The serial charger uses a
* text BD protocol which is a Phase-2 item. */
if(transport == CONTROL_LINK_TRANSPORT_SERIAL)
{
*response = "Binary commands not supported over serial";
return false;
}

QByteArray packet;

/* HEADER */
Expand Down
19 changes: 19 additions & 0 deletions Source/Links/controllink.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,15 @@

#define CONTROL_LINK_COMMAND_TIMEOUT 1000
#define CONTROL_LINK_RECONNECT_PERIOD 1000
#define CONTROL_LINK_SERIAL_BAUDRATE 115200

class SerialLink;

/* Transport used by the control link */
typedef enum{
CONTROL_LINK_TRANSPORT_TCP, /*!< EPP devices over TCP/IP (binary 0xA5 framing) */
CONTROL_LINK_TRANSPORT_SERIAL /*!< Charger device over USB CDC serial (via SerialLink) */
}control_link_transport_t;

typedef enum{
CONTROL_LINK_STATUS_ESTABLISHED,
Expand All @@ -22,7 +31,12 @@ class ControlLink : public QObject
explicit ControlLink(QObject *parent = nullptr);
~ControlLink();
control_link_status_t establishLink(QString aIpAddress, QString aPortNumber);
control_link_status_t establishSerialLink(QString aPortName, qint32 aBaudRate = CONTROL_LINK_SERIAL_BAUDRATE);
bool getDeviceName(QString* deviceName);

/* Binary board-data (EEPROM) transfer over serial (0xA5 0xA5 frame). */
bool transferBdWrite(const QByteArray& data, int timeout);
bool transferBdRead(QByteArray* out, int timeout);
bool executeCommand(QString command, QString* response, int timeout);
bool executeCommand(QByteArray request, QString* response, int timeout);

Expand All @@ -32,16 +46,21 @@ class ControlLink : public QObject
signals:
void sigDisconnected();
void sigConnected();
void sigAsyncMessage(QString message); /*!< Unsolicited notification (serial) */

public slots:
void onDisconnected();
void onReconnected();
void reconnect();
void onSerialDisconnected();

private:

QTcpSocket *tcpSocket;
SerialLink *serialLink; /*!< Threaded serial transport (charger) */
control_link_transport_t transport;
QString ipAddress;
QString serialPortName;
quint16 portNumber;
control_link_status_t linkStatus;
QTimer *reconnectTimer;
Expand Down
Loading
Loading