2017-08-16 Fred Gleason <fredg@paravelsystems.com>

* Fixed a bug in 'lib/rdlog.cpp' that caused incorrect results when
	calculating the total number of voice tracks in a log.
This commit is contained in:
Fred Gleason 2017-08-16 11:08:50 -04:00
commit 75f9482626
10 changed files with 994 additions and 7 deletions

View File

@ -15929,6 +15929,14 @@
'rlm_filewrite' RLM from 256 to 8192 characters. 'rlm_filewrite' RLM from 256 to 8192 characters.
2017-08-07 Fred Gleason <fredg@paravelsystems.com> 2017-08-07 Fred Gleason <fredg@paravelsystems.com>
* Incremented the package version to 2.16.0int06_rfa02. * Incremented the package version to 2.16.0int06_rfa02.
2017-08-12 Fred Gleason <fredg@paravelsystems.com>
* Implemented a driver for WheatNet SLIO devices.
2017-08-12 Fred Gleason <fredg@paravelsystems.com>
* Implemented a driver for WheatNet LIO devices.
2017-08-13 Fred Gleason <fredg@paravelsystems.com>
* Refactored the WheatNet LIO driver to use event subscription.
2017-08-13 Fred Gleason <fredg@paravelsystems.com>
* Refactored the WheatNet SLIO driver to use event subscription.
2017-08-16 Fred Gleason <fredg@paravelsystems.com> 2017-08-16 Fred Gleason <fredg@paravelsystems.com>
* Fixed a bug in 'lib/rdlog.cpp' that caused incorrect results when * Fixed a bug in 'lib/rdlog.cpp' that caused incorrect results when
calculating the total number of voice tracks in a log. calculating the total number of voice tracks in a log.

View File

@ -37,6 +37,8 @@ Sine Systems ACU-1 (Prophet version)
Software Authority Protocol Software Authority Protocol
StarGuide III Satellite Receiver StarGuide III Satellite Receiver
Wegener Unity4000 DVB Satellite Receiver Wegener Unity4000 DVB Satellite Receiver
WheatNet Blade LIO
WheatNet Blade SLIO
See the sections below for notes on each specific model. See the sections below for notes on each specific model.
@ -851,4 +853,36 @@ output at a time. Commanding a stream to an output will cause that
stream to be silently deselected from a previously selected output. stream to be silently deselected from a previously selected output.
----------------------------------------------------------------------------
WHEATNET BLADE LIO
Driver Name: WheatNet LIO
Supported RML Commands:
GPI Enable ('GE')
GPI Set ('GI')
GPO Set ('GO')
GENERAL NOTES:
Control is done by means of a TCP/IP connection to port 55776 on a blade.
The only required configuration parameters are IP Address and IP Port.
The number of pins is auto-detected at driver startup.
----------------------------------------------------------------------------
WHEATNET BLADE SLIO
Driver Name: WheatNet SLIO
Supported RML Commands:
GPI Enable ('GE')
GPI Set ('GI')
GPO Set ('GO')
GENERAL NOTES:
Control is done by means of a TCP/IP connection to port 55776 on a blade.
The only required configuration parameters are IP Address and IP Port.
The number of soft pins is auto-detected at driver startup.
---------------------------------------------------------------------------- ----------------------------------------------------------------------------

View File

@ -68,7 +68,9 @@ bool __mx_primary_controls[RDMatrix::LastType][RDMatrix::LastControl]=
{0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0}, // BT ADMS 44.22 {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0}, // BT ADMS 44.22
{0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0}, // BT SS 4.1 MLR {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0}, // BT SS 4.1 MLR
{0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0}, // Modbus {0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0}, // Modbus
{0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0} // Kernel GPIO {0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0}, // Kernel GPIO
{0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0}, // WheatNet SLIO
{0,0,1,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0} // WheatNet LIO
}; };
bool __mx_backup_controls[RDMatrix::LastType][RDMatrix::LastControl]= bool __mx_backup_controls[RDMatrix::LastType][RDMatrix::LastControl]=
{ {
@ -113,7 +115,9 @@ bool __mx_backup_controls[RDMatrix::LastType][RDMatrix::LastControl]=
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, // BT ADMS 44.22 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, // BT ADMS 44.22
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, // BT SS 4.1 MLR {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, // BT SS 4.1 MLR
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, // Modbus {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, // Modbus
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} // Kernel GPIO {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, // Kernel GPIO
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, // WheatNet SLIO
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} // WheatNet LIO
}; };
int __mx_default_values[RDMatrix::LastType][RDMatrix::LastControl]= int __mx_default_values[RDMatrix::LastType][RDMatrix::LastControl]=
@ -159,7 +163,9 @@ int __mx_default_values[RDMatrix::LastType][RDMatrix::LastControl]=
{0,0,0,0,0,0,0,0,0,0,0,8,2,16,13,0,0,0,0,0,0,0,0,0,0,0,0,1,0}, // BT ADMS 44.22 {0,0,0,0,0,0,0,0,0,0,0,8,2,16,13,0,0,0,0,0,0,0,0,0,0,0,0,1,0}, // BT ADMS 44.22
{0,0,0,0,0,0,0,0,0,0,0,4,1,8,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0}, // BT SS 4.1 MLR {0,0,0,0,0,0,0,0,0,0,0,4,1,8,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0}, // BT SS 4.1 MLR
{1,0,0,502,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0}, // Modbus {1,0,0,502,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0}, // Modbus
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0} // Kernel GPIO {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0}, // Kernel GPIO
{1,0,0,55776,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0}, // WheatNet SLIO
{1,0,0,55776,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0} // WheatNet LIO
}; };
RDMatrix::RDMatrix(const QString &station,int matrix) RDMatrix::RDMatrix(const QString &station,int matrix)
@ -731,6 +737,14 @@ QString RDMatrix::typeString(RDMatrix::Type type)
return QString("Kernel GPIO"); return QString("Kernel GPIO");
break; break;
case RDMatrix::WheatnetSlio:
return QString("WheatNet SLIO");
break;
case RDMatrix::WheatnetLio:
return QString("WheatNet LIO");
break;
default: default:
return QString("Unknown Type"); return QString("Unknown Type");
break; break;

