2023-05-23 Fred Gleason <fredg@paravelsystems.com>

* Implemented the 'Heartbeat' ['HB'] protocol command in ripcd(8).
	* Added support for the 'Heartbeat' ['HB'] RIPC protocol command
	to 'RDRipc'.

Signed-off-by: Fred Gleason <fredg@paravelsystems.com>
This commit is contained in:
Fred Gleason 2023-05-23 13:15:21 -04:00
parent c89b4bdc6e
commit 4236132aa8
5 changed files with 104 additions and 14 deletions

View File

@ -24162,3 +24162,7 @@
* Updated screenshot for rdlogmanager(1) in the Operations Guide. * Updated screenshot for rdlogmanager(1) in the Operations Guide.
2023-05-22 Fred Gleason <fredg@paravelsystems.com> 2023-05-22 Fred Gleason <fredg@paravelsystems.com>
* Fixed a regression in the BroadcastTools ACS8.2 driver in ripcd(8). * Fixed a regression in the BroadcastTools ACS8.2 driver in ripcd(8).
2023-05-23 Fred Gleason <fredg@paravelsystems.com>
* Implemented the 'Heartbeat' ['HB'] protocol command in ripcd(8).
* Added support for the 'Heartbeat' ['HB'] RIPC protocol command
to 'RDRipc'.

View File

@ -481,7 +481,7 @@
Return current GPI mask states. Return current GPI mask states.
</para> </para>
<para> <para>
<userinput>GM <replaceable>matrix</replaceable>!</userinput> <userinput>GI <replaceable>matrix</replaceable>!</userinput>
</para> </para>
<para> <para>
Request the list of current GPI mask states for Request the list of current GPI mask states for
@ -523,6 +523,24 @@
</variablelist> </variablelist>
</sect2> </sect2>
<sect2 xml:id="privileged_commands.heartbeat">
<title>Heartbeat</title>
<para>
Verify the TCP network connection.
</para>
<para>
<userinput>HB!</userinput>
</para>
<para>
Request a heartbeat response from the
<command>ripcd</command><manvolnum>8</manvolnum>.
</para>
<para>
<command>ripcd</command><manvolnum>8</manvolnum> will respond with
<computeroutput>HB!</computeroutput>.
</para>
</sect2>
<sect2 xml:id="privileged_commands.get_gpo_mask_states"> <sect2 xml:id="privileged_commands.get_gpo_mask_states">
<title>Get GPO Mask States</title> <title>Get GPO Mask States</title>
<para> <para>

View File

