// catch_connect.cpp // // Connect to the Rivendell Netcatcher Daemon. // // (C) Copyright 2002-2004,2016-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 <ctype.h> #include <qobject.h> #include <rdcatch_connect.h> RDCatchConnect::RDCatchConnect(int serial,QObject *parent) : QObject(parent) { cc_serial=serial; cc_connected=false; argnum=0; argptr=0; for(int i=0;i<MAX_DECKS;i++) { cc_monitor_state[i]=false; } // // TCP Connection // cc_socket=new Q3Socket(this,"cc_socket"); connect(cc_socket,SIGNAL(connected()),this,SLOT(connectedData())); connect(cc_socket,SIGNAL(readyRead()),this,SLOT(readyData())); // // Start the heartbeat timer // cc_heartbeat_timer=new QTimer(this,"cc_heartbeat_timer"); connect(cc_heartbeat_timer,SIGNAL(timeout()), this,SLOT(heartbeatTimeoutData())); cc_heartbeat_timer->start(CC_HEARTBEAT_INTERVAL,true); cc_heartbeat_valid=true; } RDCatchConnect::~RDCatchConnect() { // printf("Destroying RDCatchConnect\n"); } void RDCatchConnect::connectHost(QString hostname,Q_UINT16 hostport, QString password) { cc_password=password; cc_socket->connectToHost(hostname,hostport); } RDDeck::Status RDCatchConnect::status(unsigned chan) const { if(chan<=MAX_DECKS) { return cc_record_deck_status[chan-1]; } return cc_play_deck_status[chan-128]; } int RDCatchConnect::currentId(unsigned chan) const { if(chan<=MAX_DECKS) { return cc_record_id[chan-1]; } return cc_play_id[chan-129]; } void RDCatchConnect::enableMetering(bool state) { SendCommand(QString().sprintf("RM %d!",state)); } void RDCatchConnect::reloadHeartbeat() { SendCommand("RH!"); } void RDCatchConnect::reloadDropboxes() { SendCommand("RX!"); } void RDCatchConnect::addEvent(int id) { SendCommand(QString().sprintf("RA %d!",id)); } void RDCatchConnect::removeEvent(int id) { SendCommand(QString().sprintf("RR %d!",id)); } void RDCatchConnect::updateEvent(int id) { SendCommand(QString().sprintf("RU %d!",id)); } void RDCatchConnect::reset() { SendCommand("RS!"); } void RDCatchConnect::reload() { SendCommand("RD!"); } void RDCatchConnect::refresh() { SendCommand("RE 0!"); } void RDCatchConnect::reloadOffset() { SendCommand("RO!"); } void RDCatchConnect::stop(int deck) { SendCommand(QString().sprintf("SR %d!",deck)); } void RDCatchConnect::monitor(int deck,bool state) { SendCommand(QString().sprintf("MN %d %d!",deck,state)); } void RDCatchConnect::toggleMonitor(int deck) { if(cc_monitor_state[deck-1]) { SendCommand(QString().sprintf("MN %d 0!",deck)); } else { SendCommand(QString().sprintf("MN %d 1!",deck)); } } void RDCatchConnect::setExitCode(int id,RDRecording::ExitCode code, const QString &msg) { SendCommand(QString().sprintf("SC %d %d %s!",id,code, (const char *)msg.simplifyWhiteSpace())); } void RDCatchConnect::connectedData() { SendCommand(QString().sprintf("PW %s!",(const char *)cc_password)); } void RDCatchConnect::readyData() { char buf[1024]; int c; while((c=cc_socket->readBlock(buf,254))>0) { buf[c]=0; // printf("readyData: %s\n",buf); for(int i=0;i<c;i++) { if(buf[i]==' ') { if(argnum<CC_MAX_ARGS) { args[argnum][argptr]=0; argnum++; argptr=0; } else { if(debug) { printf("Argument list truncated!\n"); } } } if(buf[i]=='!') { args[argnum++][argptr]=0; DispatchCommand(); argnum=0; argptr=0; if(cc_socket==NULL) { return; } } if((isgraph(buf[i]))&&(buf[i]!='!')) { if(argptr<CC_MAX_LENGTH) { args[argnum][argptr]=buf[i]; argptr++; } else { if(debug) { printf("WARNING: argument truncated!\n"); } } } } } } void RDCatchConnect::heartbeatTimeoutData() { if(cc_heartbeat_valid) { emit heartbeatFailed(cc_serial); cc_heartbeat_valid=false; } } void RDCatchConnect::SendCommand(QString cmd) { // printf("SendCommand(%s)\n",(const char *)cmd); cc_socket->writeBlock((const char *)cmd,cmd.length()); } void RDCatchConnect::DispatchCommand() { int deck; int channel; int level; unsigned chan; int status; int id; int number; if(!strcmp(args[0],"PW")) { // Password Response if(args[1][0]=='+') { emit connected(cc_serial,true); SendCommand("RE 0!"); } else { emit connected(cc_serial,false); } } if(!strcmp(args[0],"DE")) { // Deck Event if(sscanf(args[1],"%d",&deck)!=1) { return; } if(sscanf(args[2],"%d",&number)!=1) { return; } emit deckEventSent(cc_serial,deck,number); } if(!strcmp(args[0],"RE")) { // Channel Status if(sscanf(args[1],"%u",&chan)!=1){ return; } if((chan<0)||((chan>(MAX_DECKS+1))&&(chan<(129)))|| (chan>(MAX_DECKS+129))) { return; } if(sscanf(args[2],"%d",&status)!=1) { return; } if(sscanf(args[3],"%d",&id)!=1) { return; } if(chan==0) { emit statusChanged(cc_serial,chan,(RDDeck::Status)status,id,""); return; } chan--; if(chan<=MAX_DECKS) { if((status!=cc_record_deck_status[chan])||(id!=cc_record_id[chan])) { cc_record_deck_status[chan]=(RDDeck::Status)status; cc_record_id[chan]=id; emit statusChanged(cc_serial,chan+1,cc_record_deck_status[chan], cc_record_id[chan],args[4]); } } if((chan>=128)&&(chan<MAX_DECKS+128)) { if((status!=cc_play_deck_status[chan-128])||(id!=cc_play_id[chan-128])) { cc_play_deck_status[chan-128]=(RDDeck::Status)status; cc_play_id[chan-128]=id; emit statusChanged(cc_serial,chan+1,cc_play_deck_status[chan-128], cc_play_id[chan-128],args[4]); } } return; } if(!strcmp(args[0],"RM")) { // Meter Level if(sscanf(args[1],"%d",&deck)!=1) { return; } if(sscanf(args[2],"%d",&channel)!=1) { return; } if(sscanf(args[3],"%d",&level)!=1) { return; } emit meterLevel(cc_serial,deck,channel,level); return; } if(!strcmp(args[0],"RU")) { // Update Event if(sscanf(args[1],"%d",&id)!=1) { return; } emit eventUpdated(id); } if(!strcmp(args[0],"PE")) { // Purge Event if(sscanf(args[1],"%d",&id)!=1) { return; } emit eventPurged(id); } if(!strcmp(args[0],"HB")) { // Heartbeat cc_heartbeat_timer->stop(); cc_heartbeat_timer->start(CC_HEARTBEAT_INTERVAL,true); } if(!strcmp(args[0],"MN")) { // Monitor State if(sscanf(args[1],"%d",&deck)!=1) { return; } if(args[2][0]=='1') { cc_monitor_state[deck-1]=true; emit monitorChanged(cc_serial,deck,true); } else { cc_monitor_state[deck-1]=false; emit monitorChanged(cc_serial,deck,false); } } }