View File

@ -38,7 +38,8 @@ class RDMatrix
BtSrc16=24,Harlond=25,Acu1p=26,LiveWireMcastGpio=27,Am16=28, BtSrc16=24,Harlond=25,Acu1p=26,LiveWireMcastGpio=27,Am16=28,
LiveWireLwrpGpio=29,BtSentinel4Web=30,BtGpi16=31,ModemLines=32, LiveWireLwrpGpio=29,BtSentinel4Web=30,BtGpi16=31,ModemLines=32,
SoftwareAuthority=33,Sas16000=34,RossNkScp=35,BtAdms4422=36, SoftwareAuthority=33,Sas16000=34,RossNkScp=35,BtAdms4422=36,
BtSs41Mlr=37,Modbus=38,KernelGpio=39,LastType=40}; BtSs41Mlr=37,Modbus=38,KernelGpio=39,WheatnetSlio=40,
WheatnetLio=41,LastType=42};
enum Endpoint {Input=0,Output=1}; enum Endpoint {Input=0,Output=1};
enum Mode {Stereo=0,Left=1,Right=2}; enum Mode {Stereo=0,Left=1,Right=2};
enum VguestAttribute {VguestEngine=0,VguestDevice=1,VguestSurface=2, enum VguestAttribute {VguestEngine=0,VguestDevice=1,VguestSurface=2,

View File

@ -76,7 +76,9 @@ dist_ripcd_SOURCES = acu1p.cpp acu1p.h\
switcher.cpp switcher.h\ switcher.cpp switcher.h\
unity4000.cpp unity4000.h\ unity4000.cpp unity4000.h\
unity_feed.cpp unity_feed.h\ unity_feed.cpp unity_feed.h\
vguest.cpp vguest.h vguest.cpp vguest.h\
wheatnet_lio.cpp wheatnet_lio.h\
wheatnet_slio.cpp wheatnet_slio.h
nodist_ripcd_SOURCES = moc_am16.cpp\ nodist_ripcd_SOURCES = moc_am16.cpp\
moc_acu1p.cpp\ moc_acu1p.cpp\
@ -118,7 +120,9 @@ nodist_ripcd_SOURCES = moc_am16.cpp\
moc_swauthority.cpp\ moc_swauthority.cpp\
moc_switcher.cpp\ moc_switcher.cpp\
moc_unity4000.cpp\ moc_unity4000.cpp\
moc_vguest.cpp moc_vguest.cpp\
moc_wheatnet_lio.cpp\
moc_wheatnet_slio.cpp
ripcd_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ ripcd_LDADD = @LIB_RDLIBS@ @LIBVORBIS@

View File

@ -2,7 +2,7 @@
// //
// Load Switcher drivers for ripcd(8) // Load Switcher drivers for ripcd(8)
// //
// (C) Copyright 2002-2016 Fred Gleason <fredg@paravelsystems.com> // (C) Copyright 2002-2017 Fred Gleason <fredg@paravelsystems.com>
// //
// This program is free software; you can redistribute it and/or modify // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as // it under the terms of the GNU General Public License version 2 as
@ -61,6 +61,8 @@
#include <swauthority.h> #include <swauthority.h>
#include <unity4000.h> #include <unity4000.h>
#include <vguest.h> #include <vguest.h>
#include <wheatnet_lio.h>
#include <wheatnet_slio.h>
bool MainObject::LoadSwitchDriver(int matrix_num) bool MainObject::LoadSwitchDriver(int matrix_num)
{ {
@ -219,6 +221,14 @@ bool MainObject::LoadSwitchDriver(int matrix_num)
ripcd_switcher[matrix_num]=new Unity4000(matrix,this); ripcd_switcher[matrix_num]=new Unity4000(matrix,this);
break; break;
case RDMatrix::WheatnetLio:
ripcd_switcher[matrix_num]=new WheatnetLio(matrix,this);
break;
case RDMatrix::WheatnetSlio:
ripcd_switcher[matrix_num]=new WheatnetSlio(matrix,this);
break;
default: default:
ripcd_switcher[matrix_num]=NULL; ripcd_switcher[matrix_num]=NULL;
delete matrix; delete matrix;

379
ripcd/wheatnet_lio.cpp Normal file
View File

@ -0,0 +1,379 @@
// wheatnet_lio.cpp
//
// A Rivendell switcher driver for Modbus TCP
//
// (C) Copyright 2017 Fred Gleason <fredg@paravelsystems.com>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation.
//
// 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#include <syslog.h>
#include <rddb.h>
#include <rdescape_string.h>
#include "wheatnet_lio.h"
WheatnetLio::WheatnetLio(RDMatrix *matrix,QObject *parent)
: Switcher(matrix,parent)
{
lio_watchdog_active=false;
lio_gpios=0;
lio_ip_address=matrix->ipAddress(RDMatrix::Primary);
lio_ip_port=matrix->ipPort(RDMatrix::Primary);
lio_card=matrix->card();
lio_socket=new QSocket(this);
connect(lio_socket,SIGNAL(connected()),this,SLOT(connectedData()));
connect(lio_socket,SIGNAL(readyRead()),this,SLOT(readyReadData()));
connect(lio_socket,SIGNAL(error(int)),this,SLOT(errorData(int)));
lio_socket->connectToHost(lio_ip_address.toString(),lio_ip_port);
lio_poll_timer=new QTimer(this);
connect(lio_poll_timer,SIGNAL(timeout()),this,SLOT(pollData()));
lio_reset_mapper=new QSignalMapper(this);
connect(lio_reset_mapper,SIGNAL(mapped(int)),
this,SLOT(resetStateData(int)));
for(int i=0;i<lio_gpios;i++) {
lio_reset_timers.push_back(new QTimer(this));
connect(lio_reset_timers.back(),SIGNAL(timeout()),
lio_reset_mapper,SLOT(map()));
lio_reset_mapper->setMapping(lio_reset_timers.back(),i);
lio_reset_states.push_back(false);
}
lio_watchdog_timer=new QTimer(this);
connect(lio_watchdog_timer,SIGNAL(timeout()),this,SLOT(watchdogData()));
}
WheatnetLio::~WheatnetLio()
{
delete lio_watchdog_timer;
delete lio_poll_timer;
for(unsigned i=0;i<lio_reset_timers.size();i++) {
delete lio_reset_timers[i];
}
delete lio_reset_mapper;
delete lio_socket;
}
RDMatrix::Type WheatnetLio::type()
{
return RDMatrix::WheatnetLio;
}
unsigned WheatnetLio::gpiQuantity()
{
return lio_gpios;
}
unsigned WheatnetLio::gpoQuantity()
{
return lio_gpios;
}
bool WheatnetLio::primaryTtyActive()
{
return false;
}
bool WheatnetLio::secondaryTtyActive()
{
return false;
}
void WheatnetLio::processCommand(RDMacro *cmd)
{
switch(cmd->command()) {
case RDMacro::GO:
if((cmd->argQuantity()!=5)||
((cmd->arg(1).toString().lower()!="i")&&
(cmd->arg(1).toString().lower()!="o"))||
(cmd->arg(2).toInt()<1)||(cmd->arg(3).toInt()>lio_gpios)||
(cmd->arg(2).toInt()>lio_gpios)||
((cmd->arg(3).toInt()!=1)&&(cmd->arg(3).toInt()!=0)&&
(cmd->arg(1).toString().lower()!="i"))||
((cmd->arg(3).toInt()!=1)&&(cmd->arg(3).toInt()!=0)&&
(cmd->arg(3).toInt()!=-1)&&(cmd->arg(1).toString().lower()=="i"))||
(cmd->arg(4).toInt()<0)) {
cmd->acknowledge(false);
emit rmlEcho(cmd);
return;
}
if(cmd->arg(3).toInt()==0) { // Turn OFF
if(cmd->arg(4).toInt()==0) {
if(cmd->arg(1).toString().lower()=="o") {
SendCommand(QString().sprintf("<LIO:%d|LVL:0>",
cmd->arg(2).toInt()-1));
emit gpoChanged(matrixNumber(),cmd->arg(2).toInt()-1,false);
}
}
else {
if(cmd->echoRequested()) {
cmd->acknowledge(false);
emit rmlEcho(cmd);
}
return;
}
}
else {
if(cmd->arg(4).toInt()==0) { // Turn ON
if(cmd->arg(1).toString().lower()=="o") {
SendCommand(QString().sprintf("<LIO:%d|LVL:1>",
cmd->arg(2).toInt()-1));
emit gpoChanged(matrixNumber(),cmd->arg(2).toInt()-1,true);
}
}
else { // Pulse
if(cmd->arg(1).toString().lower()=="o") {
SendCommand(QString().sprintf("<LIO:%d|LVL:%d>",
cmd->arg(2).toInt()-1,
cmd->arg(3).toInt()!=0));
lio_reset_states[cmd->arg(2).toInt()-1]=cmd->arg(3).toInt()==0;
lio_reset_timers[cmd->arg(2).toInt()-1]->
start(cmd->arg(4).toInt(),true);
emit gpoChanged(matrixNumber(),cmd->arg(2).toInt()-1,
cmd->arg(3).toInt()!=0);
}
}
}
if(cmd->echoRequested()) {
cmd->acknowledge(true);
emit rmlEcho(cmd);
}
break;
default:
break;
}
}
void WheatnetLio::connectedData()
{
syslog(LOG_INFO,
"connection to WheatNet LIO device at %s:%u established",
(const char *)lio_ip_address.toString(),0xffff&lio_ip_port);
lio_watchdog_active=false;
SendCommand("<SYS?LIO>");
}
void WheatnetLio::readyReadData()
{
char data[1501];
int n=0;
while((n=lio_socket->readBlock(data,1500))>0) {
data[n]=0;
for(int i=0;i<n;i++) {
switch(0xff&data[i]) {
case 13:
break;
case 10:
ProcessCommand(lio_accum);
lio_accum="";
break;
default:
lio_accum+=data[i];
break;
}
}
}
}
void WheatnetLio::errorData(int err)
{
watchdogData();
}
void WheatnetLio::resetStateData(int line)
{
SendCommand(QString().sprintf("<LIO:%d|LVL:%d>",line,
(int)lio_reset_states[line]));
emit gpoChanged(matrixNumber(),line,lio_reset_states[line]);
}
void WheatnetLio::pollData()
{
SendCommand("<SYS?BLID>");
}
void WheatnetLio::watchdogData()
{
if(!lio_watchdog_active) {
syslog(LOG_WARNING,
"connection to Wheatnet LIO device at %s:%u lost, attempting reconnect",
(const char *)lio_ip_address.toString(),0xffff&lio_ip_port);
lio_watchdog_active=true;
}
lio_socket->close();
lio_socket->connectToHost(lio_ip_address.toString(),lio_ip_port);
}
void WheatnetLio::CheckLineEntry(int line)
{
QString sql;
RDSqlQuery *q;
sql=QString("select ID from GPIS where ")+
"(STATION_NAME=\""+RDEscapeString(stationName())+"\")&&"+
QString().sprintf("(MATRIX=%d)&&",matrixNumber())+
QString().sprintf("(NUMBER=%d)",line);
q=new RDSqlQuery(sql);
if(!q->first()) {
delete q;
sql=QString("insert into GPIS set ")+
"STATION_NAME=\""+RDEscapeString(stationName())+"\","+
QString().sprintf("MATRIX=%d,",matrixNumber())+
QString().sprintf("NUMBER=%d",line);
q=new RDSqlQuery(sql);
}
delete q;
sql=QString("select ID from GPOS where ")+
"(STATION_NAME=\""+RDEscapeString(stationName())+"\")&&"+
QString().sprintf("(MATRIX=%d)&&",matrixNumber())+
QString().sprintf("(NUMBER=%d)",line);
q=new RDSqlQuery(sql);
if(!q->first()) {
delete q;
sql=QString("insert into GPOS set ")+
"STATION_NAME=\""+RDEscapeString(stationName())+"\","+
QString().sprintf("MATRIX=%d,",matrixNumber())+
QString().sprintf("NUMBER=%d",line);
q=new RDSqlQuery(sql);
}
delete q;
}
void WheatnetLio::ProcessSys(const QString &cmd)
{
// printf("SYS: %s\n",(const char *)cmd);
QString sql;
RDSqlQuery *q;
bool ok=false;
QStringList f0=f0.split(":",cmd);
if((f0[0]=="LIO")&&(f0.size()==2)) {
int lio=f0[1].toUInt(&ok);
if(ok) {
lio_gpios=lio;
for(unsigned i=0;i<lio_reset_timers.size();i++) {
delete lio_reset_timers[i];
}
lio_reset_timers.clear();
lio_reset_states.clear();
lio_gpi_states.clear();
for(int i=0;i<lio_gpios;i++) {
lio_reset_timers.push_back(new QTimer(this));
connect(lio_reset_timers.back(),SIGNAL(timeout()),
lio_reset_mapper,SLOT(map()));
lio_reset_mapper->setMapping(lio_reset_timers.back(),i);
lio_reset_states.push_back(false);
lio_gpi_states.push_back(false);
CheckLineEntry(i+1);
SendCommand(QString().sprintf("<LIOSUB:0.%d|LVL:1>",i));
}
sql=QString("update MATRICES set ")+
QString().sprintf("GPIS=%d,GPOS=%d where ",lio_gpios,lio_gpios)+
"(STATION_NAME=\""+RDEscapeString(stationName())+"\")&&"+
QString().sprintf("(MATRIX=%d)",matrixNumber());
q=new RDSqlQuery(sql);
delete q;
lio_watchdog_timer->start(WHEATNET_LIO_WATCHDOG_INTERVAL,true);
lio_poll_timer->start(WHEATNET_LIO_POLL_INTERVAL,true);
}
}
if((f0[0]=="BLID")&&(f0.size()==2)) {
lio_watchdog_timer->stop();
lio_watchdog_timer->start(WHEATNET_LIO_WATCHDOG_INTERVAL,true);
lio_poll_timer->start(WHEATNET_LIO_POLL_INTERVAL,true);
}
}
void WheatnetLio::ProcessLioevent(int chan,QString &cmd)
{
// printf("ProcessLioevent(%d,%s)\n",chan,(const char *)cmd);
QStringList f0=f0.split(":",cmd);
if((f0[0]=="LVL")&&(f0.size()==2)) {
if(chan<(int)lio_gpi_states.size()) {
bool state=f0[1]=="1";
if(state!=lio_gpi_states[chan]) {
lio_gpi_states[chan]=state;
emit gpiChanged(matrixNumber(),chan,state);
}
}
else {
syslog(LOG_WARNING,
"WheatNet device at %s:%d sent invalid LIOEVENT LVL update [%s]",
(const char *)lio_ip_address.toString(),
lio_ip_port,(const char *)cmd);
}
if((chan+1)==lio_gpios) {
lio_watchdog_timer->stop();
lio_watchdog_timer->start(1000,true);
}
}
}
void WheatnetLio::ProcessCommand(const QString &cmd)
{
// printf("ProcessCommand(%s)\n",(const char *)cmd);
bool ok=false;
if((cmd.left(1)=="<")&&(cmd.right(1)==">")) {
QStringList f0=f0.split("|",cmd.mid(1,cmd.length()-2));
if(f0.size()==2) {
QStringList f1=f1.split(":",f0[0]);
if(f1[0]=="SYS") {
ProcessSys(f0[1]);
}
if((f1[0]=="LIOEVENT")&&(f1.size()==2)) {
QStringList f2=f2.split(".",f1[1]);
if((f2[0]=="0")&&(f2.size()==2)) {
int chan=f2[1].toUInt(&ok);
if(ok) {
ProcessLioevent(chan,f0[1]);
}
}
}
}
}
}
void WheatnetLio::SendCommand(const QString &cmd)
{
lio_socket->writeBlock(cmd+"\r\n",cmd.length()+2);
}

82
ripcd/wheatnet_lio.h Normal file
View File

@ -0,0 +1,82 @@
// wheatnet_lio.h
//
// A Rivendell switcher driver for Wheatnet LIO devices
//
// (C) Copyright 2017 Fred Gleason <fredg@paravelsystems.com>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation.
//
// 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#ifndef WHEATNET_LIO_H
#define WHEATNET_LIO_H
#include <vector>
#include <qsignalmapper.h>
#include <qsocket.h>
#include <qtimer.h>
#include <rd.h>
#include <rdmatrix.h>
#include <rdmacro.h>
#include <switcher.h>
#define WHEATNET_LIO_POLL_INTERVAL 1000
#define WHEATNET_LIO_WATCHDOG_INTERVAL 5000
class WheatnetLio : public Switcher
{
Q_OBJECT
public:
WheatnetLio(RDMatrix *matrix,QObject *parent=0);
~WheatnetLio();
RDMatrix::Type type();
unsigned gpiQuantity();
unsigned gpoQuantity();
bool primaryTtyActive();
bool secondaryTtyActive();
void processCommand(RDMacro *cmd);
private slots:
void connectedData();
void readyReadData();
void errorData(int err);
void resetStateData(int line);
void pollData();
void watchdogData();
private:
void CheckLineEntry(int line);
void ProcessSys(const QString &cmd);
void ProcessLioevent(int chan,QString &cmd);
void ProcessCommand(const QString &cmd);
void SendCommand(const QString &cmd);
QSocket *lio_socket;
QTimer *lio_watchdog_timer;
bool lio_watchdog_active;
QHostAddress lio_ip_address;
uint16_t lio_ip_port;
int lio_card;
int lio_gpios;
QString lio_accum;
std::vector<bool> lio_gpi_states;
QSignalMapper *lio_reset_mapper;
std::vector<QTimer *> lio_reset_timers;
std::vector<bool> lio_reset_states;
QTimer *lio_poll_timer;
};
#endif // WHEATNET_LIO_H

374
ripcd/wheatnet_slio.cpp Normal file
View File

@ -0,0 +1,374 @@
// wheatnet_slio.cpp
//
// A Rivendell switcher driver for Modbus TCP
//
// (C) Copyright 2017 Fred Gleason <fredg@paravelsystems.com>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation.
//
// 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#include <syslog.h>
#include <rddb.h>
#include <rdescape_string.h>
#include "wheatnet_slio.h"
WheatnetSlio::WheatnetSlio(RDMatrix *matrix,QObject *parent)
: Switcher(matrix,parent)
{
slio_watchdog_active=false;
slio_gpios=0;
slio_ip_address=matrix->ipAddress(RDMatrix::Primary);
slio_ip_port=matrix->ipPort(RDMatrix::Primary);
slio_socket=new QSocket(this);
connect(slio_socket,SIGNAL(connected()),this,SLOT(connectedData()));
connect(slio_socket,SIGNAL(readyRead()),this,SLOT(readyReadData()));
connect(slio_socket,SIGNAL(error(int)),this,SLOT(errorData(int)));
slio_socket->connectToHost(slio_ip_address.toString(),slio_ip_port);
slio_poll_timer=new QTimer(this);
connect(slio_poll_timer,SIGNAL(timeout()),this,SLOT(pollData()));
slio_reset_mapper=new QSignalMapper(this);
connect(slio_reset_mapper,SIGNAL(mapped(int)),
this,SLOT(resetStateData(int)));
for(int i=0;i<slio_gpios;i++) {
slio_reset_timers.push_back(new QTimer(this));
connect(slio_reset_timers.back(),SIGNAL(timeout()),
slio_reset_mapper,SLOT(map()));
slio_reset_mapper->setMapping(slio_reset_timers.back(),i);
slio_reset_states.push_back(false);
}
slio_watchdog_timer=new QTimer(this);
connect(slio_watchdog_timer,SIGNAL(timeout()),this,SLOT(watchdogData()));
}
WheatnetSlio::~WheatnetSlio()
{
delete slio_watchdog_timer;
delete slio_poll_timer;
for(unsigned i=0;i<slio_reset_timers.size();i++) {
delete slio_reset_timers[i];
}
delete slio_reset_mapper;
delete slio_socket;
}
RDMatrix::Type WheatnetSlio::type()
{
return RDMatrix::WheatnetSlio;
}
unsigned WheatnetSlio::gpiQuantity()
{
return slio_gpios;
}
unsigned WheatnetSlio::gpoQuantity()
{
return slio_gpios;
}
bool WheatnetSlio::primaryTtyActive()
{
return false;
}
bool WheatnetSlio::secondaryTtyActive()
{
return false;
}
void WheatnetSlio::processCommand(RDMacro *cmd)
{
switch(cmd->command()) {
case RDMacro::GO:
if((cmd->argQuantity()!=5)||
((cmd->arg(1).toString().lower()!="i")&&
(cmd->arg(1).toString().lower()!="o"))||
(cmd->arg(2).toInt()<1)||(cmd->arg(3).toInt()>slio_gpios)||
(cmd->arg(2).toInt()>slio_gpios)||
((cmd->arg(3).toInt()!=1)&&(cmd->arg(3).toInt()!=0)&&
(cmd->arg(1).toString().lower()!="i"))||
((cmd->arg(3).toInt()!=1)&&(cmd->arg(3).toInt()!=0)&&
(cmd->arg(3).toInt()!=-1)&&(cmd->arg(1).toString().lower()=="i"))||
(cmd->arg(4).toInt()<0)) {
cmd->acknowledge(false);
emit rmlEcho(cmd);
return;
}
if(cmd->arg(3).toInt()==0) { // Turn OFF
if(cmd->arg(4).toInt()==0) {
if(cmd->arg(1).toString().lower()=="o") {
SendCommand(QString().sprintf("<SLIO:%d|LVL:0>",cmd->arg(2).toInt()));
emit gpoChanged(matrixNumber(),cmd->arg(2).toInt()-1,false);
}
}
else {
if(cmd->echoRequested()) {
cmd->acknowledge(false);
emit rmlEcho(cmd);
}
return;
}
}
else {
if(cmd->arg(4).toInt()==0) { // Turn ON
if(cmd->arg(1).toString().lower()=="o") {
SendCommand(QString().sprintf("<SLIO:%d|LVL:1>",cmd->arg(2).toInt()));
emit gpoChanged(matrixNumber(),cmd->arg(2).toInt()-1,true);
}
}
else { // Pulse
if(cmd->arg(1).toString().lower()=="o") {
SendCommand(QString().sprintf("<SLIO:%d|LVL:%d>",
cmd->arg(2).toInt(),
cmd->arg(3).toInt()!=0));
slio_reset_states[cmd->arg(2).toInt()-1]=cmd->arg(3).toInt()==0;
slio_reset_timers[cmd->arg(2).toInt()-1]->
start(cmd->arg(4).toInt(),true);
emit gpoChanged(matrixNumber(),cmd->arg(2).toInt()-1,
cmd->arg(3).toInt()!=0);
}
}
}
if(cmd->echoRequested()) {
cmd->acknowledge(true);
emit rmlEcho(cmd);
}
break;
default:
break;
}
}
void WheatnetSlio::connectedData()
{
syslog(LOG_INFO,
"connection to WheatNet SLIO device at %s:%u established",
(const char *)slio_ip_address.toString(),0xffff&slio_ip_port);
slio_watchdog_active=false;
SendCommand("<SYS?SLIO>");
}
void WheatnetSlio::readyReadData()
{
char data[1501];
int n=0;
while((n=slio_socket->readBlock(data,1500))>0) {
data[n]=0;
for(int i=0;i<n;i++) {
switch(0xff&data[i]) {
case 13:
break;
case 10:
ProcessCommand(slio_accum);
slio_accum="";
break;
default:
slio_accum+=data[i];
break;
}
}
}
}
void WheatnetSlio::errorData(int err)
{
watchdogData();
}
void WheatnetSlio::resetStateData(int line)
{
SendCommand(QString().sprintf("<SLIO:%d|LVL:%d>",line+1,
(int)slio_reset_states[line]));
emit gpoChanged(matrixNumber(),line,slio_reset_states[line]);
}
void WheatnetSlio::pollData()
{
SendCommand("<SYS?BLID>");
}
void WheatnetSlio::watchdogData()
{
if(!slio_watchdog_active) {
syslog(LOG_WARNING,
"connection to Wheatnet SLIO device at %s:%u lost, attempting reconnect",
(const char *)slio_ip_address.toString(),0xffff&slio_ip_port);
slio_watchdog_active=true;
}
slio_socket->close();
slio_socket->connectToHost(slio_ip_address.toString(),slio_ip_port);
}
void WheatnetSlio::CheckLineEntry(int line)
{
QString sql;
RDSqlQuery *q;
sql=QString("select ID from GPIS where ")+
"(STATION_NAME=\""+RDEscapeString(stationName())+"\")&&"+
QString().sprintf("(MATRIX=%d)&&",matrixNumber())+
QString().sprintf("(NUMBER=%d)",line);
q=new RDSqlQuery(sql);
if(!q->first()) {
delete q;
sql=QString("insert into GPIS set ")+
"STATION_NAME=\""+RDEscapeString(stationName())+"\","+
QString().sprintf("MATRIX=%d,",matrixNumber())+
QString().sprintf("NUMBER=%d",line);
q=new RDSqlQuery(sql);
}
delete q;
sql=QString("select ID from GPOS where ")+
"(STATION_NAME=\""+RDEscapeString(stationName())+"\")&&"+
QString().sprintf("(MATRIX=%d)&&",matrixNumber())+
QString().sprintf("(NUMBER=%d)",line);
q=new RDSqlQuery(sql);
if(!q->first()) {
delete q;
sql=QString("insert into GPOS set ")+
"STATION_NAME=\""+RDEscapeString(stationName())+"\","+
QString().sprintf("MATRIX=%d,",matrixNumber())+
QString().sprintf("NUMBER=%d",line);
q=new RDSqlQuery(sql);
}
delete q;
}
void WheatnetSlio::ProcessSys(const QString &cmd)
{
// printf("SYS: %s\n",(const char *)cmd);
QString sql;
RDSqlQuery *q;
bool ok=false;
QStringList f0=f0.split(":",cmd);
if((f0[0]=="SLIO")&&(f0.size()==2)) {
int slio=f0[1].toUInt(&ok);
if(ok) {
slio_gpios=slio;
for(unsigned i=0;i<slio_reset_timers.size();i++) {
delete slio_reset_timers[i];
}
slio_reset_timers.clear();
slio_reset_states.clear();
slio_gpi_states.clear();
for(int i=0;i<slio_gpios;i++) {
slio_reset_timers.push_back(new QTimer(this));
connect(slio_reset_timers.back(),SIGNAL(timeout()),
slio_reset_mapper,SLOT(map()));
slio_reset_mapper->setMapping(slio_reset_timers.back(),i);
slio_reset_states.push_back(false);
slio_gpi_states.push_back(false);
CheckLineEntry(i+1);
SendCommand(QString().sprintf("<SLIOSUB:%d|LVL:1>",i+1));
}
sql=QString("update MATRICES set ")+
QString().sprintf("GPIS=%d,GPOS=%d where ",slio_gpios,slio_gpios)+
"(STATION_NAME=\""+RDEscapeString(stationName())+"\")&&"+
QString().sprintf("(MATRIX=%d)",matrixNumber());
q=new RDSqlQuery(sql);
delete q;
slio_watchdog_timer->start(WHEATNET_SLIO_WATCHDOG_INTERVAL,true);
slio_poll_timer->start(WHEATNET_SLIO_POLL_INTERVAL,true);
}
}
if((f0[0]=="BLID")&&(f0.size()==2)) {
slio_watchdog_timer->stop();
slio_watchdog_timer->start(WHEATNET_SLIO_WATCHDOG_INTERVAL,true);
slio_poll_timer->start(WHEATNET_SLIO_POLL_INTERVAL,true);
}
}
void WheatnetSlio::ProcessSlioevent(int chan,QString &cmd)
{
// printf("ProcessSlip(%d,%s)\n",chan,(const char *)cmd);
QStringList f0=f0.split(":",cmd);
if((f0[0]=="LVL")&&(f0.size()==2)) {
if(chan<=(int)slio_gpi_states.size()) {
bool state=f0[1]=="1";
if(state!=slio_gpi_states[chan-1]) {
slio_gpi_states[chan-1]=state;
emit gpiChanged(matrixNumber(),chan-1,state);
}
}
else {
syslog(LOG_WARNING,
"WheatNet device at %s:%d sent invalid SLIOEVENT LVL update [%s]",
(const char *)slio_ip_address.toString(),
slio_ip_port,(const char *)cmd);
}
if(chan==slio_gpios) {
slio_poll_timer->start(50,true);
slio_watchdog_timer->stop();
slio_watchdog_timer->start(1000,true);
}
}
}
void WheatnetSlio::ProcessCommand(const QString &cmd)
{
// printf("ProcessCommand(%s)\n",(const char *)cmd);
bool ok=false;
if((cmd.left(1)=="<")&&(cmd.right(1)==">")) {
QStringList f0=f0.split("|",cmd.mid(1,cmd.length()-2));
if(f0.size()==2) {
QStringList f1=f1.split(":",f0[0]);
if(f1[0]=="SYS") {
ProcessSys(f0[1]);
}
if((f1[0]=="SLIOEVENT")&&(f1.size()==2)) {
int chan=f1[1].toUInt(&ok);
if(ok) {
ProcessSlioevent(chan,f0[1]);
}
}
}
}
}
void WheatnetSlio::SendCommand(const QString &cmd)
{
slio_socket->writeBlock(cmd+"\r\n",cmd.length()+2);
}

81
ripcd/wheatnet_slio.h Normal file
View File

@ -0,0 +1,81 @@
// wheatnet_slio.h
//
// A Rivendell switcher driver for Wheatnet SLIO devices
//
// (C) Copyright 2017 Fred Gleason <fredg@paravelsystems.com>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation.
//
// 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#ifndef WHEATNET_SLIO_H
#define WHEATNET_SLIO_H
#include <vector>
#include <qsignalmapper.h>
#include <qsocket.h>
#include <qtimer.h>
#include <rd.h>
#include <rdmatrix.h>
#include <rdmacro.h>
#include <switcher.h>
#define WHEATNET_SLIO_POLL_INTERVAL 1000
#define WHEATNET_SLIO_WATCHDOG_INTERVAL 5000
class WheatnetSlio : public Switcher
{
Q_OBJECT
public:
WheatnetSlio(RDMatrix *matrix,QObject *parent=0);
~WheatnetSlio();
RDMatrix::Type type();
unsigned gpiQuantity();
unsigned gpoQuantity();
bool primaryTtyActive();
bool secondaryTtyActive();
void processCommand(RDMacro *cmd);
private slots:
void connectedData();
void readyReadData();
void errorData(int err);
void resetStateData(int line);
void pollData();
void watchdogData();
private:
void CheckLineEntry(int line);
void ProcessSys(const QString &cmd);
void ProcessSlioevent(int chan,QString &cmd);
void ProcessCommand(const QString &cmd);
void SendCommand(const QString &cmd);
QSocket *slio_socket;
QTimer *slio_watchdog_timer;
bool slio_watchdog_active;
QHostAddress slio_ip_address;
uint16_t slio_ip_port;
int slio_gpios;
QString slio_accum;
std::vector<bool> slio_gpi_states;
QSignalMapper *slio_reset_mapper;
std::vector<QTimer *> slio_reset_timers;
std::vector<bool> slio_reset_states;
QTimer *slio_poll_timer;
};
#endif // WHEATNET_SLIO_H