@ -29,21 +29,26 @@ RDRipc::RDRipc(RDStation *station,RDConfig *config,QObject *parent)
{ {
ripc_station=station; ripc_station=station;
ripc_config=config; ripc_config=config;
ripc_socket=NULL;
ripc_onair_flag=false; ripc_onair_flag=false;
ripc_ignore_mask=false; ripc_ignore_mask=false;
ripc_accum=""; ripc_accum="";
ripc_watchdog_pending=false;
debug=false; debug=false;
ripc_connected=false; ripc_connected=false;
// //
// TCP Connection // Watchdog Timers
// //
ripc_socket=new QTcpSocket(this); ripc_watchdog_timer=new QTimer(this);
connect(ripc_socket,SIGNAL(connected()),this,SLOT(connectedData())); ripc_watchdog_timer->setSingleShot(true);
connect(ripc_socket,SIGNAL(error(QAbstractSocket::SocketError)), connect(ripc_watchdog_timer,SIGNAL(timeout()),this,SLOT(watchdogRetryData()));
this,SLOT(errorData(QAbstractSocket::SocketError)));
connect(ripc_socket,SIGNAL(readyRead()),this,SLOT(readyData())); ripc_heartbeat_timer=new QTimer(this);
ripc_heartbeat_timer->setSingleShot(true);
connect(ripc_heartbeat_timer,SIGNAL(timeout()),
this,SLOT(sendHeartbeatData()));
} }
@ -85,14 +90,63 @@ void RDRipc::setIgnoreMask(bool state)
void RDRipc::connectHost(QString hostname,uint16_t hostport,QString password) void RDRipc::connectHost(QString hostname,uint16_t hostport,QString password)
{ {
ripc_hostname=hostname;
ripc_hostport=hostport;
ripc_password=password; ripc_password=password;
//
// TCP Connection
//
ripc_heartbeat_timer->stop();
if(ripc_socket!=NULL) {
ripc_socket->deleteLater();
}
ripc_socket=new QTcpSocket(this);
connect(ripc_socket,SIGNAL(connected()),this,SLOT(connectedData()));
connect(ripc_socket,SIGNAL(error(QAbstractSocket::SocketError)),
this,SLOT(errorData(QAbstractSocket::SocketError)));
connect(ripc_socket,SIGNAL(readyRead()),this,SLOT(readyData()));
ripc_socket->connectToHost(hostname,hostport); ripc_socket->connectToHost(hostname,hostport);
ripc_heartbeat_timer->start(RIPC_HEARTBEAT_POLL_INTERVAL);
} }
void RDRipc::connectedData() void RDRipc::connectedData()
{ {
SendCommand(QString("PW ")+ripc_password+"!"); SendCommand(QString("PW ")+ripc_password+"!");
if(ripc_watchdog_pending) {
rda->syslog(LOG_WARNING,"connection to ripcd(8) restored");
ripc_watchdog_pending=false;
}
}
void RDRipc::disconnectedData()
{
ripc_heartbeat_timer->stop();
ripc_watchdog_timer->stop();
ripc_watchdog_timer->start(RIPC_HEARTBEAT_POLL_INTERVAL);
}
void RDRipc::sendHeartbeatData()
{
ripc_watchdog_timer->stop();
SendCommand("HB!");
ripc_watchdog_timer->start(RIPC_HEARTBEAT_POLL_INTERVAL);
}
void RDRipc::watchdogRetryData()
{
if(!ripc_watchdog_pending) {
rda->syslog(LOG_WARNING,
"connection to ripcd(8) timed out, attempting reconnect");
}
ripc_watchdog_pending=true;
connectHost(ripc_hostname,ripc_hostport,ripc_password);
ripc_watchdog_timer->start(RIPC_HEARTBEAT_POLL_INTERVAL);
} }
@ -201,12 +255,6 @@ void RDRipc::sendRml(RDMacro *macro)
} }
void RDRipc::reloadHeartbeat()
{
SendCommand("RH!");
}
void RDRipc::errorData(QAbstractSocket::SocketError err) void RDRipc::errorData(QAbstractSocket::SocketError err)
{ {
rda->syslog(LOG_DEBUG,"received socket error %d",err); rda->syslog(LOG_DEBUG,"received socket error %d",err);
@ -271,6 +319,14 @@ void RDRipc::DispatchCommand()
} }
} }
if(cmds[0]=="HB") { // Heartbeat
if(cmds.size()!=1) {
return;
}
ripc_watchdog_timer->stop();
ripc_heartbeat_timer->start(RIPC_HEARTBEAT_POLL_INTERVAL);
}
if(cmds[0]=="MS") { // Macro Sent if(cmds[0]=="MS") { // Macro Sent
if(cmds.size()<4) { if(cmds.size()<4) {
return; return;

View File

@ -34,6 +34,7 @@
#define RIPC_MAX_ARGS 100 #define RIPC_MAX_ARGS 100
#define RIPC_MAX_LENGTH 256 #define RIPC_MAX_LENGTH 256
#define RIPC_START_DELAY 2000 #define RIPC_START_DELAY 2000
#define RIPC_HEARTBEAT_POLL_INTERVAL 10000
class RDRipc : public QObject class RDRipc : public QObject
{ {
@ -59,7 +60,6 @@ class RDRipc : public QObject
void sendCatchEvent(RDCatchEvent *evt); void sendCatchEvent(RDCatchEvent *evt);
void sendOnairFlag(); void sendOnairFlag();
void sendRml(RDMacro *macro); void sendRml(RDMacro *macro);
void reloadHeartbeat();
signals: signals:
void connected(bool state); void connected(bool state);
@ -77,6 +77,9 @@ class RDRipc : public QObject
private slots: private slots:
void connectedData(); void connectedData();
void disconnectedData();
void sendHeartbeatData();
void watchdogRetryData();
void errorData(QAbstractSocket::SocketError err); void errorData(QAbstractSocket::SocketError err);
void readyData(); void readyData();
@ -85,6 +88,8 @@ class RDRipc : public QObject
void DispatchCommand(); void DispatchCommand();
QTcpSocket *ripc_socket; QTcpSocket *ripc_socket;
QString ripc_user; QString ripc_user;
QString ripc_hostname;
uint16_t ripc_hostport;
QString ripc_password; QString ripc_password;
RDStation *ripc_station; RDStation *ripc_station;
RDConfig *ripc_config; RDConfig *ripc_config;
@ -93,6 +98,9 @@ class RDRipc : public QObject
bool debug; bool debug;
QString ripc_accum; QString ripc_accum;
bool ripc_connected; bool ripc_connected;
QTimer *ripc_heartbeat_timer;
QTimer *ripc_watchdog_timer;
bool ripc_watchdog_pending;
}; };

View File

@ -522,6 +522,10 @@ bool MainObject::DispatchCommand(RipcdConnection *conn)
EchoCommand(conn->id(),cmds.join(" ")+"-!"); EchoCommand(conn->id(),cmds.join(" ")+"-!");
return true; return true;
} }
if(cmds[0]=="HB") { // Heartbeat
EchoCommand(conn->id(),"HB!");
}
if(cmds[0]=="RU") { // Request User if(cmds[0]=="RU") { // Request User
EchoCommand(conn->id(),(QString("RU ")+rda->station()->userName()+"!"). EchoCommand(conn->id(),(QString("RU ")+rda->station()->userName()+"!").
toUtf8()); toUtf8());