mirror of
				https://github.com/ElvishArtisan/rivendell.git
				synced 2025-10-31 22:24:02 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			645 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			645 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // sasusi.cpp
 | |
| //
 | |
| // A Rivendell switcher driver for the SAS USI Protocol
 | |
| //
 | |
| //   (C) Copyright 2002-2019 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 <stdlib.h>
 | |
| #include <syslog.h>
 | |
| 
 | |
| #include <rdapplication.h>
 | |
| #include <rddb.h>
 | |
| #include <rdescape_string.h>
 | |
| 
 | |
| #include "globals.h"
 | |
| #include "sasusi.h"
 | |
| 
 | |
| SasUsi::SasUsi(RDMatrix *matrix,QObject *parent)
 | |
|   : Switcher(matrix,parent)
 | |
| {
 | |
|   QString sql;
 | |
|   RDSqlQuery *q;
 | |
| 
 | |
|   RDTty *tty;
 | |
|   sas_matrix=matrix->matrix();
 | |
|   sas_ptr=0;
 | |
| 
 | |
|   //
 | |
|   // Get Matrix Parameters
 | |
|   //
 | |
|   sas_porttype=matrix->portType(RDMatrix::Primary);
 | |
|   sas_ipaddress=matrix->ipAddress(RDMatrix::Primary);
 | |
|   sas_ipport=matrix->ipPort(RDMatrix::Primary);
 | |
|   sas_inputs=matrix->inputs();
 | |
|   sas_outputs=matrix->outputs();
 | |
|   sas_gpis=matrix->gpis();
 | |
|   sas_gpos=matrix->gpos();
 | |
|   sas_start_cart=matrix->startCart(RDMatrix::Primary);
 | |
|   sas_stop_cart=matrix->stopCart(RDMatrix::Primary);
 | |
| 
 | |
|   //
 | |
|   // Load Switch Table
 | |
|   //
 | |
|   sql=QString("select ")+
 | |
|     "ENGINE_NUM,"+  // 00
 | |
|     "DEVICE_NUM,"+  // 01
 | |
|     "RELAY_NUM "+   // 02
 | |
|     "from VGUEST_RESOURCES where "+
 | |
|     "(STATION_NAME=\""+RDEscapeString(rda->config()->stationName())+"\")&&"+
 | |
|     QString().sprintf("(MATRIX_NUM=%d) ",matrix->matrix())+
 | |
|     "order by NUMBER";
 | |
|   q=new RDSqlQuery(sql);
 | |
|   while(q->next()) {
 | |
|     sas_console_numbers.push_back(q->value(0).toInt());
 | |
|     sas_source_numbers.push_back(q->value(1).toInt());
 | |
|     sas_relay_numbers.push_back(q->value(2).toInt());
 | |
|   }
 | |
|   delete q;
 | |
| 
 | |
|   //
 | |
|   // Reconnection Timer
 | |
|   //
 | |
|   sas_reconnect_timer=new QTimer(this);
 | |
|   connect(sas_reconnect_timer,SIGNAL(timeout()),this,SLOT(ipConnect()));
 | |
| 
 | |
|   //
 | |
|   // Initialize the connection
 | |
|   //
 | |
|   switch(sas_porttype) {
 | |
|   case RDMatrix::TtyPort:
 | |
|     tty=new RDTty(rda->station()->name(),matrix->port(RDMatrix::Primary));
 | |
|     sas_device=new RDTTYDevice();
 | |
|     if(tty->active()) {
 | |
|       sas_device->setName(tty->port());
 | |
|       sas_device->setSpeed(tty->baudRate());
 | |
|       sas_device->setWordLength(tty->dataBits());
 | |
|       sas_device->setParity(tty->parity());
 | |
|       sas_device->open(QIODevice::Unbuffered|QIODevice::ReadWrite);
 | |
|     }
 | |
|     delete tty;
 | |
| 
 | |
|   case RDMatrix::TcpPort:
 | |
|     sas_socket=new Q3Socket(this);
 | |
|     connect(sas_socket,SIGNAL(connected()),this,SLOT(connectedData()));
 | |
|     connect(sas_socket,SIGNAL(connectionClosed()),
 | |
| 	    this,SLOT(connectionClosedData()));
 | |
|     connect(sas_socket,SIGNAL(readyRead()),
 | |
| 	    this,SLOT(readyReadData()));
 | |
|     connect(sas_socket,SIGNAL(error(int)),this,SLOT(errorData(int)));
 | |
|     ipConnect();
 | |
|     break;
 | |
| 
 | |
|   case RDMatrix::NoPort:
 | |
|     break;
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| RDMatrix::Type SasUsi::type()
 | |
| {
 | |
|   return RDMatrix::SasUsi;
 | |
| }
 | |
| 
 | |
| 
 | |
| unsigned SasUsi::gpiQuantity()
 | |
| {
 | |
|   return sas_gpis;
 | |
| }
 | |
| 
 | |
| 
 | |
| unsigned SasUsi::gpoQuantity()
 | |
| {
 | |
|   return sas_gpos;
 | |
| }
 | |
| 
 | |
| 
 | |
| bool SasUsi::primaryTtyActive()
 | |
| {
 | |
|   return sas_porttype==RDMatrix::TtyPort;
 | |
| }
 | |
| 
 | |
| 
 | |
| bool SasUsi::secondaryTtyActive()
 | |
| {
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| 
 | |
| void SasUsi::processCommand(RDMacro *cmd)
 | |
| {
 | |
|   char str[256];
 | |
|   char cmd_byte;
 | |
|   QString label;
 | |
| 
 | |
|   switch(cmd->command()) {
 | |
|       case RDMacro::CL:
 | |
| 	if((cmd->arg(1).toInt()<1)||
 | |
| 	   ((cmd->arg(1).toInt()>256)&&(cmd->arg(1).toInt()!=999))||
 | |
| 	   (cmd->arg(2).toInt()<1)||(cmd->arg(2).toInt()>sas_inputs)) {
 | |
| 	  cmd->acknowledge(false);
 | |
| 	  emit rmlEcho(cmd);
 | |
| 	  return;
 | |
| 	}
 | |
| 	for(int i=3;i<(cmd->argQuantity()-1);i++) {
 | |
| 	  label+=(cmd->arg(i)+" ");
 | |
| 	}
 | |
| 	label+=cmd->arg(cmd->argQuantity()-1);
 | |
| 	if(label.length()>8) {
 | |
| 	  label=label.left(8);
 | |
| 	}
 | |
| 	for(int i=label.length();i<8;i++) {
 | |
| 	  label+=" ";
 | |
| 	}
 | |
| 	snprintf(str,256,"%c21%03d%04d%s\x0D\x0A",26,
 | |
| 		cmd->arg(1).toInt(),cmd->arg(2).toInt(),(const char *)label);
 | |
| 	SendCommand(str);
 | |
| 	cmd->acknowledge(true);
 | |
| 	emit rmlEcho(cmd);
 | |
| 	break;
 | |
| 
 | |
|       case RDMacro::FS:
 | |
| 	if((cmd->arg(1).toInt()<1)||(cmd->arg(1).toInt()>256)||
 | |
| 	   (sas_porttype!=RDMatrix::TcpPort)) {
 | |
| 	  cmd->acknowledge(false);
 | |
| 	  emit rmlEcho(cmd);
 | |
| 	  return;
 | |
| 	}
 | |
| 	snprintf(str,256,"%c1%03d\x0D\x0A",0x13,cmd->arg(1).toInt());
 | |
| 	SendCommand(str);
 | |
| 	cmd->acknowledge(true);
 | |
| 	emit rmlEcho(cmd);
 | |
| 	break;
 | |
| 
 | |
|       case RDMacro::SG:
 | |
| 	if((cmd->arg(1).toInt()<1)||(cmd->arg(1).toInt()>sas_inputs)||
 | |
| 	   (cmd->arg(2).toInt()<1)||(cmd->arg(2).toInt()>sas_outputs)||
 | |
| 	   (cmd->arg(3).toInt()<-1024)||(cmd->arg(3).toInt()>1024)) {
 | |
| 	  cmd->acknowledge(false);
 | |
| 	  emit rmlEcho(cmd);
 | |
| 	  return;
 | |
| 	}
 | |
| 	snprintf(str,256,"%c00%04d%04d%04d00548\x0D\x0A",26,
 | |
| 		cmd->arg(1).toInt(),cmd->arg(2).toInt(),
 | |
| 		cmd->arg(3).toInt()+1024);
 | |
| 	SendCommand(str);
 | |
| 	cmd->acknowledge(true);
 | |
| 	emit rmlEcho(cmd);
 | |
| 	break;
 | |
| 
 | |
|       case RDMacro::SX:
 | |
| 	if((cmd->arg(1).toInt()<1)||(cmd->arg(1).toInt()>sas_inputs)||
 | |
| 	   (cmd->arg(2).toInt()<1)||(cmd->arg(2).toInt()>sas_outputs)||
 | |
| 	   (cmd->arg(3).toInt()<-1024)||(cmd->arg(3).toInt()>1024)) {
 | |
| 	  cmd->acknowledge(false);
 | |
| 	  emit rmlEcho(cmd);
 | |
| 	  return;
 | |
| 	}
 | |
| 	snprintf(str,256,"%c10%04d%04d%04d0010\x0D\x0A",26,
 | |
| 		cmd->arg(1).toInt(),cmd->arg(2).toInt(),
 | |
| 		cmd->arg(3).toInt()+1024);
 | |
| 	SendCommand(str);
 | |
| 	cmd->acknowledge(true);
 | |
| 	emit rmlEcho(cmd);
 | |
| 	break;
 | |
| 
 | |
|       case RDMacro::SL:
 | |
| 	if((cmd->arg(1).toInt()<1)||(cmd->arg(1).toInt()>sas_inputs)||
 | |
| 	   (cmd->arg(2).toInt()<-1024)||(cmd->arg(2).toInt()>1024)) {
 | |
| 	  cmd->acknowledge(false);
 | |
| 	  emit rmlEcho(cmd);
 | |
| 	  return;
 | |
| 	}
 | |
| 	snprintf(str,256,"%c10%04d0000%04d0001\x0D\x0A",26,
 | |
| 		cmd->arg(1).toInt(),cmd->arg(2).toInt()+1024);
 | |
| 	SendCommand(str);
 | |
| 	cmd->acknowledge(true);
 | |
| 	emit rmlEcho(cmd);
 | |
| 	break;
 | |
| 
 | |
|       case RDMacro::SA:
 | |
| 	if((cmd->arg(1).toInt()<1)||(cmd->arg(1).toInt()>sas_inputs)||
 | |
| 	   (cmd->arg(2).toInt()<1)||(cmd->arg(2).toInt()>sas_outputs)) {
 | |
| 	  cmd->acknowledge(false);
 | |
| 	  emit rmlEcho(cmd);
 | |
| 	  return;
 | |
| 	}
 | |
| 	snprintf(str,256,"%c00%04d%04d102400036\x0D\x0A",26,
 | |
| 		cmd->arg(1).toInt(),cmd->arg(2).toInt());
 | |
| 	SendCommand(str);
 | |
| 	cmd->acknowledge(true);
 | |
| 	emit rmlEcho(cmd);
 | |
| 	break;
 | |
| 
 | |
|       case RDMacro::SR:
 | |
| 	if((cmd->arg(1).toInt()<1)||(cmd->arg(1).toInt()>sas_inputs)||
 | |
| 	   (cmd->arg(2).toInt()<1)||(cmd->arg(2).toInt()>sas_outputs)) {
 | |
| 	  cmd->acknowledge(false);
 | |
| 	  emit rmlEcho(cmd);
 | |
| 	  return;
 | |
| 	}
 | |
| 	snprintf(str,256,"%c00%04d%04d102400032\x0D\x0A",26,
 | |
| 		cmd->arg(1).toInt(),cmd->arg(2).toInt());
 | |
| 	SendCommand(str);
 | |
| 	cmd->acknowledge(true);
 | |
| 	emit rmlEcho(cmd);
 | |
| 	break;
 | |
| 
 | |
|       case RDMacro::ST:
 | |
| 	if((cmd->arg(1).toInt()<0)||(cmd->arg(1).toInt()>sas_inputs)||
 | |
| 	   (cmd->arg(2).toInt()<1)||(cmd->arg(2).toInt()>sas_outputs)) {
 | |
| 	  cmd->acknowledge(false);
 | |
| 	  emit rmlEcho(cmd);
 | |
| 	  return;
 | |
| 	}
 | |
| 	snprintf(str,256,"%cT%04d%04d\x0D\x0A",5,
 | |
| 		cmd->arg(1).toInt(),cmd->arg(2).toInt());
 | |
| 	SendCommand(str);
 | |
| 	cmd->acknowledge(true);
 | |
| 	emit rmlEcho(cmd);
 | |
| 	break;
 | |
| 
 | |
|       case RDMacro::GO:
 | |
| 	if((cmd->arg(1).lower()!="o")||
 | |
| 	   (cmd->arg(2).toInt()<1)||(cmd->arg(2).toInt()>sas_gpos)) {
 | |
| 	  cmd->acknowledge(false);
 | |
| 	  emit rmlEcho(cmd);
 | |
| 	  return;
 | |
| 	}
 | |
| 	if(cmd->arg(4).toInt()==0) {   // Latch
 | |
| 	  if(cmd->arg(3).toInt()==0) {   // Off
 | |
| 	    cmd_byte=0x03;
 | |
| 	  }
 | |
| 	  else {
 | |
| 	    cmd_byte=0x02;
 | |
| 	  }
 | |
| 	}
 | |
| 	else {
 | |
| 	  if(cmd->arg(3).toInt()==0) {
 | |
| 	    cmd->acknowledge(false);
 | |
| 	    emit rmlEcho(cmd);
 | |
| 	    return;
 | |
| 	  }
 | |
| 	  cmd_byte=0x01;
 | |
| 	}
 | |
| 	if(cmd->arg(2).toUInt()<=sas_relay_numbers.size()) {
 | |
| 	  if(sas_relay_numbers[cmd->arg(2).toUInt()-1]>=0) {
 | |
| 	    snprintf(str,256,"\x05R%d%04d\x0D\x0A",cmd_byte,
 | |
| 		    sas_relay_numbers[cmd->arg(2).toUInt()-1]);
 | |
| 	    rda->syslog(LOG_DEBUG,"USI: %s",
 | |
| 			(const char *)PrettifyCommand(str));
 | |
| 	    SendCommand(str);
 | |
| 	    cmd->acknowledge(true);
 | |
| 	    emit rmlEcho(cmd);
 | |
| 	  }
 | |
| 	  else {
 | |
| 	    if((sas_console_numbers[cmd->arg(2).toUInt()-1]>=0)&&
 | |
| 	       (sas_source_numbers[cmd->arg(2).toUInt()-1]>=0)) {
 | |
| 	      if(cmd->arg(3).toInt()==0) {   // Off
 | |
| 		cmd_byte=0;
 | |
| 	      }
 | |
| 	      else {
 | |
| 		cmd_byte=1;
 | |
| 	      }
 | |
| 	      snprintf(str,256,"\x1A%s%d%03d%04d\x0D\x0A","20",cmd_byte,
 | |
| 		      sas_console_numbers[cmd->arg(2).toUInt()-1],
 | |
| 		      sas_source_numbers[cmd->arg(2).toUInt()-1]);
 | |
| 	      SendCommand(str);
 | |
| 	      cmd->acknowledge(true);
 | |
| 	      emit rmlEcho(cmd);
 | |
| 	    }
 | |
| 	  }
 | |
| 	}
 | |
| 	break;
 | |
| 
 | |
|       default:
 | |
| 	cmd->acknowledge(false);
 | |
| 	emit rmlEcho(cmd);
 | |
| 	break;
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| void SasUsi::ipConnect()
 | |
| {
 | |
|   sas_socket->connectToHost(sas_ipaddress.toString(),sas_ipport);
 | |
| }
 | |
| 
 | |
| 
 | |
| void SasUsi::connectedData()
 | |
| {
 | |
|   rda->syslog(LOG_INFO,
 | |
| 	      "connection to SasUsi device at %s:%d established",
 | |
| 	      (const char *)sas_ipaddress.toString().toUtf8(),
 | |
| 	 sas_ipport);
 | |
|   if(sas_start_cart>0) {
 | |
|     ExecuteMacroCart(sas_start_cart);
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| void SasUsi::connectionClosedData()
 | |
| {
 | |
|   rda->syslog(LOG_WARNING,
 | |
| 	      "connection to SasUsi device at %s:%d closed unexpectedly, attempting reconnect",
 | |
| 	      (const char *)sas_ipaddress.toString().toUtf8(),
 | |
| 	 sas_ipport);
 | |
|   if(sas_stop_cart>0) {
 | |
|     ExecuteMacroCart(sas_stop_cart);
 | |
|   }
 | |
|   sas_reconnect_timer->start(SASUSI_RECONNECT_INTERVAL,true);
 | |
| }
 | |
| 
 | |
| 
 | |
| void SasUsi::readyReadData()
 | |
| {
 | |
|   char buffer[256];
 | |
|   unsigned n;
 | |
| 
 | |
|   while((n=sas_socket->readBlock(buffer,255))>0) {
 | |
|     buffer[n]=0;
 | |
|     for(unsigned i=0;i<n;i++) {
 | |
|       if(buffer[i]==10) {  // End of line
 | |
| 	sas_buffer[--sas_ptr]=0;
 | |
| 	DispatchCommand();
 | |
| 	sas_ptr=0;
 | |
|       }
 | |
|       else {
 | |
| 	if(sas_ptr==SASUSI_MAX_LENGTH) {  // Buffer overflow
 | |
| 	  sas_ptr=0;
 | |
| 	}
 | |
| 	sas_buffer[sas_ptr++]=buffer[i];
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| void SasUsi::errorData(int err)
 | |
| {
 | |
|   switch((Q3Socket::Error)err) {
 | |
|       case Q3Socket::ErrConnectionRefused:
 | |
| 	rda->syslog(LOG_WARNING,
 | |
| 	  "connection to SasUsi device at %s:%d refused, attempting reconnect",
 | |
| 		    (const char *)sas_ipaddress.toString().toUtf8(),
 | |
| 	  sas_ipport);
 | |
| 	sas_reconnect_timer->start(SASUSI_RECONNECT_INTERVAL,true);
 | |
| 	break;
 | |
| 
 | |
|       case Q3Socket::ErrHostNotFound:
 | |
| 	rda->syslog(LOG_WARNING,
 | |
| 	       "error on connection to SasUsi device at %s:%d: Host Not Found",
 | |
| 		    (const char *)sas_ipaddress.toString().toUtf8(),
 | |
| 		    sas_ipport);
 | |
| 	break;
 | |
| 
 | |
|       case Q3Socket::ErrSocketRead:
 | |
| 	rda->syslog(LOG_WARNING,
 | |
| 	     "error on connection to SasUsi device at %s:%d: Socket Read Error",
 | |
| 		    (const char *)sas_ipaddress.toString().toUtf8(),
 | |
| 		    sas_ipport);
 | |
| 	break;
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| void SasUsi::SendCommand(char *str)
 | |
| {
 | |
|   rda->syslog(LOG_INFO,"sending USI cmd: %s",
 | |
| 	      (const char *)PrettifyCommand(str));
 | |
|   switch(sas_porttype) {
 | |
|   case RDMatrix::TtyPort:
 | |
|     sas_device->write(str,strlen(str));
 | |
|     break;
 | |
| 
 | |
|   case RDMatrix::TcpPort:
 | |
|     sas_socket->writeBlock(str,strlen(str));
 | |
|     break;
 | |
| 
 | |
|   case RDMatrix::NoPort:
 | |
|     break;
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| void SasUsi::DispatchCommand()
 | |
| {
 | |
|   char buffer[SASUSI_MAX_LENGTH];
 | |
|   unsigned input;
 | |
|   unsigned output;
 | |
|   int line;
 | |
|   unsigned action;
 | |
|   int console;
 | |
|   int source;
 | |
|   bool state;
 | |
|   bool ok=false;
 | |
|   QString cmd;
 | |
|   QString label;
 | |
|   QString sql;
 | |
|   RDSqlQuery *q;
 | |
| 
 | |
|   //LogLine(RDConfig::LogNotice,QString().sprintf("DISPATCHED: %s",(const char *)sas_buffer));
 | |
| 
 | |
|   //
 | |
|   // Startup Sequence.  Get the input and output lists.  The response
 | |
|   // to the ^EI command lets us know when the lists are done.
 | |
|   //
 | |
|   if(QString("login sucessful")==(QString(sas_buffer).lower())) {
 | |
|     sprintf(buffer,"%cX9999\x0D\x0A",5);  // Request Input List
 | |
|     SendCommand(buffer);
 | |
|     sprintf(buffer,"%cY9999\x0D\x0A",5);  // Request Output List
 | |
|     SendCommand(buffer);
 | |
|     sprintf(buffer,"%cI0001\x0D\x0A",5);  // Start Finished
 | |
|     SendCommand(buffer);
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Work around the idiotic 'SAS READY' prompt
 | |
|   //
 | |
|   if(sas_buffer[0]==27) {
 | |
|     for(unsigned i=17;i<strlen(sas_buffer)+1;i++) {
 | |
|       sas_buffer[i-17]=sas_buffer[i];
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   rda->syslog(LOG_INFO,"received USI cmd: %s",
 | |
| 	      (const char *)PrettifyCommand(sas_buffer));
 | |
| 
 | |
| 
 | |
|   //
 | |
|   // Process Commands
 | |
|   //
 | |
|   switch(sas_buffer[0]) {
 | |
|   case 21:   // Input Name [^U]
 | |
|     if(strlen(sas_buffer)<13) {
 | |
|       return;
 | |
|     }
 | |
|     label=sas_buffer+5;
 | |
|     sas_buffer[5]=0;
 | |
|     if(sscanf(sas_buffer+1,"%u",&input)!=1) {
 | |
|       return;
 | |
|     }
 | |
|     sql=QString("select NUMBER from INPUTS where ")+
 | |
|       "(STATION_NAME=\""+RDEscapeString(rda->station()->name())+"\")&&"+
 | |
|       QString().sprintf("(MATRIX=%d)&&",sas_matrix)+
 | |
|       QString().sprintf("(NUMBER=%d)",input);
 | |
|     q=new RDSqlQuery(sql);
 | |
|     if(q->first()) {
 | |
|       sql=QString("update INPUTS set ")+
 | |
| 	"NAME=\""+RDEscapeString(label)+"\" where "+
 | |
| 	"(STATION_NAME=\""+RDEscapeString(rda->station()->name())+"\")&&"+
 | |
| 	QString().sprintf("(MATRIX=%d)&&",sas_matrix)+
 | |
| 	QString().sprintf("(NUMBER=%d)",input);
 | |
|     }
 | |
|     else {
 | |
|       sql=QString("insert into INPUTS set ")+
 | |
| 	"NAME=\""+RDEscapeString(label)+"\","+
 | |
| 	"STATION_NAME=\""+RDEscapeString(rda->station()->name())+"\","+
 | |
| 	QString().sprintf("MATRIX=%d,",sas_matrix)+
 | |
| 	QString().sprintf("NUMBER=%d",input);
 | |
|     }
 | |
|     delete q;
 | |
|     q=new RDSqlQuery(sql);
 | |
|     delete q;
 | |
|     break;
 | |
| 
 | |
|   case 22:   // Output Name [^V]
 | |
|     if(strlen(sas_buffer)<13) {
 | |
|       return;
 | |
|     }
 | |
|     label=sas_buffer+5;
 | |
|     sas_buffer[5]=0;
 | |
|     if(sscanf(sas_buffer+1,"%u",&output)!=1) {
 | |
|       return;
 | |
|     }
 | |
|     sql=QString("select NUMBER from OUTPUTS where ")+
 | |
|       "(STATION_NAME=\""+RDEscapeString(rda->station()->name())+"\")&&"+
 | |
|       QString().sprintf("(MATRIX=%d)&&",sas_matrix)+
 | |
|       QString().sprintf("(NUMBER=%d)",output);
 | |
|     q=new RDSqlQuery(sql);
 | |
|     if(q->first()) {
 | |
|       sql=QString("update OUTPUTS set ")+
 | |
| 	"NAME=\""+RDEscapeString(label)+"\" where "+
 | |
| 	"(STATION_NAME=\""+RDEscapeString(rda->station()->name())+"\")&&"+
 | |
| 	QString().sprintf("(MATRIX=%d)&&",sas_matrix)+
 | |
| 	QString().sprintf("(NUMBER=%d)",output);
 | |
|     }
 | |
|     else {
 | |
|       sql=QString("insert into OUTPUTS set ")+
 | |
| 	"NAME=\""+RDEscapeString(label)+"\","+
 | |
| 	"STATION_NAME=\""+RDEscapeString(rda->station()->name())+"\","+
 | |
| 	QString().sprintf("MATRIX=%d,",sas_matrix)+
 | |
| 	QString().sprintf("NUMBER=%d",output);
 | |
|     }
 | |
|     delete q;
 | |
|     q=new RDSqlQuery(sql);
 | |
|     delete q;
 | |
|     break;
 | |
| 
 | |
|   case 'M':    // Console Module Action
 | |
|     if(strlen(sas_buffer)<9) {
 | |
|       return;
 | |
|     }
 | |
|     cmd=QString(sas_buffer);
 | |
|     console=cmd.mid(2,3).toInt(&ok);
 | |
|     if(!ok) {
 | |
|       return;
 | |
|     }
 | |
|     source=cmd.mid(5,4).toInt(&ok);
 | |
|     if(!ok) {
 | |
|       return;
 | |
|     }
 | |
|     for(unsigned i=0;i<sas_console_numbers.size();i++) {
 | |
|       if((console==sas_console_numbers[i])&&(source==sas_source_numbers[i])) {
 | |
| 	action=cmd.mid(1,1).toUInt(&ok);
 | |
| 	if(!ok) {
 | |
| 	  return;
 | |
| 	}
 | |
| 	switch(action) {
 | |
| 	case 0:    // Module OFF
 | |
| 	  emit gpiChanged(sas_matrix,i,false);	  
 | |
| 	  break;
 | |
| 
 | |
| 	case 1:    // Module ON
 | |
| 	  emit gpiChanged(sas_matrix,i,true);	  
 | |
| 	  break;
 | |
| 
 | |
| 	case 2:    // Cue OFF
 | |
| 	  break;
 | |
| 
 | |
| 	case 3:    // Cue ON
 | |
| 	  break;
 | |
| 	}
 | |
|       }
 | |
|     }
 | |
|     break;
 | |
| 
 | |
|   case 'Z':    // Opto/Relay Tally Update
 | |
|     if(strlen(sas_buffer)<9) {
 | |
|       return;
 | |
|     }
 | |
|     cmd=QString(sas_buffer);
 | |
|     line=cmd.mid(4,4).toInt(&ok);
 | |
|     if(!ok) {
 | |
|       return;
 | |
|     }
 | |
|     state=cmd.right(1).toInt(&ok);
 | |
|     if(!ok) {
 | |
|       return;
 | |
|     }
 | |
|     for(unsigned i=0;i<sas_relay_numbers.size();i++) {
 | |
|       if(line==sas_relay_numbers[i]) {
 | |
| 	switch(cmd.mid(1,2).toInt()) {
 | |
| 	case 0:   // Opto
 | |
| 	  emit gpiChanged(sas_matrix,i,state);
 | |
| 	  break;
 | |
|       
 | |
| 	case 1:   // Relay
 | |
| 	  emit gpoChanged(sas_matrix,i,state);
 | |
| 	  break;
 | |
| 	}
 | |
|       }
 | |
|     }
 | |
|     break;
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| void SasUsi::ExecuteMacroCart(unsigned cartnum)
 | |
| {
 | |
|   RDMacro rml;
 | |
|   rml.setRole(RDMacro::Cmd);
 | |
|   rml.setCommand(RDMacro::EX);
 | |
|   rml.setAddress(rda->station()->address());
 | |
|   rml.setEchoRequested(false);
 | |
|   rml.addArg(cartnum);
 | |
|   emit rmlEcho(&rml);
 | |
| }
 | |
| 
 | |
| 
 | |
| QString SasUsi::PrettifyCommand(const char *cmd) const
 | |
| {
 | |
|   QString ret;
 | |
|   if(cmd[0]<26) {
 | |
|     ret=QString().sprintf("^%c%s",'@'+cmd[0],cmd+1);
 | |
|   }
 | |
|   else {
 | |
|     ret=cmd;
 | |
|   }
 | |
|   return ret;
 | |
| }
 |